NAG Technical Report 2/2009

Calling NAG Library Routines from Java


Start of report   Skip to Example 1   Skip to Example 2   Skip to Example 3   Skip to Example 4   Skip to Example 5

4.6. Example 6

A global optimization routine, E05JBF

Here we show another example of calling a NAG Fortran Library routine which takes two user-supplied routines as arguments: subroutine E05JBF.

Contents

  1. Subroutine specification from the NAG Fortran Library Manual
  2. Declaring the native function in our Java program
  3. Compiling the Java program
  4. Generating a header file for use by C
  5. Implementing the native function in C code which interfaces to Fortran
  6. Building the shareable library or DLL
  7. Running the program
  8. Quick summary of how to build the optimization solver example

  1. Subroutine specification from the NAG Fortran Library Manual
  2. According to the Fortran Library Manual, the prototype for subroutine E05JBF looks like this:

          SUBROUTINE E05JBF(N, OBJFUN, IBOUND, IINIT, BL, BU, SDLIST,
                            LIST, NUMPTS, INITPT, MONIT, X, OBJ, COMM, LCOMM,
                            IUSER, RUSER, IFAIL
                            INTEGER N, IBOUND, IINIT, SDLIST, NUMPTS(N),
                            INITPT(N), LCOMM, IUSER(*), IFAIL
                            DOUBLE PRECISION BL(N), BU(N), LIST(N,SDLIST),
                            X(N), OBJ, COMM(LCOMM), RUSER(*)
                            EXTERNAL OBJFUN, MONIT
    
    The subroutine E05JBF is designed to solve modestly-sized global optimization problems having simple bound-constraints only. It finds the global optimum of a nonlinear function subject to a set of bound constraints on the variables.

    The function f(x) to be optimized is evaluated by user-supplied routine argument OBJFUN to E05JBF, which is declared as

          SUBROUTINE OBJFUN(N, X, F, NSTATE, IUSER, RUSER, INFORM)
                            INTEGER N, NSTATE, IUSER(*), INFORM
                            DOUBLE PRECISION X(N), F, RUSER(*)
    
    In addition, a user-supplied routine argument MONIT is needed to to monitor the minimization process:
          SUBROUTINE MONIT(N, NCALL, XBEST, ICOUNT, NINIT, LIST, NUMPTS,
                            INITPT, NBASKT, XBASKT, BOXL, BOXU, NSTATE, IUSER,
                            RUSER, INFORM)
                            INTEGER N, NCALL, ICOUNT(6), NINIT, NUMPTS(N),
                            INITPT(N), NBASKT, NSTATE, IUSER(*), INFORM
                            DOUBLE PRECISION XBEST(N), LIST(N,NINIT),
                            XBASKT(N,NBASKT), BOXL(N), BOXU(N), RUSER(*)
    

    For full description of the roles of all routine arguments consult the E05JBF routine document in the NAG Fortran Library Manual.

  3. Declaring the native function in our Java program
  4. The NAG Fortran Library uses a simple integer, IFAIL, to return an error code (compare this with the NagError structure type used by the C Library).

    Although we are going to call a routine from the NAG Fortran Library, we still implement our interface code in C for convenience. Thus the full program will be a mixture of three languages - Java, C and Fortran.

      // Declaration of the Native (C) function
      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);
    
    i.e. a method with return type int. Since we are not using the ifail argument, we will use the int return value to send back any error code.

    As with Example 3, note that we cannot pass subroutine arguments directly from Java to C, and so here we just pass the names of methods via the String arguments objfun and monit.

  5. Compiling the Java program
  6. Here is the complete source code of our Java program GlobalOptimization.java.
    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(" ");
          }
    
        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(" ");
    
            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++)
                  System.out.print(x[i] + " ");
                System.out.println();
              }
          }
      }
    }
    
    ;i++)>
    Some points to note about this program:

