Pyomo / pyomo

An object-oriented algebraic modeling language in Python for structured optimization problems.
https://www.pyomo.org
Other
1.9k stars 490 forks source link

Negative number of continuous variables in the results #3301

Open parkyr opened 1 week ago

parkyr commented 1 week ago

Summary

Ran pyomo solve to optimize a model with one set of binary variables, using gurobi. The optimization was fine, but print(results) showed negative 'number of continuous variables'

Steps to reproduce the issue

$ command1 [options]
$ command2 [options]
...
# example.py
import pyomo.environ as pyo
import numpy as np

# Problem data
flow_network = {
    "f1": ("s1", "s2"),
    "f2": ("s2", "s3"),
    "f3": ("s2", "s3"),
    "f4": ("s3", "s4"),
}

flow_cost = {"f1": 2, "f2": 7, "f3": 17, "f4": 1}

total_flow = 2

# penalty weights for binary constraints
K2 = 10
K3 = 4

# Model
model = pyo.ConcreteModel(doc="Flow Optimization Problem")

# Sets
model.nodes = pyo.Set(initialize=["s1", "s2", "s3", "s4"], doc="nodes")
model.edges = pyo.Set(initialize=flow_network.keys(), doc="edges")

# Decision Variables
model.f = pyo.Var(
    model.edges, domain=pyo.Binary, doc="flow binary decision on each edge"
)

# Parameters
model.fcost = pyo.Param(
    model.edges, initialize=flow_cost, doc="cost of flow on each edge", mutable=True
)

# Objective Function (minimize cost)
model.totalcost = pyo.Objective(
    expr=sum(model.f[e] * model.fcost[e] for e in model.edges) * total_flow
    + K2 * model.f["f2"]
    + K3 * model.f["f3"],
    sense=pyo.minimize,
)

# Constraints
# Disjunction Constraint
def disjunction_rule(model):
    return model.f["f2"] + model.f["f3"] == 1

model.disjunction = pyo.Constraint(rule=disjunction_rule, doc="disjunction constraint")

# Flow Conservation Constraints
def flow_conservation_rule(model, node):
    inflow = sum(model.f[edge] for edge in model.edges if flow_network[edge][1] == node)
    outflow = sum(
        model.f[edge] for edge in model.edges if flow_network[edge][0] == node
    )
    if node == "s1":
        return outflow * total_flow == total_flow  # source node
    elif node == "s4":
        return inflow * total_flow == total_flow  # sink node
    else:
        return inflow == outflow  # intermediate nodes

model.flow_conservation = pyo.Constraint(
    model.nodes, rule=flow_conservation_rule, doc="flow conservation constraints"
)

model.xrd0 = pyo.Constraint(
    expr=model.f["f2"] + model.f["f3"] == 1, doc="f2 or f3 constraint"
)

# Solve the model using a solver
solver = pyo.SolverFactory("gurobi", solver_io="python")
results = solver.solve(model, tee=True)

model.pprint()
print(results)

Error Message

$ # Gurobi Optimizer version 11.0.0 build v11.0.0rc2 (linux64 - "Ubuntu 22.04.3 LTS")

CPU model: 13th Gen Intel(R) Core(TM) i7-1365U, instruction set [SSE2|AVX|AVX2]
Thread count: 6 physical cores, 12 logical processors, using up to 12 threads

Optimize a model with 6 rows, 4 columns and 12 nonzeros
Model fingerprint: 0x504aa310
Variable types: 0 continuous, 4 integer (4 binary)
Coefficient statistics:
  Matrix range     [1e+00, 2e+00]
  Objective range  [2e+00, 4e+01]
  Bounds range     [1e+00, 1e+00]
  RHS range        [1e+00, 2e+00]
Presolve removed 6 rows and 4 columns
Presolve time: 0.00s
Presolve: All rows and columns removed

Explored 0 nodes (0 simplex iterations) in 0.01 seconds (0.00 work units)
Thread count was 1 (of 12 available processors)

Solution count 1: 30 

Optimal solution found (tolerance 1.00e-04)
Best objective 3.000000000000e+01, best bound 3.000000000000e+01, gap 0.0000%
Flow Optimization Problem

    2 Set Declarations
        edges : edges
            Size=1, Index=None, Ordered=Insertion
            Key  : Dimen : Domain : Size : Members
            None :     1 :    Any :    4 : {'f1', 'f2', 'f3', 'f4'}
        nodes : nodes
            Size=1, Index=None, Ordered=Insertion
            Key  : Dimen : Domain : Size : Members
            None :     1 :    Any :    4 : {'s1', 's2', 's3', 's4'}

    1 Param Declarations
        fcost : cost of flow on each edge
            Size=4, Index=edges, Domain=Any, Default=None, Mutable=True
            Key : Value
             f1 :     2
             f2 :     7
             f3 :    17
             f4 :     1

    1 Var Declarations
        f : flow binary decision on each edge
            Size=4, Index=edges
            Key : Lower : Value : Upper : Fixed : Stale : Domain
             f1 :     0 :   1.0 :     1 : False : False : Binary
             f2 :     0 :   1.0 :     1 : False : False : Binary
             f3 :     0 :   0.0 :     1 : False : False : Binary
             f4 :     0 :   1.0 :     1 : False : False : Binary

    1 Objective Declarations
        totalcost : Size=1, Index=None, Active=True
            Key  : Active : Sense    : Expression
            None :   True : minimize : (fcost[f1]*f[f1] + fcost[f2]*f[f2] + fcost[f3]*f[f3] + fcost[f4]*f[f4])*2 + 10*f[f2] + 4*f[f3]

    3 Constraint Declarations
        disjunction : disjunction constraint
            Size=1, Index=None, Active=True
            Key  : Lower : Body          : Upper : Active
            None :   1.0 : f[f2] + f[f3] :   1.0 :   True
        flow_conservation : flow conservation constraints
            Size=4, Index=nodes, Active=True
            Key : Lower : Body                    : Upper : Active
             s1 :   2.0 :                 2*f[f1] :   2.0 :   True
             s2 :   0.0 : f[f1] - (f[f2] + f[f3]) :   0.0 :   True
             s3 :   0.0 :   f[f2] + f[f3] - f[f4] :   0.0 :   True
             s4 :   2.0 :                 2*f[f4] :   2.0 :   True
        xrd0 : f2 or f3 constraint
            Size=1, Index=None, Active=True
            Key  : Lower : Body          : Upper : Active
            None :   1.0 : f[f2] + f[f3] :   1.0 :   True

    8 Declarations: nodes edges f fcost totalcost disjunction flow_conservation xrd0

Problem: 
- Name: unknown
  Lower bound: 30.0
  Upper bound: 30.0
  Number of objectives: 1
  Number of constraints: 6
  Number of variables: 4
  Number of binary variables: 4
  Number of integer variables: 4
  Number of continuous variables: -4
  Number of nonzeros: 12
  Sense: 1
  Number of solutions: 1
Solver: 
- Name: Gurobi 11.00
  Status: ok
  Wallclock time: 0.015126943588256836
  Termination condition: optimal
  Termination message: Model was solved to optimality (subject to tolerances), and an optimal solution is available.
Solution: 
- number of solutions: 0
  number of solutions displayed: 0

Information on your system

Pyomo version: 6.7.1 Python version: 3.9.18 Operating system: Linux How Pyomo was installed (PyPI, conda, source): conda Solver (if applicable): gurobi

Additional information