I'm solving a LP with CPLEX using the Java API. I build my model with the methods provided (like cplex.numVar(col, lb, ub)
and cplex.addLe()
) After optimization is done, I'm interested in reading the simplex tableau of the final iteration (to be precise: not only the duals and reduced costs but also the coefficients inside the tableau).
I tried to access the IloLPMatrix object cplex.LPMatrix()
, but this only returns an empty matrix. I'm interested in the "filled" matrix associated to the problem I just solved.
So, how can I read the simplex tableau?
The short answer is that you cannot access the simplex tableau with the Concert (Java/.NET/C++) APIs. You can access this advanced feature with the C Callable Library and Python APIs, though. For example, see CPXXbinvarow and examining the simplex tableau in the Python API.
Now, to clear up your possible confusion with what IloLPMatrix
does, consider the following (mostly cribbed from this thread on the official IBM developerWorks forum).
If you add constraints to the model with cplex.addLe()
then you can use rangeIterator to access them (and possibly conversionIterator, SOS1Iterator, SO2Iterator). Note that when you use rangeIterator
you have to figure out the runtime type of an expression before you can get at the coefficients. For example:
for (Iterator it = cplex.rangeIterator(); it.hasNext(); /* nothing */) {
IloRange range = (IloRange)it.next();
IloNumExpr expr = range.getExpr(); // Cannot get the coefficients of expr directly :-(
if (expr instanceof IloLinearNumExpr) {
IloLinearNumExpr linExpr = (IloLinearNumExpr)expr;
for (IloLinearNumExprIterator jt = linExpr.linearIterator(); jt.hasNext(); /* nothing */) {
IloNumVar var = jt.nextNumVar();
double coef = jt.getValue();
...
}
}
else if (expr instance of ...) {
...
}
}
On the other hand, if you build your model with an IloLPMatrix, then you can access it with LPMatrixIterator. When you call cplex.LPMatrix it "Creates and returns an empty LP matrix object." You then have to fill it and add
it to the model. Alternately, you can use addLPMatrix to create and add it in one step (you still need to populate it).
For example:
// Create a matrix in which we setup the model.
IloLPMatrix matrix = cplex.LPMatrix();
// Create variables.
IloNumVar x = cplex.numVar();
IloNumVar y = cplex.numVar();
matrix.addCols(new IloNumVar[]{ x, y });
// Create constraint x + y <= 2.
IloLinearNumExpr lhs = cplex.linearNumExpr();
lhs.addTerm(x, 1.0);
lhs.addTerm(y, 1.0);
matrix.addRow(cplex.le(lhs, 2.0));
// When all constraints are setup add the matrix to the model.
cplex.add(matrix);
Note that you can only add linear constraints when using an IloLPMatrix
.
Whether you use the first method to build your model and rangeIterator
to access it, or the second method and LPMatrixIterator
, is a matter of taste and possibly some performance trade-offs; you'd have to experiment with both approaches.