pyomo icon indicating copy to clipboard operation
pyomo copied to clipboard

LP dual transformation loses mappings when you make a Block from dual

Open emma58 opened this issue 1 year ago • 1 comments

Summary

I can use the return from create_using to create a Block on a model, but I lose the mappings between primal and dual components when I do so. I'm not sure why, but it seems that somehow the private_data data structure is empty in this case?

Steps to reproduce the issue

This script looks like it should work:

from pyomo.environ import *

m = ConcreteModel()

m.outer1 = Var(domain=Binary)
m.outer = Var([2, 3], domain=Binary)

m.x = Var(domain=NonNegativeReals)
m.y = Var(domain=NonPositiveReals)
m.z = Var(domain=Reals)

m.obj = Objective(expr=m.outer1 + m.outer[2] + m.outer[3])

m.inner = Block()
m.inner.obj = Objective(expr=m.x + 2 * m.y - 3 * m.outer[3] * m.z)
m.inner.c1 = Constraint(expr=-4 * m.x - 2 * m.y - m.z <= -5 * m.outer1)
m.inner.c2 = Constraint(expr=m.x + m.outer[2] * m.y >= 3)
m.inner.c3 = Constraint(expr=-m.y - m.z == -4.2)
m.inner.c4 = Constraint(expr=m.z <= 42)

lp_dual = TransformationFactory('core.lp_dual')

m.dualblk = Block(
    rule=lambda blk: lp_dual.create_using(
        m.inner, parameterize_wrt=[m.outer1, m.outer])
)

dualvar = lp_dual.get_dual_var(m.dualblk, m.inner.c1)
dualvar.pprint()

Error Message

But the transformation can't find the mapping:

Traceback (most recent call last):
  File "/home/esjohn/src/pyomo/pyomo/core/tests/im_confused.py", line 31, in <module>
    dualvar = lp_dual.get_dual_var(m.dualblk, m.inner.c1)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/esjohn/src/pyomo/pyomo/core/plugins/transform/lp_dual.py", line 259, in get_dual_var
    raise ValueError(
ValueError: It does not appear that Constraint 'inner.c1' is a primal constraint on model 'dualblk'

Information on your system

Pyomo version: main branch Python version: 3.11 Operating system: linux How Pyomo was installed (PyPI, conda, source): source Solver (if applicable):

Additional information

Replacing the m.dualblk = Block(...) line with

thing = lp_dual.create_using(m.inner, parameterize_wrt=[m.outer1, m.outer])
m.add_component('dualblk', thing)

works as expected. So the rule construction is at fault.

emma58 avatar Dec 16 '24 23:12 emma58

@jsiirola this is probably my fault, but I can't figure out how at the moment. :P

emma58 avatar Dec 16 '24 23:12 emma58