wiki:JavaInterface

NOTE: Uptodate information on the JIpopt is available in the Ipopt documentation.

NOTE: THIS PAGE IS UNDER CONSTRUCTION

This page will contain information to the Java interface contributed to the Ipopt project by Rafael de Pelegrini Soares. The code is currently only available in the trunk version of Ipopt.


Ipopt Java Interface Documentation

This is the documentation of the Java Native Interface (JNI) for the Ipopt optimization solver, called JIpopt.

Author: Rafael de Pelegrini Soares

VRTech Industrial Technologies

General Notes

Ipopt is a solver for large scale nonlinear optimization problems (NLP) with non-linear contraints.

The Java Native Interface (JNI) is a programming framework that allows Java code running in the Java Virtual Machine (JVM) to call and be called by native applications and libraries written in languages such as C and C++.

JIpopt requires Java 5 or higher.

Download

  • Source code: JIPOPT will be included on the next IPOPT source distribution, currently the source code is available

only in the trunk version in the subversion repository. For more details on how to check out the source code using subversion check the IPOPT documentation.

Binary Package Contents

In the binary package you will find a jipopt-<VERSION>.jar package and some native DLL containing Ipopt to run the optimizations. Currently we provide pre-compiled DLL's with Ipopt+MUMPS for some platforms:

  • DLL/win32/jipopt.dll pre-compiled for Win32 platforms
  • DLL/i386/dapper/libjipopt.so pre-compiled for Ubuntu Linux 6.06 (i386), this also requires:
    • refblas-3 or some machine optimized blas, e.g. atlas3-3dnow for AMD 3dnow processors
    • lapack3
    • libgfortran0
  • DLL/i386/feisty/libjipopt.so pre-compiled for Ubuntu Linux 7.04 (i386), this also requires:
    • refblas-3 or some machine optimized blas, e.g. atlas3-3dnow for AMD 3dnow processors
    • lapack3
    • libgfortran1

Note that the above binary files include code from both Ipopt and MUMPS.

Obviously you can build the DLL for your specific platform using the sources, check the details below.

Compiling the DLL from sources

In order to compile the DLL from sources you will need to check out the trunk version of IPOPT from the subversion repository. For more details on how to get the sources check the documentation.

Once you have the sources:

  1. Before you run Ipopt's configure, you need to set the JAVA_HOME environment variable to the directory that contains your JDK, e.g.,
    export JAVA_HOME=/usr/lib/jvm/java-1.5.0
    
  1. Follow the regular Ipopt installation instructions. After the final 'make install' go into the JIPOPt subdirectory and type 'make'
    cd Ipopt/contrib/JavaInterface
    make
    
  1. This will generate the Java class, which you will need to add into your Java project
       org/coinor/Ipopt.class
    

and the shared object (if on Linux)

   lib/libjipopt.so

or the DLL (if on Windows)

   lib/jipopt.dll
  1. In order to test your DLL you can run two example problems with the following command inside the JIPOPT directory:
    make test
    

NOTE: This compilation procedure has been tested only on Linux so far.

Using JIpopt

First you need a DLL for your platform (get a precompiled one inside the binary package above or build it yourself with the instructions below). Yes, it is Java, but once this is a JNI it will need a native DLL to run. On Win32 platforms it will look, by default, for the file jipopt.dll and and for Linux platforms it will look for libjipopt.so. So, you will need the following:

  • the Ipopt java code (you can use the file jipopt-<VERSION>.jar included on the binary package) or get it from the sources using the subversion repository
  • the file jipopt.dll (if on Win32 platforms)
  • the file libjipopt.so (if on Linux)

Create a new Java project using your preferred IDE (e.g eclipse) and add the Ipopt java code (using the source from subversion or the jipopt-<VERSION>.jar file). Create a folder named lib in the root of your project and paste the DLL for your platform there.

Once you have the files in the right places, you only need the following code to run an optimization:

        /**
         * Main function for running a example.
         */
        public static void main(String []args){
                // Create the problem
                HS071 hs071 = new HS071();
                
                // Get the default initial guess
                double x[] = hs071.getInitialGuess();
                
                // solve the problem
                hs071.solve(x);
        }

Where the HS071 class derives from org.coinor.Ipopt and implements the abstract methods (check the class org.coinor.examples.HS071 found in the source code distribution or in the jipopt-<VERSION>.jar package):

public class HS071 extends Ipopt {
        
        // Problem sizes
        int n, m, nele_jac, nele_hess;
        
