Skip to content

Commit bc2a0e6

Browse files
claudehyperpolymath
authored andcommitted
feat(echo): echoEq — structured loss for equality (residue = operand pair)
https://claude.ai/code/session_01PgHpCFzwYB7Qy9L6kmR8CE
1 parent cc1a801 commit bc2a0e6

1 file changed

Lines changed: 187 additions & 10 deletions

File tree

proofs/Tangle.lean

Lines changed: 187 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
-- - Syntax: Expr inductive with Num, Str, Bool, Identity, BraidLit,
66
-- Compose (.), Tensor (|), Pipeline (>>), Close, Add, Eq, the echo
77
-- constructors EchoClose, Lower, Residue, EchoVal (structured loss), and
8-
-- the product constructors Pair, Fst, Snd, EchoAdd
8+
-- the product constructors Pair, Fst, Snd, EchoAdd, EchoEq
99
-- - Typing: HasType inductive relation covering T-Num, T-Str, T-Bool,
1010
-- T-Identity, T-Braid, T-Compose-Word, T-Tensor-Word, T-Pipeline,
1111
-- 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)
12+
-- rules T-Echo-Close, T-Lower, T-Residue, T-Echo-Val, the product
13+
-- rules T-Pair, T-Fst, T-Snd, T-Echo-Add, and the echo-equality rules
14+
-- T-Echo-Eq-Word, T-Echo-Eq-Num, T-Echo-Eq-Str
15+
-- - Semantics: Small-step Step relation (55 rules incl. echo + product)
1516
--
1617
-- Theorems proven:
1718
-- 1. Progress: well-typed closed terms are values or can step
@@ -26,12 +27,15 @@
2627
-- (hyperpolymath/echo-types: `Echo f y := Σ (x : A), f x ≡ y`) directly into
2728
-- the type system: closing a braid through an echo retains the residue, so the
2829
-- 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
33-
-- §ECHO-TYPES section at the foot of the file for the residue-recovery and
34-
-- non-injectivity theorems (both the `close` and `echoAdd` forms).
30+
-- product type `Ty.prod ρ σ` carries two further lossy operations, `echoAdd`
31+
-- and `echoEq`: ordinary `add` discards which two numbers were summed, but
32+
-- `echoAdd` keeps the summand pair as its residue (residue type `Num × Num`,
33+
-- result `Num`); ordinary `eq` discards which two operands were compared, but
34+
-- `echoEq` keeps the operand pair as its residue (residue type `ρ × ρ`, result
35+
-- `Bool`), so distinct inputs that collapse to the same sum or boolean stay
36+
-- distinguishable. See the §ECHO-TYPES section at the foot of the file for the
37+
-- residue-recovery and non-injectivity theorems (the `close`, `echoAdd`, and
38+
-- `echoEq` forms).
3539
--
3640
-- Note on T-Let: the let binding requires a generalized de Bruijn substitution
3741
-- lemma (standard POPLmark machinery); tracked as TG-1. The fragment here
@@ -99,6 +103,7 @@ inductive Expr where
99103
| fst : Expr → Expr -- first projection
100104
| snd : Expr → Expr -- second projection
101105
| echoAdd : Expr → Expr → Expr -- echo-preserving addition (residue = pair of summands)
106+
| echoEq : Expr → Expr → Expr -- echo-preserving equality (residue = operand pair)
102107
deriving DecidableEq, Repr
103108

104109
/-- Value predicate: fully reduced expressions. -/
@@ -197,6 +202,15 @@ inductive HasType : Ctx → Expr → Ty → Prop where
197202
| tEchoAdd (Γ : Ctx) (e₁ e₂ : Expr) : -- [T-Echo-Add]
198203
HasType Γ e₁ .num → HasType Γ e₂ .num →
199204
HasType Γ (.echoAdd e₁ e₂) (.echo (.prod .num .num) .num)
205+
| tEchoEqWord (Γ : Ctx) (e₁ e₂ : Expr) (n : Nat) : -- [T-Echo-Eq-Word]
206+
HasType Γ e₁ (.word n) → HasType Γ e₂ (.word n) →
207+
HasType Γ (.echoEq e₁ e₂) (.echo (.prod (.word n) (.word n)) .bool)
208+
| tEchoEqNum (Γ : Ctx) (e₁ e₂ : Expr) : -- [T-Echo-Eq-Num]
209+
HasType Γ e₁ .num → HasType Γ e₂ .num →
210+
HasType Γ (.echoEq e₁ e₂) (.echo (.prod .num .num) .bool)
211+
| tEchoEqStr (Γ : Ctx) (e₁ e₂ : Expr) : -- [T-Echo-Eq-Str]
212+
HasType Γ e₁ .str → HasType Γ e₂ .str →
213+
HasType Γ (.echoEq e₁ e₂) (.echo (.prod .str .str) .bool)
200214

