/* nag_opt_bounds_no_deriv (e04jbc) Example Program
 *
 * Copyright 2013 Numerical Algorithms Group.
 *
 * This example program demonstrates how to replace a call
 * of e04jbc by a call of e04ucc. If you compile the example
 * with the preprocessor macro E04JBC defined, it will call
 * the superseded function e04jbc; otherwise it will call
 * e04ucc. See mentions of E04JBC in the code below.
 *
 */

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

#ifdef E04JBC
  static void objfun(Integer n, double x[], double *f,
                     double g[], Nag_Comm *comm);
#else
  static void objfun(Integer n, const double x[], double *objf,
                     double g[], Nag_Comm *comm);
#endif

int main(void)
{
  Integer exit_status=0, n;
  Integer nclin, ncnlin;
  NagError fail;
#ifdef E04JBC
  Nag_BoundType bound;
#endif
  Nag_E04_Opt options;

  double *bl=0, *bu=0, *g=0, objf, *x=0;
  double a[1];


  INIT_FAIL(fail);
  Vprintf("e04jbc Example Program Results.\n");
  n = 4;
  if (n>=1)
    {
      if ( !( x = NAG_ALLOC(n, double)) ||
           !( g = NAG_ALLOC(n, double)) ||
           !( bl = NAG_ALLOC(n, double)) ||
           !( bu = NAG_ALLOC(n, double)) ) 
        {
          Vprintf("Allocation failure\n");
          exit_status = -1;
          goto END;
        }
    }
  else
    {
      Vprintf("Invalid n.\n");
      exit_status = 1;
      return exit_status;
    }
  x[0] = 3.0;
  x[1] = -1.0;
  x[2] = 0.0;
  x[3] = 1.0;

  /* Set bounds on variables */
#ifdef E04JBC
  bound = Nag_Bounds;
#endif
  bl[0] = 1.0;
  bu[0] = 3.0;
  bl[1] = -2.0;
  bu[1] = 0.0;
  /* x[2] is not bounded, so we set bl[2] to a large negative
   * number and bu[2] to a large positive number
   */
  bl[2] = -1.0e10;
  bu[2] = 1.0e10;
  bl[3] = 1.0;
  bu[3] = 3.0;

  /* Call optimization routine */
#ifdef E04JBC
  e04jbc(n, objfun, bound, bl, bu, x, &objf,
         g, E04_DEFAULT, NAGCOMM_NULL, &fail);

  if (fail.code != NE_NOERROR)
    {
      Vprintf("Error/Warning from e04jbc.\n%s\n", fail.message);
      if (fail.code != NW_COND_MIN)
        exit_status = 1;
      goto END;
    }
#else
  /* Initialize and set options. */
  e04xxc(&options);

  /* State that our objfun does not compute derivatives of
     objective or constraints */
  options.obj_deriv = Nag_FALSE;
  options.con_deriv = Nag_FALSE;

  /* Accuracy required in objective function */
  options.optim_tol = 1.0e-5;

  /* Print full iterations and solution. */
  options.print_level = Nag_Soln_Iter_Full;

  /* Perform a maximum of 40 iterations */
  options.max_iter = 40;

  /* Estimate that the minimum lies within 4 units of start */
  options.step_limit = 4.0;

  /* Solve the problem. */
  nclin=0;
  ncnlin=0;

  e04ucc(n, nclin, ncnlin, a, 1, bl, bu, objfun, NULLFN, x, &objf,
         g, &options, NAGCOMM_NULL, &fail);

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

  e04xzc(&options, "all", &fail);
  if (fail.code != NE_NOERROR)
    {
      Vprintf("Memory freeing failed.\n%s\n", fail.message);
      exit_status = 1;
    }
#endif
 END:
  if (x) NAG_FREE(x);
  if (g) NAG_FREE(g);
  if (bl) NAG_FREE(bl);
  if (bu) NAG_FREE(bu);
  return exit_status;

}

#ifdef E04JBC
static void objfun(Integer n, double x[], double *objf,
                   double g[], Nag_Comm *comm)
#else
static void objfun(Integer n, const double x[], double *objf,
                   double g[], Nag_Comm *comm)
#endif
{
  /* Routine to evaluate objective function. */

  double a, b, c, d, x1, x2, x3, x4;

  x1 = x[0];
  x2 = x[1];
  x3 = x[2];
  x4 = x[3];

  /* Supply a single function value */
  a = x1 + 10.0*x2;
  b = x3 - x4;
  c = x2 - 2.0*x3, c *= c;
  d = x1 - x4, d *= d;
  *objf = a*a + 5.0*b*b + c*c + 10.0*d*d;
} /* objfun */