Skip to content

Commit 60aa098

Browse files
claudehyperpolymath
authored andcommitted
feat(echo): product type + echoAdd — structured loss for arithmetic (residue = summand pair)
https://claude.ai/code/session_01PgHpCFzwYB7Qy9L6kmR8CE
1 parent 5821214 commit 60aa098

1 file changed

Lines changed: 186 additions & 7 deletions

File tree

proofs/Tangle.lean

Lines changed: 186 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
--
44
-- Models the core type system from docs/spec/FORMAL-SEMANTICS.md:
55
-- - Syntax: Expr inductive with Num, Str, Bool, Identity, BraidLit,
6-
-- Compose (.), Tensor (|), Pipeline (>>), Close, Add, Eq, and the echo
7-
-- constructors EchoClose, Lower, Residue, EchoVal (structured loss)
6+
-- Compose (.), Tensor (|), Pipeline (>>), Close, Add, Eq, the echo
7+
-- constructors EchoClose, Lower, Residue, EchoVal (structured loss), and
8+
-- the product constructors Pair, Fst, Snd, EchoAdd
89
-- - Typing: HasType inductive relation covering T-Num, T-Str, T-Bool,
910
-- T-Identity, T-Braid, T-Compose-Word, T-Tensor-Word, T-Pipeline,
10-
-- 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, T-Echo-Val
12-
-- - Semantics: Small-step Step relation (38 rules incl. echo)
11+
-- T-Close-Word, T-Add-Num, T-Eq-Word, T-Eq-Num, T-Eq-Str, the echo
12+
-- rules T-Echo-Close, T-Lower, T-Residue, T-Echo-Val, and the product
13+
-- rules T-Pair, T-Fst, T-Snd, T-Echo-Add
14+
-- - Semantics: Small-step Step relation (47 rules incl. echo + product)
1315
--
1416
-- Theorems proven:
1517
-- 1. Progress: well-typed closed terms are values or can step
@@ -23,9 +25,13 @@
2325
-- constructors `echoClose`/`lower`/`residue` integrate echo-types
2426
-- (hyperpolymath/echo-types: `Echo f y := Σ (x : A), f x ≡ y`) directly into
2527
-- the type system: closing a braid through an echo retains the residue, so the
26-
-- otherwise-irreversible `close` becomes reversible at the type level. See the
28+
-- otherwise-irreversible `close` becomes reversible at the type level. The
29+
-- product type `Ty.prod ρ σ` carries a second lossy operation, `echoAdd`:
30+
-- ordinary `add` discards which two numbers were summed, but `echoAdd` keeps
31+
-- the summand pair as its residue (residue type `Num × Num`, result `Num`), so
32+
-- distinct summands that collapse to the same sum stay distinguishable. See the
2733
-- §ECHO-TYPES section at the foot of the file for the residue-recovery and
28-
-- non-injectivity theorems.
34+
-- non-injectivity theorems (both the `close` and `echoAdd` forms).
2935
--
3036
-- Note on T-Let: the let binding requires a generalized de Bruijn substitution
3137
-- lemma (standard POPLmark machinery); tracked as TG-1. The fragment here
@@ -62,6 +68,7 @@ inductive Ty where
6268
-- (hyperpolymath/echo-types, Echo.agda): ρ is the
6369
-- residue (domain witness x : A), τ is the result
6470
-- (codomain point y). See §ECHO-TYPES below.
71+
| prod : Ty → Ty → Ty -- product (pair) type ρ × σ; residue carrier for lossy binary ops
6572
deriving DecidableEq, Repr
6673

6774
/-- Core expression AST. Mirrors the OCaml AST in compiler/lib/ast.ml.
@@ -88,6 +95,10 @@ inductive Expr where
8895
| lower : Expr → Expr -- project an echo to its result (forget residue)
8996
| residue : Expr → Expr -- project an echo to its residue (recover witness)
9097
| echoVal : Expr → Expr → Expr -- formed echo value: (residue, result)
98+
| pair : Expr → Expr → Expr -- product introduction
99+
| fst : Expr → Expr -- first projection
100+
| snd : Expr → Expr -- second projection
101+
| echoAdd : Expr → Expr → Expr -- echo-preserving addition (residue = pair of summands)
91102
deriving DecidableEq, Repr
92103

