//---------------------------------------------------------------------------
// ŠNikolai V. Shokhirev, 2004-2008  <nikolai@shokhirev.com> http://www.shokhirev.com/nikolai.html
// Reduced demo version
//---------------------------------------------------------------------------
#include <string>
#include "GenTests.h"
#include "MathUtils.h"
#include "Complex.h"
#include "StringUtils.h"

//---------------------------------------------------------------------------

using namespace std;

string MachepsTest()
{
  string ss = ">Macheps = ";
  real eps1, meps, eps = 1.0;
//  while ((1.0+eps)> 1.0){ meps = eps; eps /= 2.0; };
  do {meps = eps; eps /= 2.0; eps1 = eps + 1.0;} while (eps1 > 1.0);
  string s = ToString(meps);
  ss += s;

  eps = 1.0;
  do {meps = eps; eps /= 2.0;} while (eps > 0.0);
  s = ToString(meps);
  ss += "\n>MinDoube = ";
  ss += s;

  eps = 1.0;
  meps = 2097152.0;
  do {meps /= 2.0; eps /= 2.0;} while (eps > 0.0);
  s = ToString(meps);
  ss += "\n>SafeMinDoube = ";  // 1048576*MinDoube
  ss += s;
  return ss;
}

string ComplexTest()
{
  string s = "", ss = "Complex Test";
  bool fail = false;

  Complex c0;
  if (! Equal(c0, 0.0, 0.0)) { fail = true; s += " constructor 0 |"; };

  Complex c1(2.3);
  if (! Equal(c1, 2.3, 0.0)) { fail = true; s += " constructor 1 |"; };

  Complex c2(3.3,3.2);
  if (! Equal(c2, 3.3, 3.2)) { fail = true; s += " constructor 2 |"; };

  c0 = 2.2;
  if (! Equal(c0, 2.2, 0.0)) { fail = true; s += " real assignment |"; };

  c1.Im = 1.1; c0 = c1;  c2 = Complex(3.3, 3.2);
  if (! Equal(c0, 2.3, 1.1) || ! Equal(c2, 3.3, 3.2)) { fail = true; s += " complex assignment |"; };

  c0 = c1 = c2;
  if (! Equal(c0, c2) || !Equal(c1, c2)) { fail = true; s += " chain assignment |"; };

  c0 = c2 + 1.1;  c1 = 1.1 + c2;
  if (! Equal(c0, 4.4, 3.2) || !Equal(c1.Re, 4.4, 3.2)) { fail = true; s += "real addition |"; };

  c0 = c2 - 1.1;  c1 = 1.1 - c2;
  if (! Equal(c0, 2.2, 3.2) || !Equal(c1, -2.2, -3.2))  { fail = true; s += "real subtraction |"; };

  c0 = c2*2.0;  c1 = 2.0*c2;
  if (! Equal(c0, 6.6, 6.4) || !Equal(c1, 6.6, 6.4)) { fail = true; s += "real multiplication |"; };

  c0 = c0/2.0;  c1 = mod2(c1)/c1;
  if (! Equal(c0, c2) || !Equal(c1, 6.6, -6.4))  { fail = true; s += "real division |"; };

  c0 = -c2;  if (! Equal(-c0, c2) ) { fail = true; s += "unary minus |"; };

  c0 = +c2;  if (! Equal(+c0, c2) ) { fail = true; s += "unary plus |"; };

  c0 += c2; c1 = c2*2.0;
  if (! Equal(c0, c1) ) { fail = true; s += " += |"; };

  c0 = c2; c1 = c2*c0; c0 = c1/c2;
  if (! Equal(c0, c2) ) { fail = true; s += " complex * / |"; };

  c0 = Complex(2.2, 3.3);  c1 = Complex(4.4, 5.5);  c2 = c1 - c0;
  if (! Equal(c2, 2.2, 2.2) ) { fail = true; s += "complex addition/subtraction |"; };

  c0 = Complex(2.0, 3.0);  c1 = Complex(4.0, 5.0);  c2 = c1*c0;  c2 = c2/c1;
  if (! Equal(c0, c2) ) { fail = true; s += "complex multiplication/division |"; };

  if (fail) ss += " FAIL:" + s;
  else ss += " - OK";
  return ss;
};
/*
string MiscTests()
{
  FArr2D a2, a3;
  string s = "", ss = "Misc Tests";
  bool fail = false;
  int m = 2, n = 3;

  FArr2D a1(n,m);
  RandArr(a1,-1.0,1.0);
  a2 = MT(a1);
  a3 = MT(a2);

  if (! Equal(a3, a1) ) { fail = true;  s += " ( a^T )^T |"; };

  double y;
  y = sign( 2.2, 3.3);
  if (! Equal( 2.2, y) ) { fail = true;  s += " sign(2.2,3.3) |"; };
  y = sign(-2.2, 3.3);
  if (! Equal( 2.2, y) ) { fail = true;  s += " sign(-2.2,3.3) |"; };
  y = sign( 2.2,-3.3);
  if (! Equal(-2.2, y) ) { fail = true;  s += " sign(2.2,-3.3) |"; };
  y = sign(-2.2,-3.3);
  if (! Equal(-2.2, y) ) { fail = true;  s += " sign(-2.2,-3.3) |"; };

  y = max1(-2.2,3.3);
  if (! Equal(3.3, y) ) { fail = true;  s += " max1(-2.2,3.3) |"; };
  y = min1(-2.2,3.3);
  if (! Equal(-2.2, y) ) { fail = true;  s += " min1(-2.2,3.3) |"; };

  if (fail) ss += " FAIL:" + s;
  else ss += " - OK";
  return ss;
};

string DiffTests()
{
  string s = "", ss = "Derivative Tests";
  bool fail = false;

// function
  FArr1D f(-2,2);      // f(x)
  FArr1D f1(-2,2);     // f'(x)
  FArr1D f2(-2,2);     // f"(x)
  FArr1D f3(-2,2);     // f"'(x)
  FArr1D f4(-2,2);     // f(IV)(x)
// 5-point approximation
  FArr1D g1(-2,2);     // f(x)
  FArr1D g2(-2,2);     // f'(x)
  FArr1D g3(-2,2);     // f"(x)
  FArr1D g4(-2,2);     // f"'(x)
  double x = -2.0;     // f(IV)(x)

  for (int i=f.L1(); i<=f.H1();i++)
  {
    f(i)  = 1.0 + x + x*x + x*x*x + x*x*x*x;
    f1(i) =     1.0+2.0*x+3.0*x*x+4.0*x*x*x;
    f2(i) =           2.0 + 6.0*x +12.0*x*x;
    f3(i) =                   6.0  + 24.0*x;
    f4(i) =                            24.0;
    x+= 1.0;
  };
// x = -2
    g1(-2) = (-25.0*f(-2) +48.0*f(-1) -36.0*f(0) +16.0*f(1)- 3.0*f(2))/12.0;
    g2(-2) = (+35.0*f(-2)-104.0*f(-1)+114.0*f(0) -56.0*f(1)+11.0*f(2))/12.0;
    g3(-2) = ( -5.0*f(-2) +18.0*f(-1) -24.0*f(0) +14.0*f(1) -3.0*f(2))/2.0;
    g4(-2) = (  1.0*f(-2) - 4.0*f(-1) + 6.0*f(0) - 4.0*f(1)+ 1.0*f(2));
// x = -1
    g1(-1) = ( -3.0*f(-2) -10.0*f(-1) +18.0*f(0)  -6.0*f(1) +1.0*f(2))/12.0;
    g2(-1) = ( 11.0*f(-2) -20.0*f(-1)  +6.0*f(0) + 4.0*f(1) -1.0*f(2))/12.0;
    g3(-1) = ( -3.0*f(-2) +10.0*f(-1) -12.0*f(0) + 6.0*f(1) -1.0*f(2))/2.0;
    g4(-1) = (  1.0*f(-2) - 4.0*f(-1) + 6.0*f(0) - 4.0*f(1)+ 1.0*f(2));
// x = 0
    g1(0) = ( +1.0*f(-2)  -8.0*f(-1) + 0.0*f(0) + 8.0*f(1)- 1.0*f(2))/12.0;
    g2(0) = ( -1.0*f(-2) +16.0*f(-1) -30.0*f(0) +16.0*f(1)- 1.0*f(2))/12.0;
    g3(0) = ( -1.0*f(-2) + 2.0*f(-1) + 0.0*f(0) - 2.0*f(1)+ 1.0*f(2))/2.0;
    g4(0) = (  1.0*f(-2) - 4.0*f(-1) + 6.0*f(0) - 4.0*f(1)+ 1.0*f(2));
// x = 1
    g1(1) = ( -1.0*f(-2)  +6.0*f(-1) -18.0*f(0) +10.0*f(1) +3.0*f(2))/12.0;
    g2(1) = ( -1.0*f(-2)  +4.0*f(-1)  +6.0*f(0) -20.0*f(1)+11.0*f(2))/12.0;
    g3(1) = ( +1.0*f(-2) - 6.0*f(-1) +12.0*f(0) -10.0*f(1) +3.0*f(2))/2.0;
    g4(1) = (  1.0*f(-2) - 4.0*f(-1) + 6.0*f(0) - 4.0*f(1)+ 1.0*f(2));
// x = 2
    g1(2) = ( +3.0*f(-2) -16.0*f(-1) +36.0*f(0) -48.0*f(1)+25.0*f(2))/12.0;
    g2(2) = (+11.0*f(-2) -56.0*f(-1)+114.0*f(0)-104.0*f(1)+35.0*f(2))/12.0;
    g3(2) = ( +3.0*f(-2) -14.0*f(-1) +24.0*f(0) -18.0*f(1) +5.0*f(2))/2.0;
    g4(2) = (  1.0*f(-2) - 4.0*f(-1) + 6.0*f(0) - 4.0*f(1)+ 1.0*f(2));

  if ( ! Equal(g1, f1) ) { fail = true;   s += " d1 |"; };
  if ( ! Equal(g2, f2) ) { fail = true;   s += " d2 |"; };
  if ( ! Equal(g3, f3) ) { fail = true;   s += " d3 |"; };
  if ( ! Equal(g4, f4) ) { fail = true;   s += " d4 |"; };

  FArr1D p0(-3,3);
  FArr1D p1(-3,3);
  for (int i=-3; i<=3;i++) p0(i) = 1;
  Smooth5(p0,p1);
  if ( ! Equal(p1, p0) ) { fail = true;   s += " n=0 |"; };
  for (int i=-3; i<=3;i++) p0(i) = i;
  Smooth5(p0,p1);
  if ( ! Equal(p1, p0) ) { fail = true;   s += " n=1 |"; };
  for (int i=-3; i<=3;i++) p0(i) = i*i;
  Smooth5(p0,p1);
  if ( ! Equal(p1, p0) ) { fail = true;   s += " n=2 |"; };

  if (fail) ss += " FAIL:" + s;
  else ss += " - OK";
  return ss;
}
*/