Using If - Else for constraint

1,667 views
Skip to first unread message

madeSM

unread,
Jan 23, 2018, 12:27:49 PM1/23/18
to Gurobi Optimization

Dear All,

Is there any other way to apply an If - Else function for any constraint in Gurobi?
I'm doing a Linear Program optimization, where one of the variables would only be made If a certain condition was met.

The code looks like this:

Buy = m.addVar(...)
Sell = m.addVar(...)
Battery Status = m.addVar (...)

If Battery Status == 100:
    con1 = m.addConstr(Sell == Generation - Consumption)
else:
    con2 = m.addConstr(Sell == 0)
    con3 = m.addConstr(Buy == Consumption - Generation)

data = The consumption could be higher or lower than the generation

So I'm pretty stuck with this as I know that If Else was not allowed for an LP

Any ideas would be very much welcomed!

Thank you!

Tobias Achterberg

unread,
Jan 23, 2018, 12:38:31 PM1/23/18
to gur...@googlegroups.com
The "else" only works if the constraint has always an integer value. Otherwise, you are
getting in trouble with tolerances on how to define strict inequality.

Let me do an example.

If want to model

x1 + x2 >= 1 => y1 + y2 <= 1
else: y1 + y2 >= 2

This is equivalent to

x1 + x2 >= 1 => y1 + y2 <= 1
x1 + x2 < 1 => y1 + y2 >= 2

To model this, you need an auxiliary binary variable z and indicator constraints:

z = 0 -> x1 + x2 >= 1 (1)
z = 0 -> y1 + y2 <= 1 (2)
z = 1 -> x1 + x2 < 1 (3)
z = 1 -> y1 + y2 >= 2 (4)

The problematic constraint is (3), because LP and MIP technology does not support strict
inequality. If x1 and x2 are integer, then you can rephrase this to

z = 1 -> x1 + x2 <= 0 (3)

and everything will be fine. But if not, you need to introduce some threshold yourself at
which you would say that the strict inequality is satisfied, e.g.

z = 1 -> x1 + x2 <= 0.999 (3)

Which threshold should be used is highly dependent on the application and thus Gurobi does
not support this (through an "if-then-else" constraint) in an automatic fashion. You need
to specify the individual "if-then" conditions yourself, which forces you to specify the
threshold explicitly.

But please note that whatever threshold you choose for the continuous case, the result
will be somewhat questionable. For example, a solution with x1 + x2 == 0.9995 will neither
satisfy "x1 + x2 >= 1" nor "x1 + x2 <= 0.999" within the default feasibility tolerance of
1e-6. Hence, such a solution would never be declared feasible, no matter how the auxiliary
variable z will be set (and whatever the values of y1 and y2 are).


Hope this helps.

Tobias

madeSM

unread,
Jan 23, 2018, 5:00:50 PM1/23/18
to Gurobi Optimization
Hi Tobias! 

Thank you for the explanation, my variable right now was set to continuous, and I couldn't change one of the parameters into an integer value. 
I will look for another way to do the LP then. 

Thanks again!



madeSM

unread,
Feb 12, 2018, 9:57:08 AM2/12/18
to Gurobi Optimization
Hi Tobias,

Is it possible to use Indicator Constraint instead and predetermine the if-else situation?

The code looks like:
If battery status < 80:
    batt_ind = 0
else:
    batt_ind = 1

and then proceed with 
c1 = m.addConstr(bat_check, True, Power Equation + battery_sell = Trade)
c2 = m.addGenConstrIndicator(bat_ind, False,  battery_sell == 0)
c3 = m.addGenConstrIndicator(bat_ind, True,  battery_sell >= 0)

It gave me an error 'int' object has no attribute '__colno__'


I just want to make the battery_sell variable to become 0 when its status is below 80 and bigger than 0 when it's on and above 80

Thank you for your help!

Tobias Achterberg

unread,
Feb 13, 2018, 3:11:31 AM2/13/18
to gur...@googlegroups.com
There are two issues:

1. You are mixing up Python if-else statements with the Gurobi indicator constraints to
model "if-else" conditions in your MIP. Your Python code assigns either a value 0 or a
value 1 to an object "batt_ind". This means, that "batt_ind" will be of type "int"
afterwards. Consequently, you are getting an error when you are trying to use this object
as a Gurobi variable for the addGenConstrIndicator() function. Instead, you need to
declare batt_ind as a Gurobi variable using batt_ind = m.addVar(...).

I guess the battery status is also a model variable whose value should be determined by
Gurobi. Hence, "battery_status" should also be added to the model using m.addVar(...).

2. MIP solvers do not support strict inequality. Hence, the logical implication
"battery_status >= 80 -> battery_sell > 0" cannot be modeled. If "battery_sell" is an
integer variable, you can instead use "battery_sell >= 1". The same applies to the
"battery_status < 80" condition.

So, in this case, your model would look something like this:

battery_status = m.addVar(...)
batt_ind = m.addVar(...)
battery_sell = m.addVar(...)
m.addGenConstrIndicator(batt_ind, 0, battery_status <= 79)
m.addGenConstrIndicator(batt_ind, 1, battery_status >= 80)
m.addGenConstrIndicator(batt_ind, 0, battery_sell <= 0)
m.addGenConstrIndicator(batt_ind, 1, battery_sell >= 1)


Best regards,

Tobias
Reply all
Reply to author
Forward
0 new messages