-
Notifications
You must be signed in to change notification settings - Fork 270
Description
Hello everybody!
I'm using pyscipopt 5.4.1 and implemented a simple model with a callback function set through Model.attachEventHandlerCallback
to add some constraints during the solving process for the event SOLFOUND
. However, it seems that after the optimization has ended, the optimal solution found violates one of the constraints added inside the callback.
Here's a snippet of code to reproduce this behavior:
import pyscipopt as scip
# base model
mdl = scip.Model("example")
x = mdl.addVar("x", lb=0, ub=10, vtype='C')
y = mdl.addVar("y", lb=0, ub=10, vtype='C')
cons1 = mdl.addCons(x + y >= 1, name='C1')
mdl.setObjective(2 * x + y, sense='minimize') # at first, the expected optimal solution is x=0, y=1
# define the callback function
count = 0
def callback_function(model, event):
global count
count += 1
best_sol = model.getBestSol()
print("Best objective value: ", model.getObjVal(best_sol))
print(f"Solution: x={model.getSolVal(best_sol, x)}, y={model.getSolVal(best_sol, y)}")
if count == 1:
# first callback call
model.addCons(x >= 2, name='LazyCons_x_1')
model.addCons(x <= 5, name='LazyCons_x_2')
elif count == 2:
# second callback call
model.addCons(y >= 1, name='LazyCons_y')
# add callback
mdl.attachEventHandlerCallback(callback_function, [scip.SCIP_EVENTTYPE.SOLFOUND])
# optimize
mdl.optimize()
print("x:", mdl.getVal(x))
print("y:", mdl.getVal(y))
print(f"Callback was used {count} times.")
mdl.writeProblem("trans_model.lp", trans=True)
Basically, without the callback, the expected optimal solution is x=0
and y=1
. During the solving process, the first feasible solution found is x=10
and y=10
. The callback is called (since a new feasible solution was found). Inside the callback on its first call, I add constraints to ensure 2 <= x <= 5
. The optimal solution then correctly becomes x=2
and y=0
, which is found by SCIP, and the callback is called again. Inside the callback, for its second call, I add y >= 1
. This should make x=2
and y=1
the optimal solution. However, the solving process ends returning x=2
and y=0
as the optimal one, violating the last constraint added by the callback.
Below is the transformed model:
\ SCIP STATISTICS
\ Problem name : t_example
\ Variables : 2 (0 binary, 0 integer, 0 implicit integer, 2 continuous)
\ Constraints : 1
Minimize
Obj: +2 t_x +1 t_y
Subject to
LazyCons_y: +1 t_y >= +1
Bounds
2 <= t_x <= 2
0 <= t_y <= 0
End
We see that the constraint t_y >= 1
is present in the transformed model. One thing that caught my attention is that in the Bounds section, we see 0 <= t_y <= 0
, so maybe the fact that t_y >= 1
contradicts those bounds makes it be ignored.
Is this behavior expected? Am I using the wrong framework for this goal (I found constraint handlers framework on the online documentation as well)? I also tried the same callback routine through a class-based approach using includeEventhdlr
(following this docs) but found the same issue.
Thanks in advance for looking into this!