The index() function doesn't work well with gurobi variable
AnsweredI write a demo for the situation:
import gurobipy as gp
from gurobipy import GRB
m = gp.Model()
x = m.addVars(2, 3)
m.update()
L = [x[i, j] for i in range(2) for j in range(3)]
print(L.index(x[0, 1]))
gurobipy.GurobiError: Constraint has no bool value (are you trying "lb <= expr <= ub"?)
I assume I should get 1 as output, but it seems there is something wrong with the index() function.
Could anyone tell me why this occurred? Thanks
And what should I do if I want to query the location of a variable in a container?
-
Hi Jingwei,
I am fairly certain this issue is due to the equality operation on our gurobipy variable class.
Consider the following code:
>>> 5 == 4
False
>>> 4 == 4
True
>>> x[0,0] == x[0,0]
<gurobi.TempConstr: C0 == <gurobi.Var C0>>As you can see when you use the equality operator with gurobipy variables you get back a constraint, not a boolean. This is what allows us to write constraints in a natural manner such as
m.addConstr(x[0,0] + x[0,1] == 1)
Let's say we write our own index method like so:
def index(list, value):
for i, element in enumerate(list):
if value == element:
return i
raise ValueError(f"{value} is not in list")and call it:
>>> index(L, x[0,1])
It will suffer from the same problem, that is the same error will be raised. On the third line the equality operator will return a constraint, as the condition in an "if" statement, and then this "condition" is checked to see if it is "true or false". When python does this it looks for a __bool__ method on whatever is returned by the condition and this is where the error is raised because our gurobipy constraint objects do not have this method (and we don't want them to). I suspect this is the problem when using list.index.
However we can write an alternative method like so which uses "is" for comparison instead of the equality operator:
def index(list, value):
for i, element in enumerate(list):
if value is element:
return i
raise ValueError(f"{value} is not in list")and using this will return the value you want
>>> index(L, x[0,1])
1- Riley
1 -
Hi Riley,
Thank you so much for your timely reply!
It's extremely exhaustive and helpful. I will follow your advice and revise my implementation.
Best regards,
Jingwei
0 -
No problem Jingwei.
Although my suggestion is to avoid this approach when building your models - if they are large models.
If the time to build the models is large then, if you want to describe why you're using this index approach, I may be able to show you a better way to do it.
- Riley
0 -
Hi Riley,
It's very kind of you to help.
Actually I'm working with branch and price algorithm. Each time when I add a variable and corresponding column to the restricted master problem, I store each of them to a list, respectively. So they are one-to-one on index.
When column generation completes, which means the LP of master problem is solved to optimality, I need to find the corresponding column of a variable whose value is closest to 0.5 for branching. That means I need to iterate the "variable list", find the exact one, and use the index of that variable to find the corresponding column in "column list".
I'm not sure if there's a more efficient way. Thank you.
Best regards,
Jingwei
0 -
Hi Jingwei,
Perhaps Model.getCol can help here?If that doesn't work for you case then my advice would be to just set a "_col" attribute on your variables which you use to store the corresponding column, eg
a_variable._col = a_column
Then you won't need to worry finding the index.
You can also pair a list of variables with a list of columns like so:
for variable, column in zip(variables, columns):
variable._col = column- Riley
0 -
Hi Riley,
Thanks for your hint.
I use the following statement as what I want are exactly coefficients corresponding to the variable. It seems suitable for subsequent operations.
coeffs = [Model.getCoeff(constr, var) for constr in Model.getConstrs()]
Best regards,
Jingwei
0
Please sign in to leave a comment.
Comments
6 comments