|
| 1 | +(* SPDX-License-Identifier: PMPL-1.0-or-later *) |
| 2 | +(* SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell *) |
| 3 | + |
| 4 | +(** * Ephapax L3 — Echo / residue type former (forward-looking scaffold) |
| 5 | +
|
| 6 | + This file mechanises Layer 3 of the four-layer preservation |
| 7 | + redesign (PRESERVATION-DESIGN.md §6). L3 is the irreversibility- |
| 8 | + residue layer: every irreversible operation in Ephapax |
| 9 | + ([S_Region_Exit], [S_Drop], and Affine-implicit drop) produces a |
| 10 | + residue value whose type carries a proof-relevant witness of |
| 11 | + *which* value was erased. |
| 12 | +
|
| 13 | + Per the design doc, L3 is FORWARD-LOOKING — [preservation_l1] does |
| 14 | + not depend on this layer. The mechanisation here mirrors the Agda |
| 15 | + upstream at: |
| 16 | +
|
| 17 | + - [echo-types/proofs/agda/Echo.agda] — the fiber type former |
| 18 | + [Echo : (A → B) → B → Set] defined as [Σ A (λ x → f x ≡ y)]. |
| 19 | + - [echo-types/proofs/agda/EchoLinear.agda] — the two-mode |
| 20 | + [LEcho : Mode → Set]; the weakening [Linear → Affine]; the |
| 21 | + decoration-commuting per-mode composition lemma |
| 22 | + [degradeMode-comp]. |
| 23 | +
|
| 24 | + What is in this file (first L3 slice): |
| 25 | +
|
| 26 | + - [Mode], the [mode_le] thin-poset, [mode_le_refl] / |
| 27 | + [mode_le_trans] / [mode_le_prop] all [Qed]. |
| 28 | + - [Echo] as a record-shaped fiber type former. |
| 29 | + - A concrete [collapse : bool → unit] and |
| 30 | + [LEcho : Mode → Type] mode-polymorphic family. |
| 31 | + - [weaken : LEcho Linear → LEcho Affine] (the irreversible |
| 32 | + collapse) and [weaken_collapses_distinction] witnessing that |
| 33 | + the Linear distinction is genuinely erased. |
| 34 | + - [degrade_mode] and the headline composition law |
| 35 | + [degrade_mode_comp] ([Qed]). |
| 36 | + - [affine_canonical] / [affine_all_equal] — propositionality of |
| 37 | + Affine echoes. |
| 38 | +
|
| 39 | + What is NOT in this file (separate forward-looking PRs): |
| 40 | +
|
| 41 | + - [TEcho] type former added to [Syntax.v] (the new [ty] |
| 42 | + constructor). L3 cannot type-decorate ephapax expressions until |
| 43 | + [TEcho] lands in [ty]. |
| 44 | + - [T_Observe] typing rule. Linear-mode [T_Observe] consumes; |
| 45 | + Affine-mode [T_Observe] does not. |
| 46 | + - Residue-producing operational rules ([S_Region_Exit] and |
| 47 | + [S_Drop] with residue outputs). |
| 48 | + - Integration into [has_type_l1] / [preservation_l1]. |
| 49 | + - Full collapse/residue characteristic infrastructure (separating |
| 50 | + models, the [EchoR ⊤ TrivialCert] form, the no-section result). |
| 51 | +
|
| 52 | + Per PRESERVATION-DESIGN.md §6.4, L1 + L2 must not bake in |
| 53 | + assumptions that block L3. The three constraints are: |
| 54 | +
|
| 55 | + 1. Preservation must not assume residue ≡ nothing. |
| 56 | + 2. No per-type echo-ability predicates. |
| 57 | + 3. Typing rules are modality-polymorphic (only [T_Observe] |
| 58 | + splits per mode). |
| 59 | +
|
| 60 | + The L1 design as captured in [TypingL1.v] and [Semantics_L1.v] |
| 61 | + satisfies all three constraints. This file does not introduce |
| 62 | + contradictions with them. *) |
| 63 | + |
| 64 | +(** ** Proof-debt note (axiom dependencies) |
| 65 | +
|
| 66 | + Two lemmas in this file ([mode_le_trans] and [degrade_mode_comp]) |
| 67 | + use [dependent destruction] from [Coq.Program.Equality] to |
| 68 | + discriminate impossible cases on the indexed inductive |
| 69 | + [mode_le]. This pulls in Coq's standard [eq_rect_eq] (K / UIP) |
| 70 | + axiom. |
| 71 | +
|
| 72 | + The Agda upstream ([EchoLinear.agda]) is [--safe --without-K] |
| 73 | + and discharges these cases without K. The rest of the Ephapax |
| 74 | + Coq codebase (per [Print Assumptions] on [value_R_G_preserving_l1], |
| 75 | + [subst_preserves_typing_l1]) is also K-free. |
| 76 | +
|
| 77 | + A follow-up slice should rewrite [mode_le_trans] and |
| 78 | + [degrade_mode_comp] using raw dependent pattern matching with |
| 79 | + motive tricks to be K-free, aligning with the Agda upstream and |
| 80 | + the rest of the Coq codebase. Tracked as L3.K proof-debt. *) |
| 81 | + |
| 82 | +Require Import Coq.Bool.Bool. |
| 83 | +Require Import Coq.Program.Equality. |
| 84 | + |
| 85 | +(** ===== Modes ===== |
| 86 | +
|
| 87 | + The L2 layer of the design (PRESERVATION-DESIGN.md §5) parameterises |
| 88 | + the typing judgment over a modality [ℓ ∈ {Linear, Affine}]. L3 |
| 89 | + consumes the modality to choose the echo discipline: Linear echoes |
| 90 | + are full fibers (proof-relevant), Affine echoes are propositional |
| 91 | + residues (proof-irrelevant). *) |
| 92 | + |
| 93 | +Inductive Mode : Type := |
| 94 | + | Linear : Mode |
| 95 | + | Affine : Mode. |
| 96 | + |
| 97 | +(** The thin poset on Mode: [Linear ⊑ Linear], [Linear ⊑ Affine], |
| 98 | + [Affine ⊑ Affine]. This is the linearity-side analog of |
| 99 | + EchoLinear.agda's [_≤m_]. *) |
| 100 | + |
| 101 | +(** Sort [Type] (not [Prop]) so [mode_le] can drive the |
| 102 | + [degrade_mode] dispatch at the Type level. Mirrors the Agda |
| 103 | + [data _≤m_ : Mode → Mode → Set]. *) |
| 104 | + |
| 105 | +Inductive mode_le : Mode -> Mode -> Type := |
| 106 | + | Linear_le_Linear : mode_le Linear Linear |
| 107 | + | Linear_le_Affine : mode_le Linear Affine |
| 108 | + | Affine_le_Affine : mode_le Affine Affine. |
| 109 | + |
| 110 | +Lemma mode_le_refl : forall m, mode_le m m. |
| 111 | +Proof. intros [|]; constructor. Qed. |
| 112 | + |
| 113 | +(** [Defined] (not [Qed]) so [mode_le_trans] is transparent and |
| 114 | + [degrade_mode_comp] can [simpl] through its applications. Uses |
| 115 | + [dependent destruction] (K-dependent) — see the proof-debt note |
| 116 | + at the top of the file. *) |
| 117 | + |
| 118 | +Definition mode_le_trans |
| 119 | + (m1 m2 m3 : Mode) |
| 120 | + (H12 : mode_le m1 m2) (H23 : mode_le m2 m3) : mode_le m1 m3. |
| 121 | +Proof. |
| 122 | + destruct H12. |
| 123 | + - exact H23. |
| 124 | + - dependent destruction H23. exact Linear_le_Affine. |
| 125 | + - exact H23. |
| 126 | +Defined. |
| 127 | + |
| 128 | +(** Propositionality of the mode order. Each pair [(m1, m2)] has at |
| 129 | + most one inhabitant in [mode_le]. This is what lets us collapse |
| 130 | + composed-via-[m2] weakening proofs against an independently-given |
| 131 | + [m1 ⊑ m3] in [degrade_mode_compose]. |
| 132 | +
|
| 133 | + Mirrors EchoLinear.agda's [≤m-prop]. *) |
| 134 | + |
| 135 | +Lemma mode_le_prop : |
| 136 | + forall m1 m2 (p q : mode_le m1 m2), p = q. |
| 137 | +Proof. |
| 138 | + intros m1 m2 p q. |
| 139 | + destruct p; |
| 140 | + refine |
| 141 | + match q as q' |
| 142 | + in mode_le mA mB |
| 143 | + return |
| 144 | + (match mA, mB return mode_le mA mB -> Prop with |
| 145 | + | Linear, Linear => fun q'' => Linear_le_Linear = q'' |
| 146 | + | Linear, Affine => fun q'' => Linear_le_Affine = q'' |
| 147 | + | Affine, Affine => fun q'' => Affine_le_Affine = q'' |
| 148 | + | _, _ => fun _ => True |
| 149 | + end q') |
| 150 | + with |
| 151 | + | Linear_le_Linear => eq_refl |
| 152 | + | Linear_le_Affine => eq_refl |
| 153 | + | Affine_le_Affine => eq_refl |
| 154 | + end. |
| 155 | +Qed. |
| 156 | + |
| 157 | +(** ===== The Echo type former ===== |
| 158 | +
|
| 159 | + [Echo f y] is the fiber of [f : A → B] over [y : B] — the type of |
| 160 | + pairs [(x, p)] where [x : A] and [p : f x = y]. Proof-relevant: |
| 161 | + *which* preimage maps to [y] is information the irreversibility of |
| 162 | + [f] deliberately erased and that this type recovers as a witness. |
| 163 | +
|
| 164 | + Mirrors echo-types/proofs/agda/Echo.agda:14-15. *) |
| 165 | + |
| 166 | +Record Echo {A B : Type} (f : A -> B) (y : B) : Type := mkEcho { |
| 167 | + echo_witness : A; |
| 168 | + echo_eq : f echo_witness = y |
| 169 | +}. |
| 170 | + |
| 171 | +Arguments mkEcho {A B f y} echo_witness echo_eq. |
| 172 | +Arguments echo_witness {A B f y} _. |
| 173 | +Arguments echo_eq {A B f y} _. |
| 174 | + |
| 175 | +(** Introduction into the own fiber. Mirrors [echo-intro] in Echo.agda. *) |
| 176 | + |
| 177 | +Definition echo_intro {A B : Type} (f : A -> B) (x : A) : Echo f (f x) := |
| 178 | + mkEcho x eq_refl. |
| 179 | + |
| 180 | +(** ===== Linear vs Affine echo: the L3 carrier ===== |
| 181 | +
|
| 182 | + A concrete instance of the two-mode echo, matching |
| 183 | + EchoLinear.agda's characteristic carrier: |
| 184 | +
|
| 185 | + - Linear echo is the full fiber [Echo collapse tt] for the |
| 186 | + forgetful [collapse : bool → unit]. The fiber has two distinct |
| 187 | + inhabitants (one per bool); these are the [echo_true] and |
| 188 | + [echo_false] of EchoCharacteristic.agda. |
| 189 | + - Affine echo is the trivial residue [unit]: any two affine |
| 190 | + echoes are equal. |
| 191 | +
|
| 192 | + This concrete pair is enough to state and prove the headline |
| 193 | + weakening + decoration-commuting lemmas. The full |
| 194 | + [EchoR ⊤ TrivialCert tt] residue form and the [no-section] |
| 195 | + impossibility result are deferred to a separate slice. *) |
| 196 | + |
| 197 | +Definition collapse (b : bool) : unit := tt. |
| 198 | + |
| 199 | +Definition LEcho (m : Mode) : Type := |
| 200 | + match m with |
| 201 | + | Linear => Echo collapse tt |
| 202 | + | Affine => unit |
| 203 | + end. |
| 204 | + |
| 205 | +(** Linear-mode constants: the two distinguishable echoes. *) |
| 206 | + |
| 207 | +Definition echo_true : LEcho Linear := mkEcho true eq_refl. |
| 208 | +Definition echo_false : LEcho Linear := mkEcho false eq_refl. |
| 209 | + |
| 210 | +(** The two Linear echoes really are distinct — the witnesses are |
| 211 | + different bools. *) |
| 212 | + |
| 213 | +Lemma echo_true_ne_echo_false : echo_true <> echo_false. |
| 214 | +Proof. |
| 215 | + intro H. |
| 216 | + assert (Hwit : echo_witness echo_true = echo_witness echo_false) |
| 217 | + by (rewrite H; reflexivity). |
| 218 | + simpl in Hwit. discriminate. |
| 219 | +Qed. |
| 220 | + |
| 221 | +(** The Linear-to-Affine weakening: the irreversible collapse. |
| 222 | +
|
| 223 | + Mirrors EchoLinear.agda:38-39 ([weaken : LEcho linear → LEcho |
| 224 | + affine]). In this concrete instance the weakening simply forgets |
| 225 | + the bool witness, since the affine residue carries none. *) |
| 226 | + |
| 227 | +Definition weaken (e : LEcho Linear) : LEcho Affine := tt. |
| 228 | + |
| 229 | +(** Witness that the Linear distinction collapses under weakening — |
| 230 | + both [echo_true] and [echo_false] weaken to the same affine |
| 231 | + residue. Mirrors EchoLinear.agda's |
| 232 | + [weaken-collapses-distinction]. *) |
| 233 | + |
| 234 | +Lemma weaken_collapses_distinction : |
| 235 | + weaken echo_true = weaken echo_false. |
| 236 | +Proof. reflexivity. Qed. |
| 237 | + |
| 238 | +(** All Affine echoes are equal (propositionality of [unit]). *) |
| 239 | + |
| 240 | +Lemma affine_canonical : forall e : LEcho Affine, e = tt. |
| 241 | +Proof. intros []; reflexivity. Qed. |
| 242 | + |
| 243 | +Lemma affine_all_equal : |
| 244 | + forall e1 e2 : LEcho Affine, e1 = e2. |
| 245 | +Proof. |
| 246 | + intros e1 e2. |
| 247 | + rewrite (affine_canonical e1). |
| 248 | + rewrite (affine_canonical e2). |
| 249 | + reflexivity. |
| 250 | +Qed. |
| 251 | + |
| 252 | +(** ===== Mode weakening on echoes (decoration-commuting recipe) ===== |
| 253 | +
|
| 254 | + [degrade_mode] is the dispatch function: identity on the |
| 255 | + reflexive cases ([Linear ⊑ Linear], [Affine ⊑ Affine]) and |
| 256 | + [weaken] on the strict step ([Linear ⊑ Affine]). |
| 257 | +
|
| 258 | + Mirrors EchoLinear.agda:85-88. *) |
| 259 | + |
| 260 | +Definition degrade_mode {m1 m2 : Mode} |
| 261 | + (p : mode_le m1 m2) : LEcho m1 -> LEcho m2 := |
| 262 | + match p in mode_le mA mB return LEcho mA -> LEcho mB with |
| 263 | + | Linear_le_Linear => fun e => e |
| 264 | + | Linear_le_Affine => weaken |
| 265 | + | Affine_le_Affine => fun e => e |
| 266 | + end. |
| 267 | + |
| 268 | +(** Identity weakening corollaries: degrading along a reflexive proof |
| 269 | + is the identity. Useful when chaining with [degrade_mode_comp]. *) |
| 270 | + |
| 271 | +Lemma degrade_mode_id_linear : |
| 272 | + forall e : LEcho Linear, |
| 273 | + degrade_mode Linear_le_Linear e = e. |
| 274 | +Proof. reflexivity. Qed. |
| 275 | + |
| 276 | +Lemma degrade_mode_id_affine : |
| 277 | + forall e : LEcho Affine, |
| 278 | + degrade_mode Affine_le_Affine e = e. |
| 279 | +Proof. reflexivity. Qed. |
| 280 | + |
| 281 | +(** The strict step agrees with [weaken] definitionally. *) |
| 282 | + |
| 283 | +Lemma degrade_mode_strict_is_weaken : |
| 284 | + forall e : LEcho Linear, |
| 285 | + degrade_mode Linear_le_Affine e = weaken e. |
| 286 | +Proof. reflexivity. Qed. |
| 287 | + |
| 288 | +(** Headline per-decoration composition lemma: two successive mode |
| 289 | + weakenings agree with a single weakening along the composed |
| 290 | + ordering proof. |
| 291 | +
|
| 292 | + Mirrors EchoLinear.agda's [degradeMode-comp] (lines 93-101). This |
| 293 | + is the L3 instance of the "decoration commuting" recipe noted in |
| 294 | + PRESERVATION-DESIGN.md §3 and §5; combined with [mode_le_prop], |
| 295 | + it lets any two factorisations of a mode-weakening through the |
| 296 | + same composite [m1 ⊑ m3] agree. *) |
| 297 | + |
| 298 | +Lemma degrade_mode_comp : |
| 299 | + forall {m1 m2 m3} (p12 : mode_le m1 m2) (p23 : mode_le m2 m3) |
| 300 | + (e : LEcho m1), |
| 301 | + degrade_mode p23 (degrade_mode p12 e) = |
| 302 | + degrade_mode (mode_le_trans m1 m2 m3 p12 p23) e. |
| 303 | +Proof. |
| 304 | + intros m1 m2 m3 p12 p23 e. |
| 305 | + destruct p12. |
| 306 | + - reflexivity. |
| 307 | + - dependent destruction p23. reflexivity. |
| 308 | + - dependent destruction p23. reflexivity. |
| 309 | +Qed. |
| 310 | + |
| 311 | +(** Free-factoring composition law: any direct ordering proof |
| 312 | + [p13 : mode_le m1 m3] agrees with the composed-via-[m2] weakening, |
| 313 | + because [mode_le_prop] makes the choice of factoring irrelevant. |
| 314 | +
|
| 315 | + Mirrors EchoLinear.agda's [degradeMode-compose]. *) |
| 316 | + |
| 317 | +Lemma degrade_mode_compose : |
| 318 | + forall {m1 m2 m3} |
| 319 | + (p12 : mode_le m1 m2) (p23 : mode_le m2 m3) |
| 320 | + (p13 : mode_le m1 m3) (e : LEcho m1), |
| 321 | + degrade_mode p23 (degrade_mode p12 e) = |
| 322 | + degrade_mode p13 e. |
| 323 | +Proof. |
| 324 | + intros m1 m2 m3 p12 p23 p13 e. |
| 325 | + rewrite (mode_le_prop _ _ p13 (mode_le_trans _ _ _ p12 p23)). |
| 326 | + apply degrade_mode_comp. |
| 327 | +Qed. |
| 328 | + |
| 329 | +(** ===== Cross-mode characteristic ===== |
| 330 | +
|
| 331 | + Witness that Linear→Affine weakening is genuinely lossy: there |
| 332 | + exist distinct Linear echoes whose Affine weakenings are equal. |
| 333 | + Mirrors EchoLinear.agda's [strict-linear-example]. *) |
| 334 | + |
| 335 | +Lemma strict_linear_example : |
| 336 | + exists e1 e2 : LEcho Linear, |
| 337 | + e1 <> e2 /\ weaken e1 = weaken e2. |
| 338 | +Proof. |
| 339 | + exists echo_true, echo_false. |
| 340 | + split. |
| 341 | + - apply echo_true_ne_echo_false. |
| 342 | + - apply weaken_collapses_distinction. |
| 343 | +Qed. |
0 commit comments