93104
/-- Value predicate: fully reduced expressions. -/
@@ -98,6 +109,7 @@ inductive IsValue : Expr → Prop where
98109
| identity : IsValue .identity
99110
| braidLit : ∀ gs, IsValue (.braidLit gs)
100111
| echoVal : ∀ {r v}, IsValue r → IsValue v → IsValue (.echoVal r v) -- a formed echo value (residue r, result v)
112+
| pair : ∀ {a b}, IsValue a → IsValue b → IsValue (.pair a b)
101113

102114
-- ═══════════════════════════════════════════════════════════════════════
103115
-- WIDTH
@@ -176,6 +188,15 @@ inductive HasType : Ctx → Expr → Ty → Prop where
176188
HasType Γ r ρ →
177189
HasType Γ v τ →
178190
HasType Γ (.echoVal r v) (.echo ρ τ)
191+
| tPair (Γ : Ctx) (a b : Expr) (α β : Ty) : -- [T-Pair]
192+
HasType Γ a α → HasType Γ b β → HasType Γ (.pair a b) (.prod α β)
193+
| tFst (Γ : Ctx) (e : Expr) (α β : Ty) : -- [T-Fst]
194+
HasType Γ e (.prod α β) → HasType Γ (.fst e) α
195+
| tSnd (Γ : Ctx) (e : Expr) (α β : Ty) : -- [T-Snd]
196+
HasType Γ e (.prod α β) → HasType Γ (.snd e) β
197+
| tEchoAdd (Γ : Ctx) (e₁ e₂ : Expr) : -- [T-Echo-Add]
198+
HasType Γ e₁ .num → HasType Γ e₂ .num →
199+
HasType Γ (.echoAdd e₁ e₂) (.echo (.prod .num .num) .num)
179200

180201
-- ═══════════════════════════════════════════════════════════════════════
181202
-- SMALL-STEP SEMANTICS
@@ -234,6 +255,18 @@ inductive Step : Expr → Expr → Prop where
234255
| lowerVal : IsValue r → IsValue v → Step (.lower (.echoVal r v)) v
235256
| residueStep : Step e e' → Step (.residue e) (.residue e')
236257
| residueVal : IsValue r → IsValue v → Step (.residue (.echoVal r v)) r
258+
-- Product: congruence + projections
259+
| pairLeft : Step a a' → Step (.pair a b) (.pair a' b)
260+
| pairRight : IsValue a → Step b b' → Step (.pair a b) (.pair a b')
261+
| fstStep : Step e e' → Step (.fst e) (.fst e')
262+
| fstPair : IsValue a → IsValue b → Step (.fst (.pair a b)) a
263+
| sndStep : Step e e' → Step (.snd e) (.snd e')
264+
| sndPair : IsValue a → IsValue b → Step (.snd (.pair a b)) b
265+
-- Echo-preserving addition: residue retains the summand pair; result is the sum.
266+
| echoAddLeft : Step e₁ e₁' → Step (.echoAdd e₁ e₂) (.echoAdd e₁' e₂)
267+
| echoAddRight : IsValue e₁ → Step e₂ e₂' → Step (.echoAdd e₁ e₂) (.echoAdd e₁ e₂')
268+
| echoAddNums : Step (.echoAdd (.num n₁) (.num n₂))
269+
(.echoVal (.pair (.num n₁) (.num n₂)) (.num (n₁ + n₂)))
237270

238271
-- ═══════════════════════════════════════════════════════════════════════
239272
-- LEMMAS
@@ -246,6 +279,9 @@ theorem value_no_step {e e' : Expr} (hv : IsValue e) (hs : Step e e') : False :=
246279
| echoVal _ _ ihr ihv => cases hs with
247280
| echoValLeft h => exact ihr h
248281
| echoValRight _ h => exact ihv h
282+
| pair _ _ iha ihb => cases hs with
283+
| pairLeft h => exact iha h
284+
| pairRight _ h => exact ihb h
249285
| _ => cases hs
250286

251287
/-- Canonical forms for Num. -/
@@ -267,6 +303,7 @@ theorem canonical_word : IsValue e → HasType [] e (.word n) →
267303
| identity => left; cases ht with | tIdentity => exact ⟨rfl, rfl⟩
268304
| braidLit gs => right; cases ht with | tBraid => exact ⟨gs, rfl, rfl⟩
269305
| echoVal _ _ => cases ht
306+
| pair _ _ => cases ht
270307

