Skip to content

Block.Skip doesn't behave like OtherThings.Skip #2957

Open
@emma58

Description

@emma58

Summary

As far as I can tell, if you return Block.Skip from a block rule, you just get an empty Block, but the key is still valid. This seems unexpected relative to the behavior of something like Constraint.Skip.

This is kind of sad from the perspective of maximizing laziness: Since Skipping is all about creating indexing Sets on the fly that you probably could have actually thought about somewhere else, this is unfortunate in that you can't rely on iterating through an IndexedBlock's keys to know what is actually real.

Steps to reproduce the issue

from pyomo.environ import *

m = ConcreteModel()
m.I = Set(initialize=range(6))
m.x = Var(m.I)

@m.Constraint(m.I)
def cons(m, i):
    if i % 2 == 0:
        return Constraint.Skip
    return m.x[i] - m.x[i - 1] >= i

@m.Block(m.I)
def blk(b, i):
    if i % 2 == 1:
        return Block.Skip
    b.y = Var()
    b.cons = Constraint(expr=b.y <= i)
    return b

m.pprint()
print(1 in m.cons) # expect and get True
print(2 in m.cons) # expect and get False
print(1 in m.blk) # expect False, but get True
print(2 in m.blk) # expect and get True

# (beating a dead horse...)
m.blk[1].pprint() # empty BlockData
m.cons[2] # KeyError

output:

1 Set Declarations
    I : Size=1, Index=None, Ordered=Insertion
        Key  : Dimen : Domain : Size : Members
        None :     1 :    Any :    6 : {0, 1, 2, 3, 4, 5}

1 Var Declarations
    x : Size=6, Index=I
        Key : Lower : Value : Upper : Fixed : Stale : Domain
          0 :  None :  None :  None : False :  True :  Reals
          1 :  None :  None :  None : False :  True :  Reals
          2 :  None :  None :  None : False :  True :  Reals
          3 :  None :  None :  None : False :  True :  Reals
          4 :  None :  None :  None : False :  True :  Reals
          5 :  None :  None :  None : False :  True :  Reals

1 Constraint Declarations
    cons : Size=3, Index=I, Active=True
        Key : Lower : Body        : Upper : Active
          1 :   1.0 : x[1] - x[0] :  +Inf :   True
          3 :   3.0 : x[3] - x[2] :  +Inf :   True
          5 :   5.0 : x[5] - x[4] :  +Inf :   True

1 Block Declarations
    blk : Size=6, Index=I, Active=True
        blk[0] : Active=True
            1 Var Declarations
                y : Size=1, Index=None
                    Key  : Lower : Value : Upper : Fixed : Stale : Domain
                    None :  None :  None :  None : False :  True :  Reals

            1 Constraint Declarations
                cons : Size=1, Index=None, Active=True
                    Key  : Lower : Body     : Upper : Active
                    None :  -Inf : blk[0].y :   0.0 :   True

            2 Declarations: y cons
        blk[1] : Active=True
            0 Declarations: 
        blk[2] : Active=True
            1 Var Declarations
                y : Size=1, Index=None
                    Key  : Lower : Value : Upper : Fixed : Stale : Domain
                    None :  None :  None :  None : False :  True :  Reals

            1 Constraint Declarations
                cons : Size=1, Index=None, Active=True
                    Key  : Lower : Body     : Upper : Active
                    None :  -Inf : blk[2].y :   2.0 :   True

            2 Declarations: y cons
        blk[3] : Active=True
            0 Declarations: 
        blk[4] : Active=True
            1 Var Declarations
                y : Size=1, Index=None
                    Key  : Lower : Value : Upper : Fixed : Stale : Domain
                    None :  None :  None :  None : False :  True :  Reals

            1 Constraint Declarations
                cons : Size=1, Index=None, Active=True
                    Key  : Lower : Body     : Upper : Active
                    None :  -Inf : blk[4].y :   4.0 :   True

            2 Declarations: y cons
        blk[5] : Active=True
            0 Declarations: 

4 Declarations: I x cons blk
True
False
True
True
{Member of blk} : Size=6, Index=I, Active=True
    blk[1] : Active=True
        0 Declarations: 
Traceback (most recent call last):
  File "/home/esjohn/src/distribution/distribution/models/cont_time_alt_paths_gdp/block_skip.py", line 28, in <module>
    m.cons[2] # KeyError
    ~~~~~~^^^
  File "/home/esjohn/src/pyomo/pyomo/core/base/indexed_component.py", line 660, in __getitem__
    return self._getitem_when_not_present(index)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/esjohn/src/pyomo/pyomo/core/base/constraint.py", line 830, in _getitem_when_not_present
    raise KeyError(idx)
KeyError: 2

Information on your system

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions