/*
  Compare FailureProofTable against a raw LUT and raw function

  Usage:
      ./experiment <tableTol> <nExperiments> <nEvals> <seed>
 */

#include <iostream>
#include <func/func.hpp>
#include "../sample_functions/gamma.hpp"
#include <armadillo>

#define xstr(s) str(s)
#define str(s) #s

#define TYPE double
#define TABLE_NAME UniformChebyInterpTable
//#ifndef TABLE_DEGREE
//#define TABLE_DEGREE 3
//#endif
#define TABLE_TYPE TABLE_NAME<TABLE_DEGREE,TYPE>

//---------------------------------------------------------------------------->>
int main(int argc, char* argv[])
{
  if (argc != 6) {
    std::cout << "Usage:" << std::endl
    << argv[0] << " <Bytes> <nTables> <nExperiments> <nEvals> <seed>"
    << std::endl;
    exit(0);
  }

  unsigned int B            = std::stoi(argv[1]);
  unsigned int nTables      = std::stoi(argv[2]);
  unsigned int nExperiments = std::stoi(argv[3]);
  unsigned int nEvals       = std::stoi(argv[4]);
  unsigned int seed         = std::stoi(argv[5]);

  using namespace func;
  FunctionContainer<TYPE> fc {FUNC_SET_F(MyFunction,TYPE)};

  //std::cout << FUNCNAME << " over [" << MIN_ARG << ", " << MAX_ARG << "]\n";

  LookupTableGenerator<TYPE,TYPE> gen({FUNC_SET_F(MyFunction,TYPE)},MIN_ARG,MAX_ARG);
  TYPE step = (gen.generate_by_impl_size(xstr(TABLE_NAME) "<" xstr(TABLE_DEGREE) ">", B))->step_size();

  /* Fill in the implementations */
  std::vector<std::unique_ptr<LookupTable<TYPE>>> impls;
  impls.emplace_back(std::unique_ptr<LookupTable<TYPE>>( new DirectEvaluation<TYPE>(fc,MIN_ARG,MAX_ARG)) );
  impls.emplace_back(std::unique_ptr<LookupTable<TYPE>>( new TABLE_TYPE(fc, {MIN_ARG, MAX_ARG, step}))     );

  arma::vec percentages = arma::linspace(0.0, 1.0, nTables);
  for(double percent : percentages){
    impls.emplace_back(std::unique_ptr<LookupTable<TYPE>>(
        new FailureProofTable<TABLE_TYPE>(fc,
          {MIN_ARG, MAX_ARG + percent*(MIN_ARG-MAX_ARG), step}
        )));
  }

  std::cerr << "Running timings ...\n";
  LookupTableComparator<TYPE> implCompare(impls, MIN_ARG, MAX_ARG, nEvals, seed);
  implCompare.run_timings(nExperiments);

  /* Summarize the results */
  std::cout << "# Function:  " << FUNCNAME << "\n";
  std::cout << "# Range:     (" << MIN_ARG << "," << MAX_ARG << ")\n";

  // Not reordering because there's no way to distinguish between each
  // failureprooftable other than its position in the list
  implCompare.compute_statistics();
  implCompare.print_csv(std::cout);
  //implCompare.print_json(std::cout);
}
