Skip to content

Commit 30eb640

Browse files
hyperpolymathclaude
andcommitted
theory: EchoApprox deeper rung — separated zero-collapse + axis-1 shadow agreement
Picks up the §7 deferrals from PR #70: two of the three remaining obligations (separated zero-collapse, axis-1 shadow agreement) land in this PR. The third (B-component + tolerance-budget retract round-trip) is parked on a `Tolerance` interface design call — see PR body. Rungs landed ------------ Rung A — separated zero-collapse (§7 #7): * `Separated : Set` — predicate on a pseudo-metric: `∀ b₁ b₂ → dist b₁ b₂ ≤ zero → b₁ ≡ b₂`. Not folded into the `PseudoMetric` record; callers supply it as an explicit hypothesis at the lemma site (pseudo-metrics in general only guarantee `dist y y ≡ zero`, not the converse). * `echo-approx-zero-collapses-strict : Separated → EchoR zero f y → Echo f y` formalises the §4 statement "Approximate → strict (only when separated, at ε = 0)" from the axis-2 design note. Rung B — axis-1 shadow agreement (§7 #8): * `echo-shadow-A` — A-component projection (the axis-1 "shadow" of an approximate echo). * `echo-shadow-iso-{to,from}` — pins the §7 #8 obligation explicitly. The iso is definitional both ways because `EchoR ε f y = Σ A (λ x → dist (f x) y ≤ ε)` already IS the existential shape; the lemma pair pins the obligation, not proves a non-trivial fact. * `echo-strict→approx-shadow-A` — cross-axis cohere: the A-component of `echo-strict→approx` agrees with the strict A-component on the nose (`refl`). The transport in `echo-strict→approx` only touches the bound proof, never the A-witness. * `echo-strict→approx-collapse-shadow-A` — round-trip under separation: `zero-collapses-strict ∘ strict→approx ≡ id` on the A-component, definitionally. Closes the §4 statement at the axis-1 shadow. Rung C — DEFERRED (design call required) ----------------------------------------- The full B-component + tolerance-budget retract round-trip needs a `+`-left-identity axiom on `Tolerance` (`zero + ε ≡ ε`). The current `Tolerance` record (see `EchoApprox.agda` lines 66–76) has fields `Tol`, `zero`, `_+_`, `_≤_`, `≤-refl`, `≤-trans`, `+-mono-≤` — no identity laws on `+`. Two options: (a) Extend `Tolerance` with `+`-identity laws (`+-identityˡ`, `+-identityʳ`). Changes the interface; every instance must discharge two new fields. Ripples to consumers (currently just `EchoApproxInstance.trivialTolerance`, but that may grow). Pro: minimal scaffolding. Con: makes `Tolerance` strictly stronger than "ordered commutative-monoid-flavoured". (b) Add a separate `BalancedTolerance` record on top of `Tolerance` carrying just the identity laws. Additive; no interface breakage. Lemmas needing the laws take `BalancedTolerance T` as an extra hypothesis. Pro: layered, opt-in. Con: an extra record name to thread through. Recommendation: (b). The current `Tolerance` is deliberately the minimal interface that lets us state `echo-approx-compose` (triangle + additive monotonicity, nothing else). Identity laws are needed only by the retract round-trip, which is a downstream refinement — keeping them out of the core interface preserves the "minimal moving parts" design from §3 of the axis-2 design note. Rung C is deferred pending owner decision. The owner-deferred decision is also documented inline in `EchoApprox.agda`'s module header. Rung D — also deferred ---------------------- The Lipschitz generalisation `L_g ≠ 1` would need scalar multiplication on `Tolerance` — a third interface call. Deferred alongside Rung C. Hygiene ------- All new headlines pinned via the per-lemma proof-of-life pattern established in PR #71: `EchoApproxInstance.agda` adds top-level identifiers at the trivial-pseudometric-on-⊤ instance, `Smoke.agda` enumerates them in its `using` clause. The pattern extends mechanically; no new design needed. Verification ------------ $ agda -i proofs/agda proofs/agda/All.agda # exit 0 $ agda -i proofs/agda proofs/agda/Smoke.agda # exit 0 `--safe --without-K` throughout. No postulates. No escape pragmas. No funext. Docs ---- `docs/echo-types/composition.md` §Q3 updated to record the second slice (zero-collapse + axis-1 shadow) and the Rung C / Rung D deferrals. Refs PR #70 and `/tmp/echo-types-exploration/axis2-approximate.md` §7. Refs not Closes — §7 is a multi-rung obligation list, and the Rung C / D deferrals remain. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 0a83258 commit 30eb640

