import Sal.MRDTs.RGA_Embed.RGA_Embed_ChainLex /-! # The sided chain-lex kernel: two-sidedness as a parameter Design: `whiteboard/sided-embed-design-note.md`; Python validation: `whiteboard/litmus/embed_sided.py` (battery clean, L19 flips under the Fugue policy, all-R fragment lockstep-exact with the one-sided embed). Chains become sequences of `(side, delta)` entries and the display rule generalizes from the prefix rule to the in-order rule: L-extensions, then the node, then R-extensions. The **marker formalization** makes this plain lexicographic comparison again, a node's sort key is its coordinate followed by the terminator `3`, with symbol bands R-block symbols {1,2} < marker 3 < L-block symbols {4,5} and the L band written in the **complemented** code (order-reversing prefix-free at identical lengths), realizing the mirrored L-sibling order. The one-sided design is the L-uninhabited fragment: its existing `key = map sym ++ [3]` is literally this construction, which is why the `keyLt` machinery below is reused unchanged. This file is the sided analogue of the chain-lex core: the display relation `schainBefore` (in-order rule), its totality, and the **sided marker theorem** `sdisplay_iff_schainBefore`, display comparison of sided coordinates is exactly the in-order rule. -/ namespace Sal.EmbedRGA /-! ## Sided chains -/ inductive Side : Type where | R | L deriving DecidableEq /-- A chain entry: side and (positive) timestamp delta. -/ abbrev SEntry : Type := Side × ℕ abbrev SChain : Type := List SEntry @[simp] def PosSChain (ch : SChain) : Prop := ∀ e ∈ ch, 1 ≤ e.2 /-! ## The sided symbol alphabet -/ /-- R-band symbols. -/ def symR (b : Bool) : ℕ := if b then 2 else 1 /-- L-band symbols. -/ def symL (b : Bool) : ℕ := if b then 5 else 4 /-- Bitwise complement: the order-reversing twin of a code, at identical lengths, prefix-freedom preserved. -/ def compl (w : List Bool) : List Bool := w.map (!·) /-- The symbol block of one chain entry: R-entries carry the code in the R band; L-entries carry the *complemented* code in the L band (the mirror). -/ def sBlock (Γ : OrderedPrefixCode) : SEntry → List ℕ | (Side.R, d) => (Γ.enc d).map symR | (Side.L, d) => (compl (Γ.enc d)).map symL /-- The sided coordinate: concatenated blocks along the chain. -/ def sidedCoordOf (Γ : OrderedPrefixCode) : SChain → List ℕ | [] => [] | e :: ch => sBlock Γ e ++ sidedCoordOf Γ ch theorem sidedCoordOf_append (Γ : OrderedPrefixCode) (c1 c2 : SChain) : sidedCoordOf Γ (c1 ++ c2) = sidedCoordOf Γ c1 ++ sidedCoordOf Γ c2 := by induction c1 with | nil => simp [sidedCoordOf] | cons e es ih => simp [sidedCoordOf, ih] /-- The sort key: coordinate plus the marker. -/ def sKey (c : List ℕ) : List ℕ := c ++ [3] /-! ## Band arithmetic -/ theorem symR_lt_three (b : Bool) : symR b < 3 := by cases b <;> simp [symR] theorem three_lt_symL (b : Bool) : 3 < symL b := by cases b <;> simp [symL] theorem symR_lt_symL (b b' : Bool) : symR b < symL b' := by cases b <;> cases b' <;> simp [symR, symL] theorem sBlock_ne_nil (Γ : OrderedPrefixCode) {e : SEntry} (he : 1 ≤ e.2) : sBlock Γ e ≠ [] := by obtain ⟨sd, d⟩ := e have hne := enc_ne_nil Γ (show 1 ≤ d from he) cases sd <;> simp [sBlock, compl, hne] /-! ## The in-order display rule -/ /-- Divergence order between two distinct entries at a shared anchor: among R-siblings the newer displays first (adjacent to the node from below), among L-siblings the older displays first (the newer sits adjacent to the node from above), and every L-entry displays before every R-entry (L-subtrees precede the node precede R-subtrees). -/ def sEntryBefore : SEntry → SEntry → Prop | (Side.R, d), (Side.R, e) => e < d | (Side.L, d), (Side.L, e) => d < e | (Side.L, _), (Side.R, _) => True | (Side.R, _), (Side.L, _) => False /-- The in-order rule: L-extensions before the node, the node before its R-extensions, divergences by `sEntryBefore`. -/ inductive schainBefore : SChain → SChain → Prop where | extL (ch : SChain) (d : ℕ) (rest : SChain) : schainBefore (ch ++ (Side.L, d) :: rest) ch | extR (ch : SChain) (d : ℕ) (rest : SChain) : schainBefore ch (ch ++ (Side.R, d) :: rest) | diverge (q : SChain) (e1 e2 : SEntry) (c1 c2 : SChain) : sEntryBefore e1 e2 → schainBefore (q ++ e1 :: c1) (q ++ e2 :: c2) theorem schainBefore_cons (x : SEntry) {c1 c2 : SChain} (h : schainBefore c1 c2) : schainBefore (x :: c1) (x :: c2) := by cases h with | extL ch d rest => exact schainBefore.extL (x :: c2) d rest | extR ch d rest => exact schainBefore.extR (x :: c1) d rest | diverge q e1 e2 t1 t2 hlt => exact schainBefore.diverge (x :: q) e1 e2 t1 t2 hlt theorem sEntryBefore_total {e1 e2 : SEntry} (hne : e1 ≠ e2) : sEntryBefore e1 e2 ∨ sEntryBefore e2 e1 := by obtain ⟨s1, d1⟩ := e1 obtain ⟨s2, d2⟩ := e2 cases s1 <;> cases s2 · -- R R rcases Nat.lt_trichotomy d1 d2 with h | rfl | h · exact Or.inr h · exact absurd rfl hne · exact Or.inl h · -- R L exact Or.inr trivial · -- L R exact Or.inl trivial · -- L L rcases Nat.lt_trichotomy d1 d2 with h | rfl | h · exact Or.inl h · exact absurd rfl hne · exact Or.inr h /-- Distinct sided chains are always comparable. -/ theorem schainBefore_total : ∀ {c1 c2 : SChain}, c1 ≠ c2 → schainBefore c1 c2 ∨ schainBefore c2 c1 | [], [], hne => absurd rfl hne | [], e :: es, _ => by obtain ⟨sd, d⟩ := e cases sd with | R => exact Or.inl (schainBefore.extR [] d es) | L => exact Or.inr (schainBefore.extL [] d es) | e :: es, [], _ => by obtain ⟨sd, d⟩ := e cases sd with | R => exact Or.inr (schainBefore.extR [] d es) | L => exact Or.inl (schainBefore.extL [] d es) | e1 :: t1, e2 :: t2, hne => by by_cases he : e1 = e2 · subst he have hne' : t1 ≠ t2 := fun h => hne (by rw [h]) rcases schainBefore_total hne' with h | h · exact Or.inl (schainBefore_cons e1 h) · exact Or.inr (schainBefore_cons e1 h) · rcases sEntryBefore_total he with h | h · exact Or.inl (schainBefore.diverge [] e1 e2 t1 t2 h) · exact Or.inr (schainBefore.diverge [] e2 e1 t2 t1 h) /-! ## The sided marker theorem -/ /-- First-symbol comparison under a shared prefix. -/ theorem keyLt_append_cons_lt (p : List ℕ) {x y : ℕ} (h : x < y) (u v : List ℕ) : keyLt (p ++ x :: u) (p ++ y :: v) = true := by rw [keyLt_append_left] simp [keyLt, h] /-- **In-order ⟹ key order**: the sided coordinate comparison realizes the in-order rule. -/ theorem schainBefore_display (Γ : OrderedPrefixCode) {c1 c2 : SChain} (h1 : PosSChain c1) (h2 : PosSChain c2) (hb : schainBefore c1 c2) : keyLt (sKey (sidedCoordOf Γ c2)) (sKey (sidedCoordOf Γ c1)) = true := by cases hb with | extL ch d rest => -- c1 = c2 ++ (L,d) :: rest: at the divergence, marker 3 (c2) -- meets an L-band symbol {4,5} (c1) have hd : 1 ≤ d := h1 (Side.L, d) (List.mem_append_right _ List.mem_cons_self) obtain ⟨b, bs, hbs⟩ : ∃ b bs, Γ.enc d = b :: bs := by cases henc : Γ.enc d with | nil => exact absurd henc (enc_ne_nil Γ hd) | cons b bs => exact ⟨b, bs, rfl⟩ show keyLt (sidedCoordOf Γ c2 ++ [3]) (sidedCoordOf Γ (c2 ++ (Side.L, d) :: rest) ++ [3]) = true rw [sidedCoordOf_append, List.append_assoc, show sidedCoordOf Γ ((Side.L, d) :: rest) ++ [3] = symL (!b) :: ((compl bs).map symL ++ (sidedCoordOf Γ rest ++ [3])) from by simp [sidedCoordOf, sBlock, compl, hbs], show (sidedCoordOf Γ c2 ++ [3] : List ℕ) = sidedCoordOf Γ c2 ++ 3 :: [] from rfl] exact keyLt_append_cons_lt _ (three_lt_symL (!b)) _ _ | extR ch d rest => -- c2 = c1 ++ (R,d) :: rest: an R-band symbol {1,2} (c2) meets -- marker 3 (c1) have hd : 1 ≤ d := h2 (Side.R, d) (List.mem_append_right _ List.mem_cons_self) obtain ⟨b, bs, hbs⟩ : ∃ b bs, Γ.enc d = b :: bs := by cases henc : Γ.enc d with | nil => exact absurd henc (enc_ne_nil Γ hd) | cons b bs => exact ⟨b, bs, rfl⟩ show keyLt (sidedCoordOf Γ (c1 ++ (Side.R, d) :: rest) ++ [3]) (sidedCoordOf Γ c1 ++ [3]) = true rw [sidedCoordOf_append, List.append_assoc, show sidedCoordOf Γ ((Side.R, d) :: rest) ++ [3] = symR b :: (bs.map symR ++ (sidedCoordOf Γ rest ++ [3])) from by simp [sidedCoordOf, sBlock, hbs], show (sidedCoordOf Γ c1 ++ [3] : List ℕ) = sidedCoordOf Γ c1 ++ 3 :: [] from rfl] exact keyLt_append_cons_lt _ (symR_lt_three b) _ _ | diverge q e1 e2 t1 t2 hlt => show keyLt (sidedCoordOf Γ (q ++ e2 :: t2) ++ [3]) (sidedCoordOf Γ (q ++ e1 :: t1) ++ [3]) = true rw [sidedCoordOf_append, sidedCoordOf_append, List.append_assoc, List.append_assoc] obtain ⟨s1, d1⟩ := e1 obtain ⟨s2, d2⟩ := e2 have hd1 : 1 ≤ d1 := h1 (s1, d1) (List.mem_append_right _ List.mem_cons_self) have hd2 : 1 ≤ d2 := h2 (s2, d2) (List.mem_append_right _ List.mem_cons_self) cases s1 <;> cases s2 · -- R vs R: newer (larger delta) first have hlt' : d2 < d1 := hlt obtain ⟨p, u1, u2, hE2, hE1⟩ := enc_first_diff Γ hd2 hd1 hlt' rw [show sidedCoordOf Γ ((Side.R, d2) :: t2) ++ [3] = p.map symR ++ 1 :: (u1.map symR ++ (sidedCoordOf Γ t2 ++ [3])) from by simp [sidedCoordOf, sBlock, hE2, symR], show sidedCoordOf Γ ((Side.R, d1) :: t1) ++ [3] = p.map symR ++ 2 :: (u2.map symR ++ (sidedCoordOf Γ t1 ++ [3])) from by simp [sidedCoordOf, sBlock, hE1, symR]] rw [keyLt_append_left, keyLt_append_left] simp [keyLt] · -- R vs L: impossible divergence exact absurd hlt (by simp [sEntryBefore]) · -- L vs R: the bands decide obtain ⟨b1, bs1, hb1⟩ : ∃ b bs, Γ.enc d1 = b :: bs := by cases henc : Γ.enc d1 with | nil => exact absurd henc (enc_ne_nil Γ hd1) | cons b bs => exact ⟨b, bs, rfl⟩ obtain ⟨b2, bs2, hb2⟩ : ∃ b bs, Γ.enc d2 = b :: bs := by cases henc : Γ.enc d2 with | nil => exact absurd henc (enc_ne_nil Γ hd2) | cons b bs => exact ⟨b, bs, rfl⟩ rw [show sidedCoordOf Γ ((Side.R, d2) :: t2) ++ [3] = symR b2 :: (bs2.map symR ++ (sidedCoordOf Γ t2 ++ [3])) from by simp [sidedCoordOf, sBlock, hb2], show sidedCoordOf Γ ((Side.L, d1) :: t1) ++ [3] = symL (!b1) :: ((compl bs1).map symL ++ (sidedCoordOf Γ t1 ++ [3])) from by simp [sidedCoordOf, sBlock, compl, hb1]] exact keyLt_append_cons_lt _ (symR_lt_symL b2 (!b1)) _ _ · -- L vs L: mirrored, the complement flips the differing bit have hlt' : d1 < d2 := hlt obtain ⟨p, u1, u2, hE1, hE2⟩ := enc_first_diff Γ hd1 hd2 hlt' rw [show sidedCoordOf Γ ((Side.L, d2) :: t2) ++ [3] = (compl p).map symL ++ 4 :: ((compl u2).map symL ++ (sidedCoordOf Γ t2 ++ [3])) from by simp [sidedCoordOf, sBlock, compl, hE2, symL], show sidedCoordOf Γ ((Side.L, d1) :: t1) ++ [3] = (compl p).map symL ++ 5 :: ((compl u1).map symL ++ (sidedCoordOf Γ t1 ++ [3])) from by simp [sidedCoordOf, sBlock, compl, hE1, symL]] rw [keyLt_append_left, keyLt_append_left] simp [keyLt] theorem schainBefore_ne {c1 c2 : SChain} (h : schainBefore c1 c2) : c1 ≠ c2 := by cases h with | extL ch d rest => intro h have := congrArg List.length h simp at this | extR ch d rest => intro h have := congrArg List.length h simp at this | diverge q e1 e2 c1 c2 hlt => intro h have h2 := List.append_cancel_left h injection h2 with h3 h4 subst h3 obtain ⟨s1, d1⟩ := e1 cases s1 <;> simp [sEntryBefore] at hlt /-- **The sided marker theorem**: for distinct positive sided chains, the display comparison of the sided coordinates is exactly the in-order rule. Two-sidedness is plain lexicographic order over the marker alphabet, no bespoke three-way prefix clause. -/ theorem sdisplay_iff_schainBefore (Γ : OrderedPrefixCode) {c1 c2 : SChain} (h1 : PosSChain c1) (h2 : PosSChain c2) (hne : c1 ≠ c2) : keyLt (sKey (sidedCoordOf Γ c2)) (sKey (sidedCoordOf Γ c1)) = true ↔ schainBefore c1 c2 := by constructor · intro h rcases schainBefore_total hne with hb | hb · exact hb · have h' := schainBefore_display Γ h2 h1 hb rw [keyLt_asymm h'] at h exact Bool.noConfusion h · exact schainBefore_display Γ h1 h2 /-! ## Cross-validation against the Python model `embed_sided.py`'s symbol strings, at the unary code: an R-entry of delta 1 is `[2,1]` (code `10` in the R band), its L twin `[4,5]` (complement `01` in the L band); the marker sits between the bands. -/ example : sidedCoordOf unaryCode [(Side.R, 1)] = [2, 1] := by decide example : sidedCoordOf unaryCode [(Side.L, 1)] = [4, 5] := by decide example : sidedCoordOf unaryCode [(Side.R, 2), (Side.L, 1)] = [2, 2, 1, 4, 5] := by decide /-- The node displays before its R-child and after its L-child. -/ example : keyLt (sKey (sidedCoordOf unaryCode [(Side.R, 1), (Side.R, 2)])) (sKey (sidedCoordOf unaryCode [(Side.R, 1)])) = true := by decide example : keyLt (sKey (sidedCoordOf unaryCode [(Side.R, 1)])) (sKey (sidedCoordOf unaryCode [(Side.R, 1), (Side.L, 2)])) = true := by decide /-! ## Unique decodability over the sided alphabet -/ /-- Uniform view of a block: the code mapped through the side's symbol function (the L side pre-composes the complement). -/ def sideSym : Side → Bool → ℕ | Side.R => symR | Side.L => fun b => symL (!b) theorem sBlock_eq (Γ : OrderedPrefixCode) (sd : Side) (d : ℕ) : sBlock Γ (sd, d) = (Γ.enc d).map (sideSym sd) := by cases sd with | R => rfl | L => simp [sBlock, sideSym, compl, List.map_map, Function.comp] theorem sideSym_inj (sd : Side) : Function.Injective (sideSym sd) := by cases sd <;> intro a b h <;> cases a <;> cases b <;> simp [sideSym, symR, symL] at h ⊢ theorem sideSym_band_ne (b b' : Bool) : sideSym Side.R b ≠ sideSym Side.L b' := by cases b <;> cases b' <;> simp [sideSym, symR, symL] /-- Injective per-symbol maps reflect prefixes. -/ theorem map_prefix_reflect {f : Bool → ℕ} (hf : Function.Injective f) : ∀ {u v : List Bool}, u.map f <+: v.map f → u <+: v | [], _, _ => List.nil_prefix | a :: u, [], h => by simp at h | a :: u, b :: v, h => by simp only [List.map_cons, List.cons_prefix_cons] at h obtain ⟨hab, ht⟩ := h have hab' := hf hab subst hab' exact List.cons_prefix_cons.mpr ⟨rfl, map_prefix_reflect hf ht⟩ /-- **Unique decodability**: distinct positive sided chains mint distinct coordinates, the side is recoverable from the first symbol's band, the delta by prefix-freedom within the band. -/ theorem sidedCoordOf_inj (Γ : OrderedPrefixCode) : ∀ {c1 c2 : SChain}, PosSChain c1 → PosSChain c2 → sidedCoordOf Γ c1 = sidedCoordOf Γ c2 → c1 = c2 | [], [], _, _, _ => rfl | [], (sd, d) :: es, _, h2, h => by exfalso have hd : 1 ≤ d := h2 (sd, d) List.mem_cons_self have hne := sBlock_ne_nil Γ (e := (sd, d)) hd cases hb : sBlock Γ (sd, d) with | nil => exact hne hb | cons x xs => simp only [sidedCoordOf, hb] at h simp at h | (sd, d) :: es, [], h1, _, h => by exfalso have hd : 1 ≤ d := h1 (sd, d) List.mem_cons_self have hne := sBlock_ne_nil Γ (e := (sd, d)) hd cases hb : sBlock Γ (sd, d) with | nil => exact hne hb | cons x xs => simp only [sidedCoordOf, hb] at h simp at h | (s1, d1) :: t1, (s2, d2) :: t2, h1, h2, h => by have hd1 : 1 ≤ d1 := h1 (s1, d1) List.mem_cons_self have hd2 : 1 ≤ d2 := h2 (s2, d2) List.mem_cons_self simp only [sidedCoordOf, sBlock_eq] at h obtain ⟨b1, bs1, hb1⟩ : ∃ b bs, Γ.enc d1 = b :: bs := by cases henc : Γ.enc d1 with | nil => exact absurd henc (enc_ne_nil Γ hd1) | cons b bs => exact ⟨b, bs, rfl⟩ obtain ⟨b2, bs2, hb2⟩ : ∃ b bs, Γ.enc d2 = b :: bs := by cases henc : Γ.enc d2 with | nil => exact absurd henc (enc_ne_nil Γ hd2) | cons b bs => exact ⟨b, bs, rfl⟩ have hs : s1 = s2 := by by_contra hns rw [hb1, hb2] at h simp only [List.map_cons, List.cons_append, List.cons.injEq] at h cases s1 <;> cases s2 · exact hns rfl · exact sideSym_band_ne b1 b2 h.1 · exact sideSym_band_ne b2 b1 h.1.symm · exact hns rfl subst hs have hdd : d1 = d2 := by by_contra hnd have p1 : (Γ.enc d1).map (sideSym s1) <+: (Γ.enc d1).map (sideSym s1) ++ sidedCoordOf Γ t1 := List.prefix_append _ _ have p2 : (Γ.enc d2).map (sideSym s1) <+: (Γ.enc d1).map (sideSym s1) ++ sidedCoordOf Γ t1 := by rw [h] exact List.prefix_append _ _ rcases Nat.le_total ((Γ.enc d1).map (sideSym s1)).length ((Γ.enc d2).map (sideSym s1)).length with hle | hle · exact Γ.prefixFree hd1 hd2 hnd (map_prefix_reflect (sideSym_inj s1) (List.prefix_of_prefix_length_le p1 p2 hle)) · exact Γ.prefixFree hd2 hd1 (Ne.symm hnd) (map_prefix_reflect (sideSym_inj s1) (List.prefix_of_prefix_length_le p2 p1 hle)) subst hdd have htail := List.append_cancel_left h rw [sidedCoordOf_inj Γ (fun e he => h1 e (List.mem_cons_of_mem _ he)) (fun e he => h2 e (List.mem_cons_of_mem _ he)) htail] /-! ## The all-R fragment: the one-sided design, verbatim The erasure theorem, derived through the two marker theorems: lifting a one-sided chain to all-R sided form changes neither the coordinate's key nor the display verdict, the current datatype IS the L-uninhabited fragment. This is the Lean form of the Python all-R lockstep. -/ /-- Lift a one-sided (delta) chain to the all-R sided form. -/ def liftR (c : List ℕ) : SChain := c.map (fun d => (Side.R, d)) theorem liftR_inj {c1 c2 : List ℕ} (h : liftR c1 = liftR c2) : c1 = c2 := by have := congrArg (List.map Prod.snd) h simpa [liftR, List.map_map, Function.comp] using this theorem posSChain_liftR {c : List ℕ} (h : PosChain c) : PosSChain (liftR c) := by intro e he obtain ⟨d, hd, rfl⟩ := List.mem_map.mp he exact h d hd /-- All-R blocks are the one-sided codewords under the one-sided symbol map. -/ theorem sidedCoordOf_liftR (Γ : OrderedPrefixCode) (c : List ℕ) : sidedCoordOf Γ (liftR c) = (coordOf Γ c).map sym := by induction c with | nil => rfl | cons d ds ih => show sBlock Γ (Side.R, d) ++ sidedCoordOf Γ (liftR ds) = _ rw [ih] simp only [coordOf, List.map_append] congr 1 /-- The lifted key IS the one-sided key. -/ theorem sKey_liftR (Γ : OrderedPrefixCode) (c : List ℕ) : sKey (sidedCoordOf Γ (liftR c)) = key (coordOf Γ c) := by rw [sidedCoordOf_liftR] rfl /-- **The fragment theorem**: on all-R chains, the in-order rule IS the one-sided chain order. The current embed is the L-uninhabited fragment, as a theorem. -/ theorem schainBefore_liftR {c1 c2 : List ℕ} (h1 : PosChain c1) (h2 : PosChain c2) (hne : c1 ≠ c2) : schainBefore (liftR c1) (liftR c2) ↔ chainBefore c1 c2 := by have hlne : liftR c1 ≠ liftR c2 := fun h => hne (liftR_inj h) rw [← sdisplay_iff_schainBefore unaryCode (posSChain_liftR h1) (posSChain_liftR h2) hlne, sKey_liftR, sKey_liftR] exact display_iff_chainBefore unaryCode h1 h2 hne /-! ## In-order-interval convexity: a subtree is a display interval The Fugue intent target: everything the display places between two members of a subtree is itself in the subtree, with the node included (the empty extension), since the subtree's interval straddles it: L-descendants, the node, R-descendants. -/ theorem sEntryBefore_irrefl (e : SEntry) : ¬ sEntryBefore e e := by obtain ⟨sd, d⟩ := e cases sd <;> simp [sEntryBefore] theorem sEntryBefore_asymm {e1 e2 : SEntry} (h : sEntryBefore e1 e2) : ¬ sEntryBefore e2 e1 := by obtain ⟨s1, d1⟩ := e1 obtain ⟨s2, d2⟩ := e2 cases s1 <;> cases s2 <;> simp [sEntryBefore] at h ⊢ <;> omega /-- Inversion of the in-order rule into its three verdict shapes. -/ theorem schainBefore_inv {c1 c2 : SChain} (h : schainBefore c1 c2) : (∃ d rest, c1 = c2 ++ (Side.L, d) :: rest) ∨ (∃ d rest, c2 = c1 ++ (Side.R, d) :: rest) ∨ (∃ q e1 e2 t1 t2, sEntryBefore e1 e2 ∧ c1 = q ++ e1 :: t1 ∧ c2 = q ++ e2 :: t2) := by cases h with | extL ch d rest => exact Or.inl ⟨d, rest, rfl⟩ | extR ch d rest => exact Or.inr (Or.inl ⟨d, rest, rfl⟩) | diverge q e1 e2 t1 t2 hlt => exact Or.inr (Or.inr ⟨q, e1, e2, t1, t2, hlt, rfl, rfl⟩) /-- A shared head strips off the in-order rule. -/ theorem schainBefore_cons_strip {x : SEntry} {a b : SChain} (h : schainBefore (x :: a) (x :: b)) : schainBefore a b := by rcases schainBefore_inv h with ⟨d, rest, heq⟩ | ⟨d, rest, heq⟩ | ⟨q, e1, e2, t1, t2, hlt, ha, hb⟩ · rw [List.cons_append] at heq injection heq with h1x h2 rw [h2] exact schainBefore.extL b d rest · rw [List.cons_append] at heq injection heq with h1x h2 rw [h2] exact schainBefore.extR a d rest · cases q with | nil => simp only [List.nil_append] at ha hb injection ha with h3 h4 injection hb with h5 h6 rw [← h3, ← h5] at hlt exact absurd hlt (sEntryBefore_irrefl x) | cons y q' => rw [List.cons_append] at ha hb injection ha with hax h4 injection hb with hbx h6 rw [h4, h6] exact schainBefore.diverge q' e1 e2 t1 t2 hlt /-- Only L-headed chains display before the root. -/ theorem schainBefore_nil_right {c : SChain} (h : schainBefore c []) : ∃ d rest, c = (Side.L, d) :: rest := by rcases schainBefore_inv h with ⟨d, rest, heq⟩ | ⟨d, rest, heq⟩ | ⟨q, e1, e2, t1, t2, hlt, h1, h2⟩ · exact ⟨d, rest, by simpa using heq⟩ · simp at heq · simp at h2 /-- Only R-headed chains display after the root. -/ theorem schainBefore_nil_left {c : SChain} (h : schainBefore [] c) : ∃ d rest, c = (Side.R, d) :: rest := by rcases schainBefore_inv h with ⟨d, rest, heq⟩ | ⟨d, rest, heq⟩ | ⟨q, e1, e2, t1, t2, hlt, h1, h2⟩ · simp at heq · exact ⟨d, rest, by simpa using heq⟩ · simp at h1 /-- **In-order-interval convexity**: whatever the display places between two members of `p`'s subtree is itself in `p`'s subtree. With the empty extension allowed, the node itself is a member, the subtree interval is L-descendants, then the node, then R-descendants, with nothing foreign in between. -/ theorem schain_subtree_convex : ∀ (p : SChain) {cx cy cz : SChain}, (∃ ex, cx = p ++ ex) → (∃ ey, cy = p ++ ey) → schainBefore cx cz → schainBefore cz cy → ∃ ez, cz = p ++ ez | [], _, _, cz, _, _, _, _ => ⟨cz, rfl⟩ | e :: p', cx, cy, cz, hex, hey, h1, h2 => by obtain ⟨ex, hx⟩ := hex obtain ⟨ey, hy⟩ := hey subst hx subst hy cases cz with | nil => obtain ⟨d1, r1, hc1⟩ := schainBefore_nil_right h1 obtain ⟨d2, r2, hc2⟩ := schainBefore_nil_left h2 rw [List.cons_append] at hc1 hc2 injection hc1 with h3 h3t injection hc2 with h4 h4t rw [h3] at h4 exact absurd (congrArg Prod.fst h4) (by simp) | cons f cz' => have hfe : f = e := by by_contra hne have hEF : sEntryBefore e f := by rcases schainBefore_inv h1 with ⟨d, rest, heq⟩ | ⟨d, rest, heq⟩ | ⟨q, e1, e2, t1, t2, hlt, ha, hb⟩ · rw [List.cons_append] at heq injection heq with h3 h3t exact absurd h3.symm hne · rw [List.cons_append] at heq injection heq with h3 h3t exact absurd h3 hne · cases q with | nil => simp only [List.nil_append] at ha hb injection ha with h3 h3t injection hb with h4 h4t rw [← h3, ← h4] at hlt exact hlt | cons y q' => rw [List.cons_append] at ha hb injection ha with h3 h3t injection hb with h4 h4t exact absurd (h4.trans h3.symm) hne have hFE : sEntryBefore f e := by rcases schainBefore_inv h2 with ⟨d, rest, heq⟩ | ⟨d, rest, heq⟩ | ⟨q, e1, e2, t1, t2, hlt, ha, hb⟩ · rw [List.cons_append] at heq injection heq with h3 h3t exact absurd h3 hne · rw [List.cons_append] at heq injection heq with h3 h3t exact absurd h3.symm hne · cases q with | nil => simp only [List.nil_append] at ha hb injection ha with h3 h3t injection hb with h4 h4t rw [← h3, ← h4] at hlt exact hlt | cons y q' => rw [List.cons_append] at ha hb injection ha with h3 h3t injection hb with h4 h4t exact absurd (h3.trans h4.symm) hne exact sEntryBefore_asymm hEF hFE subst hfe obtain ⟨ez, hez⟩ := schain_subtree_convex p' ⟨ex, rfl⟩ ⟨ey, rfl⟩ (schainBefore_cons_strip h1) (schainBefore_cons_strip h2) exact ⟨ez, by rw [List.cons_append, hez]⟩ end Sal.EmbedRGA