python-mip
python-mip copied to clipboard
set_expr not working
Describe the bug The functions below are not updating the coefficients model.objective.set_expr() constraint.expr.set_expr()
To Reproduce
from mip import Model, maximize
m = Model()
v = m.add_var('v', ub=1)
m.objective = maximize(v)
print(m.objective.expr) # should print {mip.Var id : 1}
m.objective.set_expr({v: 2})
print(m.objective.expr) # should print {mip.Var id : 2}
c = m.add_constr(v <= 0.5, 'c')
print(c.expr) # should print + v - 0.5
c.expr.set_expr({v: 0.6})
print(c.expr) # should print + v - 0.6
m.optimize()
Expected behavior
The output of the print statements should be as shown above in comments. However, they are not updating so it prints 1,1 and 0.5, 0.5. The expected solution to the problem is 0.6, but instead it is 0.5. Here is the ouput:
Desktop:
- Operating System, version: Ubuntu 18.04.4 LTS
- Python version: 3.7.3
- Python-MIP: 1.9.3
Hi @braceal , thanks for the detailed bug report.
m.objective.set_expr should work
Changing the contents of one constraint is more complicated, since after adding/removing one non-zero element may be necessary to reorganize the matrix. Most solvers do not allow to change the contents of one constraint and usually it is necessary to remove and add a new constraint.
one way that works now to change the OF is:
m.objective = maximize(2 * v)
@h-g-s Thank you for your quick reply. To give a bit more context I'm working to add MIP to the optlang package so that my group can use it as part of the COBRApy package. The original issue.
The last function I am trying to optimize is called set_linear_coefficients (for both constraints and objectives). It allows the user to adjust the coefficients in the expressions (including adding new variables that already exist in the model as part of constraints). I realize that the MIP set_expr function is supposed to update the entire expression. For my problem, it would be best to only update a subset of coefficients. Is there a nice way to do this with the MIP architecture?
I'm currently trying to use m.objective.add_var(new_value + (+- old_value)). This zeroes out the old variable coefficient and then adds the new_value. However, it seems that I am seeing a similar issue with add_var as I saw in set_expr. I believe add_var is implemented correctly but it is being called when it shouldn't. I cloned a copy of MIP and added some print statements to debug. Here is the results:
Test case:
add_var with prints:
Output:
Analysis: It is not clear why there are two extra calls to add_var which set the coeff to 1. It is also unclear where these functions are being called from since it appears that the var 'v' is not currently in the LinExpr since it prints "else set coef". It also appears that even though the variable coefficient was changed to 3 at some point, when the objective is printed at the end of the test case, the coefficient is 1 again.
Do you know why this behavior is happening?
Hi,
I encountered a similar problem when trying to add terms to the objective function:
import mip
m = mip.Model()
x = m.add_var(var_type=mip.BINARY, name='x')
m.objective.add_term(x) # Has no effect on the objective
print(m.objective) # Empty
Scanning through the code, the issues seems to lie with Model.objective
in model.py
, which returns a new LinExpr
instance. It is that LinExpr
instance that is updated with the new term, but in the end does not affect the model's objective as the Model.objective
's setter method is not called.
Hence the 5 calls to add_var
from the example in the previous post seem to come from:
-
maximize(v)
- Printing the objective
-
Model.get_objective
(called duringm.objective.add_var(v, 2)
) -
add_var(v, 2)
(called duringm.objective.add_var(v, 2)
) - Printing the objective.
It seems reasonable to expect that the add_var
, add_expr
, add_const
and add_term
update the objective in place. Maybe it would be an option to add a method Model.update_objective
that does this?
Reported bugs here are actually some design issues in python-mip. All provided code examples where the constraint object is modified afterward or in-place editing of the objective should not be not possible and not allowed and ideally "forbidden" by application.
As far as I have checked with v1.14.0, when in-place editing the target function the application "crashes" (because trying to set a read-only attribute) while modifying the constraint is still silently ignored.