201215
-- ═══════════════════════════════════════════════════════════════════════
202216
-- SMALL-STEP SEMANTICS
@@ -267,6 +281,23 @@ inductive Step : Expr → Expr → Prop where
267281
| echoAddRight : IsValue e₁ → Step e₂ e₂' → Step (.echoAdd e₁ e₂) (.echoAdd e₁ e₂')
268282
| echoAddNums : Step (.echoAdd (.num n₁) (.num n₂))
269283
(.echoVal (.pair (.num n₁) (.num n₂)) (.num (n₁ + n₂)))
284+
-- Echo-preserving equality: residue retains the operand pair; result is the
285+
-- boolean. Mirrors the 8 `eq` rules; each computation produces
286+
-- `echoVal (pair <operands>) (boolLit <same bool as the matching eq rule>)`.
287+
| echoEqLeft : Step e₁ e₁' → Step (.echoEq e₁ e₂) (.echoEq e₁' e₂)
288+
| echoEqRight : IsValue e₁ → Step e₂ e₂' → Step (.echoEq e₁ e₂) (.echoEq e₁ e₂')
289+
| echoEqNums : Step (.echoEq (.num n₁) (.num n₂))
290+
(.echoVal (.pair (.num n₁) (.num n₂)) (.boolLit (n₁ == n₂)))
291+
| echoEqStrs : Step (.echoEq (.str s₁) (.str s₂))
292+
(.echoVal (.pair (.str s₁) (.str s₂)) (.boolLit (s₁ == s₂)))
293+
| echoEqBraids : Step (.echoEq (.braidLit gs₁) (.braidLit gs₂))
294+
(.echoVal (.pair (.braidLit gs₁) (.braidLit gs₂)) (.boolLit (gs₁ == gs₂)))
295+
| echoEqIdId : Step (.echoEq .identity .identity)
296+
(.echoVal (.pair .identity .identity) (.boolLit true))
297+
| echoEqIdBraid : Step (.echoEq .identity (.braidLit gs))
298+
(.echoVal (.pair .identity (.braidLit gs)) (.boolLit (gs == [])))
299+
| echoEqBraidId : Step (.echoEq (.braidLit gs) .identity)
300+
(.echoVal (.pair (.braidLit gs) .identity) (.boolLit (gs == [])))
270301

271302
-- ═══════════════════════════════════════════════════════════════════════
272303
-- LEMMAS
@@ -511,6 +542,36 @@ theorem progress : HasType [] e τ → IsValue e ∨ ∃ e', Step e e' := by
511542
exact ⟨_, .echoAddNums⟩
512543
· exact ⟨_, .echoAddRight hv₁ hs₂⟩
513544
· exact ⟨_, .echoAddLeft hs₁⟩
545+
| tEchoEqWord _ _ n h₁ h₂ =>
546+
right
547+
rcases progress h₁ with hv₁ | ⟨e₁', hs₁⟩
548+
· rcases progress h₂ with hv₂ | ⟨e₂', hs₂⟩
549+
· rcases canonical_word hv₁ h₁ with ⟨rfl, _⟩ | ⟨gs₁, rfl, _⟩ <;>
550+
rcases canonical_word hv₂ h₂ with ⟨rfl, _⟩ | ⟨gs₂, rfl, _⟩
551+
· exact ⟨_, .echoEqIdId⟩
552+
· exact ⟨_, .echoEqIdBraid⟩
553+
· exact ⟨_, .echoEqBraidId⟩
554+
· exact ⟨_, .echoEqBraids⟩
555+
· exact ⟨_, .echoEqRight hv₁ hs₂⟩
556+
· exact ⟨_, .echoEqLeft hs₁⟩
557+
| tEchoEqNum _ _ h₁ h₂ =>
558+
right
559+
rcases progress h₁ with hv₁ | ⟨e₁', hs₁⟩
560+
· rcases progress h₂ with hv₂ | ⟨e₂', hs₂⟩
561+
· obtain ⟨n₁, rfl⟩ := canonical_num hv₁ h₁
562+
obtain ⟨n₂, rfl⟩ := canonical_num hv₂ h₂
563+
exact ⟨_, .echoEqNums⟩
564+
· exact ⟨_, .echoEqRight hv₁ hs₂⟩
565+
· exact ⟨_, .echoEqLeft hs₁⟩
566+
| tEchoEqStr _ _ h₁ h₂ =>
567+
right
568+
rcases progress h₁ with hv₁ | ⟨e₁', hs₁⟩
569+
· rcases progress h₂ with hv₂ | ⟨e₂', hs₂⟩
570+
· obtain ⟨s₁, rfl⟩ := canonical_str hv₁ h₁
571+
obtain ⟨s₂, rfl⟩ := canonical_str hv₂ h₂
572+
exact ⟨_, .echoEqStrs⟩
573+
· exact ⟨_, .echoEqRight hv₁ hs₂⟩
574+
· exact ⟨_, .echoEqLeft hs₁⟩
514575

