/* nag_opt_simplex_easy (e04cbc) Example Program.
 *
 * Copyright 2014 Numerical Algorithms Group.
 *
 * Mark 9 revised, 2009.
 */

#include <nag.h>
#include <math.h>
#include <stdio.h>
#include <nag_stdlib.h>
#include <nage04.h>
#include <nagx02.h>

#ifdef __cplusplus
extern "C" {
#endif
static void NAG_CALL funct(const Integer n, const double *xc, double *fc,
                           Nag_Comm *comm);
static void NAG_CALL monit(const double fmin, const double fmax,
                           const double sim[], const Integer n,
                           const Integer ncall, const double serror,
                           const double vratio, Nag_Comm *comm);
#ifdef __cplusplus
}
#endif

int main(void)
{
  /* Scalars */
  double      f, tolf, tolx;
  Integer     exit_status, i, monitoring, maxcal = 100, n = 2;
  NagError    fail;

  /* Arrays */
  static double ruser[2] = {-1.0, -1.0};
  double      *x = 0;

  Nag_Comm    comm;

  exit_status = 0;

  INIT_FAIL(fail);

  printf("nag_opt_simplex_easy (e04cbc) Example Program Results\n");

  /* For communication with user-supplied functions: */
  comm.user = ruser;

  /* Allocate memory */
  if (!(x = NAG_ALLOC(n, double)))
    {
      printf("Allocation failure\n");
      exit_status = -1;
      goto END;
    }

  /* Set monitoring to a nonzero value to obtain monitoring information */
  monitoring = 0;
  comm.p = (Pointer)&monitoring;

  /* Starting values */
  x[0] = -1.0;
  x[1] = 1.0;
  tolf = sqrt(nag_machine_precision);
  tolx = sqrt(tolf);

  nag_opt_simplex_easy(n, x, &f, tolf, tolx, funct, monit, maxcal, &comm,
                       &fail);

  if (fail.code != NE_NOERROR)
    {
      printf("Error from nag_opt_simplex_easy (e04cbc).\n%s\n", fail.message);
      exit_status = 1;
      goto END;
    }

  printf("The final function value is %12.4f\n", f);
  printf("at the point");
  for (i = 1; i <= n; ++i)
    {
      printf(" %12.4f", x[i-1]);
    }
  printf("\n");

 END:
  NAG_FREE(x);

  return exit_status;
}

static void NAG_CALL funct(const Integer n, const double *xc, double *fc,
                           Nag_Comm *comm)
{
  if (comm->user[0] == -1.0)
    {
      printf("(User-supplied callback funct, first invocation.)\n");
      comm->user[0] = 0.0;
    }
  *fc = exp(xc[0])*(4.0*xc[0]*(xc[0]+xc[1])+2.0*xc[1]*(xc[1]+1.0)+1.0);
}

static void NAG_CALL monit(const double fmin, const double fmax,
                           const double sim[], const Integer n,
                           const Integer ncall, const double serror,
                           const double vratio, Nag_Comm *comm)
{
#define SIM(I, J) sim[(J-1)*(n+1) + (I-1)]

  Integer     i, j;
  Integer monitoring = *(Integer *)comm->p;

  if (comm->user[1] == -1.0)
    {
      printf("(User-supplied callback monit, first invocation.)\n");
      comm->user[1] = 0.0;
    }
  if (monitoring != 0)
    {
      printf("\nThere have been %5ld function calls\n", ncall);
      printf("The smallest function value is %10.4f\n", fmin);
      printf("\nThe simplex is\n");
      for (i = 1; i <= n+1; ++i)
        {
          for (j = 1; j <= n; ++j)
            {
              printf(" %13.4e", SIM(i, j));
            }
          printf("\n");
        }
      printf("\nThe standard deviation in function values at the"
              " vertices of the simplex is %10.4f\n", serror);
      printf("The linearized volume ratio of the current simplex"
              " to the starting one is %10.4f\n", vratio);
    }
}