public class GlobalOptimization
{
  // Declaration of C native function, NAG routine e05jbf
  private native int e05jbf(int n, String objfun, int ibound, int iinit,
                            double[] bl, double[] bu, int sdlist, double[] list,
                            int[] numpts, int[] initpt, String monit, 
                            double[] x, double[] obj, double[] comm, int lcomm,
                            int[] iuser, double[] ruser);

  // An interface to e05jaf, an initialisation routine for e05jbf
  private native int e05jaf(int n, double[] comm, int lcomm);

  static
  {
    System.loadLibrary("nagCJavaInterface");
  }

  /* A routine to evaluate the objective function F(x).
     This gets called from NAG routine e05jbf via the Java Native
     Interface */
  private double objfun(int n, double[] x, double f, int nstate,
                        int[] iuser, double[] ruser, int inform)
  {
    double x1, x2;
    
    if (nstate==1)
      {
        /* This is the first call to objfun */
        System.out.println(" (objfun was just called for the first time)");
        System.out.println();
      }
    x1 = x[0];
    x2 = x[1];
    f = 3.0*java.lang.Math.pow((1.0-x1),2.0)*java.lang.Math.exp(-java.lang.Math.pow(x1,2.0)-java.lang.Math.pow((x2+1),2.0)) -
        10.0*(x1/5.0-java.lang.Math.pow(x1,3.0)-java.lang.Math.pow(x2,5.0))*java.lang.Math.exp(-java.lang.Math.pow(x1,2.0)-java.lang.Math.pow(x2,2.0)) -
        1.0/3.0*java.lang.Math.exp(-java.lang.Math.pow((x1+1.0),2.0)-java.lang.Math.pow(x2,2.0));
  
  return f;
  }

  /* A routine to monitor the minimization process.
     This gets called from NAG routine e05jbf via the
     Java Native Interface. */
  private int monit(int n, int ncall, double[] xbest, int[] icount, int ninit,
                    double[] list, int[] numpts, int[] initpt, int nbaskt,
                    double[] xbaskt, double[] boxl, double[] boxu, int nstate,
                    int[] iuser, double[] ruser, int inform)
  {
    int i, iplot, j;

    inform = 0;

    iplot = iuser[0];

    if (nstate==0 || nstate==1)
      {
        /* When nstate=1, monit is called for the first time. 
           When nstate=0, monit is called for the first AND last time.
           Display a welcome message */
            
        System.out.println(" *** Begin monitoring information ***");
        System.out.println();
        
        if (iplot==1 && n==2)
          System.out.println(" <Begin displaying search boxes>");
      }
        
    if (iplot==1 && n==2)
      {
        /* Display the coordinates of the edges of the current 
           search box */
        System.out.println(boxl[0] + " " + boxl[1]);
        System.out.println(boxl[0] + " " + boxu[1]);
        System.out.println();
        System.out.println(boxl[0] + " " + boxl[1]);
        System.out.println(boxu[0] + " " + boxl[1]);
        System.out.println();
        System.out.println(boxl[0] + " " + boxu[1]);
        System.out.println(boxu[0] + " " + boxu[1]);
        System.out.println();
        System.out.println(boxu[0] + " " + boxl[1]);
        System.out.println(boxu[0] + " " + boxu[1]);
      }
    if (nstate<=0)
      {
        /* monit is called for the last time */
        if (iplot==1 && n==2)
          System.out.println(" <End displaying search boxes>");
        
        System.out.println(" Total sub-boxes = " + icount[0]);
        System.out.println(" Total function evaluations = " + ncall);
        System.out.println(" Total function evaluations used in local search = " + icount[1]);
        System.out.println(" Total points used in local search = " + icount[2]);
        System.out.println(" Total sweeps through levels = " + icount[3]);
        System.out.println(" Total splits by init. list = " + icount[4]);
        System.out.println(" Lowest level with nonsplit boxes = " + icount[5]);
        System.out.println(" Number of candidate minima in the 'shopping basket' = " + nbaskt);
        System.out.println(" Shopping backet:");
        for(i=0;i<n;i++)
          {
            for(j=0;j<nbaskt;j++)
              System.out.println(" xbaskt["+i+","+j+"] = " + xbaskt[j*n + i]);
          }
        System.out.println();
        System.out.println(" *** End monitoring information ***");
      }
    return inform;
  }