4 files changed

Lines changed: 160 additions & 6 deletions

File tree

docs/echo-types/composition.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,30 @@ at `b := f x`, `ε₁ := zero`, `ε₂ := ε`), and
172172
`echo-approx-comp-retract-A` (A-component round-trip preserves the
173173
witness up to `refl`). The B-component round-trip and the
174174
tolerance-budget round-trip need a `+`-left-identity axiom on
175-
`Tolerance` (`zero + ε ≡ ε`) — not in the current record. The full
176-
retract proof and the Lipschitz generalisation (`L_g ≠ 1`) are
177-
deferred to subsequent rungs.
175+
`Tolerance` (`zero + ε ≡ ε`) — not in the current record; a
176+
design call on whether to extend the `Tolerance` interface or layer
177+
a separate `BalancedTolerance` record on top is deferred to the
178+
caller.
179+
180+
Second slice landed alongside (axis-2 design note §7 obligations
181+
7 and 8): `Separated` (separation predicate on the pseudo-metric:
182+
`dist b₁ b₂ ≤ zero → b₁ ≡ b₂`),
183+
`echo-approx-zero-collapses-strict` (under separation, every
184+
zero-tolerance approximate echo IS a strict echo with the same
185+
A-witness — the §4 "Approximate → strict, only when separated, at
186+
ε = 0" statement made formal), and the axis-1 shadow lemmas
187+
`echo-shadow-A`, `echo-shadow-iso-{to,from}`,
188+
`echo-strict→approx-shadow-A`,
189+
`echo-strict→approx-collapse-shadow-A`. The last two pin the
190+
axis-1 / axis-2 cross-classification: the A-component (the axis-1
191+
"shadow" of the approximate echo) is preserved on the nose by
192+
`echo-strict→approx` and round-trips definitionally through the
193+
zero-collapse under separation.
194+
195+
The Lipschitz generalisation (`L_g ≠ 1`) and the full B-component
196+
+ tolerance-budget retract round-trip remain deferred — both
197+
require new structure on `Tolerance` (multiplication for the
198+
former, `+`-identity for the latter).
178199

179200
### Q4. Associativity — landed
180201

proofs/agda/EchoApprox.agda

Lines changed: 122 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,20 @@
2626
-- preserves the A-witness up to `refl`,
2727
-- witnessing the retraction direction
2828
-- definitionally
29+
-- * Separated -- separation predicate on a pseudo-metric:
30+
-- `dist b₁ b₂ ≤ zero → b₁ ≡ b₂`
31+
-- * echo-approx-zero-collapses-strict -- §7 #7: under separation, an
32+
-- ε≡zero approximate echo IS a
33+
-- strict echo
34+
-- * echo-shadow-A -- §7 #8 axis-1 shadow: the underlying
35+
-- A-witness of an approximate echo;
36+
-- `echo-strict→approx` agrees with the
37+
-- strict A-witness on the nose
38+
-- * echo-shadow-iso-to / -from -- §7 #8 trivial repackaging of `EchoR`
39+
-- as an existential `Σ A (λ x → dist
40+
-- (f x) y ≤ ε)` (definitional both ways)
41+
-- * echo-strict→approx-shadow-A -- the A-component of `echo-strict→approx`
42+
-- equals the strict A-component (refl)
2943
--
3044
-- The non-expansiveness side condition on the outer leg is the
3145
-- minimal hypothesis under which tolerances accumulate additively;
@@ -41,9 +55,13 @@
4155
-- the canonical-split forward section, and an A-component round-trip
4256
-- witness. The B-component round-trip and the full tolerance round-trip
4357
-- need a `+`-left-identity axiom on `Tolerance` (`zero + ε ≡ ε`, not
44-
-- currently in the record); §7 obligations 7 (zero-collapse under
45-
-- separation) and 8 (axis-1 shadow agreement) are deferred to
46-
-- subsequent rungs.
58+
-- currently in the record); see the `Tolerance` design-decision note
59+
-- in the PR body for two options (interface extension vs. additive
60+
-- `BalancedTolerance` record). §7 obligations 7 (separated zero-collapse)
61+
-- and 8 (axis-1 shadow agreement) are now landed below. Rung C
62+
-- (full B-component + tolerance round-trip) is deferred pending the
63+
-- design call. Rung D (Lipschitz `L_g ≠ 1`) is deferred — it requires
64+
-- multiplication on `Tolerance`, another interface call.
4765

