Skip to content

Commit 4296c0a

Browse files
committed
refactor(echo): Option B — uniform echoVal (residue,result); lower/residue as projections; capstones over Step*
https://claude.ai/code/session_01PgHpCFzwYB7Qy9L6kmR8CE
1 parent 06abb05 commit 4296c0a

1 file changed

Lines changed: 128 additions & 59 deletions

File tree

proofs/Tangle.lean

Lines changed: 128 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
-- Models the core type system from docs/spec/FORMAL-SEMANTICS.md:
55
-- - Syntax: Expr inductive with Num, Str, Bool, Identity, BraidLit,
66
-- Compose (.), Tensor (|), Pipeline (>>), Close, Add, Eq, and the echo
7-
-- constructors EchoClose, Lower, Residue (structured loss)
7+
-- constructors EchoClose, Lower, Residue, EchoVal (structured loss)
88
-- - Typing: HasType inductive relation covering T-Num, T-Str, T-Bool,
99
-- T-Identity, T-Braid, T-Compose-Word, T-Tensor-Word, T-Pipeline,
1010
-- T-Close-Word, T-Add-Num, T-Eq-Word, T-Eq-Num, T-Eq-Str, and the echo
11-
-- rules T-Echo-Close, T-Lower, T-Residue
12-
-- - Semantics: Small-step Step relation (31 rules incl. echo)
11+
-- rules T-Echo-Close, T-Lower, T-Residue, T-Echo-Val
12+
-- - Semantics: Small-step Step relation (38 rules incl. echo)
1313
--
1414
-- Theorems proven:
1515
-- 1. Progress: well-typed closed terms are values or can step
@@ -82,9 +82,12 @@ inductive Expr where
8282
-- Echo types (structured loss). `close` is TANGLE's canonical lossy map
8383
-- (Word[n] ↠ Word[0]); these constructors give it a residue-retaining
8484
-- variant and the two projections, mirroring echo-types' fibre/residue API.
85-
| echoClose : Expr → Expr -- echo-preserving closure (echo-intro for `close`)
85+
-- A formed echo is the value `echoVal residue result`; `echoClose` is the
86+
-- redex that reduces into one, and `lower`/`residue` are its two projections.
87+
| echoClose : Expr → Expr -- echo-preserving closure (redex → echoVal)
8688
| lower : Expr → Expr -- project an echo to its result (forget residue)
8789
| residue : Expr → Expr -- project an echo to its residue (recover witness)
90+
| echoVal : Expr → Expr → Expr -- formed echo value: (residue, result)
8891
deriving DecidableEq, Repr
8992

9093
/-- Value predicate: fully reduced expressions. -/
@@ -94,7 +97,7 @@ inductive IsValue : Expr → Prop where
9497
| boolLit : ∀ b, IsValue (.boolLit b)
9598
| identity : IsValue .identity
9699
| braidLit : ∀ gs, IsValue (.braidLit gs)
97-
| echoClose : ∀ {v}, IsValue v → IsValue (.echoClose v) -- a formed echo (residue v retained)
100+
| echoVal : ∀ {r v}, IsValue r → IsValue v → IsValue (.echoVal r v) -- a formed echo value (residue r, result v)
98101

99102
-- ═══════════════════════════════════════════════════════════════════════
100103
-- WIDTH
@@ -169,6 +172,10 @@ inductive HasType : Ctx → Expr → Ty → Prop where
169172
| tResidue (Γ : Ctx) (e : Expr) (ρ τ : Ty) : -- [T-Residue] (recover witness)
170173
HasType Γ e (.echo ρ τ) →
171174
HasType Γ (.residue e) ρ
175+
| tEchoVal (Γ : Ctx) (r v : Expr) (ρ τ : Ty) : -- [T-Echo-Val]
176+
HasType Γ r ρ →
177+
HasType Γ v τ →
178+
HasType Γ (.echoVal r v) (.echo ρ τ)
172179