  // Main program
  public static void main(String args[])
  {

    GlobalOptimization nlp = new GlobalOptimization();

    // Pass the names of the objective function evaluation and 
    // the monitoring routines.
    nlp.Solve("objfun", "monit");
  }

  private void Solve(String objfunction, String monitrt)
  {
    // n -- the number of variables
    int n = 2;

    // sdlist -- the second dimension of the array list
    int sdlist = 3;

    // ibound -- indicates whether the facility for dealing with
    //           bounds of special forms is to be used
    int ibound = 0;  // supply l and u individually

    // bl[n] -- lower bounds for all the variables
    double[] bl = {-3.0, -3.0};

    // bu[n] -- upper bounds for all the variables
    double[] bu = {3.0, 3.0};

    // iinit -- selects which initialization method to use
    int iinit = 0;   // simple initialization

    // list --  the 'initialization list': whenever a sub-box in the algorithm
    //          is split for the first time, for each coordinate i the split 
    //          is done at the first numpts[i] values in row i of list, 
    //          as well as at some adaptively chosen intermediate points
    double[] list;
    int[] numpts, initpt;
    list = new double[n*sdlist];  // these three parameters
    numpts = new int[n];          // need not be set on entry
    initpt = new int[n];          // if iinit!=3

    // x -- contains an estimate of the global optimum
    double[] x = new double[n];

    // obj[1] -- an array of length 1 to hold the final objective
    // function value computed by e05jbf
    double[] obj = new double[1];

    // ifail -- output error variable.
    int ifail;

    int i;

    // lcomm -- the dimension of the array comm
    int lcomm = 100;
    // comm -- communication array
    double[] comm = new double[lcomm];

    // iuser -- may be used to pass information to and from objfun 
    //          and monit routines 
    int[] iuser = new int[1];

    // lplot -- determines whether monit displays information on 
    //          the current search box
    boolean lplot = false;

    if (lplot)
      {
        iuser[0] = 1;
      }
    else
      {
        iuser[0] = 0;
      }
    
    // ruser -- may be used to pass information to and from objfun 
    //          and monit routines 
    double[] ruser = new double[1];


    // Initialize e05jbf
    ifail = e05jaf(n,comm,lcomm);
    if (ifail == 0 )
      {
        System.out.println();
        System.out.println(" Routine e05jbf has been initialised by e05jaf.");
        System.out.println(" ----------------------------------------------");
        System.out.println();
        System.out.println(" Running e05jbf example program from Java");
        System.out.println(" ----------------------------------------");
        System.out.println(" Problem:");
        System.out.println();
        System.out.println("   Find global minimum of the 'peaks' function:");
        System.out.print("   F(x,y) = 3*(1-x)^2*exp(-x^2-(y+1)^2)-10(x/5-x^3-y^5)");
        System.out.println("*exp(-x^2-y^2)");
        System.out.println("            -1/3*exp(-(x+1)^2-y^2)");
        System.out.print("   on the box [" + bl[0] + "," + bu[0] + "]x[");
        System.out.println(bl[1] + "," + bu[1] + "]");    
        System.out.println();

        // Call the NAG Library routine e05jbf via the Java Native Interface
        ifail = e05jbf(n,objfunction,ibound,iinit,bl,bu,sdlist,list,numpts,
                       initpt,monitrt,x,obj,comm,lcomm,iuser,ruser);
        
        // Output some results
        System.out.println();
        System.out.println(" Results returned by NAG global optimization routine e05jbf");
        System.out.println(" -----------------------------------------------------------");
        System.out.println(" Fail code ifail = " + ifail);
        if (ifail == 0)
          {
            System.out.println(" Final objective function value = " + obj[0]);
            System.out.print(" Global optimum x: ");
            for (i = 0; i < n; i++)
              System.out.print(x[i] + " ");
            System.out.println();
          }
      }
  }
}
