Usercuts in the root node with Gurobi Callback
Awaiting user inputHi,
I would like to add user cuts in the root node using Julia.
With the code
cb_calls = Cint[]
function my_callback_function(cb_data, cb_where::Cint)
push!(cb_calls, cb_where)
if cb_where != GRB_CB_MIPNODE
return
end
resultP = Ref{Cint}()
GRBcbget(cb_data, cb_where, GRB_CB_MIP_NODCNT, resultP)
println(resultP[])
if resultP[] != 0
return
end
Gurobi.load_callback_variable_primal(cb_data, cb_where)
variable_val = callback_value(cb_data, variable)
if Condition-val-dependent
return
end
con = @build_constraint(constraint) MOI.submit(model, MOI.UserCut(cb_data), con)
end
MOI.set(model, Gurobi.CallbackFunction(), my_callback_function)
the println shows different values along the iterations.
Optimize a model with 1809 rows, 1621 columns and 4028 nonzeros
Model fingerprint: 0xb0860acc
Model has 7 quadratic constraints
Model has 360 SOS constraints
Variable types: 1207 continuous, 414 integer (216 binary)
Coefficient statistics:
Matrix range [1e-01, 6e+03]
QMatrix range [1e+00, 1e+00]
QLMatrix range [1e+00, 4e+04]
Objective range [1e+00, 1e+00]
Bounds range [0e+00, 0e+00]
RHS range [1e+00, 2e+04]
Presolve removed 787 rows and 432 columns
Presolve time: 0.01s
Presolved: 1336 rows, 1343 columns, 3980 nonzeros
Presolved model has 188 SOS constraint(s)
Presolved model has 154 bilinear constraint(s)
Solving non-convex MIQCP
Variable types: 824 continuous, 519 integer (345 binary)
Root relaxation: objective 1.091990e+06, 1008 iterations, 0.01 seconds (0.02 work units)
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
0 0 1091990.09 0 222 - 1091990.09 - - 0s
0 0 1092050.36 0 267 - 1092050.36 - - 0s
0 0 1092057.28 0 260 - 1092057.28 - - 0s
NODCNT=999774352
0 0 1120474.19 0 361 - 1120474.19 - - 0s
NODCNT=8226
0 0 1121601.71 0 364 - 1121601.71 - - 0s
NODCNT=2
0 0 1592614.28 0 372 - 1592614.28 - - 0s
NODCNT=1
0 0 1596556.14 0 377 - 1596556.14 - - 0s
NODCNT=2
0 0 1709604.99 0 377 - 1709604.99 - - 0s
H 0 0 2956547.7433 1711258.18 42.1% - 0s
NODCNT=-170109328
0 0 1738003.96 0 377 2956547.74 1738003.96 41.2% - 0s
NODCNT=0
ADDED CUT cb_where=5 GRB_CB_MIPNODE=5: CutsAdded=0
0 0 1760103.77 0 347 2956547.74 1760103.77 40.5% - 0s
NODCNT=1659502849
NODCNT=-164296384
H 27 27 2324193.9902 1788956.75 23.0% 67.2 0s
...
NODCNT=0
ADDED CUT cb_where=5 GRB_CB_MIPNODE=5: CutsAdded=1
* 123 111 81 2282137.2087 1788956.75 21.6% 36.2 0s
Some values of MIP_NODCNT are negative. What is the meaning of these values?
Why NODCNT=0 at different points in the iterations?
Moreover, when I do not need the callback values (variable_val), and therefore I do not need to call load_callback_variable_primal, I can skip both the cb_where != GRB_CB_MIPNODE
and the != GRB_OPTIMAL
checks. BUT I was expecting to be able at this point to add a user cut to the root node only (before the root relaxation was solved) but I got the error
ERROR: LoadError: Gurobi Error 10011: User cuts only allowed from MIPNODE callback
Could you help me?
Thank you in advance,
Martina
-
Hi Martina,
If you are in the MIPNODE callback, you also need to use GRB_CB_MIPNODE_NODCNT.
GRB_CB_MIP_NODCNT is for the MIP callback and gives bogus results when used in MIPNODE. I assume you are not using Gurob 11 since with Gurobi 11 using what-arguments that do not fit the where-arguments (see Callback Codes) should cause an error message.The error message
ERROR: LoadError: Gurobi Error 10011: User cuts only allowed from MIPNODE callback
indicates that user cuts are only allowed from MIPNODE callback. So, you need to check whether you are in the MIPNODE callback when adding user cuts (you cannot skip this check).
I hope this helps,
Marika0 -
Hi Marika,
Thanks for the answer.
Actually I'm using Gurobi 11.
It seemed to me that the parameter GRB_CB_MIPNODE_NODCNT was not effective, so I replaced it with GRB_CB_MIP_NODCNT.
With the one you suggest (GRB_CB_MIPNODE_NODCNT), with the request to add 1 cut, I obtain the same solution whether I enforce the check or not.
resultP = Ref{Cint}() GRBcbget(cb_data, cb_where, GRB_CB_MIPNODE_NODCNT, resultP)
println(resultP[])
if resultP[] != 0
println(resultP[])
return
endI also ask in the check to return if resultP[] != 2, but it does not adds the cut.
How can I add the callback in the root (or in a specific node) effectively?
For the MIPNODE check, this means that I cannot add a user cut in the root node only, before the root relaxation is solved and I have to wait the root relaxation is solved (?)
Thanks
0 -
Hi Martina,
GRB_CB_MIPNODE_NODCNT should give you the number of currently explored nodes. If you want to add the user cuts only in the root node, you should check if the node count is 0.
I do not know how it is done with Julia but using the Gurobi Python API, a user cut is added with Model.cbCut().
Please have a look at this documentation, it also says that the parameter PreCrush should be set to value 1 when adding your own cuts.The MIPNODE check ensures that currently a MIP node is explored. This callback is not only called once but several times in the root node which you can see also in your log you shared above. Your output on the value NODCNT can be seen several times in the root node.
I do not know what you mean by adding a user cut "before the root relaxation is solved".
If you already know strengthening cuts without the need to solve the LP relaxation, why not add them as constraints when creating the model?Best regards,
Marika0
Please sign in to leave a comment.
Comments
3 comments