Initializing help system before first use

BCL in Java

Topics covered in this chapter:

New object-oriented solver API

In Xpress 9.4 the Java API to the Xpress Solver was extended to allow the creation of an optimization problem in a more object-oriented fashion. The new API is fully integrated with the low-level Xpress Solver API, including full support for nonlinear problems, and has been designed for high performance. The new API is a replacement for BCL, which will be deprecated in future Xpress releases.

For more information, see the Solver Java User Guide.

An overview of BCL in Java

Much as for the C++ interface, the Java interface of BCL provides the full functionality of the C version except for the data input, output and error handling for which the standard Java system functions can be used. The C modeling objects, such as variables, constraints and problems, are again converted into classes, and their associated functions into methods of the corresponding class in Java.

Whereas in C++ it is possible to use C functions, such as printf or XPRBprintf for printing output, all code in Java programs must be written in Java itself. In addition, in Java it is not possible to overload the algebraic operators as has been done for the definition of constraints in C++. Instead, the Java interface provides a set of simple methods like add or eql that have been overloaded to accept various types and numbers of parameters.

The names for classes and methods in Java have been formed in the same way as those of their counterparts in C++: All Java classes that have a direct correspondence with modeling objects in BCL (namely XPRBprob, XPRBvar, XPRBctr, XPRBcut, XPRBsol, XPRBsos, XPRBindexSet, XPRBbasis) take the same names, with the exception of XPRBindexSet. In the names of the methods the prefix XPRB has been dropped, as have references to the type of the object. For example, function XPRBgetvarname is turned into the method getName of class XPRBvar.

All Java BCL classes are contained in the package com.dashoptimization. To use the (short) class names, it is recommended to add the line

import com.dashoptimization.*;

at the beginning of every program that uses the Java classes of BCL.

The C++ classes and their methods documented in section C++ class reference correspond to a large extend to the classes defined by the Java interface, with some additional classes in the Java version. A comprehensive documentation of the BCL Java interface is available online at the BCL JavaDoc section.

Example

An example of use of BCL in Java is the following, which again constructs the example described in Chapter Modeling with BCL. Contrary to the C and C++ versions, BCL Java needs to be initialized explicitly by creating an instance of XPRB.
If a BCL Java model is embedded into an application we recommend to use explicit finalization on the XPRBprob object once it is no longer needed to free up the memory used by it (particularly, the memory used by the underlying C structures that are not taken into account by the automated garbage collection in Java). Alternatively, a problem can be reset to free up the memory used by the optimization and solution data without removing the problem definition itself.

import com.dashoptimization.*;

public class xbexpl1
{
 static final int NJ = 4;         /* Number of jobs */
 static final int NT = 10;        /* Time limit */

 static final double[] DUR = {3,4,2,2};  /* Durations of jobs */

 static XPRBvar[] start;          /* Start times of jobs */
 static XPRBvar[][] delta;        /* Binaries for start times */
 static XPRBvar z;                /* Max. completion time  */

 static XPRB bcl;
 static XPRBprob p;

 static void jobsModel()
 {
  XPRBexpr le;
  int j,t;

  start = new XPRBvar[NJ];        /* Start time variables */
  for(j=0;j<NJ;j++) start[j] = p.newVar("start");
  z = p.newVar("z",XPRB.PL,0,NT); /* Makespan variable */

  delta = new XPRBvar[NJ][NT];
  for(j=0;j<NJ;j++)               /* Binaries for each job */
   for(t=0;t<(NT-DUR[j]+1);t++)
    delta[j][t] = p.newVar("delta"+(j+1)+(t+1), XPRB.BV);

  for(j=0;j<NJ;j++)               /* Calculate max. completion time */
   p.newCtr("Makespan", start[j].add(DUR[j]).lEql(z) );

  p.newCtr("Prec", start[0].add(DUR[0]).lEql(start[2]) );
                                  /* Precedence rel. between jobs */

  for(j=0;j<NJ;j++)               /* Linking start times & binaries */
  {
   le = new XPRBexpr();
   for(t=0;t<(NT-DUR[j]+1);t++)
    le.add(delta[j][t].mul((t+1)));
   p.newCtr("Link_"+(j+1), le.eql(start[j]) );
  }

  for(j=0;j<NJ;j++)               /* Unique start time for each job */
  {
   le = new XPRBexpr();
   for(t=0;t<(NT-DUR[j]+1);t++) le.add(delta[j][t]);
   p.newCtr("One_"+(j+1), le.eql(1));
  }

  p.setObj(z);                    /* Define and set objective */

  for(j=0;j<NJ;j++) start[j].setUB(NT-DUR[j]+1);
                                  /* Upper bounds on "start" var.s */
 }

