simplify_branches
Stable function · Differentiate a model
Tier: stable · Kind: function · Topic: Differentiate a model
| Julia | Python | Rust |
|---|---|---|
simplify_branches | simplify_branches | simplify_branches |
Julia
simplify_branches(e::EarthSciAST.ASTExpr)
simplify_branches(e::ASTExpr) -> ASTExpr
Conditional-specific simplification, complementing EarthSciAST.simplify:
ifelse(lit, a, b)→a(lit ≠ 0) orb(lit == 0);ifelse(c, a, a)→awhen the branches are structurally equal;- same-condition pruning along a path: inside the true branch of
ifelse(c, …)any nestedifelse(c, a₂, b₂)collapses toa₂, inside the false branch tob₂(conditions compared structurally).
Bottom-up; nodes are rebuilt only where something changed.
STRUCTURAL EQUALITY, AND ITS COST. Conditions and branches are compared by
structure, and the pass asks for that comparison at every ifelse node it
meets. Doing it with skey — a full re-serialization of the subtree
— makes the pass Θ(n·depth): each of the k levels of an index(makearray…)
region chain re-serializes the whole chain below it, and the product rule
replicates such chains along a path. The
comparisons therefore go through hashcons.jl: a shash mismatch —
O(1) per node — settles the common case where the two differ, and only a
match pays for the exact answer from StructIndex, whose bottom-up
interning keys a node from its own shell plus its children’s ids (Θ(n) for
the tree, O(1) per compare) and memoizes on node identity, so the
identity-preserving rewrites below re-key nothing they did not change. Same
equality relation as skey, so the pass is unchanged.
The second Θ(n·depth) term is _assume, which re-descends a branch looking
for a condition that is usually not there at all. A running count of the
conditions the bottom-up pass has already built decides that in O(1) at the
branch, so a k-level chain costs Θ(n) instead of Θ(n·k); see _sbr.
Python
simplify_branches(e: Expr) -> Expr
Literal-condition fold, equal-branch collapse, same-condition pruning.