173180
-- ═══════════════════════════════════════════════════════════════════════
174181
-- SMALL-STEP SEMANTICS
@@ -213,24 +220,32 @@ inductive Step : Expr → Expr → Prop where
213220
| eqIdId : Step (.eq .identity .identity) (.boolLit true)
214221
| eqIdBraid : Step (.eq .identity (.braidLit gs)) (.boolLit (gs == []))
215222
| eqBraidId : Step (.eq (.braidLit gs) .identity) (.boolLit (gs == []))
216-
-- Echo (structured loss): closure that retains its residue, and the two
217-
-- projections. `lower` collapses to the codomain point (identity : Word[0]);
218-
-- `residue` recovers the witness braid — the fibre element echo-types keeps.
223+
-- Echo (structured loss): `echoClose` is a redex that reduces into a formed
224+
-- echo value `echoVal residue result`; `lower`/`residue` are the two generic
225+
-- projections off a formed echo value. `lower` yields the result component
226+
-- (the codomain point identity : Word[0]); `residue` recovers the witness
227+
-- braid retained in the residue component — the fibre element echo-types keeps.
219228
| echoCloseStep : Step e e' → Step (.echoClose e) (.echoClose e')
229+
| echoCloseWord : Step (.echoClose (.braidLit gs)) (.echoVal (.braidLit gs) .identity)
230+
| echoCloseId : Step (.echoClose .identity) (.echoVal .identity .identity)
231+
| echoValLeft : Step r r' → Step (.echoVal r v) (.echoVal r' v)
232+
| echoValRight : IsValue r → Step v v' → Step (.echoVal r v) (.echoVal r v')
220233
| lowerStep : Step e e' → Step (.lower e) (.lower e')
221-
| lowerEcho : IsValue v → Step (.lower (.echoClose v)) .identity
234+
| lowerVal : IsValue r → IsValue v → Step (.lower (.echoVal r v)) v
222235
| residueStep : Step e e' → Step (.residue e) (.residue e')
223-
| residueEcho : IsValue v → Step (.residue (.echoClose v)) v
236+
| residueVal : IsValue r → IsValue v → Step (.residue (.echoVal r v)) r
224237

225238
-- ═══════════════════════════════════════════════════════════════════════
226239
-- LEMMAS
227240
-- ═══════════════════════════════════════════════════════════════════════
228241

229242
/-- Values are in normal form. Recursive on the value structure because a
230-
formed echo `echoClose v` is a value exactly when its residue `v` is. -/
243+
formed echo value `echoVal r v` is a value exactly when both components are. -/
231244
theorem value_no_step {e e' : Expr} (hv : IsValue e) (hs : Step e e') : False := by
232245
induction hv generalizing e' with
233-
| echoClose _ ih => cases hs with | echoCloseStep h => exact ih h
246+
| echoVal _ _ ihr ihv => cases hs with
247+
| echoValLeft h => exact ihr h
248+
| echoValRight _ h => exact ihv h
234249
| _ => cases hs
235250

236251
/-- Canonical forms for Num. -/
@@ -251,21 +266,21 @@ theorem canonical_word : IsValue e → HasType [] e (.word n) →
251266
| boolLit => cases ht
252267
| identity => left; cases ht with | tIdentity => exact ⟨rfl, rfl⟩
253268
| braidLit gs => right; cases ht with | tBraid => exact ⟨gs, rfl, rfl⟩
254-
| echoClose _ => cases ht
269+
| echoVal _ _ => cases ht
255270