4866
module EchoApprox where
4967

@@ -261,3 +279,104 @@ module Approx
261279
(echo-approx-comp-retract-to f g e))
262280
≡ proj₁ e
263281
echo-approx-comp-retract-A f g g-nonexp (x , _) = refl
282+
283+
----------------------------------------------------------------------
284+
-- §7 obligation 7: separated zero-collapse.
285+
--
286+
-- A pseudo-metric is *separated* when zero distance implies
287+
-- propositional equality on the carrier. Pseudo-metrics in general
288+
-- only guarantee `dist y y ≡ zero`; the converse (a metric proper)
289+
-- is an extra hypothesis the `PseudoMetric` record deliberately
290+
-- does not bake in. Callers who need the converse supply a
291+
-- `Separated` witness explicitly at the lemma site.
292+
--
293+
-- Under that hypothesis, the strict-vs-approximate gap closes at
294+
-- ε = zero: any zero-tolerance approximate echo IS a strict echo,
295+
-- with the same A-witness on the nose. This realises §7 #7 of the
296+
-- axis-2 design note and the §4 "Approximate → strict (only when
297+
-- separated, at ε = 0)" statement.
298+
--
299+
-- Without separation the converse fails by design — multiple `x`s
300+
-- may share zero distance to `y` without `f x ≡ y` on the nose.
301+
-- That is the point of an approximate echo.
302+
----------------------------------------------------------------------
303+
304+
Separated : Set (b ⊔ ℓ)
305+
Separated = b₁ b₂ dist b₁ b₂ ≤ zero b₁ ≡ b₂
306+
307+
echo-approx-zero-collapses-strict :
308+
Separated
309+
{f : A B} {y : B} EchoR zero f y Echo f y
310+
echo-approx-zero-collapses-strict sep {f = f} {y = y} (x , dfx≤0) =
311+
x , sep (f x) y dfx≤0
312+
313+
----------------------------------------------------------------------
314+
-- §7 obligation 8: axis-1 shadow agreement.
315+
--
316+
-- The "shadow" of an approximate echo is its underlying A-witness —
317+
-- the projection that forgets the metric-bound proof. Two flavours:
318+
--
319+
-- * `echo-shadow-A` — extracts the A-witness from an
320+
-- approximate echo (definitional,
321+
-- the existing `proj₁`).
322+
--
323+
-- * `echo-shadow-iso-{to,from}` — the trivial repackaging of
324+
-- `EchoR ε f y` as the existential
325+
-- `Σ A (λ x → dist (f x) y ≤ ε)`.
326+
-- Both directions are `id` because
327+
-- the two shapes are definitionally
328+
-- equal; the iso lemma here pins
329+
-- the §7 #8 obligation explicitly.
330+
--
331+
-- * `echo-strict→approx-shadow-A` — axis-1 / axis-2 cross-check:
332+
-- `echo-strict→approx` preserves
333+
-- the A-component on the nose
334+
-- (`refl`). This is the
335+
-- definitional version of "the
336+
-- strict→approx inclusion and the
337+
-- A-shadow projection cohere"
338+
-- from the user-prompt framing.
339+
--
340+
-- Together these say: the A-component is a genuine axis-1 invariant
341+
-- of approximate echoes — every move in the axis-2 calculus that
342+
-- keeps the A-witness fixed (intro, strict→approx, relax,
343+
-- canonical-split retract section) preserves the axis-1 shadow
344+
-- definitionally.
345+
----------------------------------------------------------------------
346+
347+
echo-shadow-A :
348+
: Tol} {f : A B} {y : B} EchoR ε f y A
349+
echo-shadow-A = proj₁
350+
351+
-- Forward: an approximate echo IS an existential with metric bound.
352+
-- Definitionally `id`; the lemma pins the axis-1 shadow obligation.
353+
echo-shadow-iso-to :
354+
: Tol} {f : A B} {y : B}
355+
EchoR ε f y Σ A (λ x dist (f x) y ≤ ε)
356+
echo-shadow-iso-to e = e
357+
358+
echo-shadow-iso-from :
359+
: Tol} {f : A B} {y : B}
360+
Σ A (λ x dist (f x) y ≤ ε) EchoR ε f y
361+
echo-shadow-iso-from e = e
362+
363+
-- A-component of `echo-strict→approx` agrees with the strict
364+
-- A-component on the nose. The transport in `echo-strict→approx`
365+
-- only touches the bound proof, never the A-witness.
366+
echo-strict→approx-shadow-A :
367+
{f : A B} {y : B} (e : Echo f y)
368+
echo-shadow-A (echo-strict→approx e) ≡ proj₁ e
369+
echo-strict→approx-shadow-A (x , _) = refl
370+
371+
-- Round-trip: under separation, `echo-approx-zero-collapses-strict`
372+
-- and `echo-strict→approx` are mutually A-inverse at ε = zero,
373+
-- definitionally on the A-component. This closes the §4 statement
374+
-- "Approximate → strict (only when separated, at ε = 0)" with a
375+
-- definitional witness on the axis-1 shadow.
376+
echo-strict→approx-collapse-shadow-A :
377+
(sep : Separated)
378+
{f : A B} {y : B} (e : Echo f y)
379+
proj₁ (echo-approx-zero-collapses-strict sep
380+
(echo-strict→approx e))
381+
≡ proj₁ e
382+
echo-strict→approx-collapse-shadow-A sep (x , _) = refl

