Skip to main content

How do I add a quadratic constraint using an expression defined through variables of a model that I copied ?

Answered

Comments

4 comments

  • Official comment
    Simranjit Kaur
    • Gurobi Staff Gurobi Staff
    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?.
  • Jaromił Najman
    • Gurobi Staff Gurobi Staff

    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
  • Daniele Patria
    • Gurobi-versary
    • First Question
    • Conversationalist

    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 Patria

    0
  • Jaromił Najman
    • Gurobi Staff Gurobi Staff

    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.