 static void jobsSolve()
 {
  int j,t,statmip;

  for(j=0;j<NJ;j++)
   for(t=0;t<NT-DUR[j]+1;t++)
    delta[j][t].setDir(XPRB.PR, 10*(t+1));
     /* Give highest priority to var.s for earlier start times */

  p.setSense(XPRB.MINIM);
  p.mipOptimize();               /* Solve the problem as MIP */
  statmip = p.getMIPStat();      /* Get the MIP problem status */

  if((statmip == XPRB.MIP_SOLUTION) ||
     (statmip == XPRB.MIP_OPTIMAL))
  {                              /* An integer solution has been found */
   System.out.println("Objective: "+ p.getObjVal());
                                 /* Print solution for all start times */
   for(j=0;j<NJ;j++)
   System.out.println(start[j].getName() + ": "+
                       start[j].getSol());
  }
 }

 public static void main(String[] args)
 {
  bcl = new XPRB();              /* Initialize BCL */
  p = bcl.newProb("Jobs");       /* Create a new problem */

  jobsModel();                   /* Problem definition */
  jobsSolve();                   /* Solve and print solution */

  p.finalize();                  /* Delete the problem (optional) */
  p=null;
 }
}

The definition of SOS is similar to the definition of constraints.

 static XPRBsos[] set;
 static XPRBprob p;

 static void jobsModel()
 {
  ...
  delta = new XPRBvar[NJ][NT];
  for(j=0;j<NJ;j++)              /* Variables for each job */
   for(t=0;t<(NT-DUR[j]+1);t++)
    delta[j][t] = p.newVar("delta"+(j+1)+(t+1), XPRB.PL, 0, 1);

  set = new XPRBsos[NJ];
  for(j=0;j<NJ;j++)              /* SOS definition */
  {
   le = new XPRBexpr();
   for(t=0;t<(NT-DUR[j]+1);t++)
    le.add(delta[j][t].mul((t+1)));
   set[j] = p.newSos("sosj", XPRB.S1, le);
  }
 }

Branching directives for the SOSs are added as follows.

for(j=0;j<NJ;j++) set[j].setDir(XPRB.DN);
                          /* First branch downwards on sets */

Adding the following two lines during or after the problem definition will print the problem to the standard output and export the matrix to a file respectively.

p.print();                /* Print out the problem def. */
p.exportProb(XPRB.MPS,"expl1");
                          /* Output matrix to MPS file */

Similarly to what has been shown for the problem formulation in C and C++, we may read data from file and use index sets in the problem formulation. Only a few changes and additions to the basic model formulation are required for the creation and use of index sets. However, if we want to read in a data file in the format accepted by the C functions XPRBreadlinecb and XPRBreadarrlinecb (that is, using '!' as commentary sign, and ',' as separators, and skip blanks and empty lines), we need to configure the data file access in Java.

In the following program listing we leave out the method jobsSolve because it remains unchanged from the previous.

import java.io.*;
import com.dashoptimization.*;

public class xbexpl1i
{
 static final int MAXNJ = 4;       /* Max. number of jobs */
 static final int NT = 10;         /* Time limit */

 static int NJ = 0;                /* Number of jobs read in */
 static final double[] DUR;        /* Durations of jobs */

 static XPRBindexSet Jobs;         /* Job names */
 static XPRBvar[] start;           /* Start times of jobs */
 static XPRBvar[][] delta;         /* Binaries for start times */
 static XPRBvar z;                 /* Max. completion time  */

 static XPRB bcl;
 static XPRBprob p;

    /**** Initialize the stream tokenizer ****/
 static StreamTokenizer initST(FileReader file)
 {
  StreamTokenizer st=null;

  st= new StreamTokenizer(file);
  st.commentChar('!');             /* Use character '!' for comments */
  st.eolIsSignificant(true);       /* Return end-of-line character */
  st.ordinaryChar(',');            /* Use ',' as separator */
  st.parseNumbers();               /* Read numbers as numbers (not strings)*/
  return st;
 }

