#include "libscl.h"

using namespace std;
using namespace scl;

class nleqns : public nleqns_base {
public:
  bool get_f(const realmat& x, realmat& f) {
    if (x.nrow() != 2) error("Error, nleqns, wrong dimension for x");
    if (f.nrow() != 2)f.resize(2,1);
    f[1] = 2.0 - exp(1.0*x[1] + 1.0*x[2]);
    f[2] = 2.0 - exp(2.0*x[2]);
    return true;
  }
  bool get_F(const realmat& x, realmat& f, realmat& F)
  {
    if (! this->get_f(x,f) ) return false;
    if ((F.nrow() !=2)||(F.ncol()!=2)) F.resize(2,2);
    F(1,1) = f[1]-2.0; F(1,2) = f[2]-2.0;
    F(2,1) = 0.0;      F(2,2) = 2.0*(f[2]-2.0);
    return true;
  }
};

class nleqns_df : public nleqns_base {
public:
  bool get_f(const realmat& x, realmat& f) {
    if (x.nrow() != 2) error("Error, nleqns, wrong dimension for x");
    if (f.nrow() != 2)f.resize(2,1);
    f[1] = 2.0 - exp(1.0*x[1] + 1.0*x[2]);
    f[2] = 2.0 - exp(2.0*x[2]);
    return true;
  }
  bool get_F(const realmat& x, realmat& f, realmat& F)
  {
    if (! this->get_f(x,f) ) return false;
    return nleqns_base::df(x,F);
  }
};

int main(int argc, char** argp, char** envp)
{
  ofstream out_stream("nlsdemo.out");

  out_stream << starbox("/Using analytic derivatives//");

  nleqns exp_eqns;
  nlsolve solver(exp_eqns);

  solver.set_output(true, &out_stream);
  solver.set_check_derivatives(true);
  solver.set_warning_messages(true);

  realmat x_start(2,1,0.0); realmat x_stop;
  if (solver.solve(x_start, x_stop)) {
    out_stream << starbox("/The Answer!//") << x_stop; 
  }
  else {
   out_stream << starbox("/Failure!//"); 
  }

cerr << "Got to here #1 \n";

  #if defined GNU_GPP_COMPILER

  x_start[1] = 0.0;
  x_start[2] = -3.0;
  if (solver.solve(x_start, x_stop)) {
    out_stream << starbox("/The Answer!//") << x_stop; 
  }
  else {
   out_stream << starbox("/Failure!//"); 
  }

cerr << "Got to here #2 \n";

  #endif

out_stream << "Got to here #1 \n";

  out_stream << starbox("/Using numerical differentiator df//");
  
  nleqns_df exp_eqns_df;
  nlsolve solver_df(exp_eqns_df);

  solver_df.set_output(true, &out_stream);
  solver_df.set_check_derivatives(true);
  solver_df.set_warning_messages(true);

  realmat x_start_df(2,1,0.0); realmat x_stop_df;
  if (solver_df.solve(x_start_df, x_stop_df)) {
    out_stream << starbox("/The Answer!//") << x_stop_df; 
  }
  else {
   out_stream << starbox("/Failure!//"); 
  }

  out_stream << solver_df.get_norm_f() << '\n';
  out_stream << solver_df.get_rank_F() << '\n';
  out_stream << solver_df.get_iter_count() << '\n';

  return 0;

}