515576
-- ═══════════════════════════════════════════════════════════════════════
516577
-- THEOREM 2: PRESERVATION
@@ -644,6 +705,50 @@ theorem preservation : HasType [] e τ → Step e e' → HasType [] e' τ := by
644705
| echoAddNums =>
645706
cases ht with | tEchoAdd _ _ h₁ h₂ =>
646707
exact .tEchoVal _ _ _ _ _ (.tPair _ _ _ _ _ (.tNum _ _) (.tNum _ _)) (.tNum _ _)
708+
-- Echo-preserving equality: congruence rebuilds via `tEchoEq*` + `ih` (the
709+
-- inner type is ambiguous, so case-split on all three `tEchoEq*`); the 6
710+
-- computation rules invert the matching `tEchoEq*` and build the formed echo
711+
-- value `echoVal (pair <ops>) (boolLit …)`, residue typed via `tPair`.
712+
| echoEqLeft hs ih =>
713+
cases ht with
714+
| tEchoEqWord _ _ n h₁ h₂ => exact .tEchoEqWord _ _ _ n (ih h₁) h₂
715+
| tEchoEqNum _ _ h₁ h₂ => exact .tEchoEqNum _ _ _ (ih h₁) h₂
716+
| tEchoEqStr _ _ h₁ h₂ => exact .tEchoEqStr _ _ _ (ih h₁) h₂
717+
| echoEqRight _ hs ih =>
718+
cases ht with
719+
| tEchoEqWord _ _ n h₁ h₂ => exact .tEchoEqWord _ _ _ n h₁ (ih h₂)
720+
| tEchoEqNum _ _ h₁ h₂ => exact .tEchoEqNum _ _ _ h₁ (ih h₂)
721+
| tEchoEqStr _ _ h₁ h₂ => exact .tEchoEqStr _ _ _ h₁ (ih h₂)
722+
| echoEqNums => cases ht with
723+
| tEchoEqNum =>
724+
exact .tEchoVal _ _ _ _ _ (.tPair _ _ _ _ _ (.tNum _ _) (.tNum _ _)) (.tBool _ _)
725+
| tEchoEqWord _ _ _ _ h₁ => cases h₁
726+
| tEchoEqStr _ _ _ h₁ => cases h₁
727+
| echoEqStrs => cases ht with
728+
| tEchoEqStr =>
729+
exact .tEchoVal _ _ _ _ _ (.tPair _ _ _ _ _ (.tStr _ _) (.tStr _ _)) (.tBool _ _)
730+
| tEchoEqWord _ _ _ _ h₁ => cases h₁
731+
| tEchoEqNum _ _ _ h₁ => cases h₁
732+
| echoEqBraids => cases ht with
733+
| tEchoEqWord _ _ n h₁ h₂ =>
734+
exact .tEchoVal _ _ _ _ _ (.tPair _ _ _ _ _ h₁ h₂) (.tBool _ _)
735+
| tEchoEqNum _ _ _ h₁ => cases h₁
736+
| tEchoEqStr _ _ _ h₁ => cases h₁
737+
| echoEqIdId => cases ht with
738+
| tEchoEqWord _ _ n h₁ h₂ =>
739+
exact .tEchoVal _ _ _ _ _ (.tPair _ _ _ _ _ h₁ h₂) (.tBool _ _)
740+
| tEchoEqNum _ _ _ h₁ => cases h₁
741+
| tEchoEqStr _ _ _ h₁ => cases h₁
742+
| echoEqIdBraid => cases ht with
743+
| tEchoEqWord _ _ n h₁ h₂ =>
744+
exact .tEchoVal _ _ _ _ _ (.tPair _ _ _ _ _ h₁ h₂) (.tBool _ _)
745+
| tEchoEqNum _ _ _ h₁ => cases h₁
746+
| tEchoEqStr _ _ _ h₁ => cases h₁
747+
| echoEqBraidId => cases ht with
748+
| tEchoEqWord _ _ n h₁ h₂ =>
749+
exact .tEchoVal _ _ _ _ _ (.tPair _ _ _ _ _ h₁ h₂) (.tBool _ _)
750+
| tEchoEqNum _ _ _ h₁ => cases h₁
751+
| tEchoEqStr _ _ _ h₁ => cases h₁
647752

