With decision variables in 'for' loop occur:Error code 0: Constraint has no bool value (are you trying "lb <= expr <= ub"?)
AnsweredHi,
I've been doing a MIP programming with Gurobi in Python. Gurobi Optimizer version 9.1.2 build v9.1.2rc0 (win64).
The error code Error code 0: Constraint has no bool value (are you trying "lb <= expr <= ub"?) occured when I was writing a constraint shown below:
try:
m = Model()
x = m.addVars(tof.keys(), vtype=GRB.CONTINUOUS, name='x')
z = m.addVars(tdf.keys(), vtype=GRB.CONTINUOUS, name='z')
t = 0
for t in range(288):
for f in tof.keys():
if x[f] <= t and t <= x[f] + 6:
m.addConstr(y.sum('*', '*') <= qk, 'c2')
else:
t += 1
if x[f] <= t <= x[f]:
for p in fleetType:
m.addConstr(y.sum('*', p) <= xp, 'c8')
else:
t += 1
In the constraints above, variable x[f] and z[f] do not participate in the constraints, however the period between them is the prerequisite. If convenient, please help me with how to write properly about this. Thanks a lot!!
By the way, x and z are auxiliary variables with other two constraints:
for f in flights:
m.addConstr(x[f] == Deptime_base[f] + v[f], 'auxiliary1')
m.addConstr(z[f] == x[f] + jf[f] + delay + u[f], 'auxiliary2')
-
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 try Gurobot, our chatbot interface offering instant, expert-level support. -
Variable objects don't have a value and thus, cannot be used in \(\texttt{if}\)-clauses or any similar checks. This means that the check \(\texttt{x[f] <= t}\) cannot be evaluated when constructing the model. You have to formulate the conditional statement via additional binary variables and constraints. Please have a look at How do I model conditional statements in Gurobi? for more details.
Once you have formulated the conditional statements, you can use Gurobi's addGenConstrAnd method to formulate the "and" condition in your first \(\texttt{if}\)-clause.
You second \(\texttt{if}\)-clause actually reads \(\texttt{if x[f] = t then add constraints}\). Formulating an equality check where \(x\) is a continuous variable is tricky. The stackexchange post In an integer program, how I can force a binary variable to equal 1 if some condition holds? describes a good way to approach this.
Best regards,
Jaromił0 -
Thanks a lot! However, there was a typing error for the second if-clause, the code is actually:
t = 0
for t in range(288):
for f in tof.keys():
if x[f] <= t and t <= x[f] + 6:
m.addConstr(y.sum('*', '*') <= qk, 'c2')
else:
t += 1
if x[f] <= t <= z[f]:
for p in fleetType:
m.addConstr(y.sum('*', p) <= xp, 'c8')
else:
t += 1I guess it could be solved using the same method as the first if-clause?
0 -
Hi again! I revised the code compression like this:
s = m.addVar(vtype=GRB.BINARY, name="s")
h = m.addVar(vtype=GRB.BINARY, name="h")
h2 = m.addVar(vtype=GRB.BINARY, name="h2")
x2 = m.addVar(vtype=GRB.BINARY, name="x2")
y2 = m.addVar(vtype=GRB.BINARY, name="y2")
for t in range(288):
for f in tof.keys():
m.addConstr(t >= x[f] - M * (1-s), 'BigM1-1')
m.addConstr(t <= x[f] + M * s, 'BigM1-2')
m.addConstr(x[f] + 6 >= t - M * (1-h), 'BigM2-1')
m.addConstr(x[f] + 6 <= t + M * h, 'BigM2-2')
m.addConstr(z[f] >= t - M * (1-h2), 'BigM3-1')
m.addConstr(z[f] <= t + M * h2, 'BigM3-2')
m.addGenConstrAnd(x2, [s,h], 'andConstr1')
m.addGenConstrAnd(y2, [s,h2], 'andConstr2')
t = 0
for t in range(288):
if x2 == 1:
m.addConstr(y.sum('*', '*') <= qk, 'c2')
else:
t += 1
if y2 == 1:
for p in fleetType:
m.addConstr(y.sum('*', p) <= xp, 'c8')
else:
t += 1However, the error still occurs:
Error code 0: Constraint has no bool value (are you trying "lb <= expr <= ub"?)
Is there anything I didn't get?
0 -
I guess it could be solved using the same method as the first if-clause?
Yes, exactly.
However, the error still occurs:
Error code 0: Constraint has no bool value (are you trying "lb <= expr <= ub"?)
Is there anything I didn't get?
As mentioned in my first message, it is not possible to use Var objects for comparisons. Thus, the \(\texttt{if}\)-clause \(\texttt{if x2 == 1}\) and \(\texttt{if y2 == 1}\) result in an error. You have to formulate these \(\texttt{if}\)-statements with the help of binary variables and (in)equality constraints. Luckily, in your case you can use Gurobi's indicator constraints to formulate your \(\texttt{if}\)-statements.
What I don't understand is, why you loop over \(\texttt{t}\), when you have only exactly one variable \(\texttt{x2}\) and \(\texttt{y2}\).
Best regards,
Jaromił0 -
I got it. I need to set the variables differently so that it would go with the loop for t. Thanks for your time help!!!!
0 -
Hi Jaromił,
I've tried again using the code like this:
try:
m = Model()x = m.addVars(tof.keys(), lb = 0, ub= 287, vtype=GRB.CONTINUOUS, name='x')
z = m.addVars(tdf.keys(), lb = 0, ub = 287, vtype=GRB.CONTINUOUS, name='z')
s = m.addVars(288, vtype=GRB.BINARY, name="s")
h = m.addVars(288, vtype=GRB.BINARY, name="h")
h2 = m.addVars(288, vtype=GRB.BINARY, name="h2")
x2 = m.addVars(288, vtype=GRB.BINARY, name="x2")
y2 = m.addVars(288, vtype=GRB.BINARY, name="y2")for t in range(288):
for f in tof.keys():
m.addConstr(t >= x[f] - M * (1-s[t]), 'BigM1-1')
m.addConstr(t <= x[f] + M * s[t], 'BigM1-2')
m.addConstr(x[f] + 6 >= t - M * (1-h[t]), 'BigM2-1')
m.addConstr(x[f] + 6 <= t + M * h[t], 'BigM2-2')
m.addConstr(z[f] >= t - M * (1-h2[t]), 'BigM3-1')
m.addConstr(z[f] <= t + M * h2[t], 'BigM3-2')
for t in range(288):
m.addGenConstrAnd(x2[t], [s[t],h[t]], 'andConstr1')
m.addGenConstrAnd(y2[t], [s[t],h2[t]], 'andConstr2')for t in range(288):
m.addGenConstrIndicator(x2[t], True, y.sum('*', '*') <= qk, 'c2')
m.addGenConstrIndicator(y2[t], True, y.sum('*', p) <= xp, 'c8')However, the error: Error code 10003: Additional sense argument provided for general constraint of indicator type occurs.
Perhaps by using the addGenConstrIndicator the x2[t] and y2[t] cannot be decision variables?
In that way, I'm wondering how to form the code with the logics states that if the if x2[t] == 1(which is decided by the constraints 'andConstr1' and 'andConstr2') then the constraint must be satisfied.
Thank you!
Best regards,
Jingyue
0 -
Hi Jingyue,
The addGenConstrIndicator method has the arguments \(\texttt{(binvar, binval, lhs, sense=None, rhs=None, name="" )}\). The \(\texttt{lhs}\) argument can be a float, Var, LinExpr, or a TempConstr object. If you provide a TempConstr object for the \(\texttt{lhs}\) argument, you won't provide the \(\texttt{sense}\) and \(\texttt{rhs}\) argument. In this case, you have to explicitly specify that you define the \(\texttt{name}\) argument.
for t in range(288):
m.addGenConstrIndicator(x2[t], True, y.sum('*', '*') <= qk, name='c2')
m.addGenConstrIndicator(y2[t], True, y.sum('*', p) <= xp, name='c8')Best regards,
Jaromił0 -
Hi Jaromił,
your advice is very helpful. I tried and the error disappears.
Today I reviewed my code and discovers that the logic might be wrong.
The logic I'm trying to express is:
't' stands for discrete time, and there are 288 time windows. For any time t, if the big M constraints about decision variables x[f] and z[f] are satisfied (s,h,h2,x2,y2,z2 are the binary variables for any time t), then the andconstrs occurs, however now my code looks like that t is an integer and it's looping from 0 to 287.
try:
m = Model()
print('building model')x = m.addVars(tof.keys(), lb = 0, ub= 287,
vtype=GRB.CONTINUOUS, name='x')
z = m.addVars(tdf.keys(), lb = 0, ub = 287, vtype=GRB.CONTINUOUS, name='z')
s = m.addVars(288, vtype=GRB.BINARY, name="s")
h = m.addVars(288, vtype=GRB.BINARY, name="h")
h2 = m.addVars(288, vtype=GRB.BINARY, name="h2")x2 = m.addVars(288, vtype=GRB.BINARY, name="x2")
y2 = m.addVars(288, vtype=GRB.BINARY, name="y2")for t in range(288):
for f in tof.keys():
m.addConstr(t[f] >= x[f] - M * (1-s[t]), 'BigM1-1')
m.addConstr(t[f] <= x[f] + M * s[t], 'BigM1-2')
m.addConstr(x[f] + 6 >= t[f] - M * (1-h[t]), 'BigM2-1')
m.addConstr(x[f] + 6 <= t[f] + M * h[t], 'BigM2-2')
m.addConstr(z[f] >= t[f] - M * (1-h2[t]), 'BigM3-1')
m.addConstr(z[f] <= t[f] + M * h2[t], 'BigM3-2')
for t in range(288):
m.addGenConstrAnd(x2[t], [s[t],h[t]], 'andConstr1')
m.addGenConstrAnd(y2[t], [s[t],h2[t]], 'andConstr2')for t in range(288):
m.addGenConstrIndicator(x2[t], True, y.sum('*', '*'), GRB.LESS_EQUAL, qk, 'c2')
m.addGenConstrIndicator(y2[t], True, y.sum('*', p), GRB.LESS_EQUAL, xp, 'c8')I'm wondering is there any way to express the logic right?
Thanks again for your help!!!!!
Yours,
Jingyue
0 -
You would have to model a variable index as an optimization variable. This is possible but quite expensive. It is discussed in the Community post use a decision variable as an index.
Best regards,
Jaromił0 -
Hi Jaromił,
I think I almost got it from the post you shared. It expresses a way to index x[t] andy[t] for Andconstraints.
However, I still quite not get how to express the bold part of "For any time t, if the big M constraints about decision variables x[f] and z[f] are satisfied (s,h,h2,x2,y2,z2 are the binary variables for any time t), then the andconstrs occurs".
Sorry to bother you if my question is silly :)
0 -
This is where it gets tricky. You would have to introduce 288 \(\times\) tof.keys() t variables and model the big-M constraints with the particular t[i, f]. Then, you can use t[i, f] as index in your andconstr.
0 -
Hi Jaromił,
Thank you for your advice again. It's really helpful!!!!
I defined the t[i,f] and tried like this:
for i in range(288):
for f in flights:
tindex[i,f] = 0try:
m = Model()x = m.addVars(tof.keys(), lb = 0, ub= 287, vtype=GRB.CONTINUOUS, name='x')
z = m.addVars(tdf.keys(), lb = 0, ub = 287, vtype=GRB.CONTINUOUS, name='z')
s = m.addVars(288, vtype=GRB.BINARY, name="s")
h = m.addVars(288, vtype=GRB.BINARY, name="h")
h2 = m.addVars(288, vtype=GRB.BINARY, name="h2")
x2 = m.addVars(288, vtype=GRB.BINARY, name="x2")
y2 = m.addVars(288, vtype=GRB.BINARY, name="y2")
ui = m.addVars(288,vtype=GRB.BINARY, name = 'ui')
t = m.addVars(tindex.keys(), vtype = GRB.BINARY, name = 't')
m.addConstr(ui.sum('*') == 1, 'index2')
for i in range(288):
for f in tof.keys():
m.addConstr(i* ui[i] == t[i,f], 'index1')
m.addConstr(t[i,f] >= x[f] - M * (1-s[f]), 'BigM1-1')
m.addConstr(t[i,f] <= x[f] + M * s[f], 'BigM1-2')
m.addConstr(x[f] + 6 >= t[i,f] - M * (1-h[f]), 'BigM2-1')
m.addConstr(x[f] + 6 <= t[i,f] + M * h[f], 'BigM2-2')
m.addConstr(z[f] >= t[i,f] - M * (1-h2[f]), 'BigM3-1')
m.addConstr(z[f] <= t[i,f] + M * h2[f], 'BigM3-2')
m.addGenConstrAnd(x2[f], [s[f],h[f]], 'andConstr1')
m.addGenConstrAnd(y2[f], [s[f],h2[f]], 'andConstr2')for t in range(288):
m.addGenConstrIndicator(x2[t], True, y.sum('*', '*'), GRB.LESS_EQUAL, qk, 'c2')
m.addGenConstrIndicator(y2[t], True, y.sum('*', p), GRB.LESS_EQUAL, xp, 'c8')The error occurs:KeyError: '3848669'
'3848669' is the a key in tof.keys()
Also, if I try with this constraint:
for i in range(288):
for f in tof.keys():
m.addConstr(sum(i* ui[i]) == t,sum('*',f), 'index1')
"TypeError: 'gurobipy.LinExpr' object is not iterable" occurs.I'm confused and wondering where it went wrong.
0 -
The error about not iterable object occurs because the \(\texttt{i* ui[i] }\) is a LinExpr object which is not an iterable object such as a list for example. If you want to sum over all indices \(\texttt{i}\), you should try
for f in tof.keys():
m.addConstr(quicksum(i* ui[i] for i in range(288)) == t.sum('*',f), 'index1')I don't know about the KeyError. It points to an "out-of-array" access. I guess that it is some mismatch between \(\texttt{flights}\) and \(\texttt{tof.keys()}\).
Note that you defined \(\texttt{t}\) as optimization variables so you definitely should not use it in your \(\texttt{for}\)-loop.
for i in range(288):
m.addGenConstrIndicator(x2[i], True, y.sum('*', '*'), GRB.LESS_EQUAL, qk, 'c2')
m.addGenConstrIndicator(y2[i], True, y.sum('*', p), GRB.LESS_EQUAL, xp, 'c8')Hope this helps.
0 -
Thank you very much!!!!
I tried and it works!
0
Post is closed for comments.
Comments
15 comments