Recursive utility functions

SymbolicUtils.jl provides several utility functions to perform common operations that require recursing over the expression tree.

Missing docstring.

Missing docstring for SymbolicUtils.substitute. Check Documenter's build log for details.

SymbolicUtils.SubstituterType
Substituter{Fold, #= ... =# }

A functor which acts as the workhorse for substitute. Passing fold = Val(true) corresponds to Substituter{true, #= ... =# } (and similarly for Val(false)). To define substitution rules for custom types that wrap/contain BasicSymbolic, define methods for this functor. For example,

struct Equation
    lhs::BasicSymbolic{SymReal}
    rhs::BasicSymbolic{SymReal}
end

function (subst::Substituter)(eq::Equation)
    return Equation(subst(eq.lhs), subst(eq.rhs))
end

Instead of repeatedly calling substitute with the same rules, it is usually more efficient to build a Substituter and reuse it.

Substituter is also allowed to cache intermediate results as necessary. When constructing Substituter with an AbstractDict, it will alias the provided mapping. Mutating the map such that the identity of the substitution rules changes invalidates the substituter. It can be reused by clearing the cache using SymbolicUtils.clear_cache!.

The caching is only available when the SymbolicUtils.vartype of the expressions is inferrable from the substitution rules, or explicitly specified. As long as either the keys or values of the substitution rules are all BasicSymbolic{T} (for some T) the automatic inference will work. To allow the inference to work for your custom wrapper type, implement SymbolicUtils.infer_vartype. For example:

struct Num <: Real
  inner::BasicSymbolic{SymReal}
end

SymbolicUtils.infer_vartype(::Type{Num}) = SymReal

Alternatively, the vartype can be provided as the third positional argument to the Substituter constructor.

Extended help

The following is internal details of Substituter and should not be relied on as public API.

Fields

  • dict::AbstractDict: The AbstractDict of substitution rules.
  • filter::Any: The filter function to eliminate trees that do not need substitution.
  • cache::Any: Cache of intermediate results.
source
SymbolicUtils.default_substitute_filterFunction
default_substitute_filter(
    ex::SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{T}
) -> Bool

The default filter function used by substitute to determine whether to substitute within an expression. Returns false for expressions that are Terms with an Operator as the operation (preventing substitution within operator calls), and true otherwise.

Arguments

  • ex::BasicSymbolic{T}: The expression to check.

Returns

  • Bool: false if the expression should not be substituted into, true otherwise.
source
Missing docstring.

Missing docstring for SymbolicUtils.evaluate. Check Documenter's build log for details.

SymbolicUtils.queryFunction
query(
    predicate,
    expr::SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{T} where T;
    recurse,
    default
) -> Any

Recursively search an expression tree to determine if any subexpression satisfies a given predicate. This function traverses the expression tree and returns true if the predicate returns true for any node in the tree.

Arguments

  • predicate::F: A function that takes an expression and returns a Bool.
  • expr::BasicSymbolic: The expression to search.

Keyword Arguments

  • recurse::G=iscall: A function determining whether to recurse into a subexpression.
  • default::Bool=false: The default value to return if the expression is not a call or recursion is prevented.

Returns

  • Bool: true if any subexpression satisfies the predicate, false otherwise.
source
Missing docstring.

Missing docstring for SymbolicUtils.search_variables. Check Documenter's build log for details.

SymbolicUtils.search_variables!Function
search_variables!(
    buffer,
    expr::SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{T} where T;
    is_atomic,
    recurse
)

Find all variables used in expr and add them to buffer. A variable is identified by the predicate is_atomic. The predicate recurse determines whether to search further inside expr if it is not a variable. Note that recurse must at least return false if iscall returns false.

Wrappers for BasicSymbolic should implement this function by unwrapping.

See also: default_is_atomic.

source
SymbolicUtils.default_is_atomicFunction
default_is_atomic(
    ex::SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{T}
) -> Bool

The default is_atomic predicate for search_variables!. ex is considered atomic if one of the following conditions is true:

  • It is a Sym and not an internal index variable for an arrayop
  • It is a Term, the operation is a BasicSymbolic and the operation represents a dependent variable according to is_function_symbolic.
  • It is a Term, the operation is getindex and the variable being indexed is atomic.
source
SymbolicUtils.scalarizeFunction
scalarize(
    x::SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{T}
) -> Any
scalarize(
    x::SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{T},
    ::Val{toplevel}
) -> Any

Convert a symbolic expression with array operations into a fully scalarized form. This function expands array operations into element-wise operations, converting symbolic array expressions into arrays of scalar symbolic expressions.

For ArrayOp expressions, this function reduces eliminated indices and substitutes concrete values for output indices to generate scalar expressions for each array element.

Arguments

  • x::BasicSymbolic{T}: The symbolic expression to scalarize.
  • ::Val{toplevel}=Val{false}(): Whether to evaluate constant expressions at the top level. When true, constant subexpressions are evaluated; when false, they are recursively scalarized.

Returns

  • The scalarized expression. For array-shaped expressions, returns an array of scalar expressions. For scalar expressions, returns the expression unchanged or with recursively scalarized subexpressions.
source
SymbolicUtils.scalarization_functionFunction
scalarization_function(
    _
) -> typeof(SymbolicUtils._scalarize_add)

Given a function f, return a function that will scalarize an expression with f as the head. The returned function is passed f, the expression with f as the head, and Val(true) or Val(false) indicating whether to recursively scalarize or not.

This function provides a dispatch mechanism for customizing scalarization behavior based on the operation type. Different operations may require different scalarization strategies (e.g., array operations, determinants, indexing operations).

Arguments

  • f: The function/operation to get a scalarization function for.

Returns

  • A function that takes (f, x::BasicSymbolic{T}, ::Val{toplevel}) and returns the scalarized form of x.
source