Add constraint in GurobiPy using conditional decision variable

Viewed 1387

I am new to optimisation and have a fairly basic query.

I have a model with two decision variables x and y that vary in time. I'd like to add a conditional constraint on y at time t depending upon x[t-1], such that I've implemented the following code:

for t in model.timesteps:
        if t>1:
            if model.x[t-1] <= 1:
                model.addConstr(model.y[t] >= 100)
            elif model.x[t-1] <= 0.5:
                model.addConstr(model.y[t] >= 50)
            elif model.x[t-1] <= 0.3:
                model.addConstr(model.y[t] >= 20)

However, the above code produces the error:

File "tempconstr.pxi", line 44, in gurobipy.TempConstr.bool gurobipy.GurobiError: Constraint has no bool value (are you trying "lb <= expr <= ub"?)

Having done a little reading on previous related queries on this page, I believe I might need to use a binary indicator variable in order to implement the above. However, I'm not certain as to whether this would solve the above issue.

Could anyone point me in the right direction here please?

Many thanks in advance!

1 Answers

First, I assume your order of operations is incorrect; you intended that the right-hand side is 20 for 0 ≤ x[t-1] ≤ 0.3, 50 for 0.3 < x[t-1] ≤ 0.5 and 100 for 0.5 < x[t-1] ≤ 1.0.

The bigger issue is that you were mixing Python programming with MIP modeling. What you need is to convert that logic into a MIP model. There are several ways to do this. One is to use a piecewise linear constraint to represent the right-side values of the y[t] constraints. However, I prefer to model this explicitly. There are a few similar options; here is one I think is easy to understand: add binary variables z[0], z[1] and z[2] to represent the 3 ranges of x[t-1]; this gives the following code:

for t in model.timesteps:
  if t>1:
    z = model.addVars(3, vtype='B', name="z_%s" % str(t))
    model.addConstr(x[t-1] <= z.prod([0.3, 0.5, 1.0]))
    model.addConstr(y[t] >= z.prod([20, 50, 100]))
    model.addConstr(z.sum() == 1)
Related