648753
-- ═══════════════════════════════════════════════════════════════════════
649754
-- THEOREM 3: DETERMINISM
@@ -841,6 +946,51 @@ theorem determinism : Step e e₁ → Step e e₂ → e₁ = e₂ := by
841946
| echoAddLeft h => exact absurd h (value_no_step (.num _))
842947
| echoAddRight _ h => exact absurd h (value_no_step (.num _))
843948
| echoAddNums => rfl
949+
-- Echo-preserving equality: same shape as `eq` determinism — congruence is
950+
-- deterministic by IH; computations discharge congruence races via
951+
-- `value_no_step` on the atomic operand values; same-rule → `rfl`.
952+
| echoEqLeft hs ih => cases hs₂ with
953+
| echoEqLeft h => rw [ih h]
954+
| echoEqRight hv _ => exact absurd hs (value_no_step hv)
955+
| echoEqNums => exact absurd hs (value_no_step (.num _))
956+
| echoEqStrs => exact absurd hs (value_no_step (.str _))
957+
| echoEqBraids => exact absurd hs (value_no_step (.braidLit _))
958+
| echoEqIdId => exact absurd hs (value_no_step .identity)
959+
| echoEqIdBraid => exact absurd hs (value_no_step .identity)
960+
| echoEqBraidId => exact absurd hs (value_no_step (.braidLit _))
961+
| echoEqRight hv hs ih => cases hs₂ with
962+
| echoEqLeft h => exact absurd h (value_no_step hv)
963+
| echoEqRight _ h => exact congrArg (Expr.echoEq _ ·) (ih h)
964+
| echoEqNums => exact absurd hs (value_no_step (.num _))
965+
| echoEqStrs => exact absurd hs (value_no_step (.str _))
966+
| echoEqBraids => exact absurd hs (value_no_step (.braidLit _))
967+
| echoEqIdId => cases hv with | identity => exact absurd hs (value_no_step .identity)
968+
| echoEqIdBraid => cases hv with | identity => exact absurd hs (value_no_step (.braidLit _))
969+
| echoEqBraidId => cases hv with | braidLit => exact absurd hs (value_no_step .identity)
970+
| echoEqNums => cases hs₂ with
971+
| echoEqLeft h => exact absurd h (value_no_step (.num _))
972+
| echoEqRight _ h => exact absurd h (value_no_step (.num _))
973+
| echoEqNums => rfl
974+
| echoEqStrs => cases hs₂ with
975+
| echoEqLeft h => exact absurd h (value_no_step (.str _))
976+
| echoEqRight _ h => exact absurd h (value_no_step (.str _))
977+
| echoEqStrs => rfl
978+
| echoEqBraids => cases hs₂ with
979+
| echoEqLeft h => exact absurd h (value_no_step (.braidLit _))
980+
| echoEqRight _ h => exact absurd h (value_no_step (.braidLit _))
981+
| echoEqBraids => rfl
982+
| echoEqIdId => cases hs₂ with
983+
| echoEqLeft h => exact absurd h (value_no_step .identity)
984+
| echoEqRight _ h => exact absurd h (value_no_step .identity)
985+
| echoEqIdId => rfl
986+
| echoEqIdBraid => cases hs₂ with
987+
| echoEqLeft h => exact absurd h (value_no_step .identity)
988+
| echoEqRight _ h => exact absurd h (value_no_step (.braidLit _))
989+
| echoEqIdBraid => rfl
990+
| echoEqBraidId => cases hs₂ with
991+
| echoEqLeft h => exact absurd h (value_no_step (.braidLit _))
992+
| echoEqRight _ h => exact absurd h (value_no_step .identity)
993+
| echoEqBraidId => rfl
844994