256-
/-- Canonical forms for Echo[ρ, τ]: a value of echo type is a formed echo
257-
`echoClose v` whose residue `v` is itself a value. This is the canonical
258-
form that lets `lower`/`residue` make progress. -/
271+
/-- Canonical forms for Echo[ρ, τ]: a value of echo type is a formed echo value
272+
`echoVal r v` whose residue `r` and result `v` are themselves values. This
273+
is the canonical form that lets `lower`/`residue` make progress. -/
259274
theorem canonical_echo : IsValue e → HasType [] e (.echo ρ τ) →
260-
∃ v, e = .echoClose v ∧ IsValue v := by
275+
r v, e = .echoVal r v ∧ IsValue r ∧ IsValue v := by
261276
intro hv ht
262277
cases hv with
263278
| num => cases ht
264279
| str => cases ht
265280
| boolLit => cases ht
266281
| identity => cases ht
267282
| braidLit => cases ht
268-
| echoClose hv => exact ⟨_, rfl, hv⟩
283+
| echoVal hr hv => exact ⟨_, _, rfl, hr, hv⟩
269284

270285
-- Width distribution lemmas
271286
private theorem foldl_max_init (gs : List Generator) (a : Nat) :
@@ -389,21 +404,32 @@ theorem progress : HasType [] e τ → IsValue e ∨ ∃ e', Step e e' := by
389404
· exact ⟨_, .eqRight hv₁ hs₂⟩
390405
· exact ⟨_, .eqLeft hs₁⟩
391406
| tEchoClose _ n h =>
392-
-- `echoClose e` is a value once `e` is (the residue is retained); else it steps.
407+
-- `echoClose e` is always a redex: it reduces into a formed echo value.
408+
right
393409
rcases progress h with hv | ⟨e', hs⟩
394-
· exact .inl (.echoClose hv)
395-
· exact .inr ⟨_, .echoCloseStep hs⟩
410+
· rcases canonical_word hv h with ⟨rfl, _⟩ | ⟨gs, rfl, _⟩
411+
· exact ⟨_, .echoCloseId⟩
412+
· exact ⟨_, .echoCloseWord⟩
413+
· exact ⟨_, .echoCloseStep hs⟩
414+
| tEchoVal _ _ ρ τ hr hv =>
415+
-- `echoVal r v` is a value iff both r and v are; otherwise the relevant
416+
-- component steps under `echoValLeft` / `echoValRight`.
417+
rcases progress hr with hvr | ⟨r', hsr⟩
418+
· rcases progress hv with hvv | ⟨v', hsv⟩
419+
· exact .inl (.echoVal hvr hvv)
420+
· exact .inr ⟨_, .echoValRight hvr hsv⟩
421+
· exact .inr ⟨_, .echoValLeft hsr⟩
396422
| tLower _ ρ τ h =>
397423
right
398424
rcases progress h with hv | ⟨e', hs⟩
399-
· obtain ⟨v, rfl, hv'⟩ := canonical_echo hv h
400-
exact ⟨_, .lowerEcho hv'
425+
· obtain ⟨r, v, rfl, hr, hvv⟩ := canonical_echo hv h
426+
exact ⟨_, .lowerVal hr hvv
401427
· exact ⟨_, .lowerStep hs⟩
402428
| tResidue _ ρ τ h =>
403429
right
404430
rcases progress h with hv | ⟨e', hs⟩
405-
· obtain ⟨v, rfl, hv'⟩ := canonical_echo hv h
406-
exact ⟨_, .residueEcho hv'
431+
· obtain ⟨r, v, rfl, hr, hvv⟩ := canonical_echo hv h
432+
exact ⟨_, .residueVal hr hvv
407433
· exact ⟨_, .residueStep hs⟩
408434