271308
/-- Canonical forms for Echo[ρ, τ]: a value of echo type is a formed echo value
272309
`echoVal r v` whose residue `r` and result `v` are themselves values. This
@@ -281,6 +318,22 @@ theorem canonical_echo : IsValue e → HasType [] e (.echo ρ τ) →
281318
| identity => cases ht
282319
| braidLit => cases ht
283320
| echoVal hr hv => exact ⟨_, _, rfl, hr, hv⟩
321+
| pair _ _ => cases ht
322+
323+
/-- Canonical forms for products: a value of product type is a `pair a b` whose
324+
components `a` and `b` are themselves values. This is the canonical form
325+
that lets `fst`/`snd` make progress. -/
326+
theorem canonical_prod : IsValue e → HasType [] e (.prod α β) →
327+
∃ a b, e = .pair a b ∧ IsValue a ∧ IsValue b := by
328+
intro hv ht
329+
cases hv with
330+
| num => cases ht
331+
| str => cases ht
332+
| boolLit => cases ht
333+
| identity => cases ht
334+
| braidLit => cases ht
335+
| echoVal _ _ => cases ht
336+
| pair ha hb => exact ⟨_, _, rfl, ha, hb⟩
284337

285338
-- Width distribution lemmas
286339
private theorem foldl_max_init (gs : List Generator) (a : Nat) :
@@ -431,6 +484,33 @@ theorem progress : HasType [] e τ → IsValue e ∨ ∃ e', Step e e' := by
431484
· obtain ⟨r, v, rfl, hr, hvv⟩ := canonical_echo hv h
432485
exact ⟨_, .residueVal hr hvv⟩
433486
· exact ⟨_, .residueStep hs⟩
487+
| tPair _ _ α β ha hb =>
488+
rcases progress ha with hva | ⟨a', hsa⟩
489+
· rcases progress hb with hvb | ⟨b', hsb⟩
490+
· exact .inl (.pair hva hvb)
491+
· exact .inr ⟨_, .pairRight hva hsb⟩
492+
· exact .inr ⟨_, .pairLeft hsa⟩
493+
| tFst _ α β h =>
494+
right
495+
rcases progress h with hv | ⟨e', hs⟩
496+
· obtain ⟨a, b, rfl, ha, hb⟩ := canonical_prod hv h
497+
exact ⟨_, .fstPair ha hb⟩
498+
· exact ⟨_, .fstStep hs⟩
499+
| tSnd _ α β h =>
500+
right
501+
rcases progress h with hv | ⟨e', hs⟩
502+
· obtain ⟨a, b, rfl, ha, hb⟩ := canonical_prod hv h
503+
exact ⟨_, .sndPair ha hb⟩
504+
· exact ⟨_, .sndStep hs⟩
505+
| tEchoAdd _ _ h₁ h₂ =>
506+
right
507+
rcases progress h₁ with hv₁ | ⟨e₁', hs₁⟩
508+
· rcases progress h₂ with hv₂ | ⟨e₂', hs₂⟩
509+
· obtain ⟨n₁, rfl⟩ := canonical_num hv₁ h₁
510+
obtain ⟨n₂, rfl⟩ := canonical_num hv₂ h₂
511+
exact ⟨_, .echoAddNums⟩
512+
· exact ⟨_, .echoAddRight hv₁ hs₂⟩
513+
· exact ⟨_, .echoAddLeft hs₁⟩
434514

