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

IndexedSet objects can no longer be used with the within argument in pyomo 6.7.3 #3284

Open thisandthatuser opened 3 weeks ago

thisandthatuser commented 3 weeks ago

Summary

Pyomo Set objects allow users to define their supersets for validation via the within argument. This used to be possible with indexed set too (objects (e.g., pyomo 6.6) but is no longer possible.

Steps to reproduce the issue

The following script can be used to reproduce the issue. I adapted the example from the website (https://pyomo.readthedocs.io/en/stable/pyomo_modeling_components/Sets.html).

import pyomo.environ as pyo
from pyomo.opt import check_available_solvers

use_within_argument = False # change to True to trigger the error

model = pyo.AbstractModel()
# non-indexed sets not using the within argument
model.Nodes = pyo.Set()
model.Arcs = pyo.Set(dimen=2)
# non-indexed sets using within argument
model.SubsetNodes = pyo.Set(within=model.Nodes)
model.SubsetArcs = pyo.Set(within=model.Arcs, dimen=2)
# indexed sets not using the within argument
model.ThingsOfArcs = pyo.Set(model.Arcs)
model.ThingsOfNodes = pyo.Set(model.Nodes)
# indexed sets using the within/not using the argument
if not use_within_argument:
    # okay
    model.SubsetThingsOfNodes = pyo.Set(model.Nodes)
    model.SubsetThingsOfArcs = pyo.Set(model.Arcs)
else:
    # fail
    model.SubsetThingsOfNodes = pyo.Set(model.Nodes, within=model.ThingsOfNodes)
    model.SubsetThingsOfArcs = pyo.Set(model.Arcs, within=model.ThingsOfArcs)

def NodesOut_init(m, node):
    for i, j in m.Arcs:
        if i == node:
            yield j
model.NodesOut = pyo.Set(model.Nodes, initialize=NodesOut_init)

def NodesIn_init(m, node):
    for i, j in m.Arcs:
        if j == node:
            yield i
model.NodesIn = pyo.Set(model.Nodes, initialize=NodesIn_init)

model.Flow = pyo.Var(model.Arcs, domain=pyo.NonNegativeReals)
model.FlowCost = pyo.Param(model.Arcs)

model.Demand = pyo.Param(model.Nodes)
model.Supply = pyo.Param(model.Nodes)

def Obj_rule(m):
    return pyo.summation(m.FlowCost, m.Flow)
model.Obj = pyo.Objective(rule=Obj_rule, sense=pyo.minimize)

def FlowBalance_rule(m, node):
    return m.Supply[node] \
        + sum(m.Flow[i, node] for i in m.NodesIn[node]) \
        - m.Demand[node] \
        - sum(m.Flow[node, j] for j in m.NodesOut[node]) \
        == 0
model.FlowBalance = pyo.Constraint(model.Nodes, rule=FlowBalance_rule)

data_dict = {
    None: {
        'Arcs': {None: [("CityA","CityB"), ("CityA", "CityC"), ("CityC", "CityB")]},
        'Nodes': {None: ["CityA", "CityB", "CityC"]},
        'FlowCost': {("CityA","CityB"): 1.4, ("CityA", "CityC"): 2.7, ("CityC", "CityB"): 1.6},
        'Demand': {"CityA":0, "CityB": 1, "CityC": 1},
        'Supply': {"CityA": 2, "CityB": 0, "CityC": 0},
        # new data
        'SubsetNodes': {None: ["CityC"]},
        'SubsetArcs': {None: [("CityA","CityB"),("CityC", "CityB")]},
        'ThingsOfNodes': {"CityA": ['a','b','c'], "CityB": ['d', 'e', 'f'], "CityC": ['a','d']},
        'ThingsOfArcs': {("CityA","CityB"): ['m','h'], ("CityA", "CityC"): ['t','g'], ("CityC", "CityB"): ['r']},
        'SubsetThingsOfNodes': {"CityA": ['a','c'], "CityB": ['f'], "CityC": ['d']},
        'SubsetThingsOfArcs': {("CityA","CityB"): ['h'], ("CityA", "CityC"): ['t'], ("CityC", "CityB"): ['r']},
        }
    }

solver_name = 'cbc'
solver_available = bool(check_available_solvers(solver_name))
if solver_available:
     opt = pyo.SolverFactory(solver_name)
     problem = model.create_instance(data=data_dict)
     opt.solve(problem, tee=True)

Error Message

$ ERROR: Constructing component 'SubsetThingsOfNodes' from data={'CityA': ['a',
'c'], 'CityB': ['f'], 'CityC': ['d']} failed:
        AttributeError: 'InsertionOrderSetData' object has no attribute
        'construct'
Traceback (most recent call last):

  File ~\Documents\Trabalho\Python\pyvenv\lib\site-packages\spyder_kernels\py3compat.py:356 in compat_exec
    exec(code, globals, locals)

  File c:\users\mend_pd\documents\trabalho\example\ptomo_sparse_set.py:112
    problem = model.create_instance(data=data_dict)

  File ~\Documents\Trabalho\Python\pyvenv\lib\site-packages\pyomo\core\base\PyomoModel.py:731 in create_instance
    instance.load(data, namespaces=_namespaces, profile_memory=profile_memory)

  File ~\Documents\Trabalho\Python\pyvenv\lib\site-packages\pyomo\core\base\PyomoModel.py:768 in load
    self._load_model_data(dp, namespaces, profile_memory=profile_memory)

  File ~\Documents\Trabalho\Python\pyvenv\lib\site-packages\pyomo\core\base\PyomoModel.py:820 in _load_model_data
    self._initialize_component(

  File ~\Documents\Trabalho\Python\pyvenv\lib\site-packages\pyomo\core\base\PyomoModel.py:868 in _initialize_component
    declaration.construct(data)

  File ~\Documents\Trabalho\Python\pyvenv\lib\site-packages\pyomo\core\base\set.py:2181 in construct
    IndexedComponent.__getitem__(self, index)

  File ~\Documents\Trabalho\Python\pyvenv\lib\site-packages\pyomo\core\base\indexed_component.py:658 in __getitem__
    return self._getitem_when_not_present(index)

  File ~\Documents\Trabalho\Python\pyvenv\lib\site-packages\pyomo\core\base\set.py:2221 in _getitem_when_not_present
    domain.construct()

AttributeError: 'InsertionOrderSetData' object has no attribute 'construct'

Information on your system

Pyomo version: 6.7.3 Python version: 3.10.6 Operating system: Windows 10 How Pyomo was installed (PyPI, conda, source): pip Solver (if applicable): cbc, scip, etc

Additional information

I ran into this error when I upgraded to pyomo 6.7.3. The error should not be obtained with pyomo 6.6.x and earlier versions.