Source code for ufl.corealg.traversal

"""Various expression traversal utilities.

The algorithms here are non-recursive, which is faster than recursion
by a factor of 10 or so because of the function call overhead.
"""

# Copyright (C) 2008-2016 Martin Sandve Alnæs
#
# This file is part of UFL (https://www.fenicsproject.org)
#
# SPDX-License-Identifier:    LGPL-3.0-or-later
#
# Modified by Massimiliano Leoni, 2016


[docs]def pre_traversal(expr): """Yield ``o`` for each tree node ``o`` in *expr*, parent before child.""" lifo = [expr] while lifo: expr = lifo.pop() yield expr for op in expr.ufl_operands: lifo.append(op)
[docs]def post_traversal(expr): """Yield ``o`` for each node ``o`` in *expr*, child before parent.""" lifo = [(expr, list(reversed(expr.ufl_operands)))] while lifo: expr, deps = lifo[-1] for i, dep in enumerate(deps): if dep is not None: lifo.append((dep, list(reversed(dep.ufl_operands)))) deps[i] = None break else: yield expr lifo.pop()
[docs]def cutoff_post_traversal(expr, cutofftypes): """Cut-off post-tranversal. Yield ``o`` for each node ``o`` in *expr*, child before parent, but skipping subtrees of the cutofftypes. """ lifo = [(expr, list(reversed(expr.ufl_operands)))] while lifo: expr, deps = lifo[-1] if cutofftypes[expr._ufl_typecode_]: yield expr lifo.pop() else: for i, dep in enumerate(deps): if dep is not None: lifo.append((dep, list(reversed(dep.ufl_operands)))) deps[i] = None break else: yield expr lifo.pop()
[docs]def unique_pre_traversal(expr, visited=None): """Yield ``o`` for each tree node ``o`` in *expr*, parent before child. This version only visits each node once. """ if visited is None: visited = set() lifo = [expr] visited.add(expr) while lifo: expr = lifo.pop() yield expr for op in expr.ufl_operands: if op not in visited: lifo.append(op) visited.add(op)
[docs]def unique_post_traversal(expr, visited=None): """Yield ``o`` for each node ``o`` in *expr*, child before parent. Never visit a node twice. """ lifo = [(expr, list(expr.ufl_operands))] if visited is None: visited = set() visited.add(expr) while lifo: expr, deps = lifo[-1] for i, dep in enumerate(deps): if dep is not None and dep not in visited: lifo.append((dep, list(dep.ufl_operands))) deps[i] = None break else: yield expr visited.add(expr) lifo.pop()
[docs]def cutoff_unique_post_traversal(expr, cutofftypes, visited=None): """Yield ``o`` for each node ``o`` in *expr*, child before parent. Never visit a node twice. """ lifo = [(expr, list(reversed(expr.ufl_operands)))] if visited is None: visited = set() while lifo: expr, deps = lifo[-1] if cutofftypes[expr._ufl_typecode_]: yield expr visited.add(expr) lifo.pop() else: for i, dep in enumerate(deps): if dep is not None and dep not in visited: lifo.append((dep, list(reversed(dep.ufl_operands)))) deps[i] = None break else: yield expr visited.add(expr) lifo.pop()
[docs]def traverse_terminals(expr): """Traverse terminals.""" for op in pre_traversal(expr): if op._ufl_is_terminal_: yield op
[docs]def traverse_unique_terminals(expr, visited=None): """Traverse unique terminals.""" for op in unique_pre_traversal(expr, visited=visited): if op._ufl_is_terminal_: yield op