Search code examples
pythonintegeruniquepyomoipopt

Pyomo assignes floats to Integer domain


Having a simplified problem: I'd like to assign an instance ID anywhere in in the instance_map. The goal is to have the ID's uniquely distributed over the instance_map, so each ID should occur exatcly once.

Pyomo in turn raises that this task is unfeasbile and most surprisingly started assigning with floats in an integer domain. Here's the code

import pyomo.environ as pe

model = pe.ConcreteModel()

model.rows = pe.RangeSet(1, 2)
model.cols = pe.RangeSet(1, 5)
model.instances = pe.RangeSet(1, 5)
model.n_instances = pe.Var(initialize=5)
model.n_cols = pe.Var(initialize=5)
model.n_rows = pe.Var(initialize=2)

model.instances_map = pe.Var(model.rows, model.cols, within=pe.Integers, initialize=0, bounds=(0, model.n_instances.value))

def unique_instances_check(model, instance):
    if instance == 0:
        return sum(model.instances_map[i,j] == instance for i in model.rows for j in model.cols) >= 0
    else:
        return sum(model.instances_map[i,j] == instance for i in model.rows for j in model.cols) == 1
model.C1 = pe.Constraint(model.instances, rule=unique_instances_check)

def objective(model):
    return sum(model.instances_map[1,j] for j in model.cols)
model.obj = pe.Objective(rule=objective, sense=pe.minimize)

opt = pe.SolverFactory("ipopt").solve(model)
model.instances_map.pprint()

When running it I get the the following output for the last code line

WARNING: Loading a SolverResults object with a warning status into
    model.name="unknown";
      - termination condition: infeasible
      - message from solver: Ipopt 3.14.5\x3a Converged to a locally
        infeasible point. Problem may be infeasible.
instances_map : Size=10, Index=instances_map_index
    Key    : Lower : Value             : Upper : Fixed : Stale : Domain
    (1, 1) :     0 : 5.000000049983252 :     5 : False : False : Integers
    (1, 2) :     0 : 5.000000049983252 :     5 : False : False : Integers
    (1, 3) :     0 : 5.000000049983252 :     5 : False : False : Integers
    (1, 4) :     0 : 5.000000049983252 :     5 : False : False : Integers
    (1, 5) :     0 : 5.000000049983252 :     5 : False : False : Integers
    (2, 1) :     0 : 5.000000049983252 :     5 : False : False : Integers
    (2, 2) :     0 : 5.000000049983252 :     5 : False : False : Integers
    (2, 3) :     0 : 5.000000049983252 :     5 : False : False : Integers
    (2, 4) :     0 : 5.000000049983252 :     5 : False : False : Integers
    (2, 5) :     0 : 5.000000049983252 :     5 : False : False : Integers

I was expecting many 0 assignments but 1,2,3,4,5 only once.

I'm honestly not sure where to go from here


Solution

  • First, your problem is not converging to a feasible point, so there is no guarantee that the returned solution respects any constraints or bounds.

    More importantly, ipopt is a continuous interior point solver and ignores discrete domains. If you look at the solver output (by adding tee=True' to the solve call), you should see:

    ==> Warning: Treating __ binary and __ integer variables as continous.
    

    at the top of the solver output log.