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

#include <iostream>
#include <armadillo>
#include <vector>
#include <memory>
#include <iostream>
#include <limits>

#include <boost/multiprecision/cpp_bin_float.hpp>
#define ERR_PREC boost::multiprecision::cpp_bin_float_quad
#define TYPE double

//#define MIN_ERR_EXP -11
#define MIN_ERR_EXP -9
#define MAX_ERR_EXP -2
#define NUM_SAMPLES 30

//#define MIN_ERR_EXP -4
//#define NUM_SAMPLES 15

template <typename TIN, typename TERR>
void compare(std::vector<std::string> implNames, double step, unsigned nTests, unsigned nEvals, unsigned seed){
  using namespace func;
  LookupTableGenerator<TIN> gen({FUNC_SET_F(MyFunction,TIN)}, MIN_ARG, MAX_ARG);
  std::vector<std::unique_ptr<LookupTable<TIN>>> impls;
  for(auto name : implNames)
    impls.emplace_back(gen.generate_by_tol(name, step));
  LookupTableComparator<TIN> implCompare(impls, MIN_ARG, MAX_ARG, nEvals, seed);
  implCompare.run_timings(nTests);
  implCompare.compute_statistics();
  implCompare.print_csv(std::cout, Sorter::MEAN);
}

/*
  Uses the LookupTableGenerator class to compute errors for varying table step sizes
  Or, will plot a collection of LUTs against a direct evaluation
*/
int main(int argc, char* argv[]) {
  using namespace func;

  if(argc != 5){
    std::cout << "usage:\n";
    std::cout << argv[0] << " <filename> <nTests> <nEvals> <seed>" << std::endl;
    return 1;
  }
  std::ifstream implNameFile(argv[1]);
  unsigned nTests = std::stoi(argv[2]);
  unsigned nEvals = std::stoi(argv[3]);
  unsigned seed   = std::stoi(argv[4]);

  std::string name; std::vector<std::string> implNames;
  while(getline(implNameFile,name))
    implNames.push_back(name);
  implNameFile.close();

  std::cout << FUNCNAME << " over [" << MIN_ARG << ", " << MAX_ARG << "]\n";
  // print each implementation name in one long row
  std::cout << "Error |Time (s)" << "\n";
  for(auto name : implNames)
    std::cout << name << " ";
  std::cout << "\n";

  arma::vec errors = arma::logspace(MIN_ERR_EXP, MAX_ERR_EXP, NUM_SAMPLES);
  std::cerr << "plotting " << errors.n_elem << " operator() times\n";
  for(double err : errors){
    std::cout << err << " "; compare<TYPE,ERR_PREC>(implNames,err,nTests,nEvals,seed);
    std::cerr << "computed err=" << err << "\n";
    std::cout << std::endl;
  }
}
