Branching: the rose-tree interface #
A carrier T is Branching when each value exposes an ordered list
of children. One field derives, for every instance:
- Gorn-address machinery:
subtreeAt,validPaths,daughters - the dominance order on positions (
toTreeOrder), unlocking the [BP90] command-relation library (Core/Order/Command.lean) - via
Core/Order/TreePath.lean, mathlib's rooted-tree order stack on positions: root (⊥), parent (Order.pred), least common ancestor (⊓), finite ancestor chains.
Sibling order (the List) is the load-bearing choice: linear
precedence and planarity are real structure that mathlib's
Quiver/Digraph/SimpleGraph forget, so those are forgetful shadows
of this class, not its basis.
No well-foundedness is required for the base class. The path
machinery recurses on the path (structurally decreasing List Nat),
not on T, so Branching is law-free on the carrier and still
theorem-rich; carriers with infinite depth are admissible. Recursion
on the carrier (size, subtrees, yield, inductionOn) needs
the IsFiniteBranching mixin below, a Prop-valued well-foundedness
assertion on the child relation (mathlib idiom: structure-bearing
class + Is… Prop mixin, like RootedTree + IsPredArchimedean).
Known instance candidates across the library (2026-06-06 audit):
Syntax.Tree (constituency), NanoTree (Nanosyntax features),
CFGTree (CFG derivations — subtreeAt is classical Gorn
addressing), RoseTree (Hopf-algebra
trees), FreeMagma (bare phrase structure), Dependency-Grammar
positions.
Rose-tree interface: a carrier with an ordered list of children.
[] for leaves. See the module docstring for what one field buys.
- children : T → List T
Ordered children.
Instances
The "is a child of" relation on a Branching carrier.
Equations
- Core.Order.Branching.IsChild c t = (c ∈ Core.Order.Branching.children t)
Instances For
Subtree at a Gorn address; none if the path leaves the tree.
Recursion is on the path, so no well-foundedness on T is needed.
Equations
- Core.Order.Branching.subtreeAt t [] = some t
- Core.Order.Branching.subtreeAt t (i :: rest) = (Core.Order.Branching.children t)[i]?.bind fun (c : T) => Core.Order.Branching.subtreeAt c rest
Instances For
Valid positions of a tree. Node identity is the position
(TreePath), never the subtree value: identical subtrees occur at
multiple positions, so orders and graphs must live on paths.
Equations
- Core.Order.Branching.validPaths t = {p : Core.Order.TreePath | (Core.Order.Branching.subtreeAt t p.toList).isSome = true}
Instances For
Membership characterization for non-root positions: descend one child, then recurse.
Valid paths are closed under prefixes (ancestors of a position are
positions): the set of positions is downward closed, hence inherits
the rooted-tree order stack from TreePath.
The dominance order of any Branching carrier, as a
[BP90] TreeOrder on positions. Every instance inherits
the command-relation library through this single definition —
generalizing the former Syntax.Tree.toTreeOrder.
Equations
- Core.Order.Branching.toTreeOrder t = { nodes := Core.Order.Branching.validPaths t, root := ⊥, root_in_nodes := ⋯, root_le_all := ⋯, ancestor_connected := ⋯ }
Instances For
IsFiniteBranching: the well-foundedness mixin #
Prop-valued mixin asserting that Branching.IsChild is well-founded
on T — i.e. every descent chain is finite. Unlocks carrier recursion
(size, subtrees, yield, inductionOn) via WellFounded.fix.
Mathlib idiom: structure-bearing class (Branching) + Is… Prop
mixin asserting a property (IsFiniteBranching), like PartialOrder
IsPredArchimedeaninRootedTree. The mixin isPropso instances are nevernoncomputable; concrete inductives discharge it viaSubrelation.wfagainst the auto-derivedsizeOfwell-founded relation (one-liner per instance). Carriers without auto-SizeOf(e.g.FreeMagma, whosegenSizeOfSpecisfalse) discharge viaAcc.intro+ the carrier's recursor.
Previously this was a data class carrying measure : T → Nat, but
that design forced noncomputable on inductive instances (LCNF crash
on nested-List recursors) and broke equation-theorem elaboration
for downstream WF defs. The redesign — Prop mixin +
compile_inductive% at inductive definition sites — fixes both.
A Branching carrier whose "is a child of" relation is well-founded
— i.e. every descent chain ends. Unlocks carrier recursion.
- wf : WellFounded Branching.IsChild
Instances
Build IsFiniteBranching T from any Nat-valued measure that
children strictly decrease (canonically sizeOf for inductives).
Number of nodes.
Equations
- One or more equations did not get rendered due to their size.
Instances For
One-step unfolding of size. Proved by WellFounded.fix_eq.
Attach-free unfolding of size, for concrete computation.
All subtrees including self, pre-order.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Attach-free unfolding of subtrees, for concrete computation.
Strong induction over an IsFiniteBranching carrier: prove
motive t from motive on all children. Canonical mathlib pattern —
delegates to WellFounded.fix.
Equations
- One or more equations did not get rendered due to their size.
Instances For
HasContent and yield #
Separate class because not every rose-tree carrier has terminal content (Nanosyntax trees carry features on every node; CFG derivation trees distinguish terminal from nonterminal types).
Carriers whose nodes may carry pronounceable terminal content.
W is an outParam: in linguistics use each carrier has one content
reading. (Multi-content scenarios — phonological vs orthographic — can
be supported via different wrapper types if needed.)
- content? : T → Option W
Terminal content, if any.
Instances
Terminal yield, left to right: the frontier string. The most basic tree-to-string map — linear precedence lives over it.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Attach-free unfolding of yield, for concrete computation.
Yield with positions — the precedence-is-yield-order substrate #
yieldWithPaths pairs each terminal with its Gorn address. Defined
via WellFounded.fix (not Lean's WF elaborator) so its unfold lemma is
a one-liner via WellFounded.fix_eq — the mathlib-reviewer's escape
from the equation-compiler timeout that the earlier
attach.zipIdx.flatMap formulation hit. The pairwise-Precedes bridge
(Precedes is yield order, [Kay94] LCA-style) is a follow-up
that builds on this substrate.
Yield with positions: each terminal paired with its Gorn address.
Equations
- One or more equations did not get rendered due to their size.
Instances For
One-step unfolding of yieldWithPaths, by WellFounded.fix_eq —
the lemma that the old WF-elaborator approach could not produce.
Instance: FreeMagma #
Mathlib's free magma is the binary rose tree (bare phrase structure in
the Minimalist reading); the instance lives here because mathlib types
take their instances in the class's home file. FreeMagma is declared
with set_option genSizeOfSpec false, so IsFiniteBranching cannot
use the sizeOf shortcut — but the inductive recursor FreeMagma.recOnMul
suffices for a direct Acc.intro proof.
Equations
- Core.Order.instBranchingFreeMagma = { children := fun (x : FreeMagma α) => match x with | FreeMagma.of a => [] | l.mul r => [l, r] }
Decidable command relations over toTreeOrder #
commandRelation (toTreeOrder t) P is decidable at concrete positions:
the dominators of a are exactly the prefixes of a's path
(List.inits), a finite list, so the defining universal collapses to a
List-bounded one. This unlocks decide for c-command facts on
concrete trees ([BP90], [Rei76]). The branching
property is supplied by isBranchingAt (≥ 2 children at the position),
the geometric reading of [Rei76]'s "branching node".
Dominance (p ≤ q, prefix order) on positions is decidable.
Equations
- Core.Order.Branching.instDecidableLETreePath p q = decidable_of_iff (p.toList <+: q.toList) ⋯
A position p is a branching node of t when its subtree has at
least two children — the geometric reading of [Rei76]'s "first
branching node" generating relation.
Equations
- Core.Order.Branching.isBranchingAt t p = ∃ (s : T), Core.Order.Branching.subtreeAt t p.toList = some s ∧ 2 ≤ (Core.Order.Branching.children s).length
Instances For
Equations
- One or more equations did not get rendered due to their size.
Membership in commandRelation (toTreeOrder t) P collapses to a
finite universal over the proper prefixes of a: the only nodes that
properly dominate a are its proper prefixes (a.toList.inits). This
is the key reduction making c-command facts decide-able.
Equations
- Core.Order.Branching.decMemCommandRelation t P a b = decidable_of_iff (∀ x ∈ List.map Core.Order.TreePath.mk a.toList.inits, x ≠ a → x ∈ P → x ≤ b) ⋯
c-command over a concrete carrier ([Rei76]'s c-command):
the [BP90] command relation generated by the geometric
branching nodes isBranchingAt t. Unlike the abstract cCommand
(Core/Order/Command.lean, parameterised by the order-theoretic
branchingNodes), this reads the branching property directly off the
carrier, so it is decidable and matches sister-form c-command on binary
trees. abbrev so membership inherits decMemCommandRelation.
Equations
Instances For
Computability sentinels #
Branching.size/yield on FreeMagma reduce by decide at concrete
data — protecting against noncomputable-regressions during refactors.