Originally posted by: Michael_D
In a C++ application using concert technology with cplex 12.2, a LazyConstraintCallback is used to solve an MIP.
For a small test instance, the following output is generated:
This is @(#)IBM ILOG Software: product Concert, library concert.lib, version 12.2, date 07/20/2010, (C) Copyright IBM Co
rp. 1990, 2010 All Rights Reserved. US Government Users Restricted Rights - Use, duplication or disclosure restricted by
GSA ADP Schedule Contract with IBM Corp. This product includes software developed by the University of California, Berk
eley and its contributors.
Tried aggregator 1 time.
MIP Presolve eliminated 2 rows and 3 columns.
MIP Presolve modified 10 coefficients.
Reduced MIP has 18 rows, 418 columns, and 106 nonzeros.
Reduced MIP has 53 binaries, 0 generals, 0 SOSs, and 0 indicators.
Probing time = 0.00 sec.
Tried aggregator 1 time.
Presolve time = 0.05 sec.
Probing time = 0.00 sec.
Clique table members: 18.
MIP emphasis: balance optimality and feasibility.
MIP search method: traditional branch-and-cut.
Parallel mode: none, using 1 thread.
Root relaxation solution time = 0.00 sec.
Lazy constraint callback called.
Separated lazy constraints for k = 2.
Nodes Cuts/
Node Left Objective IInf Best Integer Best Node ItCnt Gap Variable B NodeID Parent Depth
0 0 -64.8000 16 -70.0000 12
Lazy constraint callback called.
No lazy constraints separated.
0 0 -63.5000 8 Fract: 1 18
Lazy constraint callback called.
No lazy constraints separated.
Lazy constraint callback called.
No lazy constraints separated.
-
0 0 integral 0 -63.0000 Cuts: 2 22 0.00%
0 0 cutoff -63.0000 -63.0000 22 0.00% 0 0
Elapsed real time = 0.23 sec. (tree size = 0.00 MB, solutions = 1)
Cover cuts applied: 1
Gomory fractional cuts applied: 2
Questions:
Why is the callback called twice in a row? After the first of the two consecutive calls, no lazy constraints are separated. So, what is to be expected from a second call?
After the line with 'Cuts: 2', the lazy constraint callback is not called again, but the resulting solution is declared optimal. How can this be? How can cplex know whether a solution is optimal without calling the lazy constraint callback?
In an earlier thread, Tobias Achterberg wrote the following on when a lazy constraint callback is called (most probably referring to version 12.3):
'There are two cases to distinguish:
(a) the incumbent was found as integral solution to a node LP relaxation,
(b) the incumbent was found by a primal heuristic.
In case (a) we call first the lazy constraint callback and then the incumbent callback.
In case (b) it is only guaranteed that we call the incumbent callback, with "wherefrom" equal to CPX_CALLBACK_MIP_INCUMBENT_USERSOLN or CPX_CALLBACK_MIP_INCUMBENT_HEURSOLN. We may also call the lazy constraint callback (before calling the incumbent callback), but this happens only for heuristics that look close to the LP optimum and for which adding lazy constraints tightens the formulation at the area of interest.'
Does this mean that in cplex 12.3, instead of the former cut callback, there are three callbacks to be implemented: lazy constraint callback, cut callback (as Tobias wrote earlier, it is also sometimes sensible to check the lazy constraints during the cut loop), and incumbent callback (to handle case (b))?
Why shouldn't the lazy constraint callback be called under all circumstances before a potential solution is declared an 'incumbent'? If the lazy constraint callback is not called, it is impossible to say whether a potential incumbent is feasible, that is, fulfils all constraints, including the lazy ones.
What could be meant by 'heuristics that look close to the LP optimum and for which adding lazy constraints tightens the formulation at the area of interest'? How can cplex know whether or not 'adding lazy constraints tightens the formulation at the area of interest' when the lazy constraints are not separated?
Could it be that also in version 12.2, the cut callback may or may not be called when a potential incumbent is found by a heuristic, although the documentation (version 12.2) says: 'An instance of the class IloCplex::CutCallbackI represents a user-written callback in an application that uses an instance of IloCplex to solve a mixed integer programming problem (a MIP). This class offers a method to add a local or global cut to the current node LP subproblem from a user-written callback. CPLEX also calls the callback when comparing an integer feasible solution, including one provided by a MIP start before any nodes exist, against lazy constraints.' (IDE and OPL > OPL Interfaces > C++ interface reference manual > optim.cplex.cpp.advanced > Classes > Class IloCplex::CutCallbackI)?
Thanks in advance for shedding some light on this issue.
Michael
#CPLEXOptimizers#DecisionOptimization