409435
-- ═══════════════════════════════════════════════════════════════════════
@@ -500,21 +526,30 @@ theorem preservation : HasType [] e τ → Step e e' → HasType [] e' τ := by
500526
| tEqWord => exact .tBool _ _
501527
| tEqNum _ _ _ h₁ => cases h₁
502528
| tEqStr _ _ _ h₁ => cases h₁
503-
-- Echo congruence preserves the (residue Word[n], result Word[0]) echo type.
529+
-- Echo congruence preserves types; `echoClose` reduces into a formed echo
530+
-- value `echoVal residue result`; `lower`/`residue` project off it.
504531
| echoCloseStep hs ih =>
505532
cases ht with | tEchoClose _ n h => exact .tEchoClose _ _ n (ih h)
533+
| echoCloseWord =>
534+
cases ht with | tEchoClose _ n h =>
535+
cases h with | tBraid => exact .tEchoVal _ _ _ _ _ (.tBraid _ _) (.tIdentity _)
536+
| echoCloseId =>
537+
cases ht with | tEchoClose _ n h =>
538+
cases h with | tIdentity => exact .tEchoVal _ _ _ _ _ (.tIdentity _) (.tIdentity _)
539+
| echoValLeft hs ih =>
540+
cases ht with | tEchoVal _ _ _ _ hr hv => exact .tEchoVal _ _ _ _ _ (ih hr) hv
541+
| echoValRight _ hs ih =>
542+
cases ht with | tEchoVal _ _ _ _ hr hv => exact .tEchoVal _ _ _ _ _ hr (ih hv)
506543
| lowerStep hs ih =>
507544
cases ht with | tLower _ _ _ h => exact .tLower _ _ _ _ (ih h)
545+
| lowerVal _ _ =>
546+
cases ht with | tLower _ _ _ h =>
547+
cases h with | tEchoVal _ _ _ _ hr hv => exact hv
508548
| residueStep hs ih =>
509549
cases ht with | tResidue _ _ _ h => exact .tResidue _ _ _ _ (ih h)
510-
-- `lower` yields the codomain point identity : Word[0]; the echo type forces τ = Word[0].
511-
| lowerEcho hv =>
512-
cases ht with | tLower _ _ _ h =>
513-
cases h with | tEchoClose _ n _ => exact .tIdentity _
514-
-- `residue` recovers the witness, whose type is exactly the echo's residue type.
515-
| residueEcho hv =>
550+
| residueVal _ _ =>
516551
cases ht with | tResidue _ _ _ h =>
517-
cases h with | tEchoClose _ n h' => exact h'
552+
cases h with | tEchoVal _ _ _ _ hr hv => exact hr
518553

519554
-- ═══════════════════════════════════════════════════════════════════════
520555
-- THEOREM 3: DETERMINISM
@@ -650,21 +685,35 @@ theorem determinism : Step e e₁ → Step e e₂ → e₁ = e₂ := by
650685
| eqRight _ h => exact absurd h (value_no_step .identity)
651686
| eqBraidId => rfl
652687
-- Echo: congruence is deterministic by IH; the computation rules fire only
653-
-- on a formed echo (a value), so they never race with their congruence rule.
688+
-- on a formed echo value's component, so they never race their congruence.
654689
| echoCloseStep hs ih => cases hs₂ with
655690
| echoCloseStep h => exact congrArg Expr.echoClose (ih h)
691+
| echoCloseWord => exact absurd hs (value_no_step (.braidLit _))
692+
| echoCloseId => exact absurd hs (value_no_step .identity)
693+
| echoCloseWord => cases hs₂ with
694+
| echoCloseStep h => exact absurd h (value_no_step (.braidLit _))
695+
| echoCloseWord => rfl
696+
| echoCloseId => cases hs₂ with
697+
| echoCloseStep h => exact absurd h (value_no_step .identity)
698+
| echoCloseId => rfl
699+
| echoValLeft hs ih => cases hs₂ with
700+
| echoValLeft h => exact congrArg (Expr.echoVal · _) (ih h)
701+
| echoValRight hr _ => exact absurd hs (value_no_step hr)
702+
| echoValRight hr hs ih => cases hs₂ with
703+
| echoValLeft h => exact absurd h (value_no_step hr)
704+
| echoValRight _ h => exact congrArg (Expr.echoVal _ ·) (ih h)
656705
| lowerStep hs ih => cases hs₂ with
657706
| lowerStep h => exact congrArg Expr.lower (ih h)
658-
| lowerEcho hv => exact absurd hs (value_no_step (.echoClose hv))
707+
| lowerVal hr hv => exact absurd hs (value_no_step (.echoVal hr hv))
708+
| lowerVal hr hv => cases hs₂ with
709+
| lowerStep h => exact absurd h (value_no_step (.echoVal hr hv))
710+
| lowerVal _ _ => rfl
659711
| residueStep hs ih => cases hs₂ with
660712
| residueStep h => exact congrArg Expr.residue (ih h)
661-
| residueEcho hv => exact absurd hs (value_no_step (.echoClose hv))
662-
| lowerEcho hv => cases hs₂ with
663-
| lowerStep h => exact absurd h (value_no_step (.echoClose hv))
664-
| lowerEcho _ => rfl
665-
| residueEcho hv => cases hs₂ with
666-
| residueStep h => exact absurd h (value_no_step (.echoClose hv))
667-
| residueEcho _ => rfl
713+
| residueVal hr hv => exact absurd hs (value_no_step (.echoVal hr hv))
714+
| residueVal hr hv => cases hs₂ with
715+
| residueStep h => exact absurd h (value_no_step (.echoVal hr hv))
716+
| residueVal _ _ => rfl
668717

