Originally posted by: AndreaTramontani
Dear Daniele,
there are three fundamental differences between user cuts separated with a usercut callback and usercuts stored in the usercut pool.
I think all of those differences can play a role in your case, and create this difference you observe in the number of usercuts applied.
1. The first difference is about strategies for filtering the cuts.
When you add usercuts with a callback, you call CPXXcutcallbackadd (assuming you are using C APIs).
As specified in the documentation (www.ibm.com/support/knowledgecenter/SSSA5P_12.6.3/ilog.odms.cplex.help/refcallablelibrary/mipapi/cutcallbackadd.html)
this callback has a parameter, 'int purgeable', that you can use to specify which strategy CPLEX should apply to manage your cut.
The possible values for purgeable are:
CPX_USECUT_FORCE:
The cut is added to the relaxation and stays there
CPX_USECUT_PURGE:
The cut is added to the relaxation but can be purged later on if CPLEX deems the cut ineffective.
CPX_USECUT_FILTER:
The cut is treated exactly as cuts generated by CPLEX; that is, CPLEX applies its filtering process and may not even add the cut to the relaxation, for example, if CPLEX deems other cuts more effective, or if the cut is too dense.
If you are using other APIs then nothing changes since you still have the same possibility.
On the contrary, you don't have any control on the strategies for filtering the cuts, with cuts stored in the usercut pool.
I can tell you that for usercut in the pool the strategy is equivalent to CPX_USECUT_PURGE above, but there is no way to change it.
This difference can play an important role if most of the user cuts are separated at the root node.
I don't know which strategy you are using when adding cuts from usercut callback, but if you use CPX_USECUT_FORCE then this might explain the differences.
Please note that the number of usercuts applied reported at the end in the log reflects the number of usercuts present in the final relaxation.
Thus, cuts that are added to the relaxation but then purged (i.e., removed) afterwards will not be counted in those final statistics.
2. The second difference is about strategies to give up with cut separation.
When your usercut callback is called, it receives on input the 'wherefrom' parameter, that in the case of a usercut callback can have 2 values:
CPX_CALLBACK_MIP_CUT_LOOP: callback called inside the CPLEX cut loop, when CPLEX is also generating its own cuts
CPX_CALLBACK_MIP_CUT_LAST: callback called after the CPLEX cut loop, when CPLEX has decided to stop generating its own cuts
So, usercuts stored in the pool are only separated together with CPLEX cuts, during CPLEX cut loop.
If you instead use a callback, then you can be more aggressive and separate usercuts also when CPLEX has decided to stop separating cuts.
3. The third difference is about separation strategies during the branch-and-bound, i.e., cut separation in the tree.
If you have a usercut callback installed, this is called at every node (every node with an optimal solution that is fractional, of course),
and thus you have a lot of flexibility in deciding when/if separating the cuts.
On the other hand, usercuts stored in the pool are separated only together with other CPLEX cuts.
In the tree, CPLEX is quite conservative with cut separation. It does not separate cuts at every node, but only at some nodes, depending on some internal rules/strategies.
Therefore there might be many nodes at which usercuts in the pool are not separated, but CPLEX stll calls the usercut callback.
#CPLEXOptimizers#DecisionOptimization