Skip to content

Supporting operations on indexed components #3611

Open
@bertkdowns

Description

@bertkdowns

Summary

If I have two indexed sets, and I want to write an expression on them, I have to create a new function:

m = ConcreteModel()
m.time = ContinuousSet(initialize=[1,2,3,4,5])
m.x = Var(m.time)
m.y = Var(m.time)

# Creating an expression to element-wise add m.x and m.y
def _add(m,t):
   return m.x[t] + m.y[t]

m.z = Expression(m.time,rule=_add)

It would be nice if there was some syntactic sugar to be able to simply go

m.z = m.x + m.y # Element-wise addition of m.x and m.y, as both are indexed by the same set

This could be combined with spread operators for adding items with different index sets

m.w = m.x + 5 # adds 5 to each element in m.x

Rationale

I'm trying to parse sympy expressions (entered by a user) and add them to a pyomo model.

If m.x and m.y were variables, I can use the sympy2pyomo_expression to convert the string "x + y" to the pyomo expression m.x + m.y (internally represented as a pyomo.core.expr.SumExpression(m.x,m.y) ). However, I want m.x and m.y to be indexed by time, and the SumExpression operation is not defined on indexed variables.

I could call sympy2pyomoExpression once for every timestep, where the sympy symbols x and y are mapped to the pyomo variables m.x[t] and m.y[t] . However, that doesn't work with more complex scenarios, e.g if I wanted to define a sympy function "sum(x)" which returns a scalar representing the sum of all elements of the indexed variable x.

Description

pyomo.core.expr.numeric_expr.py supports the types:

class ARG_TYPE(enum.IntEnum):
    MUTABLE = -2
    ASNUMERIC = -1
    INVALID = 0
    NATIVE = 1
    NPV = 2
    PARAM = 3
    VAR = 4
    MONOMIAL = 5
    LINEAR = 6
    SUM = 7
    OTHER = 8

Not sure what all of these mean, but I think we'd have to add an Indexed Arg type, and then all the functions /mappings to handle arguments in this file. We might have to add some data type to support indexed expressions at a more fundamental level.

Additional information

The "NumericExpressions" in this file seem different to the "Expressions" you add to a model. These "NumericExpressions" seem to be able to be created as a symbol tree internally in a Pyomo Expression. E.g I can do:

internal_expr_tree = SumExpression((1,SumExpression((2,3))))
value(internal_expr_tree) # returns 6

But I can't do

from pyomo.environ import Expression
expr = Expression(rule=1+ Expression(rule = 2 + 3)) 
value(expr) # Fails with: 
# Error:  Evaluating the expression of Expression 'ScalarExpression' before the Expression has been constructed (there is currently no value to return).

because those sub-expressions need to be attached to a model and "built" first, e.g

m = ConcreteModel()
m.sub_expr = Expression(rule = 2 + 3)
m.expr = Expression(rule= 1 + m.sub_expr)
value(m.expr)  # returns 6

Not sure if this is a feature that is wanted, or if I should implement it in a custom manner just for my use case. However, I am happy to help out if someone can give me some more direction on what to do.

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