Using BCL with the Optimizer library



BCL provides both modeling and basic optimization functions, which correspond to the functionality of Xpress-Mosel, or of the Xpress-Modeler and the functions of the Xpress-Optimizer library in `Console Mode', respectively. However, if the user wishes to access the more advanced features of the Optimizer, obtain additional information, or change algorithm settings, the relevant Optimizer library functions have to be used directly.

The following sections explain in more detail how to use Optimizer library functions within a BCL program. The first section lists those functions which are compatible with BCL. It is followed by some general remarks about initialization, loading the matrix and the use of indices. The last section contains some typical examples for the use of BCL-compatible Optimizer functions in BCL programs.

Important: If a program uses Optimizer library functions the Optimizer header file has to be included in addition to the BCL header file. That is, the first lines of the program should contain the following:

#include "xprb.h"
#include "xprs.h"

Switching between libraries

Generally speaking, there are two types of Optimizer library functions: those that access information about a problem or change settings for the search algorithms, and those that make changes to the problem definition. The first group of functions may be used in a BCL program without any problem. The second group requires the user to switch completely to the Optimizer library, for instance after a problem has been defined in BCL and the matrix has been loaded into the Optimizer.

BCL-compatible Optimizer functions

The following Optimizer library functions may be used with BCL (however, some caution is required with all functions that take column or row indices as input parameters, see Section Indices of matrix elements below. Furthermore, the solution information in BCL is only updated automatically at the end of the search, in the global callbacks it needs to be updated by calling XPRBsync with the parameter XPRB_XPRS_SOL):

Incompatible Optimizer functions

The following Optimizer library functions may be used only after or in place of BCL:

Once any of the functions in the preceding list have been called for a given problem, the information held in BCL may be different from the problem in the Optimizer and it is not possible to update BCL accordingly. The program must therefore continue using only Optimizer library functions on that problem, that is, switch completely to the Optimizer library. The `switching' from BCL to the Optimizer library always refers to a single problem. If other problems are being worked on in parallel, for which none of the above incompatible function have been called, users can continue to work with them using BCL functions.

Initialization and termination

The Optimizer library is initialized at the same time as BCL and so there is no need to call the Optimizer library initialization function, XPRSinit, from a user program. In standard use of BCL the function XPRBnewprob calls the BCL initialization function XPRBinit that automatically initializes the Optimizer if this is the first call to XPRBinit. In very large applications or integration with other systems it may be preferrable to call XPRBinit explicitly to separate the initialization from the definition of the problem(s).

At the end of the program, the normal BCL termination routine should be applied, first releasing any memory associated to problems using XPRBdelprob and subsequently calling XPRBfree to tidy up. These routines also free memory associated with the Optimizer library and hence neither of the XPRSdestroyprob or XPRSfree functions must be used. However, if one wishes to continue working with the Optimizer after terminating BCL, the Optimizer needs to be initialized (possibly before initializing BCL) and terminated separately.

Thus, the standard use of BCL is as follows:

XPRBprob prob;
prob = XPRBnewprob("Example1"); 
   ...                       /* Define and solve the problem */

Integration of a BCL problem into some larger application:

XPRBprob prob;
XPRBinit("");
   ...                       /* Perform other initialization tasks */
prob = XPRBnewprob("Example1"); 
   ...                       /* Define and solve the problem */
XPRBdelprob(prob);
XPRBfree();

Loading the matrix

BCL loads the matrix into the Optimizer library whenever (through BCL) an action is required from the Optimizer and the matrix in the Optimizer does not correspond to the one in BCL. This means, if a user wishes to switch to using Optimizer library commands, for instance for performing the optimization, he should explicitly load the current BCL problem into the Optimizer (function XPRBloadmat).

Since both BCL and the Optimizer require separate problem pointers to specify the problem being worked on, there is an issue about how to obtain the Optimizer problem pointer referring to a problem just loaded by BCL. Such issues are handled using the function XPRBgetXPRSprob, which returns the required Optimizer pointer. It should be noted that no call to XPRScreateprob is necessary in this instance, as the problem is created by BCL at the point that it is first passed to the Optimizer.

Standard use of BCL:

XPRBarrvar x;
   ...
x = XPRBnewarrvar(prob, 10, XPRB_PL, "x", 0, 100);
   ...                        /* (Define the rest of the problem) */
