Skip to content

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

Open
@emma58

Description

@emma58

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions