
public class Minimization
{

  // Declaration of C native function, NAG routine e04ucf
  private native int e04ucf(int n, int nclin, int ncnln,
                            double[] a, int lda, double[] bl, double[] bu,
                            String confun, String objfun,
                            double[] objf, double[] objgrd, double[] x);

  // An interface to e04uef, an option setting routine for e04ucf
  private native void e04uef(String option);

  static
  {
    System.loadLibrary("nagCJavaInterface");
  }

  /* A routine to evaluate the nonlinear constraint functions and
     Jacobian. This gets called from NAG routine e04ucf via the
     Java Native Interface. N.B. cjac is stored as a 1D array
     rather than 2D array for convenience. */
  private void confun(int mode, int ncnln, int n, int ldcj,
                      int[] needc, double[] x, double[] c,
                      double[] cjac, int nstate)
  {
    if (nstate == 1)
      {
        // First call to confun. Set all Jacobian elements to zero.
        // Note that this will only work when 'Derivative Level = 3'
        // (the default (see Section 11.2).
        for (int j=0; j<n; j++)
          {
            for (int i=0; i<ncnln; i++)
              {
                // Notice how we address the array cjac so that contents
                // are in the order required by a 2D Fortran array.
                cjac[i+j*ldcj] = 0.0;
              }
          }
      }

    if (needc[0] > 0)
      {
        if (mode == 0 || mode == 2)
          {
            c[0] = x[0]*x[0] + x[1]*x[1] + x[2]*x[2] + x[3]*x[3];
          }
        if (mode == 1 || mode == 2)
          {
            cjac[0+0*ldcj] = 2.0e0*x[0];
            cjac[0+1*ldcj] = 2.0e0*x[1];
            cjac[0+2*ldcj] = 2.0e0*x[2];
            cjac[0+3*ldcj] = 2.0e0*x[3];
          }
      }

    if (needc[1] > 0)
      {
        if (mode == 0 || mode == 2)
          {
            c[1] = x[0]*x[1]*x[2]*x[3];
          }
        if (mode == 1 || mode == 2)
          {
            cjac[1+0*ldcj] = x[1]*x[2]*x[3];
            cjac[1+1*ldcj] = x[0]*x[2]*x[3];
            cjac[1+2*ldcj] = x[0]*x[1]*x[3];
            cjac[1+3*ldcj] = x[0]*x[1]*x[2];
          }
      }
  }

  /* A routine to evaluate the objective function and its gradient.
     This gets called from NAG routine e04ucf via the Java Native
     Interface */
  private double objfun(int mode, int n, double[] x,
                        double[] objgrd, int nstate)
  {
    double objf = 0.0;
    if (mode == 0 || mode == 2)
      {
        objf = x[0]*x[3]*(x[0]+x[1]+x[2]) + x[2];
      }

    if (mode == 1 || mode == 2)
      {
        objgrd[0] = x[3]*(2.0e0*x[0]+x[1]+x[2]);
        objgrd[1] = x[0]*x[3];
        objgrd[2] = x[0]*x[3] + 1.0e0;
        objgrd[3] = x[0]*(x[0]+x[1]+x[2]);
      }
    return objf;
  }

  // Main program
  public static void main(String args[])
  {

    Minimization nlp = new Minimization();

    // Pass the names of the constraint function and the objective
    // function evaluation routines.
    nlp.Solve("confun", "objfun");
  }

  private void Solve(String confunction, String objfunction)
  {

    // n -- the number of variables (excluding slacks)
    int n = 4;

    // nclin -- the number of linear constraints
    int nclin = 1;

    // ncnln -- the number of nonlinear constraints
    int ncnln = 2;

    // a[lda*n] -- array of linear constraints, where
    // lda = max(1, nclin). Although the NAG routine e04ucf
    // has A as a two dimensional matrix, for ease of access via the
    // Java Native Interface (JNI) it is much easier to store it as
    // a one dimensional array in Java. We still require the
    // value lda which Fortran will be told is the leading dimension
    // of its 2D array.
    int lda = java.lang.Math.max(1,nclin);
    double[] a;
    a = new double[lda*n];
    // a[i+j*lda] references array element a[i,j] in Fortran order.
    a[0+0*lda] = 1.0;
    a[0+1*lda] = 1.0;
    a[0+2*lda] = 1.0;
    a[0+3*lda] = 1.0;

    // bl[n+nclin+ncnln] -- lower bounds for all the variables and general constraints
    double[] bl = {1.0, 1.0, 1.0, 1.0, -1.0e+25, -1.0e+25, 25.0};

    // bu[n+nclin+ncnln] -- upper bounds for all the variables and general constraints
    double[] bu = {5.0, 5.0, 5.0, 5.0, 20.0, 40.0, 1.0e+25};

    // x[n] -- initial estimate of the solution
    double[] x = {1.0, 5.0, 5.0, 1.0};

    // objf[1] -- an array of length 1 to hold the final objective
    // function value computed by e04ucf
    double[] objf = new double[1];

    // objgrd[n] -- an array to hold the gradient of the objectve function,
    // computed by e04ucf
    double[] objgrd = new double[n];

    // ifail -- output error variable.
    int ifail;

    int i;

    // Set some options for e04ucf
    e04uef("Nolist");          // Turn off echoing of options by e04uef
    e04uef("Print Level = 0"); // Turn off e04ucf internal monitoring information

    System.out.println(" Running e04ucf example program from Java");
    System.out.println(" ----------------------------------------");
    System.out.println(" Problem:");
    System.out.println("");
    System.out.println("   Minimize F(x) = x0*x3*(x0 + x1 + x2) + x2");
    System.out.println("   Subject to bounds");
    for (i = 0; i < n; i++)
      System.out.println("     " + bl[i] + " <= x" + i + " <= " + bu[i]);
    System.out.println("   General linear constraint");
    System.out.println("     x0 + x1 + x2 + x3 <= 20");
    System.out.println("   Nonlinear constraints");
    System.out.println("     x0^2 + x1^2 + x2^2 + x3^2 <= 40");
    System.out.println("     x0*x1*x2*x3 >= 25");

    // Call the NAG Library routine e04ucf via the Java Native Interface
    ifail = e04ucf(n, nclin, ncnln, a, lda, bl, bu, confunction, objfunction,
                   objf, objgrd, x);

    // Output some results
    System.out.println("");
    System.out.println(" Results returned by NAG nonlinear minimization routine e04ucf");
    System.out.println(" -------------------------------------------------------------");
    System.out.println(" Fail code ifail = " + ifail);
    if (ifail == 0)
      {
        System.out.println(" Final objective function value = " + objf[0]);
        System.out.println(" Solution vector x:");
        for (i = 0; i < n; i++)
          System.out.println("   x[" + i + "] = " + x[i]);
      }
  }

}
