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 . -/
231244theorem 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. -/
259274theorem 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
271286private 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. -/
698756theorem 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. -/
705765theorem 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`). -/
714774theorem 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`. -/
787851theorem 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`. -/
850919theorem infer_iff_hasType {Γ : Ctx} {e : Expr} {τ : Ty} :
0 commit comments