Variant of an "elseif" loop with binary values

Hi !

I’m looking for another possibility to implement my elseif loop for my linear program.
The goal is to implement the following:

if q_out >= 9
    eff == 0.75
elseif 7 <= q_out < 9
    eff == 1
else
    eff == 0.5
end

I have already implemented these lines of code (see an extract below).

set_optimizer_attribute(model, "NonConvex",2)

M = 10^(10) # parameter to select my binary variable

# definition of the variables
@variable(model, 0 <= q_out <= 15)
@variable(model, 0 <= eff <= 1)
@variable(model, 0 <= z_1 <= 1, binary=true)  
@variable(model, 0 <= z_2 <= 1, binary=true)

# constraints
@constraint(model, q_out <= 7-0.1*10^(-1) + M * (1 - z_1)) 
@constraint(model, q_out >= 7-0.1*10^(-1) - M * z_1)
    
@constraint(model, q_out <= 9-0.1*10^(-1) + M * (1 - z_2)) 
@constraint(model, q_out >= 9-0.1*10^(-1)  - M * z_2)

@constraint(model, eff == 0.75 * (1-z_2) +  1*z_2 + (0.5-1)*z_1 )

But I’m not convinced of its result.
When q_out approaches the limit 9, for example q_out = 8.989999389648451, my binary value z_2=0.9999999999999933 is no longer binary, which is problematic for the variable eff.

Has somebody an idea of other possibilities to write my code to avoid this kind of problem?

Thank you in advance for your help!

I think it is expected binary/integer variables do not fulfil their constraint exactly for performance reasons. The details will depend on the solver used (example). If you want exact values then I suggest rounding with round(Int, x)

1 Like

Just to clarify, you cannot use round(Int, x) inside a JuMP model.

Gurobi has some helpful articles for understanding what is going on:

As suggested at the bottom of the last article, you could also use indicator constraints:

using JuMP, Gurobi
model = Model(Gurobi.Optimizer)
@variable(model, q_out)
@variable(model, eff)
@variable(model, z[1:3], Bin)
@constraint(model, sum(z) == 1)
@constraint(model, z[1] --> {q_out >= 9})
@constraint(model, z[2] --> {q_out >= 7})
@constraint(model, z[2] --> {q_out <= 9})
@constraint(model, z[3] --> {q_out <= 7})
@constraint(model, eff == 0.75 * z[1] + 1.0 * z[2] + 0.5 * z[3])

(I haven’t tested this code, so there might be typos, etc.)

1 Like

Hi Odow,

thank you for your answer! It was very helpful!

1 Like