        /**
         * Initialize the bounds and create the native Ipopt problem.
         */
        public HS071() {

                /* Number of nonzeros in the Jacobian of the constraints */
                nele_jac = 8;
                /* Number of nonzeros in the Hessian of the Lagrangian (lower or
                 * upper triangual part only) */
                nele_hess = 10;

                /* set the number of variables and allocate space for the bounds */
                n=4;
                double x_L[] = new double[n];
                double x_U[] = new double[n];
                for(int i=0; i < x_L.length; i++){
                        x_L[i] = 1.0;
                        x_U[i] = 5.0;
                }

                /* set the number of constraints and allocate space for the bounds */
                m=2;
                double g_L[] = new double[m];
                double g_U[] = new double[m];
                /* set the values of the constraint bounds */
                g_L[0] = 25;
                g_U[0] = 2e19;
                g_L[1] = 40;
                g_U[1] = 40;
                
                /* Index style for the irow/jcol elements */
                int index_style = Ipopt.C_STYLE;

                /* create the IpoptProblem */
                create(n, x_L, x_U, m, g_L, g_U, nele_jac, nele_hess, index_style);
        }
        
        public double[] getInitialGuess(){
                /* allocate space for the initial point and set the values */
                double x[] = new double[4];
                x[0] = 1.0;
                x[1] = 5.0;
                x[2] = 5.0;
                x[3] = 1.0;
                
                return x;
        }

        protected boolean eval_f(int n, double[] x, boolean new_x, double[] obj_value) {
                assert n == this.n;

                obj_value[0] = x[0] * x[3] * (x[0] + x[1] + x[2]) + x[2];

                return true;
        }

        protected boolean eval_grad_f(int n, double[] x, boolean new_x, double[] grad_f) {
                assert n == this.n;

                grad_f[0] = x[0] * x[3] + x[3] * (x[0] + x[1] + x[2]);
                grad_f[1] = x[0] * x[3];
                grad_f[2] = x[0] * x[3] + 1;
                grad_f[3] = x[0] * (x[0] + x[1] + x[2]);

                return true;
        }

        protected boolean eval_g(int n, double[] x, boolean new_x, int m, double[] g) {
                assert n == this.n;
                assert m == this.m;

                g[0] = x[0] * x[1] * x[2] * x[3];
                g[1] = x[0]*x[0] + x[1]*x[1] + x[2]*x[2] + x[3]*x[3];

                return true;
        }

        protected boolean eval_jac_g(int n, double[] x, boolean new_x,
                        int m, int nele_jac, int[] iRow, int[] jCol, double[] values) {
                assert n == this.n;
                assert m == this.m;

                if (values == null) {
                        /* return the structure of the jacobian */

                        /* this particular jacobian is dense */
                        iRow[0] = 0;
                        jCol[0] = 0;
                        iRow[1] = 0;
                        jCol[1] = 1;
                        iRow[2] = 0;
                        jCol[2] = 2;
                        iRow[3] = 0;
                        jCol[3] = 3;
                        iRow[4] = 1;
                        jCol[4] = 0;
                        iRow[5] = 1;
                        jCol[5] = 1;
                        iRow[6] = 1;
                        jCol[6] = 2;
                        iRow[7] = 1;
                        jCol[7] = 3;
                }
                else {
                        /* return the values of the jacobian of the constraints */

                        values[0] = x[1]*x[2]*x[3]; /* 0,0 */
                        values[1] = x[0]*x[2]*x[3]; /* 0,1 */
                        values[2] = x[0]*x[1]*x[3]; /* 0,2 */
                        values[3] = x[0]*x[1]*x[2]; /* 0,3 */

                        values[4] = 2*x[0];         /* 1,0 */
                        values[5] = 2*x[1];         /* 1,1 */
                        values[6] = 2*x[2];         /* 1,2 */
                        values[7] = 2*x[3];         /* 1,3 */
                }

                return true;
        }

