if statement in constraint
AnsweredHi,
I am trying to have a conditional constraint for when x [t-1] = 0.
Here is some current code:
model.addConstrs(sum(x[time,zone] for zone in zones) >= 0.95*sum(x[times[time_index-1],zone] for zone in zones) for time_index, time in enumerate(times)
if time != times[0])
model.addConstrs(sum(x[time,zone] for zone in zones) <= 1.05*sum(x[times[time_index-1],zone] for zone in zones) for time_index, time in enumerate(times)
if time != times[0])
This line of code works for the time conditional if statement, however, these constraints do not work if
x[times[time_index-1],zone] = 0
This is due to the multiplication. I have added a constant which makes it feasible, however, this makes for very bad results in all other cases (x[t-1] not equal to 0). I would like to add another conditional statement for these lines like:
if x[times[time_index-1],zone] != 0
When I add this I get :
NameError: name 'zone' is not defined
If I change to:
if x[times[time_index-1],zone]for zone in zones != 0)
I get:
UnboundLocalError: local variable 'zone' referenced before assignment
I am not sure what to do in this case or maybe if there is a better way. I appreciate any help.
-
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 why not try our AI Gurobot?. -
Hi Nicolas,
Comparisons of optimization variables are not possible, i.e.,
if x[times[time_index-1],zone] != 0
cannot be executed, because \(\texttt{x}\) does not have any value. It is an optimization variable object.
If \(\texttt{x}\) are binary variables, then you might want to use indicator constraints
model.addConstr( (x[times[time_index-1],zone] == 1) >> (some constraint) )
which basically states that if \(\texttt{x=1}\) then some constraint will be enforced.
If this is not what you had in mind, could you please elaborate and possibly add a minimal working example?
Do you try to achieve something likemodel.addConstrs(sum(x[time,zone] for zone in zones) >= 0.95*sum(x[times[time_index-1],zone] for zone in zones if zone != 0) for time_index, time in enumerate(times)
if time != times[0])Best regards,
Jaromił0 -
Hi Jaromil,
The minimal working example won't work without excel files but I will include code for you to see:
from gurobipy import *
import numpy as np
import pandas as pd
import numpy as np
zones = ['R1','SO1','MO1','LO3','H4']
times = [str(i) for i in range(1,1440)]
epcompile = pd.read_excel('miniwork.xlsx', index_col=0)
cum_epcompile= epcompile.cumsum()
ub = {"R1":20.75, "SO1":epcompile["SO1"].max(),"MO1":27.933,
"LO3":epcompile["LO3"].max(),"H4":epcompile["H4"].max()}
lb = {"R1":0.8, "SO1":0.36,"MO1":1.0,"LO3":9.7,"H4":13.59}
lb2 = {(i, j): lb[j] for i in times for j in zones}
ub2 = {(i, j): ub[j] for i in times for j in zones}
model = Model('flex')
#Variables
x = model.addVars(times, zones, ub=ub2, lb=lb2, vtype='S', name='x')
e = model.addVars(times,zones, name = "e", vtype = 'C')
cumm = model.addVars(times,zones, name = "cumm",vtype = 'C')
peak = model.addVar(name = "peak", vtype = 'C')
#Constraints
model.addConstrs(cumm[times[i], zone] == cum_epcompile.loc[cum_epcompile.index[i], zone] for zone in zones for i in range(1439))
model.addConstrs(e[times[0], zone] == cum_epcompile.loc[cum_epcompile.index[0], zone] for zone in zones)
model.addConstrs(e[time,zone] == x[times[time_index-1], zone] + e[times[time_index-1], zone] for zone in zones for time_index, time in enumerate(times)
if time != times[0])
model.addConstrs(e[time,zone] >= (0.98)*cumm[time,zone] for time in times for zone in zones
if time != times[0])
model.addConstrs(e[time,zone] <= (1.02)*cumm[time,zone] for time in times for zone in zones
if time != times[0])
model.addConstrs(sum(x[time,zone] for zone in zones) >= 0.97*sum(x[times[time_index-1],zone] for zone in zones) for time_index, time in enumerate(times)
if time != times[0])
model.addConstrs(sum(x[time,zone] for zone in zones) <= 1.03*sum(x[times[time_index-1],zone] for zone in zones) for time_index, time in enumerate(times)
if time != times[0])
model.addConstrs(peak >= sum(x[time, zone] for zone in zones) for time in times)
model.addConstrs(e[times[1438],zone] <=1.0001*cumm[times[1438],zone] for zone in zones)
#Objective
model.setObjective(peak, GRB.MINIMIZE)
model.Params.timeLimit = 800
model.optimize()E restricts a range which is an accumulation of x over all of time and compares it to a data file.
The sum(x) constraint keeps the aggregate signal, which is the sum of x, from bouncing up and down to much per time interval. The issue is that the constraint only works if the sum(x) is not equal to 0. For particular zones the sum(x) will and has to equal to 0 for some times, so I am forced to include a constant:
model.addConstrs(sum(x[time,zone] for zone in zones) >= 10+0.97*sum(x[times[time_index-1],zone] for zone in zones) for time_index, time in enumerate(times)
if time != times[0])Where that constant is equal to the lower bound of the decision variable. The big issue is that this gets applied to all times even when sum(x) is not zero. Now the restricted control I had over sum(x) has +10 more range which is huge. I want it to be able to jump +10 IF it sum(x(t-1)) is zero, and only jump 0.97 sum(x(t-1)) otherwise.
0 -
Hi Nicolas,
Do I understand correctly that the error you described in your first message is no longer an issue and you are currently interested in modelling of an \(\texttt{if-then}\)-statement for the \(\texttt{sum(x(t-1))}\) term?
You can model the statement \(\texttt{if sum(x(t-1)) > 0 then z = 0 else z = 1}\) as described in the stackexchange post How to write if else statement in Linear programming? You will have to introduce an additional binary variable \(\texttt{z}\) and introduce a small tolerance because strict inequality constraint are not supported in Gurobi. After modelling the \(\texttt{if-then}\)-statement, your constraint would be
\[\sum x_{time,zone} \geq z\cdot 10 + 0.97 \cdot \sum x_{timeIndex,zone} \]
where I skip to notate all indices to keep the constraint readable.
Best regards,
Jaromił0 -
Hello
I met a trouble while declaring a constraint into my model.my problem is a multi-product multi-period lot sizing problem. in the inventory balance constraint :
P_{ijt} = \sum_{\tau=1}^{t} \tau+ld_{j} = t \gg y_{ijt}.x_{ij\tau} \quad \forall j \in S, \quad \forall t \in T \\I_{it} = \max\{0,\sum_{j=1}^{} P_{ijt} + I_{it-1} - b_{it-1} - d_{it}\} \quad \forall t \in \{1,\dots,T\}, \quad\forall i \in \Gammaplease let me know how to satisfy the P_{ijt} into the second equation?I tried to apply indicator for \tau+ld_{j} = t.P_{ijt} is the sum of all incoming products from all "j" suppliers till the period of which we aim for balancing the inventory.for instance: we are at the 6th period. and we placed some orders from any of j suppliers within first period to the 6th period. considering the transferring leadtime. the y indicator represents the moment the product should reach in hand.0 -
Hi Saeed,
Your constraints compile to:
\[P_{ijt} = \sum_{\tau=1}^{t} \tau+ld_{j} = t \gg y_{ijt}.x_{ij\tau} \quad \forall j \in S, \quad \forall t \in T\]
\[I_{it} = \max\{0,\sum_{j=1}^{} P_{ijt} + I_{it-1} - b_{it-1} - d_{it}\} \quad \forall t \in \{1,\dots,T\}, \quad\forall i \in \Gamma\]
Could you please clarify your first constraint? What do variables \(y_{ijt}\), \(x_{ij\tau}\) represent? Are \(d_j\) and \(l\) variables too? Do you want to only sum over the \(\tau\) indices which satisfy \(\tau+ld_{j} = t\)?
Best regards,
Maliheh
0 -
Hi Maliheh
Consider a network flow. The p_{ijt} means the total delivered product type “i” from supplier “j” at period “t”.
It exactly meant: look for all purchased items from the beginning period till the period t( current) and sum those that their delivery will be taking place at period “t”.
/tau + ld_j = t ensures that only consider orders at period /tau which their delivery will at t .Please note that : d , ld_{j} are parameters. ld_{j} stands for leadtime delivery and d_{it} means demand of product i at period t
Regards
saeed
0 -
Hi Saeed,
Thanks for further clarification. It is not still clear to me what you are summing over to find \(P_{ijt}\). I guess you are trying to model the following:
\[P_{ijt} = \sum_{\tau | \tau + ld_{j} = t} y_{ijt} x_{ij\tau}\]
Since the condition is over the indices, you can filter through them using an \(\texttt{if}\) statement:
for i in range(types):
for j in range(suppliers):
for t in range(periods):
model.addConstr(
P[i, j, t]
== gp.quicksum(
y[i, j, t] * x[i, j, tau]
for tau in range(1, t+1)
if tau + ld[j] == t
),
name=f"P_{i}_{j}_{t}",
)Best regards,
Maliheh
0
Post is closed for comments.
Comments
8 comments