435515
-- ═══════════════════════════════════════════════════════════════════════
436516
-- THEOREM 2: PRESERVATION
@@ -550,6 +630,20 @@ theorem preservation : HasType [] e τ → Step e e' → HasType [] e' τ := by
550630
| residueVal _ _ =>
551631
cases ht with | tResidue _ _ _ h =>
552632
cases h with | tEchoVal _ _ _ _ hr hv => exact hr
633+
-- Product: congruence preserves the product type; projections recover the
634+
-- component types. `echoAdd` reduces into a formed echo value whose residue
635+
-- is the (num, num) summand pair and whose result is the num sum.
636+
| pairLeft hs ih => cases ht with | tPair _ _ α β ha hb => exact .tPair _ _ _ _ _ (ih ha) hb
637+
| pairRight _ hs ih => cases ht with | tPair _ _ α β ha hb => exact .tPair _ _ _ _ _ ha (ih hb)
638+
| fstStep hs ih => cases ht with | tFst _ α β h => exact .tFst _ _ _ _ (ih h)
639+
| fstPair _ _ => cases ht with | tFst _ α β h => cases h with | tPair _ _ _ _ ha hb => exact ha
640+
| sndStep hs ih => cases ht with | tSnd _ α β h => exact .tSnd _ _ _ _ (ih h)
641+
| sndPair _ _ => cases ht with | tSnd _ α β h => cases h with | tPair _ _ _ _ ha hb => exact hb
642+
| echoAddLeft hs ih => cases ht with | tEchoAdd _ _ h₁ h₂ => exact .tEchoAdd _ _ _ (ih h₁) h₂
643+
| echoAddRight _ hs ih => cases ht with | tEchoAdd _ _ h₁ h₂ => exact .tEchoAdd _ _ _ h₁ (ih h₂)
644+
| echoAddNums =>
645+
cases ht with | tEchoAdd _ _ h₁ h₂ =>
646+
exact .tEchoVal _ _ _ _ _ (.tPair _ _ _ _ _ (.tNum _ _) (.tNum _ _)) (.tNum _ _)
553647

554648
-- ═══════════════════════════════════════════════════════════════════════
555649
-- THEOREM 3: DETERMINISM
@@ -714,6 +808,39 @@ theorem determinism : Step e e₁ → Step e e₂ → e₁ = e₂ := by
714808
| residueVal hr hv => cases hs₂ with
715809
| residueStep h => exact absurd h (value_no_step (.echoVal hr hv))
716810
| residueVal _ _ => rfl
811+
-- Product: congruence is deterministic by IH; projections fire only on a
812+
-- formed pair value, so they never race their congruence rule. `echoAdd`
813+
-- computes only on two `num` values.
814+
| pairLeft hs ih => cases hs₂ with
815+
| pairLeft h => exact congrArg (Expr.pair · _) (ih h)
816+
| pairRight hva _ => exact absurd hs (value_no_step hva)
817+
| pairRight hva hs ih => cases hs₂ with
818+
| pairLeft h => exact absurd h (value_no_step hva)
819+
| pairRight _ h => exact congrArg (Expr.pair _ ·) (ih h)
820+
| fstStep hs ih => cases hs₂ with
821+
| fstStep h => exact congrArg Expr.fst (ih h)
822+
| fstPair ha hb => exact absurd hs (value_no_step (.pair ha hb))
823+
| fstPair ha hb => cases hs₂ with
824+
| fstStep h => exact absurd h (value_no_step (.pair ha hb))
825+
| fstPair _ _ => rfl
826+
| sndStep hs ih => cases hs₂ with
827+
| sndStep h => exact congrArg Expr.snd (ih h)
828+
| sndPair ha hb => exact absurd hs (value_no_step (.pair ha hb))
829+
| sndPair ha hb => cases hs₂ with
830+
| sndStep h => exact absurd h (value_no_step (.pair ha hb))
831+
| sndPair _ _ => rfl
832+
| echoAddLeft hs ih => cases hs₂ with
833+
| echoAddLeft h => exact congrArg (Expr.echoAdd · _) (ih h)
834+
| echoAddRight hv₁ _ => exact absurd hs (value_no_step hv₁)
835+
| echoAddNums => exact absurd hs (value_no_step (.num _))
836+
| echoAddRight hv₁ hs ih => cases hs₂ with
837+
| echoAddLeft h => exact absurd h (value_no_step hv₁)
838+
| echoAddRight _ h => exact congrArg (Expr.echoAdd _ ·) (ih h)
839+
| echoAddNums => exact absurd hs (value_no_step (.num _))
840+
| echoAddNums => cases hs₂ with
841+
| echoAddLeft h => exact absurd h (value_no_step (.num _))
842+
| echoAddRight _ h => exact absurd h (value_no_step (.num _))
843+
| echoAddNums => rfl
717844

718845
-- ═══════════════════════════════════════════════════════════════════════
719846
-- COROLLARY: TYPE SAFETY
@@ -786,6 +913,25 @@ theorem echo_roundtrip_typed (e : Expr) (n : Nat) (h : HasType [] e (.word n)) :
786913
HasType [] (.lower (.echoClose e)) (.word 0) :=
787914
⟨.tResidue _ _ _ _ (.tEchoClose _ _ n h), .tLower _ _ _ _ (.tEchoClose _ _ n h)⟩
788915

