Decision Optimization

Decision Optimization

Delivers prescriptive analytics capabilities and decision intelligence to improve decision-making.


#Analytics
#DecisionOptimization
#DecisionOptimization
 View Only
Expand all | Collapse all

Cut Activation using Callbacks

  • 1.  Cut Activation using Callbacks

    Posted 06/05/20 01:25 PM
    Edited by System Admin 01/20/23 04:50 PM

    Hey everyone,

    I have a cutting plane algorithm, where I predefined a series of mixed-integer cuts from the beginning, but they will only be activated if a certain violation is detected. To be more precise, I only want to activate the callbacks if CPLEX finds an integer solution and then using the solution at that moment, it will calculate an indicator and if that indicator is violating a condition, the cuts will be effectively activated.  Some people in this forum already help me out with the initial callback code (thank you for that), but the following part is still a bit confusing to me. I know that this is where, I should check the solution and my criteria is activated, the cuts are added. 

    Could someone explain how this following function in the callback class is used?



    ######################################

    def __call__(self):

    sol = self.make_solution()


    unsats = self.get_cpx_unsatisfied_cts(self.cts, sol, self.eps) # in this function a given criteria should be checked??

    for ct, cut, sense, rhs in unsats: # the respective cuts will be activated??

    self.add(cut, sense, rhs)
    self.nb_cuts += 1

    Thank you

    #################################

    ------------------------------
    Fernando Dias
    ------------------------------
    ​​​​​​​​​​​​​​​​​​​​
    #DecisionOptimization


  • 2.  RE: Cut Activation using Callbacks

    Posted 06/08/20 02:05 AM
    The function takes a list of cuts (self.cts) and for each of them returns whether it is violated by at least self.eps. It returns the list of violated cuts. Moreover, it translates the cuts (which are specified using docplex variable objects) into something that can be used to the engine's self.add() function (where variables are specified by index).

    If you want to have a different criterion to check whether to add a cut or not then you have to roll your own. In order to get the index of a variable you can use its 'index' property.

    ------------------------------
    Daniel Junglas
    ------------------------------



  • 3.  RE: Cut Activation using Callbacks

    Posted 06/08/20 07:57 AM

    Ok. If I understood correctly, the function will test the current solution is violating the cuts that I've had set up before, correct? 

    Sorry for asking, but what do you mean by "roll your own"?

    Thanks



    ------------------------------
    Fernando Dias
    ------------------------------



  • 4.  RE: Cut Activation using Callbacks

    Posted 06/08/20 08:00 AM
    Ok. If I understood correctly, the function will test the current solution is violating the cuts that I've had set up before, correct?
    Correct.

    Sorry for asking, but what do you mean by "roll your own"?
    I mean you have to implement your own function that finds the cuts that should be added and transforms them from object expressions to index expressions.

    ------------------------------
    Daniel Junglas
    ------------------------------



  • 5.  RE: Cut Activation using Callbacks

    Posted 06/16/20 02:17 PM

    So, if I understood correct, CPLEX check if the current solution is violating the cuts that I've had pre-defined. 

    And then using the function self.add()  add them into the model. However, I got this mistake here:

    status CPLEX Error 1121: Can't crush solution form.

    Any ideas?



    ------------------------------
    Fernando Dias
    ------------------------------



  • 6.  RE: Cut Activation using Callbacks

    Posted 06/17/20 01:13 AM
    This problem is described in the user manual in CPLEX > User's Manual for CPLEX > Advanced programming techniques > User-cut and lazy-constraint pools > Limitations on user-cut pools. In order to avoid this error you have to disable non-linear reductions by setting the linear reduction switch to 0.

    ------------------------------
    Daniel Junglas
    ------------------------------



  • 7.  RE: Cut Activation using Callbacks

    Posted 06/17/20 01:18 AM
    Edited by System Admin 01/20/23 04:19 PM

    Thank you 

    I had a look at it. But still have the same issue.



    ------------------------------
    Fernando Dias
    ------------------------------



  • 8.  RE: Cut Activation using Callbacks

    Posted 06/17/20 01:39 AM

    I attached the code here, maybe there's another issue.

    If anyone could help, it would be very much appreciated.



    ------------------------------
    Fernando Dias
    ------------------------------



  • 9.  RE: Cut Activation using Callbacks

    Posted 06/17/20 02:09 AM
    Can you provide a minimally working code that reproduces the issue? In order to run your code a number of other libraries (like Pyomo) are required.

    ------------------------------
    Daniel Junglas
    ------------------------------



  • 10.  RE: Cut Activation using Callbacks

    Posted 06/17/20 02:51 AM

    Thank you

    I removed most of the things I could. It should be easier to run now.



    ------------------------------
    Fernando Dias
    ------------------------------



  • 11.  RE: Cut Activation using Callbacks

    Posted 06/17/20 06:56 AM
    Edited by System Admin 01/20/23 04:16 PM
    Also, how do I defined those cuts to be lazy constraints instead of user cuts?

    ------------------------------
    Fernando Dias
    ------------------------------



  • 12.  RE: Cut Activation using Callbacks

    Posted 06/18/20 07:02 AM

    Hey

    I made some adjustments and now the code at least run but the cuts don't work properly. Probably because they're set up as usercuts, but what I need to do is use them as lazy constraints.

    Any idea how to change that?



    ------------------------------
    Fernando Dias
    ------------------------------



  • 13.  RE: Cut Activation using Callbacks

    Posted 06/18/20 08:40 AM
    In order to separate lazy constraints derive from the LazyConstraintCallback class instead of the UserCutClass.

    ------------------------------
    Daniel Junglas
    ------------------------------



  • 14.  RE: Cut Activation using Callbacks

    Posted 06/19/20 03:35 PM

    Thank you very much for your answer.
    One more question:  The current version check for cut violation at every LP solution, I want to change that so it can check violation and eventually add the cuts only after it finds an integer solution. Any suggestions on how to do that?

    Thank you again;



    ------------------------------
    Fernando Dias
    ------------------------------



  • 15.  RE: Cut Activation using Callbacks

    Posted 06/20/20 10:52 AM

    I got this current class for callbacks using lazy constraints:

    #######################################################################
    class MyCutCallback(IncumbentCallback, LazyConstraintCallback):

    def __init__(self, env):
    LazyConstraintCallback.__init__(self, env)
    IncumbentCallback.__init__(self)
    self.eps = 1e-6
    self.nb_cuts = 0

    def add_cut_constraint(self, ct):
    self.register_constraint(ct)

    def __call__(self):

    sol = self.make_solution()

    unsats = self.get_cpx_unsatisfied_cts(self.cts, sol, self.eps)

    for ct, cut, sense, rhs in unsats:
    self.add(cut, sense, rhs)
    self.nb_cuts += 1
    print('-- add new cut[{0}]: [{1!s}]'.format(self.nb_cuts, ct))
    ##########################################################################

    But I need to make this only add cuts after finding an integer solution. How can I make this happen?

    I found some material about incumbent callbacks, but how do I get there?

    Thank you very much

    ​​​​​

    ------------------------------
    Fernando Dias
    ------------------------------



  • 16.  RE: Cut Activation using Callbacks

    Posted 06/22/20 12:19 AM
    What is the problem? As you can read in the documentation here, the lazy constraint callack is only invoked when CPLEX finds an integer solution. That is the hole point of lazy constraints: they are only checked on solutions that are otherwise integer feasible. They give you an additional chance to reject those solutions.

    ------------------------------
    Daniel Junglas
    ------------------------------



  • 17.  RE: Cut Activation using Callbacks

    Posted 06/22/20 01:35 PM

    If this is the case, I think it will work then

    Another issue that I'm facing is that the callbacks are adding many cuts early in the B&C? I don't think this is necessarily correct.

    Any ideas?

    Thank you very much for your help


    #######################################################################
    class MyCutCallback(IncumbentCallback, LazyConstraintCallback):

    def __init__(self, env):
    LazyConstraintCallback.__init__(self, env)
    IncumbentCallback.__init__(self)
    self.eps = 1e-6
    self.nb_cuts = 0

    def add_cut_constraint(self, ct):
    self.register_constraint(ct)

    def __call__(self):

    sol = self.make_solution()

    unsats = self.get_cpx_unsatisfied_cts(self.cts, sol, self.eps)

    for ct, cut, sense, rhs in unsats:
    self.add(cut, sense, rhs)
    self.nb_cuts += 1
    print('-- add new cut[{0}]: [{1!s}]'.format(self.nb_cuts, ct))
    ##########################################################################



    ------------------------------
    Fernando Dias
    ------------------------------



  • 18.  RE: Cut Activation using Callbacks

    Posted 06/23/20 01:28 AM
    Why do you think it is not correct? Also, it seems like this should best we handled by a new question.

    ------------------------------
    Daniel Junglas
    ------------------------------