Skip to content

Commit

Permalink
Merge pull request #3436 from jsiirola/identify-vars
Browse files Browse the repository at this point in the history
Clean up `identify_variables` / `identify_mutable_parameters`; deprecate `SimpleExpressionVisitor`
  • Loading branch information
mrmundt authored Feb 5, 2025
2 parents cd778c5 + 8d1fff7 commit 95fa211
Show file tree
Hide file tree
Showing 7 changed files with 289 additions and 169 deletions.
37 changes: 12 additions & 25 deletions doc/OnlineDocs/explanation/philosophy/expressions/managing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,6 @@ tree:
seven event callbacks that users can hook into, providing very
fine-grained control over the expression walker.

:class:`SimpleExpressionVisitor <pyomo.core.expr.SimpleExpressionVisitor>`
A :func:`visitor` method is called for each node in the tree,
and the visitor class collects information about the tree.

:class:`ExpressionValueVisitor <pyomo.core.expr.ExpressionValueVisitor>`
When the :func:`visitor` method is called on each node in the
tree, the *values* of its children have been computed. The
Expand All @@ -166,25 +162,18 @@ These classes define a variety of suitable tree search methods:

* ``walk_expression``: depth-first traversal of the expression tree.

* :class:`SimpleExpressionVisitor <pyomo.core.expr.SimpleExpressionVisitor>`

* ``xbfs``: breadth-first search where leaf nodes are immediately visited
* ``xbfs_yield_leaves``: breadth-first search where leaf nodes are
immediately visited, and the visit method yields a value

* :class:`ExpressionValueVisitor <pyomo.core.expr.ExpressionValueVisitor>`

* ``dfs_postorder_stack``: postorder depth-first search using a
nonrecursive stack


To implement a visitor object, a user needs to provide specializations
for specific events. For legacy visitors based on the PyUtilib
visitor pattern (e.g., :class:`SimpleExpressionVisitor` and
:class:`ExpressionValueVisitor`), one must create a subclass of one of these
classes and override at least one of the following:
for specific events. For legacy visitors based on the PyUtilib visitor
pattern (e.g., :class:`ExpressionValueVisitor`), one must create a
subclass and override at least one of the following:

:func:`visitor`
:func:`visit`
Defines the operation that is performed when a node is visited. In
the :class:`ExpressionValueVisitor
<pyomo.core.expr.ExpressionValueVisitor>` and
Expand All @@ -196,10 +185,7 @@ classes and override at least one of the following:
Checks if the search should terminate with this node. If no,
then this method returns the tuple ``(False, None)``. If yes,
then this method returns ``(False, value)``, where *value* is
computed by this method. This method is not used in the
:class:`SimpleExpressionVisitor
<pyomo.core.expr.SimpleExpressionVisitor>` visitor
class.
computed by this method.

:func:`finalize`
This method defines the final value that is returned from the
Expand All @@ -216,19 +202,20 @@ callbacks, which are documented in the class documentation.
Detailed documentation of the APIs for these methods is provided
with the class documentation for these visitors.

SimpleExpressionVisitor Example
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
StreamBasedExpressionVisitor Example
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In this example, we describe an visitor class that counts the number
of nodes in an expression (including leaf nodes). Consider the following
class:

.. literalinclude:: /src/expr/managing_visitor1.spy

The class constructor creates a counter, and the :func:`visit` method
increments this counter for every node that is visited. The :func:`finalize`
method returns the value of this counter after the tree has been walked. The
following function illustrates this use of this visitor class:
The :func:`initializeWalker` method creates a counter, and the
:func:`exitNode` method increments this counter for every node that is
visited. The :func:`finalizeResult` method returns the value of this
counter after the tree has been walked. The following function
illustrates this use of this visitor class:

.. literalinclude:: /src/expr/managing_visitor2.spy

Expand Down
1 change: 0 additions & 1 deletion doc/OnlineDocs/reference/topical/expressions/visitors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ Visitor Classes
.. autosummary::

pyomo.core.expr.StreamBasedExpressionVisitor
pyomo.core.expr.SimpleExpressionVisitor
pyomo.core.expr.ExpressionValueVisitor
pyomo.core.expr.ExpressionReplacementVisitor
24 changes: 16 additions & 8 deletions doc/OnlineDocs/src/expr/managing.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,17 +101,17 @@
import pyomo.core.expr as EXPR


class SizeofVisitor(EXPR.SimpleExpressionVisitor):
def __init__(self):
class SizeofVisitor(EXPR.StreamBasedExpressionVisitor):
def initializeWalker(self, expr):
self.counter = 0
return True, expr

def visit(self, node):
def exitNode(self, node, data):
self.counter += 1

def finalize(self):
def finalizeResult(self, result):
return self.counter

# @visitor1
# @visitor1


# ---------------------------------------------
Expand All @@ -122,12 +122,20 @@ def sizeof_expression(expr):
#
visitor = SizeofVisitor()
#
# Compute the value using the :func:`xbfs` search method.
# Compute the value using the :func:`walk_expression` search method.
#
return visitor.xbfs(expr)
return visitor.walk_expression(expr)
# @visitor2


# Test:
m = ConcreteModel()
m.x = Var()
m.p = Param(mutable=True)
assert sizeof_expression(m.x) == 1
assert sizeof_expression(m.x + m.p) == 3
assert sizeof_expression(2 * m.x + m.p) == 5

# ---------------------------------------------
# @visitor3
import pyomo.core.expr as EXPR
Expand Down
6 changes: 6 additions & 0 deletions pyomo/core/expr/numvalue.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ def __repr__(self):
def __call__(self, exception=None):
return self.value

def is_constant(self):
return True

def is_fixed(self):
return True


nonpyomo_leaf_types.add(NonNumericValue)

Expand Down
Loading

0 comments on commit 95fa211

Please sign in to comment.