916+
/-- `echoAdd` recovers the summands: `add` discards which numbers were added,
917+
but the residue retains the pair. -/
918+
theorem echoAdd_residue_recovers (n₁ n₂ : Int) :
919+
StepStar (.residue (.echoAdd (.num n₁) (.num n₂))) (.pair (.num n₁) (.num n₂)) :=
920+
.head (.residueStep .echoAddNums) (.head (.residueVal (.pair (.num _) (.num _)) (.num _)) .refl)
921+
922+
/-- `lower ∘ echoAdd` is ordinary addition (the lossy result). -/
923+
theorem echoAdd_lower_sums (n₁ n₂ : Int) :
924+
StepStar (.lower (.echoAdd (.num n₁) (.num n₂))) (.num (n₁ + n₂)) :=
925+
.head (.lowerStep .echoAddNums) (.head (.lowerVal (.pair (.num _) (.num _)) (.num _)) .refl)
926+
927+
/-- **Echo distinguishes what `add` collapses.** 1+3 and 2+2 both lower to 4,
928+
but their residues (the summand pairs) stay distinct. -/
929+
theorem echoAdd_distinguishes :
930+
(StepStar (.lower (.echoAdd (.num 1) (.num 3))) (.num 4) ∧
931+
StepStar (.lower (.echoAdd (.num 2) (.num 2))) (.num 4)) ∧
932+
(Expr.pair (.num 1) (.num 3) ≠ Expr.pair (.num 2) (.num 2)) :=
933+
⟨⟨echoAdd_lower_sums 1 3, echoAdd_lower_sums 2 2⟩, by decide⟩
934+
789935
-- ═══════════════════════════════════════════════════════════════════════
790936
-- TG-2: DECIDABILITY OF TYPE CHECKING
791937
-- ═══════════════════════════════════════════════════════════════════════
@@ -846,6 +992,22 @@ def infer (Γ : Ctx) : Expr → Option Ty
846992
match infer Γ r, infer Γ v with
847993
| some ρ, some τ => some (.echo ρ τ)
848994
| _, _ => none
995+
| .pair a b =>
996+
match infer Γ a, infer Γ b with
997+
| some α, some β => some (.prod α β)
998+
| _, _ => none
999+
| .fst e =>
1000+
match infer Γ e with
1001+
| some (.prod α _) => some α
1002+
| _ => none
1003+
| .snd e =>
1004+
match infer Γ e with
1005+
| some (.prod _ β) => some β
1006+
| _ => none
1007+
| .echoAdd e₁ e₂ =>
1008+
match infer Γ e₁, infer Γ e₂ with
1009+
| some .num, some .num => some (.echo (.prod .num .num) .num)
1010+
| _, _ => none
8491011

8501012
/-- **Completeness**: every typing derivation is computed by `infer`. -/
8511013
theorem infer_complete {Γ : Ctx} {e : Expr} {τ : Ty} :
@@ -914,6 +1076,23 @@ theorem infer_sound {Γ : Ctx} {e : Expr} {τ : Ty} :
9141076
next ρ τ' he_r he_v =>
9151077
injection h with h; subst h; exact .tEchoVal _ _ _ ρ τ' (ihr he_r) (ihv he_v)
9161078
all_goals simp at h
1079+
| pair a b iha ihb =>
1080+
intro h; simp only [infer] at h; split at h
1081+
next α β he_a he_b =>
1082+
injection h with h; subst h; exact .tPair _ _ _ α β (iha he_a) (ihb he_b)
1083+
all_goals simp at h
1084+
| fst e ih =>
1085+
intro h; simp only [infer] at h; split at h
1086+
next α β he => injection h with h; subst h; exact .tFst _ _ α β (ih he)
1087+
all_goals simp at h
1088+
| snd e ih =>
1089+
intro h; simp only [infer] at h; split at h
1090+
next α β he => injection h with h; subst h; exact .tSnd _ _ α β (ih he)
1091+
all_goals simp at h
1092+
| echoAdd e₁ e₂ ih₁ ih₂ =>
1093+
intro h; simp only [infer] at h; split at h
1094+
next he₁ he₂ => injection h with h; subst h; exact .tEchoAdd _ _ _ (ih₁ he₁) (ih₂ he₂)
1095+
all_goals simp at h
9171096

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

0 commit comments

Comments
 (0)