669718
-- ═══════════════════════════════════════════════════════════════════════
670719
-- COROLLARY: TYPE SAFETY
@@ -682,40 +731,51 @@ theorem type_safety (ht : HasType [] e τ) (hs : Step e e') :
682731
-- `close : Word[n] → Word[0]` is TANGLE's canonical lossy map: it collapses
683732
-- every braid to the identity, discarding the word. This mirrors echo-types'
684733
-- `collapse : Bool → ⊤` (hyperpolymath/echo-types, EchoResidue.agda). The echo
685-
-- constructors above (`echoClose`/`lower`/`residue`, type former `Ty.echo`)
686-
-- make that loss *recoverable in the type system*: the residue `Word[n]` is
687-
-- retained and projected back out. Progress, Preservation, Determinism, and
688-
-- Type Safety (proved above) all cover these constructors — echo types are not
689-
-- a bolt-on, they are part of the metatheory.
734+
-- constructors above (`echoClose`/`lower`/`residue`/`echoVal`, type former
735+
-- `Ty.echo`) make that loss *recoverable in the type system*: `echoClose`
736+
-- reduces into a formed echo value `echoVal residue result` from which the
737+
-- residue `Word[n]` is projected back out. Progress, Preservation,
738+
-- Determinism, and Type Safety (proved above) all cover these constructors —
739+
-- echo types are not a bolt-on, they are part of the metatheory.
690740
--
691741
-- The three theorems below are the TANGLE instantiation of the echo-types
692742
-- `no-section` / `sigma-distinguishes` results: `lower` collapses, `residue`
693-
-- distinguishes.
743+
-- distinguishes. They are stated over `StepStar` (multi-step reduction) since
744+
-- `echoClose` now takes two steps to project: reduce to `echoVal`, then project.
745+
746+
/-- Reflexive-transitive closure of `Step` (multi-step reduction). -/
747+
inductive StepStar : Expr → Expr → Prop where
748+
| refl : StepStar e e
749+
| head : Step e e' → StepStar e' e'' → StepStar e e''
694750

695751
/-- `lower ∘ echoClose` is the collapsing map: every closed braid lowers to the
696-
identity (the single `Word[0]` value). This is `close` re-derived through the
697-
echo — the step that loses information. -/
752+
identity (the single `Word[0]` value). `echoClose` first reduces into a
753+
formed echo value `echoVal (braidLit gs) identity`, then `lower` projects out
754+
the result component `identity` — `close` re-derived through the echo, the
755+
step that loses information. -/
698756
theorem echo_lower_collapses (gs : List Generator) :
699-
Step (.lower (.echoClose (.braidLit gs))) .identity :=
700-
.lowerEcho (.braidLit gs)
757+
StepStar (.lower (.echoClose (.braidLit gs))) .identity :=
758+
.head (.lowerStep .echoCloseWord) (.head (.lowerVal (.braidLit gs) .identity) .refl)
701759

702760
/-- `residue ∘ echoClose` recovers the witness: the original braid is retained in
703-
the residue. This is echo-types' `proj₁`/`echo-intro` round-trip — the lossy
704-
`close` becomes reversible once its echo is carried. -/
761+
the residue. `echoClose` reduces into `echoVal (braidLit gs) identity`, then
762+
`residue` projects out the residue component `braidLit gs`. This is
763+
echo-types' `proj₁`/`echo-intro` round-trip — the lossy `close` becomes
764+
reversible once its echo is carried. -/
705765
theorem echo_residue_recovers (gs : List Generator) :
706-
Step (.residue (.echoClose (.braidLit gs))) (.braidLit gs) :=
707-
.residueEcho (.braidLit gs)
766+
StepStar (.residue (.echoClose (.braidLit gs))) (.braidLit gs) :=
767+
.head (.residueStep .echoCloseWord) (.head (.residueVal (.braidLit gs) .identity) .refl)
708768

709769
/-- **Echo distinguishes what `close` collapses.** Two distinct braids close to
710770
the *same* identity (the residue forgotten by `lower`), yet their echoes carry
711771
distinct residues (recovered by `residue`). This is the TANGLE form of
712772
echo-types' non-injectivity barrier (`collapse-residue-same` paired with
713773
`echo-true≢echo-false` / `no-section-collapse-to-residue`). -/
714774
theorem echo_distinguishes_collapsed {gs₁ gs₂ : List Generator} (h : gs₁ ≠ gs₂) :
715-
(Step (.lower (.echoClose (.braidLit gs₁))) .identity ∧
716-
Step (.lower (.echoClose (.braidLit gs₂))) .identity) ∧
775+
(StepStar (.lower (.echoClose (.braidLit gs₁))) .identity ∧
776+
StepStar (.lower (.echoClose (.braidLit gs₂))) .identity) ∧
717777
(Expr.braidLit gs₁ ≠ Expr.braidLit gs₂) :=
718-
⟨⟨.lowerEcho (.braidLit gs₁), .lowerEcho (.braidLit gs₂)⟩,
778+
⟨⟨echo_lower_collapses gs₁, echo_lower_collapses gs₂⟩,
719779
fun heq => h (Expr.braidLit.inj heq)⟩
720780