XPRBmaxim(prob,"");           /* Load matrix and maximize LP problem */
for(i=0; i<10; i++)           /* Print solution values for variables */
  printf("%s: %d, ",XPRBgetvarname(prob,x[i]),
                    XPRBgetsol(prob,x[i]));

Switch to using the Optimizer library after problem input with BCL:

XPRBprob bcl_prob;
XPRSprob opt_prob;
XPRBarrvar x;
int i, cols, len;
double sol;
char names;

bcl_prob = XPRBnewprob("Example1");  /* Initialize BCL (and the Optimizer
                                 library) and create a new problem */
x = XPRBnewarrvar(bcl_prob, 10, XPRB_PL, "x", 0, 100);
   ...                        /* Define the rest of the problem */
XPRBloadmat(bcl_prob);        /* Load matrix into the Optimizer */
opt_prob = XPRBgetXPRSprob(bcl_prob); 
                              /* Get the Optimizer problem */
XPRSmaxim(opt_prob,"");       /* Maximize the LP problem */
XPRSgetintattrib(opt_prob,XPRS_COLS, &cols); 
                              /* Get the number of columns */
sol = malloc(cols * sizeof(double));
XPRSgetlpsol(opt_prob,sol,NULL,NULL,NULL); 
                              /* Get entire primal solution */
XPRSgetintattrib(opt_prob,XPRS_NAMELENGTH,&len);  /* Get the
                              length of names (divided by 8) */
names = malloc((8*len+1)*cols);
XPRSgetnames(opt_prob,2, names, 0, cols-1); 
                              /* Get variable names */
for(i=0; i<cols; i++)         /* Print all solution values */
  printf("%s: %g, ", names+((8*len+1)*i), sol[i]);

Indices of matrix elements

The row and column indices that are returned by the BCL functions XPRBgetrownum and XPRBgetcolnum correspond to the position of variables and constraints in the unpresolved matrix with empty rows or columns removed. The position of matrix elements may be modified by the presolve/preprocessing algorithms. That means, if these algorithms are not switched off (control parameters XPRS_PRESOLVE and XPRS_MIPPRESOLVE), the indices for variables and constraints held by BCL should not be used with any Optimizer library functions. The same rule applies to any other variable or constraint-specific information, such as solution and dual values. This problem does not occur within BCL (that is, if only BCL functions are used) since the solution information is accessible only after the optimization run has finished and the postsolve has been performed by the Optimizer.

An exception from the rule stated above are the Optimizer library functions XPRSgetlpsol / XPRSgetmipsol: XPRSgetlpsol may be used, for instance, in Optimizer library callback functions during the global search to access the current solution values, and in combination with the indices for variables and constraints held by BCL. This is possible because XPRSgetlpsol / XPRSgetmipsol return the postsolved solution (depending on the setting of the control parameter XPRS_SOLUTIONFILE).

Using BCL-compatible functions

The Optimizer library functions that are most likely to be used in a BCL program are those for setting and accessing control and problem parameters, as shown in the following examples. The control parameters can be set and accessed at any time after the software has been initialized (see Section Initialization and termination). The problem attributes only return the problem-specific values once the problem has been loaded into the Optimizer. Note that all the parameters take their default values at the beginning of a BCL program but they are not reset if several problems are solved in a single program and changes are made to the parameter values along the way.

Setting control parameters:

XPRBprob bcl_prob;
XPRSprob opt_prob;

bcl_prob = XPRBnewprob("Example1");  /* Initialize BCL (and the Optimizer
                                  library) and create a new problem */
   ...                         /* Define the problem */
XPRBloadmat(bcl_prob);
opt_prob = XPRBgetXPRSprob(bcl_prob);
XPRSsetintcontrol(opt_prob,XPRS_MAXTIME, 60); 
                               /* Set a time limit of 60 seconds */
XPRSsetdblcontrol(opt_prob,XPRS_MIPADDCUTOFF, 0.999);    
                               /* Set an ADDCUTTOFF value */
XPRBmaxim(bcl_prob,"");        /* Load matrix and maximize LP problem */

Accessing problem parameters:

int rows;
XPRBprob bcl_prob;
XPRSprob opt_prob;

bcl_prob = XPRBnewprob("Example1");  /* Initialize BCL (and the Optimizer
                                  library) and create a new problem */
    ...                        /* Define the problem */
