Forum Discussion
FICO
9 months agoCommunity Manager
Variable names in callback (Java API)
I construct a cut in a preintsol callback using variables from the model containing the callback. When constructing the model, I give the variables names (using withName(...)) and store them in a vector. In the callback, though, the variables are named X[0], X[1], etc. Is there a reason why they are not carrying the names they were assigned when first defined? It's an issue both when printing the cut (where I could work around it by storing the names and "translating" the cut in the code) and when using a debugger (where I am stuck mentally converting "X[17]" into the corresponding original name).
4 Replies
- FICOCommunity Manager
This behavior is a bit strange but expected :-(
A Variable object is just a glorified index, that is, it contains only a single field: the index of the corresponding column in the underlying optimizer model (these indices are updated when variables are deleted).
As soon as you start optimization, the model will be presolved and the model will go from "original" state into a presolved state. In this presolved state, the indices stored in the Variable objects are no longer meaningful: they are indices in the original space but the model is now in presolved space in which the indices have different meanings. During a solve, the model in the original space is not available, so there is no way to make Variable.getName() make return the name you assigned (unless the column index points to the same column in original and presolved space by accident).
In order to print variable names from a callback you have to capture the names before you start the solve and then use the captured names when printing variables.
Here is an example code that prints a linear expression from a callback:
import java.util.Map; import java.util.Arrays; import static java.util.stream.Collectors.toMap; import com.dashoptimization.*; import com.dashoptimization.objects.*; public final class NameInCallback { private static final class PreIntsolCallback implements XpressProblem.CallbackAPI.PreIntsolCallback { /** Variables in the model. */ public final Variable[] x; /** Maps variables to their names. */ public final Map<Variable,String> names; public PreIntsolCallback(Variable[] x, Map<Variable,String> names) { this.x = x; this.names = names; } @Override public void preIntsol(XpressProblem p, int soltype, IntHolder p_reject, DoubleHolder p_cutoff) { // Build the left-hand side of the cut. LinExpression lhs = LinExpression.create(); lhs.addTerm(2.0, x[0]); lhs.addTerm(3.0, x[1]); // Get a linear view on the expression and print that. // The cast to Expression is not necessary. It is only here to illustrate // that you can do this with any expression. If the expression is not an // instance of a linear expression class then getLinearView() will raise // an exception. for (LinCoef t : ((Expression)lhs).getLinearView()) { System.out.printf(" %+f*%s", t.getCoefficient(), names.get(t.getVariable())); } System.out.println(); } } public static void main(String[] args) { try (XpressProblem prob = new XpressProblem()) { Variable[] x = prob.addVariables(10).withName(i -> "myX" + i).toArray(); prob.callbacks.addPreIntsolCallback(new PreIntsolCallback(prob.getVariables(), Arrays.stream(prob.getVariables()).collect(toMap(v -> v, v -> v.getName())))); prob.optimize(); } } }We have already identified this as "not so nice" and have already filed a user wish to make it possible to print expressions from callbacks with the correct variable names, even if the model is in a presolved state.
- FICOCommunity Manager
Daniel,
While I understand original versus "crushed" model, it's still unclear to me why Xpress behaves the way it does. The added cuts are expressed in terms of the original variables, not those of the presolved model. By that I mean that I create an instance of LinExpression and fill it with a linear combination of original variables. Since Xpress apparently understands that the column indices are from the original model (judging by the fact that it appears to implement the cut correctly), shouldn't the toString method of LinExpression look up the names of the original variables?
Paul
- FICOCommunity Manager
The problem is that the names in the original space are not accessible while the model is in presolved space. They are stored internally but no longer accessible from any API.
I totally understand that printing your cut for debugging reasons is important. I filed an internal request for improvement to make this possible out of the box.
- FICOCommunity Manager
Thanks Daniel.
Related Content
Related Content
Variable object mapping issue in Python Callbacks with Presolve enabled
Hi, I am implementing a Branch-and-Cut algorithm using the Xpress Python interface. I have structured my code as a class where I create variables (using xp.var) and store them in a dictionary attrib...8 months agoPlace FICO® Xpress Optimization ForumFICO® Xpress Optimization Forum6 unread comments6 unread0Views0likes6CommentsAre preintsol callbacks threadsafe?
The optimizer documentation states "When the MIP callbacks are called they are MUTEX protected to allow non threadsafe user callbacks." In my Java code for one-tree Benders, if I specify a single thr...9 months agoPlace FICO® Xpress Optimization ForumFICO® Xpress Optimization Forum3 unread comments3 unread2Views0likes3CommentsObtaining the variable values in a callback
In the XPRSoptNodeEvent callback, in order to separate valid inequalities, one must access the values of the variables. Let's say we want to obtain the values of XBRBvar[] myVarSubset. To my understa...5 years agoPlace FICO® Xpress Optimization ForumFICO® Xpress Optimization Forum2 unread comments2 unread0Views0likes2Comments