Originally posted by: AndreaTramontani
Hello,
First, let me try to answer to your specific questions related to the CPLEX log.
**********************************************************************************************
1. At the root node, we display information for every iteration of the root node.
As an example, let me take a snapshot of your log:
Nodes Cuts/
Node Left Objective IInf Best Integer Best Bound ItCnt Gap
0 0 0.0000 33 1.40000e+07 Cuts: 4783 46 100.00%
0 0 0.0000 71 1.40000e+07 Cuts: 32 186 100.00%
* 0+ 0 15.0000 0.0000 100.00%
0 0 0.0000 13 15.0000 UserPurge1: 1 205 100.00%
First line indicates that:
.. the current Objective of the LP relaxation (a lower bound for the whole problem, given that you are at the root node) has value 0
.. the fractional solution has 33 integer infeasibilities (33 integer or binary variables with fractional value in the solution)
.. the incumbent solution has value 1.4e+7 (this is an upper bound)
.. 4783 cuts (a mix of CPLEX cuts and user cuts) have been added to the problem in this round
.. 46 simplex iteration have been spent so far to solve the problem, from the beginning of optimization
.. the gap between upper bound UB and lower bound LB, calculated as (UB-LB)/(eps+|UB|), is 100% (obvious, since LB = 0).
Third line indicates that a heuristic has found an incumbent of value 15.0, still the best lower bound so far is 0, so the gap is still 100%.
Fourth line is the same as first line, but it reports "UserPurge1: 1" for the cuts.
This means that no CPLEX cut has been added to the problem, so CPLEX by itself would have aborted the cut loop, but one user cut with key "UserPurge1" has been added, so CPLEX will continue the loop.
The key "UserPurge1" means that the cut is a user cut that CPLEX is allowed to purge. It does not mean that the cut has been purged, but that it was added to the problem and it could be purged later on. Unfortunately, CPLEX does not display information on the number of purged cuts.
2. In the tree, we display at most one line per node processed, and by default:
.. we do not display information at every node
.. we do not display information on number of applied cuts.
The verbosity of the log can be controlled by those two parameters: CPXPARAM_MIP_Display and CPXPARAM_MIP_Interval.
In particular, to see the number of applied cuts in the tree, you need to set CPXPARAM_MIP_Display to 4.
Please note that there is currently a small bug in the display of number of cuts applied in the tree, visible only if you set CPXPARAM_MIP_Display to 4.
By mistake, in the tree we display twice the cuts that are added. This issue has been now fixed and the fix will be available in the next release, CPLEX 12.9.0.
**********************************************************************************************
Then, let me try to give you some performance hints related to your case.
**********************************************************************************************
1. In general, CPLEX applies quite heavy machinary at the root node.
At every pass of the root cut loop, it applies heuristics, probing, aggressive separation of cuts, etc.
The same machinery is applied also at the nodes in the tree, but much less aggressively (probing, heuristics, cuts are applied only at some nodes, and in a much more conservative way).
So it is somehow expected that the root node can take much more than a single node.
2. Nevertheless, it seems that in your specific case the root node could be shortened and you need to find a way to reduce the number of iterations.
Looking at the evolution of the lower bound (always stuck at 0), I'm wondering if your usercuts are really helpful.
In any case, here's few suggestions to try to make the root node shorter.
.. If possible, add more user cuts per iteration. Adding only one cut per iteration and then having to resolve the problem at every iteration is in general not a good choice.
.. Since the lower bound never moves (it is stuck at 0), maybe you are repeatedly adding the same user cuts that then gets purged, and separated again, and so on.
If possible, you can implement, in your callback, a check to avoid separating/adding twice the same cut.
Or you can simply try to add the cuts with CPX_USECUT_FORCE. In this way every (violated) cut is added exactly once, and hopefully the root cut loop will stop much earlier, when you do not find violated cuts anymore. But note that you have to check for violation yourself, because with CPX_USECUT_FORCE and CPX_USECUT_PURGE CPLEX adds usercuts even if not violated.
.. By default, CPLEX adopts various criteria to decide when to stop separating cuts at the root node.
However, with a usercut callback, CPLEX will never stop the root cut loop as long as the user adds cuts. It is up to the user to decide when to break the cut loop.
A simple way is to limit the number of cut passes with the parameter CPXPARAM_MIP_Limits_CutPasses.
Otherwise, you can implement more elaborated criteria. For instance, you can use CPXgetcallbacknodeinfo() to query various information, like the value of the lower bound, of the upper bound, etc, and break the separation if you don't observe enough progress for some iterations.
3. Even if it seems that in the tree you are not seeing performance issues, please pay attention at not forcing too many cut loop iterations for the same node in the tree.
.. I see that you separate cuts only if depth <= 10, which of course limits the number of nodes for which you apply cuts.
.. But there is no limit on the cut loop iterations for those nodes. An easy thing you can try is the following.
When your callback is invoked in the tree, you can query the sequential nodeid of the node, again with CPXgetcallbacknodeinfo(). Then, for every nodeid, you can limit the number of times you separate cuts, to make sure that, at every node in which you decide to separate cuts, the number of iterations of the node cut loop is under control.
**********************************************************************************************
Hope this can help you.
Andrea
#CPLEXOptimizers#DecisionOptimization