XPRBloadmat(bcl_prob);         /* Load matrix into the Optimizer */
opt_prob = XPRBgetXPRSprob(bcl_prob);
XPRSgetintattrib(opt_prob,XPRS_ROWS, &rows); 
                               /* Get number of rows */
XPRBmaxim(bcl_prob,"");        /* Maximize the LP problem */

Another likely set of functions are the Optimizer library callbacks for solution printout and possibly for directing the branch and bound search (see the remarks about indices in Section Indices of matrix elements):

void XPRS_CC printsol(XPRSprob opt_prob,void *my_object)
{
  XPRBprob bcl_prob
  XPRBvar x;
  int num;

  bcl_prob = (XPRBprob)my_object;
  XPRSgetintattrib(opt_prob,XPRS_INTSOL,&num);
                               /* Get number of the solution */
  XPRSsetintcontrol(opt_prob,XPRS_SOLUTIONFILE,0); 
  XPRBsync(bcl_prob, XPRB_XPRS_SOL);
                               /* Update BCL solution values */
  XPRBprintf(bcl_prob,"Solution %d: Objective value: %g\n", 
              num, XPRBgetobjval(bcl_prob));
  x = XPRBgetbyname(bcl_prob, "x_1", XPRB_VAR);
  if(XPRBgetcolnum(x)>-1)      /* Test whether variable is in the 
                                  matrix */
    XPRBprintf(bcl_prob, "%s: %g\n", XPRBgetvarname(x), XPRBgetsol(x)); 
  XPRSsetintcontrol(opt_prob,XPRS_SOLUTIONFILE,1);
}

int main(int argc, char **argv)
{
  XPRBprob bcl_prob;
  XPRSprob opt_prob;
  XPRBvar x;
  
  bcl_prob = XPRBnewprob("Example1");  /* Initialize BCL (and the Optimizer
                                  library) and create a new problem */
  x = XPRBnewvar(bcl_prob,XPRB_BV,"x_1",0,1);   /* Define a variable */
     ...                       /* Define the rest of the problem */
  opt_prob = (XPRSprob)XPRBgetXPRSprob(bcl_prob);
  XPRSsetcbintsol(opt_prob,printsol,bcl_prob); 
                               /* Define an integer solution callback */
  XPRBmaxim(bcl_prob,"g");     /* Maximize the MIP problem */
}

Using the Optimizer with BCL C++

Everything that has been said above about the combination of BCL and Xpress-Optimizer functions remains true if the BCL program is written in C++.

The examples of BCL-compatible Optimizer functions in the previous section become:

Setting and accessing parameters:

int rows;
XPRSprob opt_prob;
XPRBprob bcl_prob("Example1"); // Initialize BCL (and the Optimizer
                               // library) and create a new problem
   ...                         // Define the problem
bcl_prob.loadMat();
opt_prob = bcl_prob.getXPRSprob();
XPRSsetintcontrol(opt_prob,XPRS_MAXTIME, 60); 
                               // Set a time limit of 60 seconds 
XPRSsetdblcontrol(opt_prob,XPRS_MIPADDCUTOFF, 0.999);    
                               // Set an ADDCUTTOFF value
XPRSgetintattrib(opt_prob,XPRS_ROWS, &rows); 
                               // Get number of rows 
bcl_prob.maxim("");            // Maximize the LP problem 

Using Xpress-Optimizer callbacks:

void XPRS_CC printsol(XPRSprob opt_prob,void *my_object)
{
  XPRBprob *bcl_prob
  XPRBvar x;
  int num;

  bcl_prob = (XPRBprob*)my_object;
  XPRSgetintattrib(opt_prob, XPRS_MIPSOLS, &num);
                               // Get number of the solution 
  XPRSsetintcontrol(opt_prob, XPRS_SOLUTIONFILE, 0); 
  bcl_prob->sync(XPRB_XPRS_SOL);
                               // Update BCL solution values 
  cout << "Solution " << num << ": Objective value: ";
  cout << bprob->getObjVal() << endl;
  x = bcl_prob->getVarByName("x_1");
  if(x.getColNum()>-1)         // Test whether variable is in the 
                               // matrix 
    cout << x.getName() << ": " << x.getSol() << endl; 
  XPRSsetintcontrol(opt_prob, XPRS_SOLUTIONFILE, 1);
}