        protected boolean eval_h(int n, double[] x, boolean new_x, double obj_factor, int m, double[] lambda, boolean new_lambda, int nele_hess, int[] iRow, int[] jCol, double[] values) {
                int idx = 0; /* nonzero element counter */
                int row = 0; /* row counter for loop */
                int col = 0; /* col counter for loop */
                if (values == null) {
                        /* return the structure. This is a symmetric matrix, fill the lower left
                         * triangle only. */

                        /* the hessian for this problem is actually dense */
                        idx=0;
                        for (row = 0; row < 4; row++) {
                                for (col = 0; col <= row; col++) {
                                        iRow[idx] = row;
                                        jCol[idx] = col;
                                        idx++;
                                }
                        }

                        assert idx == nele_hess;
                        assert nele_hess == this.nele_hess;
                }
                else {
                        /* return the values. This is a symmetric matrix, fill the lower left
                         * triangle only */

                        /* fill the objective portion */
                        values[0] = obj_factor * (2*x[3]);               /* 0,0 */

                        values[1] = obj_factor * (x[3]);                 /* 1,0 */
                        values[2] = 0;                                   /* 1,1 */

                        values[3] = obj_factor * (x[3]);                 /* 2,0 */
                        values[4] = 0;                                   /* 2,1 */
                        values[5] = 0;                                   /* 2,2 */

                        values[6] = obj_factor * (2*x[0] + x[1] + x[2]); /* 3,0 */
                        values[7] = obj_factor * (x[0]);                 /* 3,1 */
                        values[8] = obj_factor * (x[0]);                 /* 3,2 */
                        values[9] = 0;                                   /* 3,3 */


                        /* add the portion for the first constraint */
                        values[1] += lambda[0] * (x[2] * x[3]);          /* 1,0 */

                        values[3] += lambda[0] * (x[1] * x[3]);          /* 2,0 */
                        values[4] += lambda[0] * (x[0] * x[3]);          /* 2,1 */

                        values[6] += lambda[0] * (x[1] * x[2]);          /* 3,0 */
                        values[7] += lambda[0] * (x[0] * x[2]);          /* 3,1 */
                        values[8] += lambda[0] * (x[0] * x[1]);          /* 3,2 */

                        /* add the portion for the second constraint */
                        values[0] += lambda[1] * 2;                      /* 0,0 */

                        values[2] += lambda[1] * 2;                      /* 1,1 */

                        values[5] += lambda[1] * 2;                      /* 2,2 */

                        values[9] += lambda[1] * 2;                      /* 3,3 */
                }
                return true;
        }
}

Performance Penalty

Using Java introduces some impact in the performance of the function evaluations. It follows the results I have found so far for the test LukVlE1 when N=20000.

Native Ipopt+Mumps on Ubuntu Linux 7.04:

Total CPU secs in IPOPT (w/o function evaluations)   =      1.844
Total CPU secs in NLP function evaluations           =      0.220

JIpopt with Sun JDK 6+Ipopt+Mumps on Ubuntu Linux 7.04:

Total CPU secs in IPOPT (w/o function evaluations)   =      2.032
Total CPU secs in NLP function evaluations           =      0.396

Note: The tests above were executed on the same machine, the numerical results are identical. Some details of the problem LukVlE1 when N=20000:

Number of nonzeros in equality constraint Jacobian...:    59994
Number of nonzeros in inequality constraint Jacobian.:        0
Number of nonzeros in Lagrangian Hessian.............:    39999

Total number of variables............................:    20000
                     variables with only lower bounds:        0
                variables with lower and upper bounds:        0
                     variables with only upper bounds:        0
Total number of equality constraints.................:    19998
Total number of inequality constraints...............:        0
        inequality constraints with only lower bounds:        0
   inequality constraints with lower and upper bounds:        0
        inequality constraints with only upper bounds:        0

iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
   0  5.0815160e+06 2.48e+01 2.73e+01  -1.0 0.00e+00    -  0.00e+00 0.00e+00   0
   1  2.7027399e+06 1.49e+01 8.27e+01  -1.0 2.20e+00    -  1.00e+00 1.00e+00f  1
   2  3.0294536e+05 4.28e+00 1.36e+02  -1.0 1.43e+00    -  1.00e+00 1.00e+00f  1
   3  1.1956749e+02 3.09e-01 2.18e+01  -1.0 5.63e-01    -  1.00e+00 1.00e+00f  1
   4  6.2352166e+00 1.73e-02 8.47e-01  -1.0 2.10e-01    -  1.00e+00 1.00e+00h  1
   5  6.2324586e+00 1.15e-05 8.16e-04  -1.7 3.35e-03    -  1.00e+00 1.00e+00h  1
   6  6.2324586e+00 8.36e-12 7.97e-10  -5.7 2.00e-06    -  1.00e+00 1.00e+00h  1

Number of Iterations....: 6

                                   (scaled)                 (unscaled)
Objective...............:   7.8692659500479756e-01    6.2324586324379965e+00
Dual infeasibility......:   7.9744508296434521e-10    6.3157650570776142e-09
Constraint violation....:   8.3555384833289281e-12    8.3555384833289281e-12
Complementarity.........:   0.0000000000000000e+00    0.0000000000000000e+00
Overall NLP error.......:   7.9744508296434521e-10    6.3157650570776142e-09


Number of objective function evaluations             = 7
Number of objective gradient evaluations             = 7
Number of equality constraint evaluations            = 7
Number of inequality constraint evaluations          = 0
Number of equality constraint Jacobian evaluations   = 7
Number of inequality constraint Jacobian evaluations = 0
Number of Lagrangian Hessian evaluations             = 6

License

  • JIpopt is available under the Commom Plublic License
  • Ipopt is available under the Commom Plublic License
  • MUMPS is public domain

Last modified 12 months ago Last modified on Apr 13, 2018 11:12:46 AM