Using BCL with the Optimizer library
Topics covered in this chapter:
- Switching between libraries
- Initialization and termination
- Loading the matrix
- Indices of matrix elements
- Using BCL-compatible functions
- Using the Optimizer with BCL C++
- Using the Optimizer with BCL Java
- Using the Optimizer with BCL .NET
BCL provides both modeling and basic optimization functions, which correspond to the functionality of Xpress Mosel, or of 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 MIP callbacks—not for parallelized MIP—it needs to be updated by calling XPRBsync with the parameter XPRB_XPRS_SOL or XPRB_XPRS_SOLMIP):
- setting and accessing problem and control parameters: functions XPRSsetintcontrol, XPRSgetintcontrol, XPRSgetintattrib etc.;
- output and saving: functions XPRSsave, XPRSwritebasis, XPRSiis, XPRSwriteprtsol, XPRSwritesol, XPRSgetlpsol, XPRSgetmipsol, XPRSwriteomni, XPRSwriteprob, all logging and solution callbacks with the exception of XPRSsetcbmessage that is used by BCL and must not be re-defined by the user;
- accessing information: all functions XPRSget...,;
- settings for algorithms: XPRSreaddirs, XPRSloaddirs, XPRSreadbasis, XPRSloadbasis, XPRSloadsecurevecs, XPRSscale, XPRSftran, XPRSbtran, all MIP callbacks;
- cut manager.
Incompatible Optimizer functions
The following Optimizer library functions may be used only after or in place of BCL:
- changing, adding, and deleting matrix elements: all functions XPRSadd..., XPRSchg..., XPRSdel...;
- solution algorithms: XPRSlpoptimize, XPRSmipoptimize;
- input of data or problem(s): XPRSreadprob, XPRSloadlp, XPRSloadmip, XPRSloadmiqp, XPRSloadqp, XPRSalter, XPRSsetprobname;
- manipulation of the matrix: XPRSrestore;
- callback: XPRSsetcbmessage
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) */ XPRBsetsense(prob, XPRB_MAXIM); /* Set sense to maximization */ XPRBlpoptimize(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, offset; 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 */ XPRSchgobjsense(opt_prob,XPRS_OBJ_MAXIMIZE); /* Select maximization */ XPRSlpoptimize(opt_prob,""); /* Maximize the LP problem */ XPRSgetintattrib(opt_prob, XPRS_INPUTCOLS, &cols); /* Get the number of columns */ sol = malloc(cols * sizeof(double)); XPRSgetsolution(opt_prob, NULL, sol, 0, cols-1); /* Get entire primal solution */ XPRSgetnamelist(opt_prob, 2, NULL, 0, &len, 0, cols-1); /* Get number of bytes required for retrieving names */ names = (char *)malloc(len*sizeof(char)); XPRSgetnamelist(opt_prob, 2, names, len, NULL, 0, ncol-1); /* Get the variable names */ offset=0; for(i=0; i<cols; i++) { /* Print all solution values */ printf("%s: %g, ", names+offset, sol[i]); offset += strlen(names+offset)+1; }
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 branch and bound tree 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.
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 */ XPRBsetsense(bcl_prob, XPRB_MAXIM); /* Select maximization */ XPRBlpoptimize(bcl_prob,""); /* Load matrix and solve as 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_INPUTROWS, &rows); /* Get number of rows */ XPRBsetsense(bcl_prob, XPRB_MAXIM); /* Select maximization */ XPRBlpoptimize(bcl_prob,""); /* Load matrix and solve as 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; XPRBbegincb(bcl_prob, opt_prob); /* Use local Optimizer problem in BCL */ XPRSgetintattrib(opt_prob, XPRS_MIPSOLS, &num); /* Get number of solutions */ 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)); XPRBendcb(bcl_prob); /* Reset BCL to main problem */ } 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 */ XPRBsetsense(bcl_prob, XPRB_MAXIM); /* Select maximization */ XPRBmipoptimize(bcl_prob,""); /* Solve as MIP problem */ }
The synchronization between BCL and the Optimizer during the MIP search requires some special care. The code extract above shows how to use the functions XPRBbegincb and XPRBendcb to coordinate the BCL solution information with the Optimizer subproblem in a default multi-threaded MIP search. Alternatively, you may choose to disable parallelism by setting the XPRS_MIPTHREADS control to 1.
opt_prob = XPRBgetXPRSprob(bcl_prob); XPRSsetintcontrol(opt_prob, XPRS_MIPTHREADS, 1); /* Use single-threaded MIP */
MIP solution information can also be accessed through the Optimizer library functions whereby it is possible to use the column or row indices saved for BCL modeling objects as shown below. In this case there is no need for synchronizing the BCL solution information.
void XPRS_CC printsol(XPRSprob opt_prob,void *my_object) { int num,ncol; XPRBprob bprob; XPRBvar x; double *sol, objval; bprob = (XPRBprob)vp; XPRSgetintattrib(oprob, XPRS_INPUTCOLS, &ncol); /* Get the number of columns */ sol = (double *)malloc(ncol * sizeof(double)); /* Create the solution array */ XPRSgetintattrib(oprob, XPRS_MIPSOLS, &num); /* Get number of solutions */ XPRSgetsolution(oprob, NULL, sol, 0, ncol-1); /* Get the solution values */ XPRSgetdblattrib(oprob, XPRS_OBJVAL, &objval); printf("Solution %d: Objective value: %g\n", num, objval); x = XPRBgetbyname(bprob, "x_1", XPRB_VAR); if(XPRBgetcolnum(x)>-1) printf("%s: %g\n", XPRBgetvarname(x), sol[XPRBgetcolnum(x)]); free(sol); }
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_INPUTROWS, &rows); // Get number of rows bcl_prob.setSense(XPRB_MAXIM); // Select maximization bcl_prob.lpOptimize(); // Maximize the LP problem
Using Xpress Optimizer callbacks (multi-threaded MIP):
void XPRS_CC printsol(XPRSprob opt_prob,void *my_object) { XPRBprob *bcl_prob XPRBvar x; int num; bcl_prob = (XPRBprob*)my_object; bcl_prob->beginCB(opt_prob); // Use local Optimizer problem in BCL XPRSgetintattrib(opt_prob, XPRS_MIPSOLS, &num); // Get number of solutions 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; bcl_prob->endCB(); // Reset BCL to main problem } 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.setSense(XPRB_MAXIM); // Select maximization bcl_prob.mipOptimize(); // Maximize the MIP problem }
The code extract below shows how to access MIP solution information directly through the Optimizer library functions using the column or row indices saved for BCL modeling objects. In this case there is no need for synchronization of BCL with the local solution information.
void XPRS_CC printsol(XPRSprob opt_prob,void *my_object) { XPRBprob *bcl_prob XPRBvar x; int num, ncol; double *sol, objval; bcl_prob = (XPRBprob*)my_object; XPRSgetintattrib(opt_prob, XPRS_INPUTCOLS, &ncol); // Get the number of columns sol = new double[ncol]; // Create the solution array // Get number of solutions XPRSgetintattrib(opt_prob, XPRS_MIPSOLS, &num); // Get the solution XPRSgetsolution(opt_prob, NULL, sol, 0, ncol-1); XPRSgetdblattrib(opt_prob, XPRS_OBJVAL, &objval); cout << "Solution " << num << ": Objective value: " << objval << endl; x = bcl_prob->getVarByName("x_1"); if(x.getColNum()>-1) // Test whether variable is in the // matrix cout << x.getName() << ": " << sol[x.getColNum()] << endl; delete [] sol; }
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.INPUTROWS); /* Get number of rows */ bcl_prob.setSense(XPRB.MAXIM); // Select maximization bcl_prob.lpOptimize(); // Maximize the LP problem
Using Xpress Optimizer callbacks (multi-threaded MIP):
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 { bcl_prob.beginCB(opt_prob); /* Use local Optimizer problem in BCL */ num = opt_prob.getIntAttrib(XPRS.MIPSOLS); /* Get number of solutions */ 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()); bcl_prob.endCB(); /* Reset BCL to main problem */ } 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.setSense(XPRB.MAXIM); /* Select maximization */ bcl_prob.mipOptimize(); /* Maximize the MIP problem */ }
The code extract below shows how to access MIP solution information directly through the Optimizer library functions using the column or row indices saved for BCL modeling objects. In this case there is no need for synchronization of BCL with the local solution information.
static class IntSolCallback implements XPRSintSolListener { public void XPRSintSolEvent(XPRSprob opt_prob, Object my_object) { XPRBprob bcl_prob XPRBvar x; int num; double [] sol; bcl_prob = (XPRBprob)my_object; try { ncol = opt_prob.getIntAttrib(XPRS.INPUTCOLS); /* Get the number of columns */ sol = opt_prob.getSolution(null, 0, ncol-1); /* Get the solution */ num = opt_prob.getIntAttrib(XPRS.MIPSOLS); /* Get number of solutions */ System.out.println("Solution " + num + ": Objective value: " + opt_prob.getDblAttrib(XPRS.OBJVAL)); x = bcl_prob.getVarByName("x_1"); if(x.getColNum()>-1) /* Test whether variable is in the matrix */ System.out.println(x.getName() + ": " + sol[x.getColNum()]); sol = null; } catch(XPRSprobException e) { System.out.println("Error " + e.getCode() + ": " + e.getMessage()); } } }
Using the Optimizer with BCL .NET
Using the Optimizer with BCL .NET is very similar to the other interfaces already seen and the same considerations regarding BCL-compatible functions remain true. The BCL .NET interface also requires an explicit intialization of the Optimizer .NET interface (by calling XPRS.Init()) before the Optimizer problem is accessed.
The following are .NET implementations of the code extracts showing the use of BCL-compatible functions:
Setting and accessing parameters:
int rows; XPRB.init(); // Initialize BCL XPRS.Init(); // Initialize Xpress Optimizer XPRSprob opt_prob; XPRBprob bcl_prob; bcl_prob = new XPRBprob("Example1"); // Create a new problem in BCL ... // Define the problem bcl_prob.loadMat(); opt_prob = bcl_prob.getXPRSprob(); opt_prob.MaxTime = 60; // Set a time limit of 60 seconds opt_prob.MIPAddCutoff = 0.999; // Set an ADDCUTTOFF value rows = opt_prob.InputRows; // Get number of rows bcl_prob.setSense(BCLconstant.XPRB_MAXIM); // Select maximization bcl_prob.lpOptimize(); // Maximize the LP problem
Using Xpress Optimizer callbacks (multi-threaded MIP):
public class IntSolExample public static void PrintSolution(XPRSprob opt_prob, object my_object) { XPRBprob bcl_prob = (XPRBprob)my_object; bcl_prob.beginCB(opt_prob); int num = opt_prob.MIPSols; bcl_prob.sync(BCLconstant.XPRB_XPRS_SOL); // Update BCL solution values System.Console.WriteLine("Solution "+num+": Objective value: "+bcl_prob.getObjVal()); XPRBvar x = bcl_prob.getVarByName("x_1"); if( x.getColNum() > -1 ) // Test whether variable is in the matrix System.Console.WriteLine(x.getName() + ": " + x.getSol()); bcl_prob.endCB(); } public static void Main() { XPRB.init(); XPRS.Init(); XPRBprob bcl_prob = new XPRBprob("Example1"); XPRBvar x = bcl_prob.newVar("x_1", BCLconstant.XPRB_BV); // Define a variable ... // Define the rest of the problem XPRSprob opt_prob = bcl_prob.getXPRSprob(); // Define an integer solution callback IntsolCallback printsol = new IntsolCallback(PrintSolution); opt_prob.AddIntsolCallback(printsol, (object)bcl_prob); bcl_prob.setSense(BCLconstant.XPRB_MAXIM); bcl_prob.mipOptimize(); // Maximize the MIP problem } }
The code extract below shows how to access MIP solution information directly through the Optimizer library functions using the column or row indices saved for BCL modeling objects. In this case there is no need for synchronization of BCL with the local solution information.
public class IntSolExample2 public static void XPRSIntSolEvent(XPRSprob opt_prob, object my_object) { XPRBprob bcl_prob = (XPRBprob)my_object; int ncol = opt_prob.InputCols; // Get the number of columns double[] sol = new double[ncol]; opt_prob.GetSolution(null, sol, 0, ncol-1); // Get the solution int num = opt_prob.MIPSols; // Get number of solutions System.Console.WriteLine("Solution {0}: Objective value: {1}",num,opt_prob.ObjVal); XPRBvar x = bcl_prob.getVarByName("x_1"); if( x.getColNum() >= 0 ) // Test whether variable is in the matrix System.Console.WriteLine(x.getName() + ": " + sol[x.getColNum()]); } }
© 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.