    /**** Read data from files ****/
 static void readData() throws IOException
 {
  FileReader datafile=null;
  StreamTokenizer st;
  int i;
                                   /* Create a new index set */
  Jobs = p.newIndexSet("Jobs", MAXNJ);
  DUR = new double[MAXNJ];

  datafile = new FileReader("durations.dat");
  st = initST(datafile);
  do
  {
   do
   {
    st.nextToken();
   } while(st.ttype==st.TT_EOL);   /* Skip empty lines */
   if(st.ttype != st.TT_WORD) break;
   i=Jobs.addElement(st.sval);
   if(st.nextToken() != ',') break;
   if(st.nextToken() != st.TT_NUMBER) break;
   DUR[i] = st.nval;
   NJ+=1;
  } while( st.nextToken() == st.TT_EOL && NJ<MAXNJ);
  datafile.close();
  System.out.println("Number of jobs read: " + Jobs.getSize());
 }

static void jobsModel()
 {
  XPRBexpr le;
  int j,t;

  start = new XPRBvar[NJ];
  for(j=0;j<NJ;j++)               /* Start time variables with bounds */
   start[j] = p.newVar("start",XPRB.PL,0,NT-DUR[j]+1);
  z = p.newVar("z",XPRB.PL,0,NT); /* Makespan variable */

  delta = new XPRBvar[NJ][NT];
  for(j=0;j<NJ;j++)               /* Binaries for each job */
   for(t=0;t<(NT-DUR[j]+1);t++)
    delta[j][t] =
          p.newVar("delta"+Jobs.getIndexName(j)+"_"+(t+1),
                   XPRB.BV);

  for(j=0;j<NJ;j++)               /* Calculate max. completion time */
   p.newCtr("Makespan", start[j].add(DUR[j]).lEql(z) );

  p.newCtr("Prec", start[0].add(DUR[0]).lEql(start[2]) );
                                  /* Precedence rel. between jobs */

  for(j=0;j<NJ;j++)               /* Linking start times & binaries */
  {
   le = new XPRBexpr();
   for(t=0;t<(NT-DUR[j]+1);t++)
    le.add(delta[j][t].mul((t+1)));
   p.newCtr("Link_"+(j+1), le.eql(start[j]) );
  }

  for(j=0;j<NJ;j++)               /* Unique start time for each job */
  {
   le = new XPRBexpr();
   for(t=0;t<(NT-DUR[j]+1);t++) le.add(delta[j][t]);
   p.newCtr("One_"+(j+1), le.eql(1));
  }

  p.setObj(z);                    /* Define and set objective */
 }

 public static void main(String[] args)
 {
  bcl = new XPRB();               /* Initialize BCL */
  p = bcl.newProb("Jobs");        /* Create a new problem */

  try
  {
   readData();                    /* Data input from file */
  }
  catch(IOException e)
  {
   System.err.println(e.getMessage());
   System.exit(1);
  }
  jobsModel();                    /* Problem definition */
  jobsSolve();                    /* Solve and print solution */

  p.finalize();                   /* Delete the problem (optional) */
  p=null;
 }
}

QCQP Example

The following is an implementation with BCL Java of the QCQP example described in Section Example:

import java.io.*;
import com.dashoptimization.*;

