Research source · Plain text
RootSharing.lean
formalizations/frontier-derivative/FrontierDerivative/RootSharing.lean
467 lines. Source is displayed for inspection; it is not executed by this page.
File fingerprint
SHA-256: e2818ebdb46febe4a424b3087084d118f428342dd55abe1255ca2bd2db766495
import FPRDTransfer.Compile
/-!
# Coordinate-carrying persistent root sharing
The fixed-port stack decoder cannot clone one historical stack into another
coordinate. Here each cell carries the coordinate to use *after* its symbol.
The decoder follows the current coordinate's port and then switches to the
carried coordinate. This permits several output slots to derive, with
different operations, from one old stack root.
This module proves the representation theorem only. It does not infer a
stationary slot allocator from a bound on frontier cardinality.
-/
namespace FrontierDerivative.RootSharing
open FPRD
universe u
/-- A symbol and the coordinate at which decoding continues after its edge. -/
structure Cell (s : Nat) (A : Type u) where
symbol : A
next : Fin s
deriving DecidableEq, Repr
abbrev RootLabel (s : Nat) (A : Type u) := Fin s → Option (Cell s A)
variable {s : Nat} {A : Type u}
def cellComp (S : Scaffold s (RootLabel s A)) (v : Nat) (j : Fin s) :
Option (Cell s A) :=
(S.label v).bind fun g => g j
def cellCompOpt (S : Scaffold s (RootLabel s A)) (v : Option Nat) (j : Fin s) :
Option (Cell s A) :=
v.bind fun m => cellComp S m j
/-- Read component `j`, follow port `j`, then use the cell's next coordinate. -/
def decode (S : Scaffold s (RootLabel s A)) (j : Fin s) (v : Nat) : List A :=
match cellComp S v j with
| none => []
| some c =>
match S.edge v j with
| none => [c.symbol]
| some m => if _h : m < v then c.symbol :: decode S c.next m else [c.symbol]
termination_by v
decreasing_by exact _h
def decodeOpt (S : Scaffold s (RootLabel s A)) (j : Fin s) :
Option Nat → List A
| none => []
| some m => decode S j m
@[simp] theorem decodeOpt_none (S : Scaffold s (RootLabel s A)) (j : Fin s) :
decodeOpt S j none = [] := rfl
@[simp] theorem decodeOpt_some (S : Scaffold s (RootLabel s A)) (j : Fin s)
(m : Nat) : decodeOpt S j (some m) = decode S j m := rfl
theorem decode_empty (S : Scaffold s (RootLabel s A)) (j : Fin s) (v : Nat)
(h : cellComp S v j = none) : decode S j v = [] := by
rw [decode, h]
theorem decode_cons (S : Scaffold s (RootLabel s A)) (hb : S.Backward)
(j : Fin s) (v : Nat) (c : Cell s A) (h : cellComp S v j = some c) :
decode S j v = c.symbol :: decodeOpt S c.next (S.edge v j) := by
rw [decode, h]
cases he : S.edge v j with
| none => simp
| some m =>
have hlt : m < v := hb v j m he
simp [hlt]
/-! A reducible twin supports exact kernel-checked calibrations. -/
def decodeAux (S : Scaffold s (RootLabel s A)) : Nat → Fin s → Nat → List A
| 0, _, _ => []
| fuel + 1, j, v =>
match cellComp S v j with
| none => []
| some c =>
match S.edge v j with
| none => [c.symbol]
| some m => if m < v then c.symbol :: decodeAux S fuel c.next m else [c.symbol]
theorem decodeAux_eq (S : Scaffold s (RootLabel s A)) :
∀ (fuel : Nat) (j : Fin s) (v : Nat), v < fuel →
decodeAux S fuel j v = decode S j v := by
intro fuel
induction fuel with
| zero => intro j v hv; exact absurd hv (by omega)
| succ f ih =>
intro j v hv
cases h : cellComp S v j with
| none => simp only [decodeAux, h, decode_empty S j v h]
| some c =>
cases he : S.edge v j with
| none => simp [decodeAux, decode, h, he]
| some m =>
by_cases hlt : m < v
· rw [decode, h, he]
simp only [decodeAux, h, he, if_pos hlt]
rw [ih c.next m (by omega)]
simp [hlt]
· simp [decodeAux, decode, h, he, hlt]
theorem decode_eq_decodeAux (S : Scaffold s (RootLabel s A)) (j : Fin s)
(v : Nat) : decode S j v = decodeAux S (v + 1) j v :=
(decodeAux_eq S (v + 1) j v (Nat.lt_succ_self v)).symm
/-- An empty cell owns no edge, ruling out stale tails. -/
def CleanMissing (S : Scaffold s (RootLabel s A)) : Prop :=
∀ v j, cellComp S v j = none → S.edge v j = none
/-! ## Congruence below a freshly appended node -/
theorem decodeAux_congr (S T : Scaffold s (RootLabel s A)) :
∀ (fuel : Nat) (j : Fin s) (v : Nat),
(∀ u, u ≤ v → S.label u = T.label u) →
(∀ u, u ≤ v → ∀ k, S.edge u k = T.edge u k) →
decodeAux S fuel j v = decodeAux T fuel j v := by
intro fuel
induction fuel with
| zero => intro j v hlab hedge; rfl
| succ f ih =>
intro j v hlab hedge
have hcell : cellComp S v j = cellComp T v j := by
simp only [cellComp, hlab v (Nat.le_refl v)]
simp only [decodeAux, hcell]
cases hc : cellComp T v j with
| none => rfl
| some c =>
have he : S.edge v j = T.edge v j := hedge v (Nat.le_refl v) j
rw [he]
cases htarget : T.edge v j with
| none => rfl
| some m =>
by_cases hlt : m < v
· simp only [if_pos hlt, List.cons.injEq, true_and]
exact ih c.next m
(fun u hu => hlab u (Nat.le_trans hu (Nat.le_of_lt hlt)))
(fun u hu => hedge u (Nat.le_trans hu (Nat.le_of_lt hlt)))
· simp [hlt]
theorem decode_congr (S T : Scaffold s (RootLabel s A)) (v : Nat)
(hlab : ∀ u, u ≤ v → S.label u = T.label u)
(hedge : ∀ u, u ≤ v → ∀ j, S.edge u j = T.edge u j) :
∀ j, decode S j v = decode T j v := by
intro j
rw [decode_eq_decodeAux, decode_eq_decodeAux]
exact decodeAux_congr S T (v + 1) j v hlab hedge
theorem decode_append_below (S : Scaffold s (RootLabel s A)) (g : RootLabel s A)
(tgt : Fin s → Target s) (j : Fin s) (v : Nat) (hv : v ≤ S.top) :
decode (S.append g tgt) j v = decode S j v := by
apply decode_congr (S.append g tgt) S v
· intro u hu
exact S.append_label_old g tgt (by omega)
· intro u hu k
exact S.append_edge_old g tgt (by omega) k
theorem decodeOpt_append_below (S : Scaffold s (RootLabel s A))
(g : RootLabel s A) (tgt : Fin s → Target s) (j : Fin s) (o : Option Nat)
(ho : ∀ m, o = some m → m ≤ S.top) :
decodeOpt (S.append g tgt) j o = decodeOpt S j o := by
cases h : o with
| none => rfl
| some m =>
simp only [decodeOpt_some]
exact decode_append_below S g tgt j m (ho m h)
/-! ## Simultaneous source-selecting actions -/
inductive Derive (s : Nat) (A : Type u) where
| push (source : Fin s) (symbol : A)
| keep (source : Fin s)
| pop (source : Fin s)
deriving Repr
namespace Derive
def source : Derive s A → Fin s
| .push i _ | .keep i | .pop i => i
def apply (op : Derive s A) (stacks : Fin s → List A) : List A :=
match op with
| .push i a => a :: stacks i
| .keep i => stacks i
| .pop i => (stacks i).tail
end Derive
def tailCell (S : Scaffold s (RootLabel s A)) (i : Fin s) : Option (Cell s A) :=
match cellComp S S.top i with
| none => none
| some c => cellCompOpt S (S.edge S.top i) c.next
def newLabel (S : Scaffold s (RootLabel s A)) (ops : Fin s → Derive s A) :
RootLabel s A :=
fun j =>
match ops j with
| .push i a => some ⟨a, i⟩
| .keep i => cellComp S S.top i
| .pop i => tailCell S i
/-- Each output coordinate owns its edge; pop uses the source's carried next
coordinate as the second port in a distance-two path. -/
def newTarget (S : Scaffold s (RootLabel s A)) (ops : Fin s → Derive s A) :
Fin s → Target s :=
fun j =>
match ops j with
| .push _ _ => .path []
| .keep i =>
match cellComp S S.top i with
| none => .missing
| some _ => .path [i]
| .pop i =>
match cellComp S S.top i with
| none => .missing
| some c =>
match tailCell S i with
| none => .missing
| some _ => .path [i, c.next]
theorem newTarget_ne_self (S : Scaffold s (RootLabel s A))
(ops : Fin s → Derive s A) (j : Fin s) : newTarget S ops j ≠ .self := by
cases hop : ops j with
| push i a => simp [newTarget, hop]
| keep i =>
cases hc : cellComp S S.top i <;> simp [newTarget, hop, hc]
| pop i =>
cases hc : cellComp S S.top i with
| none => simp [newTarget, hop, hc]
| some c =>
cases ht : tailCell S i <;> simp [newTarget, hop, hc, ht]
theorem newTarget_distance (S : Scaffold s (RootLabel s A))
(ops : Fin s → Derive s A) (j : Fin s) (p : List (Fin s))
(h : newTarget S ops j = .path p) : p.length ≤ 2 := by
cases hop : ops j with
| push i a =>
simp [newTarget, hop] at h
subst p
simp
| keep i =>
cases hc : cellComp S S.top i with
| none => simp [newTarget, hop, hc] at h
| some c =>
simp [newTarget, hop, hc] at h
subst p
simp
| pop i =>
cases hc : cellComp S S.top i with
| none => simp [newTarget, hop, hc] at h
| some c =>
cases ht : tailCell S i with
| none => simp [newTarget, hop, hc, ht] at h
| some d =>
simp [newTarget, hop, hc, ht] at h
subst p
simp
theorem resolve_mixed_two (S : Scaffold s (RootLabel s A)) (i k : Fin s)
(new : Nat) :
S.resolve S.top new (.path [i, k]) =
(S.edge S.top i).bind fun m => S.edge m k := by
show S.follow S.top [i, k] = _
cases he : S.edge S.top i with
| none => rw [S.follow_cons_none S.top i [k] he]; rfl
| some m =>
rw [S.follow_cons_some S.top i [k] m he, S.follow_single m k]
rfl
theorem append_backward (S : Scaffold s (RootLabel s A)) (hb : S.Backward)
(ops : Fin s → Derive s A) :
(S.append (newLabel S ops) (newTarget S ops)).Backward :=
S.append_backward hb _ _ (newTarget_ne_self S ops)
/-! ## Exact one-step root sharing -/
theorem decode_new (S : Scaffold s (RootLabel s A)) (hb : S.Backward)
(stacks : Fin s → List A) (hst : ∀ i, decode S i S.top = stacks i)
(ops : Fin s → Derive s A) (j : Fin s) :
decode (S.append (newLabel S ops) (newTarget S ops)) j (S.top + 1) =
(ops j).apply stacks := by
let S' := S.append (newLabel S ops) (newTarget S ops)
have hb' : S'.Backward := append_backward S hb ops
have hlabel : cellComp S' (S.top + 1) j = newLabel S ops j := by
simp only [S', cellComp, Scaffold.append_label_new, Option.bind_some]
have hedge : S'.edge (S.top + 1) j =
S.resolve S.top (S.top + 1) (newTarget S ops j) := by
simp only [S', Scaffold.append_edge_new]
cases hop : ops j with
| push i a =>
have hl : cellComp S' (S.top + 1) j = some ⟨a, i⟩ := by
rw [hlabel]; simp [newLabel, hop]
rw [decode_cons S' hb' j (S.top + 1) ⟨a, i⟩ hl, hedge]
simp only [newTarget, hop, Scaffold.resolve, Scaffold.follow_nil,
decodeOpt_some, Derive.apply]
rw [decode_append_below S _ _ i S.top (Nat.le_refl _), hst i]
| keep i =>
cases hc : cellComp S S.top i with
| none =>
have hl : cellComp S' (S.top + 1) j = none := by
rw [hlabel]; simp [newLabel, hop, hc]
have hempty : stacks i = [] := by
rw [← hst i]; exact decode_empty S i S.top hc
rw [decode_empty S' j (S.top + 1) hl, Derive.apply, hempty]
| some c =>
have hl : cellComp S' (S.top + 1) j = some c := by
rw [hlabel]; simp [newLabel, hop, hc]
have ht : S'.edge (S.top + 1) j = S.edge S.top i := by
rw [hedge]; simp [newTarget, hop, hc, Scaffold.resolve, Scaffold.follow_single]
have hbound : ∀ m, S.edge S.top i = some m → m ≤ S.top := by
intro m hm; exact Nat.le_of_lt (hb S.top i m hm)
rw [decode_cons S' hb' j (S.top + 1) c hl, ht,
decodeOpt_append_below S _ _ c.next (S.edge S.top i) hbound,
← decode_cons S hb i S.top c hc, hst i]
rfl
| pop i =>
cases hc : cellComp S S.top i with
| none =>
have hl : cellComp S' (S.top + 1) j = none := by
rw [hlabel]; simp [newLabel, tailCell, hop, hc]
have hempty : stacks i = [] := by
rw [← hst i]; exact decode_empty S i S.top hc
rw [decode_empty S' j (S.top + 1) hl, Derive.apply, hempty]
rfl
| some c =>
have hsource : stacks i = c.symbol :: decodeOpt S c.next (S.edge S.top i) := by
rw [← hst i]; exact decode_cons S hb i S.top c hc
cases he : S.edge S.top i with
| none =>
have hl : cellComp S' (S.top + 1) j = none := by
rw [hlabel]; simp [newLabel, tailCell, hop, hc, he, cellCompOpt]
rw [decode_empty S' j (S.top + 1) hl, Derive.apply, hsource, he]
rfl
| some m =>
have hmlt : m < S.top := hb S.top i m he
cases hd : cellComp S m c.next with
| none =>
have hl : cellComp S' (S.top + 1) j = none := by
rw [hlabel]
simp [newLabel, tailCell, hop, hc, he, cellCompOpt, hd]
rw [decode_empty S' j (S.top + 1) hl, Derive.apply, hsource, he,
decodeOpt_some, decode_empty S c.next m hd]
rfl
| some d =>
have hl : cellComp S' (S.top + 1) j = some d := by
rw [hlabel]
simp [newLabel, tailCell, hop, hc, he, cellCompOpt, hd]
have ht : S'.edge (S.top + 1) j = S.edge m c.next := by
rw [hedge]
simp [newTarget, hop, hc, tailCell, he, cellCompOpt, hd,
resolve_mixed_two]
have hbound : ∀ m', S.edge m c.next = some m' → m' ≤ S.top := by
intro m' hm'
have hm'lt : m' < m := hb m c.next m' hm'
omega
rw [decode_cons S' hb' j (S.top + 1) d hl, ht,
decodeOpt_append_below S _ _ d.next (S.edge m c.next) hbound,
Derive.apply, hsource, he, decodeOpt_some,
← decode_cons S hb c.next m d hd]
rfl
theorem cleanMissing_append (S : Scaffold s (RootLabel s A))
(hc : CleanMissing S) (ops : Fin s → Derive s A) :
CleanMissing (S.append (newLabel S ops) (newTarget S ops)) := by
intro v j hv
by_cases hnew : v = S.top + 1
· subst hnew
simp only [cellComp, Scaffold.append_label_new, Option.bind_some] at hv
rw [Scaffold.append_edge_new]
cases hop : ops j with
| push i a => simp [newLabel, hop] at hv
| keep i =>
simp only [newLabel, hop] at hv
simp [newTarget, hop, hv, Scaffold.resolve]
| pop i =>
simp only [newLabel, hop] at hv
simp only [newTarget, hop]
cases hs : cellComp S S.top i with
| none => simp [Scaffold.resolve]
| some c =>
have ht : tailCell S i = none := hv
simp [ht, Scaffold.resolve]
· rw [S.append_edge_old (newLabel S ops) (newTarget S ops) hnew j]
apply hc v j
rw [cellComp] at hv ⊢
rw [S.append_label_old (newLabel S ops) (newTarget S ops) hnew] at hv
exact hv
/-! ## Exact shared-tail calibration -/
def firstOps (j : Fin 2) : Derive 2 Nat :=
if j = 0 then .push 0 1 else .push 1 9
def rootBase : Scaffold 2 (RootLabel 2 Nat) :=
Scaffold.base 2 (RootLabel 2 Nat)
def history1 : Scaffold 2 (RootLabel 2 Nat) :=
rootBase.append (newLabel rootBase firstOps) (newTarget rootBase firstOps)
def secondOps (j : Fin 2) : Derive 2 Nat :=
if j = 0 then .push 0 2 else .keep 1
def history : Scaffold 2 (RootLabel 2 Nat) :=
history1.append (newLabel history1 secondOps) (newTarget history1 secondOps)
def splitOps (j : Fin 2) : Derive 2 Nat :=
if j = 0 then .push 0 7 else .push 0 8
def splitHistory : Scaffold 2 (RootLabel 2 Nat) :=
history.append (newLabel history splitOps) (newTarget history splitOps)
theorem rootBase_backward : rootBase.Backward :=
Scaffold.base_backward 2 (RootLabel 2 Nat)
theorem rootBase_cleanMissing : CleanMissing rootBase := by
intro v j h
rfl
theorem history1_backward : history1.Backward :=
append_backward rootBase rootBase_backward firstOps
theorem history1_cleanMissing : CleanMissing history1 :=
cleanMissing_append rootBase rootBase_cleanMissing firstOps
theorem history_backward : history.Backward :=
append_backward history1 history1_backward secondOps
theorem history_cleanMissing : CleanMissing history :=
cleanMissing_append history1 history1_cleanMissing secondOps
theorem splitHistory_backward : splitHistory.Backward :=
append_backward history history_backward splitOps
theorem splitHistory_cleanMissing : CleanMissing splitHistory :=
cleanMissing_append history history_cleanMissing splitOps
theorem source_before_split : decode history 0 history.top = [2, 1] := by
rw [decode_eq_decodeAux]
native_decide
theorem destination_before_split : decode history 1 history.top = [9] := by
rw [decode_eq_decodeAux]
native_decide
theorem first_after_split : decode splitHistory 0 splitHistory.top = [7, 2, 1] := by
rw [decode_eq_decodeAux]
native_decide
theorem second_after_split : decode splitHistory 1 splitHistory.top = [8, 2, 1] := by
rw [decode_eq_decodeAux]
native_decide
#check decode_new
#check append_backward
#check cleanMissing_append
#check splitHistory_backward
#check splitHistory_cleanMissing
#check first_after_split
#check second_after_split
end FrontierDerivative.RootSharing