721781
/-- The echo round-trip is type-safe: from `e : Word[n]`, `residue` recovers a
@@ -782,6 +842,10 @@ def infer (Γ : Ctx) : Expr → Option Ty
782842
match infer Γ e with
783843
| some (.echo ρ _) => some ρ
784844
| _ => none
845+
| .echoVal r v =>
846+
match infer Γ r, infer Γ v with
847+
| some ρ, some τ => some (.echo ρ τ)
848+
| _, _ => none
785849

786850
/-- **Completeness**: every typing derivation is computed by `infer`. -/
787851
theorem infer_complete {Γ : Ctx} {e : Expr} {τ : Ty} :
@@ -845,6 +909,11 @@ theorem infer_sound {Γ : Ctx} {e : Expr} {τ : Ty} :
845909
intro h; simp only [infer] at h; split at h
846910
next ρ τ' he => injection h with h; subst h; exact .tResidue _ _ ρ τ' (ih he)
847911
all_goals simp at h
912+
| echoVal r v ihr ihv =>
913+
intro h; simp only [infer] at h; split at h
914+
next ρ τ' he_r he_v =>
915+
injection h with h; subst h; exact .tEchoVal _ _ _ ρ τ' (ihr he_r) (ihv he_v)
916+
all_goals simp at h
848917

849918
/-- **Decidability of type checking** (TG-2): `infer` decides `HasType`. -/
850919
theorem infer_iff_hasType {Γ : Ctx} {e : Expr} {τ : Ty} :

0 commit comments

Comments
 (0)