We can compile our Java program with the following command:

  % javac GlobalOptimization.java

  • Generating a header file for use by C
  • Having compiled GlobalOptimization.java, we can use javah to create a C header file:

      % javah -jni GlobalOptimization
    
    The generated header file, GlobalOptimization.h, contains these two function prototypes for ther two JNI functions:
      JNIEXPORT jint JNICALL Java_GlobalOptimization_e05jbf
      (JNIEnv *, jobject, jint, jstring, jint, jint, jdoubleArray, jdoubleArray,
      jint, jdoubleArray, jintArray, jintArray, jstring, jdoubleArray, jdoubleArray,
      jdoubleArray, jint, jintArray, jdoubleArray);
    
      JNIEXPORT jint JNICALL Java_GlobalOptimization_e05jaf
        (JNIEnv *, jobject, jint, jdoubleArray, jint);
     

  • Implementing the native function in C code
  • Now that we have created the header file GlobalOptimization.h, we can write our C code implementation of Java_GlobalOptimization_e05jbf.

    5.1 Source code for the C interface library

    Here is the C source code, from file GlobalOptimizationImp.c:

    #include "GlobalOptimization.h"
    #include <math.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <jni.h>
    
    /* Nasty global variables to store pointers to Java environment
       and methods so that we can use them in different parts of this
       C code. */
    JNIEnv *globalJavaEnv;
    jobject globaljavaobject;
    jmethodID globalObjfunID;
    jmethodID globalMonitID;
    
    /* This routine has the interface required by NAG routine e05jbf for
       argument objfun. It makes calls back to the Java version of objfun */
    void objfunFun(int *n, double x[], double *f, int *nstate,
                   int iuser[], double ruser[], int *inform)
    {
      int i;
    
      /* First create Java arrays to pass to objfun */
      jdoubleArray jx = (*globalJavaEnv)->NewDoubleArray(globalJavaEnv, *n);
      jintArray jiuser = (*globalJavaEnv)->NewIntArray(globalJavaEnv, 1);
      jdoubleArray jruser = (*globalJavaEnv)->NewDoubleArray(globalJavaEnv, 1);
    
      /* Copy input array x to Java array jx */
      double *jxpt = (*globalJavaEnv)->GetDoubleArrayElements(globalJavaEnv, jx, 0);
      int *jiuserpt = (*globalJavaEnv)->GetIntArrayElements(globalJavaEnv, jiuser, 0);
      double *jruserpt = (*globalJavaEnv)->GetDoubleArrayElements(globalJavaEnv, jruser, 0);
      for (i = 0; i < *n; i++)
        jxpt[i] = x[i];
      for (i = 0; i < 1; i++)
        jiuserpt[i] = iuser[i];
      for (i = 0; i < 1; i++)
        jruserpt[i] = ruser[i];
    
      /* Release array elements back to Java (this puts the values into jx, jiuser, jruser) */
      (*globalJavaEnv)->ReleaseDoubleArrayElements(globalJavaEnv, jx, jxpt, 0);
      (*globalJavaEnv)->ReleaseIntArrayElements(globalJavaEnv, jiuser, jiuserpt, 0);
      (*globalJavaEnv)->ReleaseDoubleArrayElements(globalJavaEnv, jruser, jruserpt, 0);
    
      /* We need to set inform to a non-negative value */
      *inform = 0;
    
      /* Call Java objfun which returns objf */
      *f = (*globalJavaEnv)->CallDoubleMethod(globalJavaEnv, globaljavaobject,
                                              globalObjfunID, (jint) (*n), jx,
                                              (jdouble) (*f), (jint) (*nstate),
                                              jiuser, jruser, (jint) (*inform));
    }
    
    /* This routine has the interface required by NAG routine e05jbf for
       argument monit. It makes calls back to the Java version of monit */
    void monitFun(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,j;
      int *jicountpt, *jnumptspt, *jinitptpt, *jiuserpt;
      double *jxbestpt, *jlistpt, *jxbasktpt, *jboxlpt, *jboxupt, *jruserpt;
    
      /* First create some Java arrays to pass to monit */
      jintArray jicount = (*globalJavaEnv)->NewIntArray(globalJavaEnv, 6);
      jintArray jnumpts = (*globalJavaEnv)->NewIntArray(globalJavaEnv, *n);
      jintArray jinitpt = (*globalJavaEnv)->NewIntArray(globalJavaEnv, *n);
      jintArray jiuser = (*globalJavaEnv)->NewIntArray(globalJavaEnv, 1);
      jdoubleArray jxbest = (*globalJavaEnv)->NewDoubleArray(globalJavaEnv, *n);
      jdoubleArray jlist = (*globalJavaEnv)->NewDoubleArray(globalJavaEnv, ((*n)*(*ninit)));
      jdoubleArray jxbaskt = (*globalJavaEnv)->NewDoubleArray(globalJavaEnv, ((*n)*(*nbaskt)));
      jdoubleArray jboxl = (*globalJavaEnv)->NewDoubleArray(globalJavaEnv, *n);
      jdoubleArray jboxu = (*globalJavaEnv)->NewDoubleArray(globalJavaEnv, *n);
      jdoubleArray jruser = (*globalJavaEnv)->NewDoubleArray(globalJavaEnv, 1);
    
      /* Copy input arguments to Java arrays*/
      jicountpt = (*globalJavaEnv)->GetIntArrayElements(globalJavaEnv, jicount, 0);
      jnumptspt = (*globalJavaEnv)->GetIntArrayElements(globalJavaEnv, jnumpts, 0);
      jinitptpt = (*globalJavaEnv)->GetIntArrayElements(globalJavaEnv, jinitpt, 0);
      jiuserpt = (*globalJavaEnv)->GetIntArrayElements(globalJavaEnv, jiuser, 0);
      jxbestpt = (*globalJavaEnv)->GetDoubleArrayElements(globalJavaEnv, jxbest, 0);
      jlistpt = (*globalJavaEnv)->GetDoubleArrayElements(globalJavaEnv, jlist, 0);
      jxbasktpt = (*globalJavaEnv)->GetDoubleArrayElements(globalJavaEnv, jxbaskt, 0);
      jboxlpt = (*globalJavaEnv)->GetDoubleArrayElements(globalJavaEnv, jboxl, 0);
      jboxupt = (*globalJavaEnv)->GetDoubleArrayElements(globalJavaEnv, jboxu, 0);
      jruserpt = (*globalJavaEnv)->GetDoubleArrayElements(globalJavaEnv, jruser, 0);
      for (i = 0; i < 6; i++)
        jicountpt[i] = icount[i];
      for (i = 0; i < *n; i++)
        jnumptspt[i] = numpts[i];
      for (i = 0; i < *n; i++)
        jinitptpt[i] = initpt[i];
      for (i = 0; i < *n; i++)
        jxbestpt[i] = xbest[i];
      for (i = 0; i < *n; i++)
        {
          for (j = 0; j < *ninit; j++)
            jlistpt[j*(*n) + i] = list[j*(*n) + i];
        }
      for (i = 0; i < *n; i++)
        {
          for (j = 0; j < *nbaskt; j++)
            jxbasktpt[j*(*n) + i] = xbaskt[j*(*n) + i];
        }
      for (i = 0; i < *n; i++)
        jboxlpt[i] = boxl[i];
      for (i = 0; i < *n; i++)
        jboxupt[i] = boxu[i];
      for (i = 0; i < 1; i++)
        jiuserpt[i] = iuser[i];
      for (i = 0; i < 1; i++)
        jruserpt[i] = ruser[i];
      /* Release array elements back to Java (this puts the values
         back into Java arrays) */
      (*globalJavaEnv)->ReleaseIntArrayElements(globalJavaEnv, jicount, jicountpt, 0);
      (*globalJavaEnv)->ReleaseIntArrayElements(globalJavaEnv, jnumpts, jnumptspt, 0);
      (*globalJavaEnv)->ReleaseIntArrayElements(globalJavaEnv, jinitpt, jinitptpt, 0);
      (*globalJavaEnv)->ReleaseIntArrayElements(globalJavaEnv, jiuser, jiuserpt, 0);
      (*globalJavaEnv)->ReleaseDoubleArrayElements(globalJavaEnv, jxbest, jxbestpt, 0);
      (*globalJavaEnv)->ReleaseDoubleArrayElements(globalJavaEnv, jlist, jlistpt, 0);
      (*globalJavaEnv)->ReleaseDoubleArrayElements(globalJavaEnv, jxbaskt, jxbasktpt, 0);
      (*globalJavaEnv)->ReleaseDoubleArrayElements(globalJavaEnv, jboxl, jboxlpt, 0);
      (*globalJavaEnv)->ReleaseDoubleArrayElements(globalJavaEnv, jboxu, jboxupt, 0);
      (*globalJavaEnv)->ReleaseDoubleArrayElements(globalJavaEnv, jruser, jruserpt, 0);
    
      /* Call the Java method via its method ID */
      *inform = (*globalJavaEnv)->CallIntMethod(globalJavaEnv, globaljavaobject,
                                                globalMonitID, (jint)(*n),
                                                (jint) (*ncall), jxbest, jicount,
                                                (jint)(*ninit), jlist, jnumpts,
                                                jinitpt, (jint)(*nbaskt), jxbaskt,
                                                jboxl, jboxu, (jint)(*nstate),
                                                jiuser, jruser, (jint) (*inform));
    }
    
    JNIEXPORT jint JNICALL Java_GlobalOptimization_e05jbf
    (
     JNIEnv *env,
     jobject object,
     jint n,
     jstring objfun,
     jint ibound,
     jint iinit,
     jdoubleArray bl,
     jdoubleArray bu,
     jint sdlist,
     jdoubleArray list,
     jintArray numpts,
     jintArray initpt,
     jstring monit,
     jdoubleArray x,
     jdoubleArray obj,
     jdoubleArray comm,
     jint lcomm,
     jintArray iuser,
     jdoubleArray ruser
     )
    {
      /* Local variables and arrays */
      int ifail;
    
      jclass cls;
      const char *objfunction;
      const char *monitrt;
    
      jdouble *bl_pt, *bu_pt, *list_pt, *x_pt, *obj_pt,
              *comm_pt, *ruser_pt;
      jint *numpts_pt, *initpt_pt, *iuser_pt;
    
      /* Copy the Java env pointers to global space
         so that monitFun and objfunFun can access them. */
      globalJavaEnv = env;
      globaljavaobject = object;
    
      /* Get hold of the name of the user's Java evaluation functions. */
      objfunction = (*env)->GetStringUTFChars(env, objfun, 0);
      monitrt = (*env)->GetStringUTFChars(env, monit, 0);
    
      /* Now we have the Java evaluation function names we can use
         them to get hold of handles (method IDs) to the functions.
         Once more, the method IDs are stored globally so that objfunFun
         and monitFun can use them. Note that the Java function signatures
         must be correct. You can find out the signatures after compiling
         the Java program GlobalOptimization.java by using the command
         % javap -private -s GlobalOptimization
       */
      cls = (*env)->GetObjectClass(env, object);
      globalObjfunID = (*env)->GetMethodID(env, cls, objfunction, "(I[DDI[I[DI)D");
      globalMonitID = (*env)->GetMethodID(env, cls, monitrt, "(II[D[II[D[I[II[D[D[DI[I[DI)I");
    
      /* Free up the Java string argument so we don't leak memory. */
      (*env)->ReleaseStringUTFChars(env, objfun, objfunction);
      (*env)->ReleaseStringUTFChars(env, monit, monitrt);
    
      if (globalObjfunID == 0)
        {
          printf("Cannot find objfun method \"%s\" with signature \"(I[DDI[I[DI)D\"\n",
                 objfunction);
          return -1;
        }
      if (globalMonitID == 0)
        {
          printf("Cannot find monit method \"%s\" with signature \"(II[D[II[D[I[II[D[D[DI[I[DI)I\"\n",
                 monitrt);
          return -1;
        }
    
      /* Extract the arrays from Java */
      bl_pt = (*env)->GetDoubleArrayElements(env, bl, 0);
      bu_pt = (*env)->GetDoubleArrayElements(env, bu, 0);
      list_pt = (*env)->GetDoubleArrayElements(env, list, 0);
      x_pt = (*env)->GetDoubleArrayElements(env, x, 0);
      obj_pt = (*env)->GetDoubleArrayElements(env, obj, 0);
      comm_pt = (*env)->GetDoubleArrayElements(env, comm, 0);
      ruser_pt = (*env)->GetDoubleArrayElements(env, ruser, 0);
      numpts_pt = (*env)->GetIntArrayElements(env, numpts, 0);
      initpt_pt = (*env)->GetIntArrayElements(env, initpt, 0);
      iuser_pt = (*env)->GetIntArrayElements(env, iuser, 0);
    
      /* Call to main NAG Library routine e05jbf */
      ifail = -1;
    #ifdef WINDOWS
        E05JBF
    #else
        e05jbf_
    #endif
          (&n, objfunFun, &ibound, &iinit, bl_pt, bu_pt,
           &sdlist, list_pt, numpts_pt, initpt_pt, monitFun,
           x_pt, obj_pt, comm_pt, &lcomm, iuser_pt, ruser_pt,
           &ifail);
    
      /* Release the array elements back to Java and free memory. */
      (*env)->ReleaseDoubleArrayElements(env, bl, bl_pt, 0);
      (*env)->ReleaseDoubleArrayElements(env, bu, bu_pt, 0);
      (*env)->ReleaseDoubleArrayElements(env, list, list_pt, 0);
      (*env)->ReleaseDoubleArrayElements(env, x, x_pt, 0);
      (*env)->ReleaseDoubleArrayElements(env, obj, obj_pt, 0);
      (*env)->ReleaseDoubleArrayElements(env, comm, comm_pt, 0);
      (*env)->ReleaseDoubleArrayElements(env, ruser, ruser_pt, 0);
      (*env)->ReleaseIntArrayElements(env, numpts, numpts_pt, 0);
      (*env)->ReleaseIntArrayElements(env, initpt, initpt_pt, 0);
      (*env)->ReleaseIntArrayElements(env, iuser, iuser_pt, 0);
    
      return ifail;
    
    }
    
    // Interface to initialization routine e05jaf
    JNIEXPORT jint JNICALL Java_GlobalOptimization_e05jaf
    (JNIEnv *env, jobject object, jint n, jdoubleArray comm, jint lcomm)
    {
      jdouble *comm_pt;
      int ifail;
    
      /* Extract the array from Java */
      comm_pt = (*env)->GetDoubleArrayElements(env, comm, 0);
    
      ifail = -1;
      /* Call the initialization routine */
    #ifdef WINDOWS
      E05JAF(&n,comm_pt,&lcomm,&ifail);
    #else
      e05jaf_(&n,comm_pt,&lcomm,&ifail);
    #endif
    
      /* Release the array elements back to Java and free memory. */
      (*env)->ReleaseDoubleArrayElements(env, comm, comm_pt, 0);
    
      return ifail;
    }
      

    5.2 Description of the C code

    The function named Java_GlobalOptimization_e05jbf is our C implementation of the Java-declared method e05jbf.

    We cannot pass the Java methods objfun and monit which evaluate the objective function and nonlinear constraints directly to the NAG Fortran Library routine E05JBF, so we need to wrap them in C functions. These C functions we name objfunFun and monitFun respectively:

       void objfunFun(int *n, double x[], double *f, int *nstate,
                   int iuser[], double ruser[], int *inform)
    
       void monitFun(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)
    
    These functions have the argument types and return types required by the NAG Library routine E05JBF. Notice in particular that all scalar arguments (such as n) are passed as pointers, as required by Fortran. Further, notice that arguments list and xbaskt are declared as a one-dimensional arrays rather than the 2-D arrays specified by the Fortran routine. We do this because 2-D Java arrays do not map easily onto Fortran 2-D arrays.

    Inside objfunFun and monitFun we do nothing but call the equivalent Java methods. Once again, the trick is in knowing how to make these calls to Java. We do this using the JNI functions CallDoubleMethod for objfun (because in Java we defined that method to have return type double) and CallIntMethod for monit.

    The Java methods objfun and monit both need to be passed array arguments, elements of which the methods need to fill in. As with Example 3, we obtain the method ID of the two methods and store them in global variables in our C code so that they can be accessed from inside the C evaluation functions as well as the main JNI function. These IDs are obtained by passing the appropriate names and signatures to calls of JNI function GetMethodID. Note that a good way to discover Java method signatures is to use the command

      % javap -private -s GlobalOptimization
    
    after compiling the Java program GlobalOptimization.java.

    A complication is that our C functions objfunFun and monitFun need to pass Java arrays to the Java methods, but themselves have only C (or Fortran) style arrays. Therefore the C code needs to create Java arrays, then copy the contents of the C arrays to the Java arrays. To create a Java double array, we use the JNI function NewDoubleArray followed by a call of GetDoubleArrayElements to get a C pointer to the array elements, then ReleaseDoubleArrayElements to put the C contents into the Java array, before calling the Java method. On return from the Java method we again call GetDoubleArrayElements to obtain the results. For integer arrays, JNI functions NewIntArray, GetIntArrayElements and ReleaseIntArrayElements are appropriate. It is very important to get the order of calls to these JNI functions exactly right to ensure that data is in the right place at the right time. Follow the example in GlobalOptimizationImp.c.

    5.3 Returning results to Java

    In this example all results are returned to Java via the array arguments which came from the Java call to the native method - apart from the error code IFAIL which is returned via the function name. Notice that we declared the argument obj, which contains the optimal function value, as an array of length 1. This is because Java methods cannot update the contents of scalar arguments, but can update array contents.

  • Building the shareable library or DLL
  • This step is operating-system dependent.

    The compiler flags used were described in Section 7 of Example 1. Note that when building under Microsoft Windows we also add the C compiler switch -DWINDOWS to tell the C code that the name of the Fortran Library routines E05JBF and E05JAF must be given in upper case, as required by Windows versions of the NAG Fortran Library. For UNIX machines the name will typically be in lower case with an appended underscore, when called from C, i.e. "e05jbf_".

  • Running the program
  • Assuming that all has gone well, we can run the program using the command

      % java GlobalOptimization
    
    The expected output looks like this:

     Routine e05jbf has been initialised by e05jaf.
     ----------------------------------------------
    
     Running e05jbf example program from Java
     ----------------------------------------
     Problem:
    
       Find global minimum of the 'peaks' function:
       F(x,y) = 3*(1-x)^2*exp(-x^2-(y+1)^2)-10(x/5-x^3-y^5)*exp(-x^2-y^2)
                -1/3*exp(-(x+1)^2-y^2)
       on the box [-3.0,3.0]x[-3.0,3.0]
    
     (objfun was just called for the first time)
    
     *** Begin monitoring information ***
    
     Total sub-boxes = 228
     Total function evaluations = 196
     Total function evaluations used in local search = 87
     Total points used in local search = 13
     Total sweeps through levels = 12
     Total splits by init. list = 5
     Lowest level with nonsplit boxes = 7
     Number of candidate minima in the 'shopping basket' = 2
     Shopping backet:
     xbaskt[0,0] = -1.347396243542219
     xbaskt[0,1] = 0.2282789212962065
     xbaskt[1,0] = 0.20451885579921375
     xbaskt[1,1] = -1.6255349573219788
    
     *** End monitoring information ***
    
     Results returned by NAG global optimization routine e05jbf
     -----------------------------------------------------------
     Fail code ifail = 0
     Final objective function value = -6.551133332835838
     Global optimum x: 0.2282789212962065 -1.6255349573219788
    

    (If you get an error message saying that a library cannot be located, see the tip given in Example 1).

  • Quick summary of how to build the optimization example
  • Given the two source files GlobalOptimization.java and GlobalOptimizationImp.c, issue the following commands:
    Start of report   Skip to Example 1   Skip to Example 2   Skip to Example 3   Skip to Example 4   Skip to Example 5
    Copyright 2009 Numerical Algorithms Group
    Page last updated 2011-01-25 annak
    [NP3671]