How to add conditions in objective functions?
AnsweredHi Gurobi team,
I want to implement some conditions in my objective function. I know adding conditions to constraints is possible through addGenConstrIndicator() but I don't know how I can add conditions in the objective function. Here is a minimal example snippet for my problem. I have variable v with size = 3, prev_values are the previous values for this variable (consider a temporal scenario with the next variable values is dependent on the previous variable values). Now, I want to check if the current value is either equal to 0 or equal to its previous values, and use it in my objective function. How can I implement this in Gurobi (below is a sketch of what I intend to implement)?
model = gp.Model()
E = [2, 4, 7]
prev_values = [4, 5, 1]
v = model.addVar(3, lb=0, vtype=gp.GRB.INTEGER, )
def check(vn, vp):
if vn == 0 or vn == vp:
return 0
return 1
model.setObjective(max([check(v[i], prev_values[i]) * E[i] for i in range(3)]) , gp.GRB.MINIMIZE)
Thank you!
-
To work with general expressions, you may need to add intermediate decision variables, see How do I model logical and general expressions? This is not only the case for constraints but also for conditions on objective variables.
A possible solution for your case could be
import gurobipy as gp
model = gp.Model()
# get current integer feasibility tolerance value
IntFeasTol = model.getParamInfo('IntFeasTol')[2]
E = [2, 4, 7]
prev_values = [4, 5, 1]
v = model.addVars(3, lb=0, vtype=gp.GRB.INTEGER)
# several helper variables are needed
diff_v_prev = model.addVars(3, lb=-gp.GRB.INFINITY, vtype=gp.GRB.INTEGER)
absVar =model.addVars(3, vtype=gp.GRB.INTEGER)
check_v = model.addVars(3, vtype=gp.GRB.BINARY)
forObj = model.addVars(3, vtype = gp.GRB.INTEGER)
objVar = model.addVar(name='obj')
model.addConstrs(diff_v_prev[i] == prev_values[i] - v[i] for i in range(3))
model.addConstrs(absVar[i] == gp.abs_(diff_v_prev[i]) for i in range(3))
# check_v is only allowed to be 0 if 0 < v and |v - prev_values| > 0 (use IntFeasTol)
model.addConstrs((check_v[i]==0) >> (v[i] >= IntFeasTol) for i in range(3))
model.addConstrs((check_v[i]==0) >> (absVar[i] >= IntFeasTol) for i in range(3))
model.addConstrs(forObj[i] == check_v[i] * E[i] for i in range(3))
model.addConstr(objVar == gp.max_([forObj[i] for i in range(3)]))
model.setObjective(objVar , gp.GRB.MINIMIZE)
model.optimize()There might be a simpler solution that I am currently not aware of.0 -
Hi,
Thank you for your response, It was very helpful. I faced another problem implementing that.
Actually, instead of 0 we want check_v to be 1 if both the conditions (v > 0 and |v-p| > 0) are true.
But when I do:
(check_v[i]==1) >> ...
I see no effect and check_v values are all zero, while v[i] and absVar[i] values are all positive integers.
0 -
The two indicator constraints
model.addConstrs((check_v[i]==0) >> (v[i] >= IntFeasTol) for i in range(3))
model.addConstrs((check_v[i]==0) >> (absVar[i] >= IntFeasTol) for i in range(3))make sure that if check_v == 0 then also v > 0 and |v-p| > 0. It also implies if v==0 or v-p==0 then check_v=1. But it does not forbid to set check_v to 1 if v > 0 and |v-p| > 0.
I probably misinterpreted your check-function. Here is another try.
So we want to have the following condition:
If v != 0 and v != p then check_v=1
This is equivalent to
If check_v = 0 then v=0 or v=p
which, I think, can be achieved with the following codev = model.addVars(3, lb=1, ub=2, vtype=gp.GRB.INTEGER, name='v')
check_v = model.addVars(3, vtype=gp.GRB.BINARY, name='check_v')
vIs0 = model.addVars(3, vtype=gp.GRB.BINARY, name='vIs0')
vIsP = model.addVars(3, vtype=gp.GRB.BINARY, name='vIsP')
# if check_v is 0 then v=0 or v=p (this implies if v!=0 and v!=p then check_v=1)
model.addConstrs((vIs0[i]==1) >> (v[i] == 0) for i in range(3))
model.addConstrs((vIsP[i]==1) >> (v[i] == prev_values[i]) for i in range(3))
model.addConstrs((check_v[i]==0) >> (vIs0[i] + vIsP[i] >= 1) for i in range(3))0
Please sign in to leave a comment.
Comments
3 comments