Core Types & Trees

Expression Nodes

All expression trees are composed of AbstractNode subtypes:

  • Constant(value::Float64) — literal numeric values
  • Variable(name::Symbol) — variable references (untyped)
  • Variable(name::Symbol, type) — variable references (typed)
  • FunctionNode(func::Symbol, children...) — function applications

Building Trees Manually

x = Variable(:x)
tree = FunctionNode(:+,
    FunctionNode(:sin, x),
    Constant(1.0)
)

Type Queries

isconstant(node)    # true for Constant
isvariable(node)    # true for Variable
isfunction(node)    # true for FunctionNode
isterminal(node)    # true for Constant or Variable
vartype(node)       # type of a Variable
istyped(node)       # true if Variable has a type
children(node)      # child nodes of a FunctionNode
arity(node)         # number of children

Tree Utilities

Size and Structure

count_nodes(node)        # Total node count
tree_depth(node)         # Maximum depth
tree_size_stats(node)    # Comprehensive statistics

Traversal

flatten_tree(node)       # All nodes in pre-order
indexed_nodes(node)      # (index, node) pairs
terminals(node)          # Leaf nodes only
nonterminals(node)       # Internal nodes only

Collection

collect_variables(node)  # Set of variable names
collect_constants(node)  # Vector of constant values
collect_functions(node)  # Vector of function symbols

Manipulation

copy_tree(node)                      # Deep copy
replace_subtree(tree, old, new)      # Substitute subtrees
map_tree(f, node)                    # Transform all nodes
get_subtree_at_index(node, i)        # Access by index
random_subtree(node)                 # Random selection
random_subtree_index(node)           # Random index

Printing

node_to_string(node)    # Human-readable: "(sin(x) + 1)"
node_to_latex(node)     # LaTeX: "\sin(x) + 1"
print_tree(node)        # Hierarchical ASCII view
tree_to_string_block(node)  # Block format

Types Reference

SymbolicOptimization.ConstantType
Constant <: AbstractNode
Constant(value::Float64)

A constant (literal) numeric value in the expression tree.

Examples

c = Constant(3.14)
c.value  # 3.14
source
SymbolicOptimization.VariableType
Variable{T} <: AbstractNode
Variable(name::Symbol, type::T)
Variable(name::Symbol)  # untyped

A variable reference in the expression tree.

The type parameter T encodes the variable's type in typed grammars (e.g., Symbol for :Scalar, :Vector), or is Nothing for untyped grammars.

Examples

# Untyped variable
x = Variable(:x)

# Typed variable
ps = Variable(:ps, :Vector)
vartype(ps)  # :Vector
source
SymbolicOptimization.FunctionNodeType
FunctionNode <: AbstractNode
FunctionNode(func::Symbol, children::Vector{AbstractNode})
FunctionNode(func::Symbol, children::AbstractNode...)

A function application node with child nodes as arguments.

Examples

# Addition: x + y
add_node = FunctionNode(:+, Variable(:x), Variable(:y))

# Nested: sin(x + 1)
nested = FunctionNode(:sin, FunctionNode(:+, Variable(:x), Constant(1.0)))
source
SymbolicOptimization.copy_treeFunction
copy_tree(node::AbstractNode) -> AbstractNode

Create a deep copy of the expression tree.

Examples

original = FunctionNode(:+, Variable(:x), Constant(1.0))
copied = copy_tree(original)
original == copied  # true
original === copied # false (different objects)
source
SymbolicOptimization.count_nodesFunction
count_nodes(node::AbstractNode) -> Int

Count the total number of nodes in the tree.

Examples

tree = FunctionNode(:+, Variable(:x), Constant(1.0))
count_nodes(tree)  # 3
source
SymbolicOptimization.tree_depthFunction
tree_depth(node::AbstractNode) -> Int

Compute the maximum depth of the tree. Terminals have depth 1.

Examples

tree = FunctionNode(:sin, FunctionNode(:+, Variable(:x), Constant(1.0)))
tree_depth(tree)  # 3
source
SymbolicOptimization.tree_size_statsFunction
tree_size_stats(node::AbstractNode) -> NamedTuple

Return various size statistics about the tree.

Returns

  • nodes: Total node count
  • depth: Maximum depth
  • terminals: Number of terminal nodes
  • functions: Number of function nodes
  • constants: Number of constant nodes
  • variables: Number of variable nodes
  • unique_vars: Number of unique variable names
  • unique_funcs: Number of unique function symbols
source
SymbolicOptimization.flatten_treeFunction
flatten_tree(node::AbstractNode) -> Vector{AbstractNode}

Return all nodes in the tree in pre-order traversal (root first, then children recursively).

Examples

