Search code examples
pythonbinaryipopt

PYOMO: Binary variable giving float values with IPOPT


I am facing a strange problem using IPOPT solver in PYOMO. A variable in the binary domain gives float values. It is totally fine if you get values such as 0.999 or 0.001. But values such as 0.4 or 0.5 are not practical. I have seen a similar post, but it did not help me as I cannot use an MIP solver.

My problem is described in PYOMO as follows.

# Select one material for each face.

materials = [ 'alum', 'carbon', 'zinc', 'steel']
faces = ['Face 1','Face 2','Face 3','Face 4','Face 5','Face 6']

model.M = pyo.Set(initialize=materials)
model.P = pyo.Set(initialize=faces)

# Selection variable

model.x = pyo.Var(mdl.M, mdl.P, domain=pyo.Binary)

# Constraint to make sure each face get one material

def c2(model, plate):
    return sum(model.x[m, plate] for m in model.M) == 1
model.c2 = pyo.Constraint(model.P, rule=c2)

Unfortunately the binary variable gives float values. A relevant part of the output is shown below:

 Variables:
    x : Size=24, Index=x_index
        Key                  : Lower : Value                 : Upper : Fixed : Stale : Domain
          ('zinc', 'Face 1') :     0 :    0.5648148977886973 :     1 : False : False : Binary
          ('zinc', 'Face 2') :     0 :                   1.0 :     1 : False : False : Binary
          ('zinc', 'Face 3') :     0 :                   1.0 :     1 : False : False : Binary
          ('zinc', 'Face 4') :     0 :                   1.0 :     1 : False : False : Binary
          ('zinc', 'Face 5') :     0 :                   1.0 :     1 : False : False : Binary
          ('zinc', 'Face 6') :     0 :                   1.0 :     1 : False : False : Binary
        ('copper', 'Face 1') :     0 :   0.43518512159762096 :     1 : False : False : Binary
        ('copper', 'Face 2') :     0 : 9.893803483769687e-09 :     1 : False : False : Binary
        ('copper', 'Face 3') :     0 : 9.893803483769687e-09 :     1 : False : False : Binary
        ('copper', 'Face 4') :     0 : 9.893803483769687e-09 :     1 : False : False : Binary
        ('copper', 'Face 5') :     0 : 9.893803483769687e-09 :     1 : False : False : Binary
        ('copper', 'Face 6') :     0 : 9.893803483769687e-09 :     1 : False : False : Binary
   

('zinc', 'Face 1') and ('copper', 'Face 1') keys have float values such as 0.4 and 0.5 which are not practical for a binary decision. I can't use MIP solvers since my problem is not an integer problem.

ONE IDEA:

One way that I am trying to implement is to define a constraint for the binary variable model.x[m.p] such as 0 < model.x[m.p] < 0.01 or 0.99 < model.x[m.p] < 1. But is it feasible to define two intervals for a variable in python?

If someone has any ideas, please help!

Thank you.


Solution

  • Ipopt is a Non Linear Solver (NLP) and not a Mixed Integer NLP (MINLP) so your binary variables... FYI, the I of Ipopt means 'Interior' and not 'Integer'.

    Now if you really need a MINLP solver, you could use Bonmin as open-source alternative. However, is your problem really non-linear? If yes, maybe you can try to approximate the non-linear function by a piecewise-linear function?