int main(int argc, char **argv)
{
  XPRBprob bcl_prob;
  XPRSprob opt_prob;
  XPRBvar x;
  
  bcl_prob = XPRBnewprob("Example1");  // Initialize BCL (and the Optimizer
                               // library) and create a new problem 
  x = bcl_prob.newVar("x_1", XPRB_BV); // Define a variable 
     ...                       // Define the rest of the problem 
  opt_prob = bcl_prob.getXPRSprob();
  XPRSsetcbintsol(opt_prob, printsol, &bcl_prob); 
                               // Define an integer solution callback 
  bcl_prob.maxim("g");         // Maximize the MIP problem 
}

As in the C case, it is possible within a BCL program written in C++ to switch entirely to Xpress-Optimizer (see Section Loading the matrix).

Using the Optimizer with BCL Java

Starting with Release 3.0 of BCL it is possible to combine BCL Java problem definition with direct access to the Optimizer problem in Java. All that is said in the previous sections about BCL-compatible functions remains true. The only noticeable difference is that the Optimizer Java needs to be initialized explicitly (by calling XPRSinit) before the Optimizer problem is accessed.

The following are Java implementations of the code extracts showing the use of BCL-compatible functions:

Setting and accessing parameters (this code throws the exceptions XPRSprobException and XPRSexception):

int rows;
XPRB bcl;
XPRSprob opt_prob;
XPRBprob bcl_prob;

bcl = new XPRB();              /* Initialize BCL */
bcl_prob = bcl.newProb("Example1");  /* Create a new problem in BCL */
XPRS.init();                   /* Initialize Xpress-Optimizer */
   ...                         /* Define the problem */
bcl_prob.loadMat();
opt_prob = bcl_prob.getXPRSprob();
opt_prob.setIntControl(XPRS.MAXTIME, 60); 
                               /* Set a time limit of 60 seconds */
opt_prob.setDblControl(XPRS.MIPADDCUTOFF, 0.999);    
                               /* Set an ADDCUTTOFF value */
rows = opt_prob.getIntAttrib(XPRS.ROWS); 
                               /* Get number of rows */
bcl_prob.maxim("");            /* Maximize the LP problem */

Using Xpress-Optimizer callbacks:

static class IntSolCallback implements XPRSintSolListener
{
  public void XPRSintSolEvent(XPRSprob opt_prob, Object my_object)
  {
    XPRBprob bcl_prob
    XPRBvar x;
    int num;

    bcl_prob = (XPRBprob)my_object;
    try {
      num = oprob.getIntAttrib(XPRS.MIPSOLS);
                               /* Get number of the solution */
      oprob.setIntControl(XPRS.SOLUTIONFILE, 0); 
      bcl_prob.sync(XPRB.XPRS_SOL);
                               /* Update BCL solution values */
      System.out.println("Solution " + num + ": Objective value: " +
                         bcl_prob.getObjVal());
      x = bcl_prob.getVarByName("x_1");
      if(x.getColNum()>-1)     /* Test whether variable is in the 
                                  matrix */
        System.out.println(x.getName() + ": " + x.getSol()); 
      oprob.setIntControl(XPRS.SOLUTIONFILE, 1);
    }
    catch(XPRSprobException e) {
      System.out.println("Error " + e.getCode() + ": " + e.getMessage());
    }
  }
}

public static void main(String[] args) throws XPRSexception
{
  XPRB bcl;
  XPRBprob bcl_prob;
  XPRSprob opt_prob;
  IntSolCallback cb;
  XPRBvar x;
    
  bcl = new XPRB();                    /* Initialize BCL */
  bcl_prob = bcl.newProb("Example1");  /* Create a new problem in BCL */
  XPRS.init();                         /* Initialize Xpress-Optimizer */
  
  x = bcl_prob.newVar("x_1", XPRB_BV); /* Define a variable */
     ...                       /* Define the rest of the problem */
  opt_prob = bcl_prob.getXPRSprob();
  cb = new IntSolCallback();
  opt_prob.addIntSolListener(cb, bcl_prob); 
                               /* Define an integer solution callback */
  bcl_prob.maxim("g");         /* Maximize the MIP problem */
}


If you have any comments or suggestions about these pages, please send mail to docs@dashoptimization.com.