With decision variables in 'for' loop occur:Error code 0: Constraint has no bool value (are you trying "lb <= expr <= ub"?)
回答済みHi,
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')
-
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
サインインしてコメントを残してください。
コメント
14件のコメント