tree = FunctionNode(:+, Variable(:x), Constant(1.0))
nodes = flatten_tree(tree)  # [FunctionNode(:+, ...), Variable(:x), Constant(1.0)]
length(nodes)  # 3
source
SymbolicOptimization.indexed_nodesFunction
indexed_nodes(node::AbstractNode) -> Vector{Tuple{Int, AbstractNode}}

Return (index, node) pairs for all nodes in pre-order traversal.

Examples

tree = FunctionNode(:+, Variable(:x), Constant(1.0))
for (i, n) in indexed_nodes(tree)
    println("$i: $n")
end
source
SymbolicOptimization.collect_variablesFunction
collect_variables(node::AbstractNode) -> Set{Symbol}

Return the set of all variable names used in the tree.

Examples

tree = FunctionNode(:+, Variable(:x), FunctionNode(:*, Variable(:x), Variable(:y)))
collect_variables(tree)  # Set([:x, :y])
source
SymbolicOptimization.collect_constantsFunction
collect_constants(node::AbstractNode) -> Vector{Float64}

Return all constant values in the tree (with duplicates, in pre-order).

Examples

tree = FunctionNode(:+, Constant(1.0), FunctionNode(:*, Constant(2.0), Constant(1.0)))
collect_constants(tree)  # [1.0, 2.0, 1.0]
source
SymbolicOptimization.collect_functionsFunction
collect_functions(node::AbstractNode) -> Vector{Symbol}

Return all function symbols used in the tree (with duplicates, in pre-order).

Examples

tree = FunctionNode(:+, Variable(:x), FunctionNode(:+, Constant(1.0), Constant(2.0)))
collect_functions(tree)  # [:+, :+]
source
SymbolicOptimization.replace_subtreeFunction
replace_subtree(tree, old_node, new_node) -> AbstractNode

Replace old_node (by identity, i.e., ===) with new_node in the tree. Returns a new tree; the original is not modified.

Examples

x = Variable(:x)
tree = FunctionNode(:+, x, Constant(1.0))
new_tree = replace_subtree(tree, x, Constant(2.0))
# new_tree is now: (+ 2.0 1.0)
source
SymbolicOptimization.map_treeFunction
map_tree(f, node::AbstractNode) -> AbstractNode

Apply function f to each node in the tree, building a new tree from the results. The function f receives each node and should return an AbstractNode.

The mapping is applied bottom-up: children are mapped first, then the parent.

Examples

# Double all constants
tree = FunctionNode(:+, Constant(1.0), Constant(2.0))
doubled = map_tree(tree) do node
    node isa Constant ? Constant(node.value * 2) : node
end
# doubled is now: (+ 2.0 4.0)
source
SymbolicOptimization.get_subtree_at_indexFunction
get_subtree_at_index(node::AbstractNode, idx::Int) -> AbstractNode

Get the subtree at the given index (1-based, pre-order traversal).

Examples

tree = FunctionNode(:+, Variable(:x), Constant(1.0))
get_subtree_at_index(tree, 1)  # The FunctionNode itself
get_subtree_at_index(tree, 2)  # Variable(:x)
get_subtree_at_index(tree, 3)  # Constant(1.0)
source
SymbolicOptimization.random_subtreeFunction
random_subtree(node::AbstractNode; rng=Random.GLOBAL_RNG) -> AbstractNode

Select a random subtree from the tree.

Examples

tree = FunctionNode(:+, Variable(:x), Constant(1.0))
subtree = random_subtree(tree)  # Could be any of the 3 nodes
source
SymbolicOptimization.node_to_stringFunction
node_to_string(node::AbstractNode; digits::Int=3) -> String

Convert an expression tree to a human-readable string representation.

Infix operators (+, -, *, /, ^) are printed in infix notation. Other functions use prefix notation: f(arg1, arg2, ...).

Examples

tree = FunctionNode(:+, Variable(:x), FunctionNode(:*, Constant(2.0), Variable(:y)))
node_to_string(tree)  # "(x + (2.0 * y))"

tree2 = FunctionNode(:sin, Variable(:x))
node_to_string(tree2)  # "sin(x)"
source
SymbolicOptimization.node_to_latexFunction
node_to_latex(node::AbstractNode; digits::Int=3) -> String

Convert an expression tree to LaTeX math notation.

Examples

tree = FunctionNode(:/, 
    FunctionNode(:+, Variable(:x), Constant(1.0)),
    FunctionNode(:sqrt, Variable(:y))
)
node_to_latex(tree)  # "\frac{x + 1}{\sqrt{y}}"
source
SymbolicOptimization.print_treeFunction
print_tree(node::AbstractNode; io::IO=stdout, indent::Int=0)

Print a tree in a hierarchical format showing the structure.

Examples

tree = FunctionNode(:+, Variable(:x), FunctionNode(:*, Constant(2.0), Variable(:y)))
print_tree(tree)
# Output:
# +
#   x
#   *
#     2.0
#     y
source