# Is it expected that a zero-one variable may have a non-integer value after an optimal solution is found?

**URL:** https://discourse.julialang.org/t/is-it-expected-that-a-zero-one-variable-may-have-a-non-integer-value-after-an-optimal-solution-is-found/107430
**Category:** Optimization (Mathematical)
**Tags:** question, gurobi, boolean
**Created:** [December 11, 2023, 11:43am UTC](https://discourse.julialang.org/t/is-it-expected-that-a-zero-one-variable-may-have-a-non-integer-value-after-an-optimal-solution-is-found/107430 "2023-12-11T11:43:26Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [December 11, 2023, 11:43am UTC](https://discourse.julialang.org/t/is-it-expected-that-a-zero-one-variable-may-have-a-non-integer-value-after-an-optimal-solution-is-found/107430/1 "2023-12-11T11:43:27Z")

</div>

I formulate a mathematical optimization (MIQCP) problem with MathOptInterface.jl and solve it with Gurobi.jl. Certain variables in my problem are constrained (with `MOI.add_constrained_variables(optimizer, [MOI.ZeroOne() for _ ∈ 1:n])`) to be Boolean. After `MOI.optimize!(optimizer)` is done, I check that `MOI.get(optimizer, MOI.TerminationStatus()) == MOI.OPTIMAL`, then retrieve the values of the variables using `MOI.get(optimizer, MOI.VariablePrimal(), logical_vars)`.

To my surprise, the value of such a variable need not be integral, in one case it’s `prevfloat(1.0, 7)`, very close to one, but not exactly integral.

Is this expected, or is it a bug?

I guess my workaround will be such, does it seem OK:

```julia
x = MOI.get(optimizer, MOI.VariablePrimal(), logical_variable)
ub = 1e-50
lb = true - 1e-10
((false ≤ x ≤ ub) | (lb ≤ x ≤ true)) || error("unexpected")
y = round(Bool, x)

```

---

<div class="post-metadata">

### Author: ![torressa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/torressa/32/202204_2.png) [@torressa](https://discourse.julialang.org/u/torressa)
#### Post date: [December 11, 2023, 11:55am UTC](https://discourse.julialang.org/t/is-it-expected-that-a-zero-one-variable-may-have-a-non-integer-value-after-an-optimal-solution-is-found/107430/2 "2023-12-11T11:55:14Z")

</div>

Hi!  
This is under the default integer feasibility tolerance of 1e-5, so this is expected.  
From: [Why does Gurobi sometimes return non-integral values for integer variables?](https://support.gurobi.com/hc/en-us/articles/360012237872-Why-does-Gurobi-sometimes-return-non-integral-values-for-integer-variables-) you can tighten this up or set the [IntegralityFocus](https://www.gurobi.com/documentation/current/refman/integralityfocus.html) parameter to 1.

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [December 11, 2023, 12:01pm UTC](https://discourse.julialang.org/t/is-it-expected-that-a-zero-one-variable-may-have-a-non-integer-value-after-an-optimal-solution-is-found/107430/3 "2023-12-11T12:01:48Z")

</div>

I guess there’s no option like `IntegralityFocus` for MathOptInterface.jl in general? Would it make sense to add it to MOI?

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [December 11, 2023, 12:07pm UTC](https://discourse.julialang.org/t/is-it-expected-that-a-zero-one-variable-may-have-a-non-integer-value-after-an-optimal-solution-is-found/107430/4 "2023-12-11T12:07:27Z")

</div>

Actually, I can’t figure out how to set the `IntegralityFocus` Gurobi parameter from Julia at all. How to do it?

---

<div class="post-metadata">

### Author: ![torressa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/torressa/32/202204_2.png) [@torressa](https://discourse.julialang.org/u/torressa)
#### Post date: [December 11, 2023, 12:09pm UTC](https://discourse.julialang.org/t/is-it-expected-that-a-zero-one-variable-may-have-a-non-integer-value-after-an-optimal-solution-is-found/107430/5 "2023-12-11T12:09:01Z")

</div>

You can set it using JuMPs [`set_attribute`](https://jump.dev/JuMP.jl/stable/api/JuMP/#set_attribute) or [`set_optimizer_attribute`](https://jump.dev/JuMP.jl/stable/api/JuMP/#JuMP.set_optimizer_attribute) or even [`MOI.RawOptimizerAttribute`](https://jump.dev/JuMP.jl/stable/moi/reference/models/#MathOptInterface.RawOptimizerAttribute)

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [December 11, 2023, 12:37pm UTC](https://discourse.julialang.org/t/is-it-expected-that-a-zero-one-variable-may-have-a-non-integer-value-after-an-optimal-solution-is-found/107430/6 "2023-12-11T12:37:37Z")

</div>

> [@torressa](#):
>
> or even [`MOI.RawOptimizerAttribute`](https://jump.dev/JuMP.jl/stable/moi/reference/models/#MathOptInterface.RawOptimizerAttribute)

Thanks! I ended up doing this, in addition to the above workaround:

```julia
import Gurobi as Opt
const gurobi_environment = Opt.Env()
import MathOptInterface as MOI
function make_opt()
  opt = Opt.Optimizer(gurobi_environment)
  MOI.set(opt, MOI.Silent(), true)
  MOI.set(opt, MOI.RawOptimizerAttribute("IntegralityFocus"), true)
  opt
end
my_program(make_opt, ...)

```

The `MOI.Silent` is there because otherwise Gurobi seems to print a line about setting the `IntegralityFocus` parameter each time that happens, which is each time an optimization problem gets formulated and solved.
