How do I add a quadratic constraint using an expression defined through variables of a model that I copied ?
AnsweredI am trying to do the following:
- create a model
- add variables
- define a quadratic expression using those variables
- creating a new model that is a copy (made with the method Model.copy()) of the first one
- defining a constraint for the new model using the quadratic expression containing the copied model variables
When performing this operations with a linear (using addLConstr()) expression everything works flawlessly but I am having some troubles with a quadratic one (tried both addQConstr() and addConstr()).
Find code and error below.
Code:
from gurobipy import Model
from gurobipy import GRB
m = Model()
x1 = m.addVar(vtype = GRB.CONTINUOUS, name = 'x1', ub = 5, lb = 0)
x2 = m.addVar(vtype = GRB.CONTINUOUS, name = 'x2', ub = 5, lb = 0)
# a linear expression
lin_expr = x1 + x2
# a quadratic expression
quad_expr = x1 * x2
m.addLConstr(lin_expr <= 3)
m.addQConstr(quad_expr <= 6)
m.update()
m_copy = m.copy()
# works
m_copy.addLConstr(lin_expr <= 2)
# doesn't work
m_copy.addQConstr(quad_expr <= 5)
Error:
Traceback (most recent call last):
File "quadtest.py", line 24, in <module>
m_copy.addQConstr(quad_expr <= 5)
File "src/gurobipy/model.pxi", line 3398, in gurobipy.Model.addQConstr
File "src/gurobipy/model.pxi", line 3234, in gurobipy.Model.__addConstr
gurobipy.GurobiError: Variable not in model
P.S.: when using addConstr() with the linear expression the same error is thrown...
-
Official comment
This post is more than three years old. Some information may not be up to date. For current information, please check the Gurobi Documentation or Knowledge Base. If you need more help, please create a new post in the community forum. Or why not try our AI Gurobot?. -
Hi Daniele,
When using the copy function, one should definitely avoid working with the objects used for the original model. Working with objects used to define the original model can have any possibility of side effects. In your case, you are lucky and the \(\texttt{lin_expr}\) object can be re-used in \(\texttt{m_copy}\). However, this behavior is not guaranteed and Gurobi throws the \(\texttt{Variable not in model}\) error to tell you that the variable objects \(\texttt{x1, x2}\) are not part of \(\texttt{m_copy}\). The intended way to access the variable and constraint objects of the copied model is to either access them directly by name or loop through the lists provided by the getVars and getConstrs functions. In your case, since you are only interested in the right hand side, you don't have to add a new constraint but can rather directly alter the right hand side of the corresponding constraints. The following code shows one possible way of working with a copied model.
import gurobipy as gp
from gurobipy import GRB
m = gp.Model()
x1 = m.addVar(vtype = GRB.CONTINUOUS, name = 'x1', ub = 5, lb = 0)
x2 = m.addVar(vtype = GRB.CONTINUOUS, name = 'x2', ub = 5, lb = 0)
# a linear expression
lin_expr = x1 + x2
# a quadratic expression
quad_expr = x1 * x2
m.addLConstr(lin_expr <= 3, name = "lconstr1")
m.addQConstr(quad_expr <= 6, name = "qconstr1")
m.update()
# write original model
m.write("myLP.lp")
m_copy = m.copy()
# get the corresponding linear constraint (needs to have a unique name)
lconstr = m_copy.getConstrByName("lconstr1")
# set right hand side value of constraint in copied model
lconstr.rhs = 2
# get all quadratic constraints
# (note that there is no getByName function for quadratic constraints)
qconstrs = m_copy.getQConstrs()
# loop over the constraints until the correct constraint is found
for c in qconstrs:
if c.qcname == "qconstr1":
# set the right hand side of the quadratic constraint
c.qcrhs = 5
m_copy.update()
# write copied model to LP file for sanity check
m_copy.write("myLP2.lp")Best regards,
Jaromił1 -
Dear Jaromił,
thanks for your answer. I managed to solve my problem and now the code works fine.
By the way I am still curious about why it does work that way when adding linear constraints... It would be interesting to understand.Thanks again for your help!
Kind regards,
Daniele Patria0 -
Hi Daniele,
By the way I am still curious about why it does work that way when adding linear constraints... It would be interesting to understand.
It can be quantified as "you are lucky that no pointer has been invalidated in the meantime". This means that there is no good explanation other than when using the addLConstr function, the references to the variable objects, columns, and rows are still in a correct constellation and the copied model can access the linear expression you constructed. Already a small change in the code such as using the addConstr function instead is enough to break this volatile situation. Altogether, it is not intended and not safe at all to work with original model objects in the copied model.
Best regards,
Jaromił1
Post is closed for comments.
Comments
4 comments