Search code examples
javacplex

CPLEX+JAVA: Retrieving Solution inside Heuristic Callback behaves weirdly


I have the following problem: I solve a large VRP with many synchronization constraints using CPLEX integrated with a heuristic component to improve incumbents. The general algorithm is as follows: If a new incumbent is found in CPLEX, or if a time limit is reached, I move to a heuristic, and try to improve the current incumbent. The former is done using an Incumbent Callback, the latter using a Heuristic Callback. While I am able to query all variables in the incumbent callback, I get some weird behavior in the heuristic callback: When I query

this.getStatus().toString()

this returns "Optimal", even though the solution is not optimal yet (there is an incumbent, but still a rather large integrality gap). I made sure that the model actually queries the correct cplex object by looking into objective value and current integrality gap, they match the log. Then,

this.getIncumbentValue(v[n][i][j]);

fails (it also fails if I query the values using this.getIncumbentValues(v[n][i]);).

When I check in the model (using cplex.exportModel(String filename), all variables are present.

I was thinking that this might be related to the fact that I use CPLEX as a singleton, but the status is already "optimal" when I use the singleton for the first time (in the first iteration however, all variables can be queried, this problem only exists in the second iteration).

I create the singleton as such:

public static IloCplex getCplex() {
    if (cplex == null) {
        try {
            cplex = new IloCplex();
        } catch (IloException e) {
            e.printStackTrace();
        }
    } else {
        try {
            cplex.clearModel();
            cplex.setDefaults();
        } catch (IloException e) {
            e.printStackTrace();
        }
    }
    return cplex;
}

Did I maybe do something wrong here?

EDIT: The exact error message including back trace is:

ilog.cplex.IloCplex$UnknownObjectException: CPLEX Error: object is unknown to IloCplex
 at ilog.cplex.CpxNumVar.getVarIndexValue(CpxNumVar.java:295)
 at ilog.cplex.IloCplex$MIPInfoCallback.getIndex(IloCplex.java:13648)
 at ilog.cplex.IloCplex$MIPInfoCallback.getIncumbentValues(IloCplex.java:13807)
 at ilog.cplex.IloCplex$MIPInfoCallback.getIncumbentValues(IloCplex.java:13785)
 at SolverHybridCRP$InsertSolution.getV(SolverHybridCRP.java:2091)
 at SolverHybridCRP$InsertSolution.improveIncumbent(SolverHybridCRP.java:2054)
 at SolverHybridCRP$InsertSolution.main(SolverHybridCRP.java:2024)
 at ilog.cplex.CpxCallback.callmain(CpxCallback.java:160)
 at ilog.cplex.CpxHeuristicCallbackFunction.callIt(CpxHeuristicCallbackFunction.java:48)
 at ilog.cplex.Cplex.CPXmipopt(Native Method)
 at ilog.cplex.CplexI$SolveHandle.start(CplexI.java:2837)
 at ilog.cplex.CplexI.solve(CplexI.java:2963)
 at ilog.cplex.IloCplex.solve(IloCplex.java:10254)
 at SolverHybridCRP.solveModel(SolverHybridCRP.java:1525)
 at AppHelp.runtimeTest4(AppHelp.java:1218)
 at AppHelp.main(AppHelp.java:61)

it occurs when I query ANY variable, but only after I query the cplex object the second time. (So: I start the program, it iterates over a lot of instances, the first instance is fine, all heuristic callbacks work, in all further iterations, I end up in the catch-block and get the above exception trace.) That is why I assumed that maybe the singleton does not work exactly as supposed, and not everything is deleted from the first iteration.


Solution

  • Looking at the reference documentation you can see for IloCplex.HeuristicCallback.getStatus()

    Returns the solution status for the current node.

    This method returns the status of the solution found by the instance of IloCplex at the current node during the last call to the method IloCplex.HeuristicCallback.solve (which may have been called directly in the callback or by IloCplex when processing the node just before the callback is called).

    In other words, the function does not return a global status but only a node-local status. It is expected that the node is currently solved to optimality when the callback is invoked.

    With respect to the exception in the callback: you are trying to access a variable object that is not in the model being solved. Typical cases in which this happens are:

    1. You created the variable but it does not appear in any constraints or in the objective, i.e., it is not used anywhere. You can force its usage by explicitly calling cplex.add() with the variable as argument.
    2. The variable was created in a previous iteration and is no longer part of the model in the current iteration. A good way to debug this is to assing a name to each variable and have that name include the iteration index. Then in the exception handler print the name of the offending variable. That should give a very good hint about what is wrong.