public class xbairport
{
 static final int N = 42;
/* Initialize the data tables:
 static final double CX[] = ...
 static final double CY[] = ...
 static final double R[] = ...
*/
 public static void main(String[] args) throws IOException
 {
  XPRB bcl;
  XPRBprob prob;
  int i,j;
  XPRBvar[] x,y;                  /* x-/y-coordinates to determine */
  XPRBexpr qe;
  XPRBctr cobj, c;

  bcl = new XPRB();                 /* Initialize BCL */
  prob = bcl.newProb("airport");    /* Create a new problem in BCL */

/**** VARIABLES ****/
  x = new XPRBvar[N];
  for(i=0;i<N;i++)
   x[i] = prob.newVar("x(" + (i+1) + ")", XPRB.PL, -10, 10);
  y = new XPRBvar[N];
  for(i=0;i<N;i++)
   y[i] = prob.newVar("y(" + (i+1) + ")", XPRB.PL, -10, 10);

/****OBJECTIVE****/
/* Minimize the total distance between all points */
  qe = new XPRBexpr();
  for(i=0;i<N-1;i++)
   for(j=i+1;j<N;j++) qe .add((x[i].add(x[j].mul(-1))).sqr())
                         .add((y[i].add(y[j].mul(-1))).sqr());
  cobj = prob.newCtr("TotDist", qe);
  prob.setObj(cobj);                 /* Set objective function */

/**** CONSTRAINTS ****/
/* All points within given distance of their target location */
  for(i=0;i<N;i++)
   c = prob.newCtr("LimDist", (x[i].add(-CX[i])).sqr()
                   .add( (y[i].add(-CY[i])).sqr()) .lEql(R[i]) );

/****SOLVING + OUTPUT****/
  prob.setSense(XPRB.MINIM);         /* Sense of optimization */
  prob.lpOptimize();                 /* Solve the problem */

  System.out.println("Solution: " + prob.getObjVal());
  for(i=0;i<N;i++)
   System.out.println(x[i].getName() + ": " + x[i].getSol() +
               ", " + y[i].getName() + ": " + y[i].getSol());

  p.finalize();                      /* Delete the problem */
  p=null;
 }
}  

Error handling

If an error occurs, BCL Java raises exceptions. A large majority of these execeptions are of class XPRBerror, during initialization of class XPRBlicenseError, and if file access is involved (such as in method exportProb) of class IOException. For simplicity's sake most of the Java program examples in this manual omit the error handling. Below we show a Java implementation of the example of user error handling with BCL from Section User error handling. Other features demonstrated by this example include

  • redirection of the BCL output stream for the whole program and for an individual problem;
  • setting the BCL message printing level;
  • forcing garbage collection for a problem after explicitly finalizing it to free up memory;
  • finalization of BCL to release the license.
import java.io.*;
import com.dashoptimization.*;

public class xbexpl3
{
 static XPRB bcl;

/***********************************************************************/

 public static void modexpl3(XPRBprob prob) throws XPRBerror
 {
  XPRBvar[] x;
  XPRBexpr cobj;
  int i;

  x = new XPRBvar[3];                 /* Create the variables */
  for(i=0;i<2;i++) x[i] = prob.newVar("x_"+i, XPRB.UI, 0, 100);

                /* Create the constraints:
                   C1: 2x0 + 3x1 >= 41
                   C2:  x0 + 2x1  = 13 */
  prob.newCtr("C1", x[0].mul(2).add(x[1].mul(3)) .gEql(41));
  prob.newCtr("C2", x[0].add(x[1].mul(2)) .eql(13));

/* Uncomment the following line to cause an error in the model that
   triggers the error handling: */

//  x[2] = prob.newVar("x_2", XPRB.UI, 10, 1);

                /* Objective: minimize x0+x1 */
  cobj = new XPRBexpr();
  for(i=0;i<2;i++) cobj.add(x[i]);
  prob.setObj(cobj);             /* Select objective function */
  prob.setSense(XPRB.MINIM);     /* Set objective sense to minimization */

  prob.print();                  /* Print current problem definition */

  prob.lpOptimize();             /* Solve the LP */
  System.out.println("Problem status: " + prob.getProbStat() +
                     "  LP status: " + prob.getLPStat() +
                     "  MIP status: " + prob.getMIPStat());

/* This problem is infeasible, that means the following command will fail.
   It prints a warning if the message level is at least 2 */

  System.out.println("Objective: " + prob.getObjVal());

  for(i=0;i<2;i++)               /* Print solution values */
   System.out.print(x[i].getName() + ":" + x[i].getSol() + ", ");
  System.out.println();
}

/***********************************************************************/