845995
-- ═══════════════════════════════════════════════════════════════════════
846996
-- COROLLARY: TYPE SAFETY
@@ -932,6 +1082,16 @@ theorem echoAdd_distinguishes :
9321082
(Expr.pair (.num 1) (.num 3) ≠ Expr.pair (.num 2) (.num 2)) :=
9331083
⟨⟨echoAdd_lower_sums 1 3, echoAdd_lower_sums 2 2⟩, by decide⟩
9341084

1085+
/-- **Echo distinguishes what `eq` collapses.** 1≟2 and 3≟4 both lower to
1086+
`false`, but their residues (the operand pairs) stay distinct. -/
1087+
theorem echoEq_distinguishes :
1088+
(StepStar (.lower (.echoEq (.num 1) (.num 2))) (.boolLit (1 == 2)) ∧
1089+
StepStar (.lower (.echoEq (.num 3) (.num 4))) (.boolLit (3 == 4))) ∧
1090+
(Expr.pair (.num 1) (.num 2) ≠ Expr.pair (.num 3) (.num 4)) :=
1091+
⟨⟨.head (.lowerStep .echoEqNums) (.head (.lowerVal (.pair (.num _) (.num _)) (.boolLit _)) .refl),
1092+
.head (.lowerStep .echoEqNums) (.head (.lowerVal (.pair (.num _) (.num _)) (.boolLit _)) .refl)⟩,
1093+
by decide⟩
1094+
9351095
-- ═══════════════════════════════════════════════════════════════════════
9361096
-- TG-2: DECIDABILITY OF TYPE CHECKING
9371097
-- ═══════════════════════════════════════════════════════════════════════
@@ -1008,6 +1168,12 @@ def infer (Γ : Ctx) : Expr → Option Ty
10081168
match infer Γ e₁, infer Γ e₂ with
10091169
| some .num, some .num => some (.echo (.prod .num .num) .num)
10101170
| _, _ => none
1171+
| .echoEq e₁ e₂ =>
1172+
match infer Γ e₁, infer Γ e₂ with
1173+
| some (.word n), some (.word m) => if n = m then some (.echo (.prod (.word n) (.word n)) .bool) else none
1174+
| some .num, some .num => some (.echo (.prod .num .num) .bool)
1175+
| some .str, some .str => some (.echo (.prod .str .str) .bool)
1176+
| _, _ => none
10111177

10121178
/-- **Completeness**: every typing derivation is computed by `infer`. -/
10131179
theorem infer_complete {Γ : Ctx} {e : Expr} {τ : Ty} :
@@ -1093,6 +1259,17 @@ theorem infer_sound {Γ : Ctx} {e : Expr} {τ : Ty} :
10931259
intro h; simp only [infer] at h; split at h
10941260
next he₁ he₂ => injection h with h; subst h; exact .tEchoAdd _ _ _ (ih₁ he₁) (ih₂ he₂)
10951261
all_goals simp at h
1262+
| echoEq e₁ e₂ ih₁ ih₂ =>
1263+
intro h; simp only [infer] at h; split at h
1264+
next n m he₁ he₂ =>
1265+
split at h
1266+
next hnm =>
1267+
injection h with h; subst h; subst hnm
1268+
exact .tEchoEqWord _ _ _ _ (ih₁ he₁) (ih₂ he₂)
1269+
next => simp at h
1270+
next he₁ he₂ => injection h with h; subst h; exact .tEchoEqNum _ _ _ (ih₁ he₁) (ih₂ he₂)
1271+
next he₁ he₂ => injection h with h; subst h; exact .tEchoEqStr _ _ _ (ih₁ he₁) (ih₂ he₂)
1272+
all_goals simp at h
10961273

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

0 commit comments

Comments
 (0)