Multi-path grafting on RoseTree α #
multiGraft T pairs grafts trees onto T at several paths simultaneously, every path read
in the original T (Foissy's convention). Several pairs may share a path; their trees are
prepended in pair-list order, so multiGraft is order-sensitive, and commutativity is recovered
at the multiset level in Insertion.lean.
Main definitions and results #
multiGraft,multiGraftChildren: the mutual recursion.multiGraftChildrendescends by shifting path indices: pairs starting0 :: restgo to the head child as(rest, t), pairs starting(k + 1) :: restgo to the tail as(k :: rest, t).rootPrependFilter,headChildFilter,tailChildFilter: the three pair projections, with theirList.filtercharacterizations.multiGraft_nil: no pairs, no change.multiGraft_singleton: one pair isinsertAt.
References #
- [foissy-typed-decorated-rooted-trees-2018]
- [Foi]
§1: Filter helpers (top-level for matcher stability) #
The multiGraft recursion uses three pair-filtering functions: extracting
root-prepends (empty path), extracting head-child pairs (first index 0),
and shifting tail-child pairs (first index k+1). Each is defined as a
top-level function so that all filterMap callers reference the same
elaborated matcher — rw with filter equalities then works cleanly across
files. Without this, Lean's inline-match elaboration generates fresh
match_N aux constants per scope, blocking unification.
Each helper carries unfolding @[simp] lemmas on every pattern so that
simp can reduce them where rfl would otherwise fail.
Extract pair as root prepend iff its path is empty.
Equations
- RoseTree.Pathed.rootPrependFilter pair = match pair.1 with | [] => some pair.2 | head :: tail => none
Instances For
Extract pair as head-child pair iff its path starts with 0,
stripping the leading index.
Equations
- RoseTree.Pathed.headChildFilter pair = match pair.1 with | 0 :: rest => some (rest, pair.2) | x => none
Instances For
Extract pair as tail-child pair iff its path starts with k+1,
decrementing the leading index by one.
Equations
- RoseTree.Pathed.tailChildFilter pair = match pair.1 with | k.succ :: rest => some (k :: rest, pair.2) | x => none
Instances For
§2: multiGraft mutual definition #
multiGraft T pairs: walk T, prepend the trees assigned to each
path. Pairs whose path is [] graft at the root (prepended to the
children list in pair-list order). Pairs whose path is i :: rest
descend into the i-th child with the projected pair (rest, _).
Equations
- RoseTree.Pathed.multiGraft (RoseTree.node a cs) x✝ = RoseTree.node a (List.filterMap RoseTree.Pathed.rootPrependFilter x✝ ++ RoseTree.Pathed.multiGraftChildren cs x✝)
Instances For
Auxiliary: descend pair list into children. Pairs with first index
0 apply to the head child (with the rest of the path); pairs with
first index k+1 are forwarded to the tail (with the rest of the
list and index decremented).
Equations
- One or more equations did not get rendered due to their size.
- RoseTree.Pathed.multiGraftChildren [] x✝ = []
Instances For
Filter characterizations #
Each pair filter is a List.filter on the path followed by a projection, so pair lists can be
bucketed by a predicate on paths (bind_listChoices_filter in Insertion.lean).
multiGraftChildren depends on its pair list only through the two child filters.
Root pairs never reach the children.
multiGraftChildren cs pairs has the same length as cs.
§3: Nil identity #
Empty pair list: multiGraft is the identity.
Empty pair list: multiGraftChildren is the identity on the
children list.
§4: Singleton bridge to insertAt #
A single-pair multiGraft is exactly insertAt. The proof splits into:
- §4.1
multiGraftChildren cs [([], T₂)] = cs— the empty path contributes only to root prepends, not to the children. - §4.2
multiGraftChildren cs [(j :: rest, T₂)]agrees withcs.set jwhenj < cs.length, else is the identity. - §4.3 Top-level
multiGraft_singletoncombines these.
Single-pair multiGraft is insertAt. Bridges the multi-graft
primitive to the single-vertex insertion in Insert.lean.