#include "libscl.h"
using namespace std;
using namespace scl;

class rosenbrock : public nleqns_base { //see Fletcher p. 7
public:
bool get_f(const realmat& x, realmat& f) 
{
  if (x.nrow()!=2) error("Error, rosenbrock, wrong dim for x");
  if (f.nrow()!=1) f.resize(1,1);
  f[1] = 100.0*pow(x[2] - pow(x[1],2),2) + pow(1.0 - x[1],2);
  return true;
}
bool get_F(const realmat& x, realmat& f, realmat& F)
{
  if (x.nrow()!=2) error("Error, rosenbrock, wrong dim for x");
  if (f.nrow()!=1) f.resize(1,1);
  if (F.nrow()!=1 || F.ncol()!=2) F.resize(1,2);
  f[1] = 100.0*pow(x[2] - pow(x[1],2),2) + pow(1.0 - x[1],2);
  F(1,1) = -400.0*(x[2] - pow(x[1],2))*x[1] - 2.0*(1.0 - x[1]);
  F(1,2) = 200.0*(x[2] - pow(x[1],2));
  return true;
}
};

int main(int argc, char *argp[], char *envp[])
{
  std::cerr << "Warning: " << *argp << " writes to tstnlopt.out, the usage\n"
              << "         " << *argp << "> tstnlopt.out is incorrect\n";
  rosenbrock rb;
  nlopt minimizer(rb);
  ofstream os("tstnlopt.out");
  minimizer.set_output(true, &os);
  minimizer.set_check_derivatives(true);
  minimizer.set_warning_messages(true);
  realmat x_start(2,1,0.0); realmat x_stop;
  if (minimizer.minimize(x_start, x_stop)) {
    os << starbox("/The Answer!//") << x_stop << '\n'; 
    os << starbox("/Status//") << '\n';
    os << "\t termination_code = " << minimizer.get_termination_code() << '\n';
    os << "\t iter_count = " << minimizer.get_iter_count() << '\n';
    os << "\t H = " << minimizer.get_H_matrix() << '\n';
  return 0;
  }
  else {
    os << starbox("/Failure/Check your derivatives!//"); 
    return 1;
  }
}