proofs/agda/EchoApproxInstance.agda

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,10 @@ approx-compose = echo-approx-compose
9696
approx-comp-sound = echo-approx-comp-sound
9797
approx-comp-retract-to = echo-approx-comp-retract-to
9898
approx-comp-retract-A = echo-approx-comp-retract-A
99+
approx-Separated = Separated
100+
approx-zero-collapses-strict = echo-approx-zero-collapses-strict
101+
approx-shadow-A = echo-shadow-A
102+
approx-shadow-iso-to = echo-shadow-iso-to
103+
approx-shadow-iso-from = echo-shadow-iso-from
104+
approx-strict→approx-shadow-A = echo-strict→approx-shadow-A
105+
approx-strict→approx-collapse-shadow-A = echo-strict→approx-collapse-shadow-A

proofs/agda/Smoke.agda

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ open import EchoApproxInstance using
9090
; approx-comp-sound
9191
; approx-comp-retract-to
9292
; approx-comp-retract-A
93+
; approx-Separated
94+
; approx-zero-collapses-strict
95+
; approx-shadow-A
96+
; approx-shadow-iso-to
97+
; approx-shadow-iso-from
98+
; approx-strict→approx-shadow-A
99+
; approx-strict→approx-collapse-shadow-A
93100
)
94101

95102
open import EchoIndexed using

0 commit comments

Comments
 (0)