 public static void main(String[] args)
 {
  FileWriter f;
  XPRBprob prob;

  try
  {
   bcl = new XPRB();             /* Initialize BCL */
  }
  catch(XPRBlicenseError e)
  {
   System.err.println("BCL error "+ e.getErrorCode() + ": " + e.getMessage());
   System.exit(1);
  }

  bcl.setMsgLevel(2);            /* Set the printing flag. Try other values:
                                    0 - no printed output,
                                    2 - print warnings, 3 - all messages */
  try
  {
   f=new FileWriter("expl3out.txt");
   bcl.setOutputStream(f);       /* Redirect all output from BCL to a file */

   prob = bcl.newProb("Expl3");  /* Create a new problem */
   prob.setOutputStream();       /* Output for this prob. on standard output */
   modexpl3(prob);               /* Formulate and solve the problem */

   prob.setOutputStream(f);      /* Redirect problem output to file */
   prob.print();                 /* Write to the output file */
   prob.setOutputStream();       /* Re-establish standard output for prob */
   bcl.setOutputStream();        /* Re-establish standard output for BCL */
   f.close();

   prob.finalize();              /* Delete the problem */
   prob=null;

   bcl.finalize();               /* Release license */
   bcl=null;

   System.gc();                  /* Force garbage collection */
   System.runFinalization();

   System.err.flush();
  }
  catch(IOException e)
  {
   System.err.println(e.getMessage());
   System.exit(1);
  }
  catch(XPRBerror e)
  {
   System.err.println("BCL error "+ e.getErrorCode() + ": " + e.getMessage());
   System.exit(1);
  }
 }
}

Java class reference

The complete set of classes of the BCL Java interface is summarized in the following list. For a detailed documentation of the Java interface the reader is referred to the BCL Javadoc that is part of the Xpress distribution (located in subdirectory docs/bcl/dhtml/javadoc of the Xpress installation directory).

XPRB
Initialization and general settings, definition of all parameters.
XPRBprob
Problem definition, including methods for creating and deleting the modeling objects, problem solving, changing settings, and retrieving solution information.
XPRBvar
Methods for modifying and accessing variables.
XPRBctr
Methods for constructing, modifying and accessing constraints.
XPRBcut
Methods for constructing, modifying and accessing cuts.
XPRBsol
Methods for constructing, modifying and accessing solutions.
XPRBsos
Methods for constructing, modifying and accessing Special Ordered Sets.
XPRBindexSet
Methods for constructing and accessing index sets and accessing set elements.
XPRBbasis
Methods for accessing bases.
XPRBexpr
Methods for constructing linear and quadratic expressions.
XPRBrelation
Methods for constructing linear or quadratic relations from expressions (extends XPRBexpr).
XPRBerror
Exception raised by BCL errors (extends Error).
XPRBlicenseError
Exception raised by BCL licensing errors (extends XPRBerror).
XPRBlicense
For OEM licensing.

All Java classes that have a direct correspondence with modeling objects in BCL (namely XPRBprob, XPRBvar, XPRBctr, XPRBcut, XPRBsol, XPRBsos, XPRBindexSet, XPRBbasis) take the same names, with the exception of XPRBindexSet. It is possible to obtain the Xpress Optimizer problem corresponding to a BCL Java problem by using method getXPRSprob of class XPRBprob, please see Section Using the Optimizer with BCL Java for further detail on using BCL with the Optimizer library.

Most of the methods of the classes with direct correspondence with C modeling objects call standard BCL C functions and return their result. Where the C functions return 0 or 1 to indicate success or failure of the execution of a function the Java methods have return type void, raising an exception if an error occurs.

An important class that does not correspond to any standard BCL modeling object is class XPRB that contains methods relating to the initialization and the general status of the software and also the definition of all parameters. This means, any parameter with the prefix XPRB_ in standard BCL is referred to as a constant of the Java class XPRB. For example, XPRB_BV in standard BCL becomes XPRB.BV in Java.

In Java, it is not possible to overload operators as this is the case in the C++ interface; instead, a set of simple methods is provided, for example, add or eql that have been overloaded to accept various types and numbers of parameters. Some additional classes have been introduced to aid the termwise definition of constraints. Linear and quadratic expressions (class XPRBexpr) are required in the definition of constraints and Special Ordered Sets. Linear or quadratic relations (class XPRBrelation), may be used as an intermediary in the definition of constraints.

A few other additional classes are related to error handling and licensing, namely XPRBerror, XPRBlicense, and XPRBlicenseError (overloads XPRBerror). License errors are raised by the initialization of BCL, all other BCL errors are handled by exceptions of the type XPRBerror. Output functions involving file access (in particular matrix output with exportProb) may also generate exceptions of type IOException. The class XPRBlicense only serves for OEM licensing; for further detail please see the Xpress OEM licensing documentation.


© 2001-2025 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.