/* test_newinterp.cc
 * Daniel S. Roche, January 2011
 * See COPYING.txt for permissions.
 *
 * Simple tests for the approximate interpolation algorithm
 */

#include <iostream>
#include <NTL/ZZ.h>
#include "blackbox.h"
#include "newinterp.h"

using namespace NTL;
using namespace std;

typedef double Ftype;

int main (int argc, char** argv) {
  cout << "********************************************************************************" << endl
       << "                             NEW INTERPOLATION TEST" << endl
       << "********************************************************************************" << endl;
  ZZ D;
  long T;
  unsigned long which;

  cout.precision(2);

  if (argc >= 2) which = strtoul(argv[1],NULL,2);
  else which = 7;

  if (which <= 0 || which > 7 || argc == 3 || argc > 4 ) {
    cout << "Usage: " << argv[0] << " [which-tests [degree-bound sparsity-bound]]" << endl
         << "\twhich-tests indicates which algorithms to test among:" << endl
         << "\t\t0: New method A" << endl
         << "\t\t1: New method B" << endl
         << "\tby writing 1 for that bit. So e.g. 10 means test New B only."
         << endl;
    return 1;
  }

  if (argc == 4) {
    conv(D,argv[2]);
    T = strtol(argv[3],NULL,10);
  }
  else {
    conv(D,"1000000");
    T = 5;
    cout << "D = " << D << " ; T = " << T << endl;
  }

  Ftype machinepres = manbits<Ftype>();
  cout << "Machine precision: " << machinepres << endl;

  randseed();
  //ullseed(0xae5bd9cda8e678dc);
  Ftype epsilon = .00000000001;

  RandomGen<Ftype> rg (1.0,5.0);
  vector< complex<Ftype> > g;
  random(g,10,rg);
  cout << "g: " << g << endl;
  cout << "0.1-diverse bound: " << diversity_bound(g,(Ftype)0.1,10) << endl;
  cout << "1-diverse bound: " << diversity_bound(g,(Ftype)1.0,10) << endl;

  SparsePoly<Ftype> f;
  random (f,D,T,rg);
  cout << "orig\t" << f << endl;

  cout << "abs(orig) = [ ";
  for (size_t i = 0; i < f.rep.size(); ++i) cout << abs(f.rep[i].first) << ' ';
  cout << ']' << endl << endl;

  FakeApproxBB<Ftype> bb(f, epsilon);

  Ftype realnorm = norm(f);
  Ftype anorm = approxnorm(bb,D,T);
  cout << "norm(f) = " << realnorm << "; approximation off by " << abs(anorm-realnorm) << endl;

  if (which & 1) {
    cout << "========================== New method A  =======================================" << endl;
    SparsePoly<Ftype> out;
    if (new_interpA (out, bb, D, T) ) {
      Ftype relerr = diffnorm(f,out)/realnorm;
      cout << out << endl;
      cout << "Relative error: " << relerr << endl;
      if (relerr > 4.0*epsilon) {
        cout << "FAIL" << endl;
        return 1;
      }
    }
    else {
      cout << "KNOWN FAIL" << endl;
      return 1;
    }
  }

  cout << "SUCCESS" << endl;
  return 0;
}

