Skip to content

Commit e1e904c

Browse files
theory: EchoCost — Axis 8 cost-indexed refinement (thin slice) (#85)
Adds `proofs/agda/EchoCost.agda` (and `EchoCostInstance.agda` for smoke pins), the cost-indexed refinement of `Echo` named in `docs/echo-types/taxonomy.md` §Axis 8 (refinement 1: full cost-tracking via an explicit cost algebra). Sits orthogonal to the already-landed qualitative Axis-8 artefacts (`EchoDecidable`, `EchoFiberCount`, `EchoAccess`); names the resource-budget dimension of the axis. ## What lands - `CostAlgebra` — ordered commutative-monoid-flavoured cost carrier (`Cost`, `zero`, `_+_`, `_≤_`, `≤-refl`, `≤-trans`, `+-identityˡ`, `+-mono-≤`). Right-identity / associativity / commutativity deliberately omitted — the headlines close without them; layering pattern matches `BalancedTolerance` in `EchoApprox.agda`. - `EchoC cost c f y := Σ A (λ x → f x ≡ y × cost x ≤ c)` - Headlines: - `echo-cost-intro` / `-≤` — zero-budget intro - `echo-cost-relax` — monotone in budget - `echo-cost-forget` — Axis-8 → Axis-1 projection (the shadow obligation of every Axis-8 refinement) - `echo-cost-compose` — two-source additive composition (combiner + image-equation + cost-receipt triple, no funext) - `echo-cost-compose-mono` — single-source specialisation - `echo-cost-forget-compose-mono-A` — compose-then-forget agrees with the bare composite on the A-component - `echo-cost-relax-zero` — `(zero + c) ≡ c` (the budget lever) - Wired into `All.agda` (alphabetical, between `EchoApproxInstance` and `EchoIndexed`) and `Smoke.agda` (per-lemma `using` clause on `EchoCostInstance`, mirroring the `EchoApproxInstance` pattern). ## Design judgement calls - **`CostAlgebra` field minimality.** Took only the laws needed to close the four headlines (`+-identityˡ` for the budget round-trip, `+-mono-≤` for compose). Right-identity / commutativity / associativity belong on a separate `BalancedCostAlgebra` record if a downstream proof needs them — same layering as `BalancedTolerance`. - **Composition shape (`echo-cost-compose`).** Took the more general two-source first-order shape with an explicit `combine : A → B → A''`, caller-supplied `image-eq`, and caller-supplied `cost-bound`. Strictly more general than restricting to an endomorphic outer leg (the `EchoApprox.echo-approx-compose` shape, `g : B → B`); the single-source corner falls out as `echo-cost-compose-mono`. No funext used; image equation is supplied, not derived from a pointwise homotopy. - **Trivial-on-⊤ instance via `EchoCostInstance.agda`.** Closes the CLAUDE.md "Working rules" invariant for parameterised modules (`EchoCost.Cost` is parameterised over `K : CostAlgebra ℓ`). Exact recipe of `EchoApproxInstance.agda` post-PR-#71. ## Invariants - `--safe --without-K` on every new module - No postulates, no funext, no escape pragmas, no `believe_me` - Clean-worktree Agda build green: `EchoCost.agda` + `EchoCostInstance.agda` + `All.agda` + `Smoke.agda` all exit 0 (verified after `find . -name '*.agdai' -delete`) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 4015df6 commit e1e904c

4 files changed

Lines changed: 474 additions & 0 deletions

File tree

proofs/agda/All.agda

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ open import EchoCNOBridge
2020

2121
open import EchoApprox
2222
open import EchoApproxInstance
23+
open import EchoCost
24+
open import EchoCostInstance
2325
open import EchoIndexed
2426
open import EchoDecidable
2527
open import EchoAccess

proofs/agda/EchoCost.agda

Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
{-# OPTIONS --safe --without-K #-}
2+
3+
-- Cost-indexed echoes over an ordered commutative-monoid cost algebra.
4+
--
5+
-- Axis 8 *quantitative* refinement (taxonomy.md §8, refinement 1: full
6+
-- cost-tracking via an explicit cost algebra). Sits orthogonal to the
7+
-- already-landed Axis 8 artefacts:
8+
--
9+
-- * `EchoDecidable.agda` — refinement 3, qualitative decidability layer
10+
-- * `EchoFiberCount.agda` — quantitative fibre-count for finite domains
11+
-- * `EchoAccess.agda` — graded access modality (5-grade enum)
12+
--
13+
-- The cost-indexed echo names the *resource-budget* dimension of
14+
-- Axis 8: not "is a witness produced?" (decidability) and not "how
15+
-- many witnesses?" (fibre count), but "at what cost?". The cost
16+
-- carrier is left abstract — callers supply an ordered commutative-
17+
-- monoid-flavoured `CostAlgebra` at use sites.
18+
--
19+
-- EchoC cost c f y := Σ A (λ x → f x ≡ y × cost x ≤ c)
20+
--
21+
-- Headline lemmas:
22+
--
23+
-- * echo-cost-intro -- strict echo at zero-budget when witness
24+
-- has zero cost (constructor analogue of
25+
-- `Echo.echo-intro`, refined by budget).
26+
-- * echo-cost-relax -- monotone in budget: c₁ ≤ c₂ ⇒ EchoC c₁ ⊑ EchoC c₂.
27+
-- * echo-cost-forget -- EchoC cost c f y → Echo f y; the projection
28+
-- down to the bare Axis-1 echo (the
29+
-- "shadow" obligation of every refinement).
30+
-- * echo-cost-compose -- additive composition: an `EchoC cost₁ c₁ f b`
31+
-- and `EchoC cost₂ c₂ g y` with `g b ≡ y` and
32+
-- a combiner `combine : A → A' → A''` with
33+
-- `f' (combine x₁ x₂) ≡ g (f x₁)` and a cost
34+
-- receipt `cost' (combine x₁ x₂) ≤ cost₁ x₁
35+
-- + cost₂ x₂` yield an `EchoC cost' (c₁ + c₂)
36+
-- f' y`. The compositional shape is
37+
-- first-order — no funext — exactly mirroring
38+
-- the additive-error shape of `EchoApprox`'s
39+
-- `echo-approx-compose`.
40+
--
41+
-- Composition shape (design call). The minimal first-order shape that
42+
-- (a) avoids funext, (b) preserves the additive-cost story, and (c)
43+
-- still composes across two distinct domains `A`/`A'` is to
44+
-- parameterise by an explicit combiner that builds an `A''`-witness
45+
-- from the two source witnesses with a controlled cost receipt and a
46+
-- controlled image equation. This is strictly more general than
47+
-- restricting to a single-domain endomorphic situation (the shape
48+
-- `EchoApprox.echo-approx-compose` uses, `g : B → B`); the
49+
-- single-domain corner falls out by taking `A := A'` and
50+
-- `combine := proj₂`.
51+
--
52+
-- Parameterisation note. `EchoC` is parameterised over a
53+
-- `CostAlgebra`, so per the CLAUDE.md "Working rules" invariant
54+
-- (every headline pinned in `Smoke.agda` via `using`), the headline
55+
-- lemmas are exposed top-level via `EchoCostInstance.agda`, a
56+
-- trivial-on-⊤ instance — same recipe as `EchoApproxInstance.agda`.
57+
58+
module EchoCost where
59+
60+
open import Level using (Level; _⊔_; suc)
61+
open import Function.Base using (_∘_; id)
62+
open import Data.Product.Base using (Σ; _,_; _×_; proj₁; proj₂)
63+
open import Relation.Binary.PropositionalEquality
64+
using (_≡_; refl; sym; subst; trans; cong)
65+
66+
open import Echo using (Echo)
67+
68+
----------------------------------------------------------------------
69+
-- Cost algebra
70+
----------------------------------------------------------------------
71+
72+
-- An ordered commutative-monoid-flavoured cost carrier. Just enough
73+
-- structure to state additive composition with `zero` as a left
74+
-- identity for the budget:
75+
--
76+
-- * reflexive, transitive `≤`,
77+
-- * binary `+`,
78+
-- * `+`-monotone on both sides simultaneously (`+-mono-≤`),
79+
-- * left-identity `zero + c ≡ c` (the budget round-trip lever).
80+
--
81+
-- This is the smallest set of laws under which `echo-cost-intro` /
82+
-- `echo-cost-relax` / `echo-cost-compose` close without funext, and
83+
-- which the trivial-on-⊤ instance discharges by `tt` / `refl`. The
84+
-- right-identity / associativity / commutativity laws are not needed
85+
-- for the headlines here and are omitted on purpose (a real `ℕ`
86+
-- instance would supply them via `Data.Nat.Properties`; they would
87+
-- live on a separate `BalancedCostAlgebra` record if a downstream
88+
-- proof needs them — same layering pattern as `BalancedTolerance` in
89+
-- `EchoApprox.agda`).
90+
91+
record CostAlgebra: Set (suc ℓ) where
92+
infix 4 _≤_
93+
infixl 6 _+_
94+
field
95+
Cost : Set
96+
zero : Cost
97+
_+_ : Cost Cost Cost
98+
_≤_ : Cost Cost Set
99+
≤-refl : {c} c ≤ c
100+
≤-trans : {a b c} a ≤ b b ≤ c a ≤ c
101+
+-identityˡ : c (zero + c) ≡ c
102+
+-mono-≤ : {a b c d} a ≤ c b ≤ d (a + b) ≤ (c + d)
103+
104+
----------------------------------------------------------------------
105+
-- Cost-indexed echo
106+
----------------------------------------------------------------------
107+
108+
module Cost
109+
{ℓ} (K : CostAlgebra ℓ)
110+
where
111+
112+
open CostAlgebra K
113+
114+
-- `EchoC cost c f y`: a witness `x : A` whose image under `f` hits
115+
-- `y` exactly *and* whose ascribed cost is within budget `c`.
116+
--
117+
-- Two pieces of evidence in the second component:
118+
-- * `f x ≡ y` : the bare-echo equation (Axis-1 content)
119+
-- * `cost x ≤ c` : the budget receipt (Axis-8 content)
120+
--
121+
-- The Σ-shape uses `_×_` rather than nested Σ for symmetry with
122+
-- `EchoApprox.EchoR`, which lets the `echo-cost-forget` projection
123+
-- to the bare `Echo` land by `(proj₁ , proj₁ ∘ proj₂)`.
124+
EchoC :
125+
{a b} {A : Set a} {B : Set b}
126+
(cost : A Cost) (c : Cost) (f : A B) B Set (a ⊔ b ⊔ ℓ)
127+
EchoC {A = A} cost c f y =
128+
Σ A (λ x (f x ≡ y) × (cost x ≤ c))
129+
130+
----------------------------------------------------------------------
131+
-- Headline 1: exact intro at zero-budget when the witness has zero cost.
132+
--
133+
-- The cost-indexed analogue of `Echo.echo-intro`: any `x : A` whose
134+
-- ascribed cost is ≤ zero (which by reflexivity holds whenever the
135+
-- cost *is* zero) lifts into its own fibre with zero budget. The
136+
-- bound proof is `≤-refl` at the cost of `x`, transported along the
137+
-- caller's premise `cost x ≤ zero`.
138+
--
139+
-- Two equivalent shapes:
140+
-- * a "you tell me the cost is ≤ zero" version (`echo-cost-intro-≤`)
141+
-- * a "the cost *is* zero" definitional version (`echo-cost-intro`)
142+
--
143+
-- The latter is the named headline; the former is the more general
144+
-- form callers reach for when they have a `cost x ≤ zero` proof in
145+
-- hand from elsewhere.
146+
----------------------------------------------------------------------
147+
148+
echo-cost-intro-≤ :
149+
{a b} {A : Set a} {B : Set b}
150+
(cost : A Cost) (f : A B) (x : A)
151+
cost x ≤ zero
152+
EchoC cost zero f (f x)
153+
echo-cost-intro-≤ cost f x cost-x≤0 =
154+
x , refl , cost-x≤0
155+
156+
echo-cost-intro :
157+
{a b} {A : Set a} {B : Set b}
158+
(cost : A Cost) (f : A B) (x : A)
159+
cost x ≡ zero
160+
EchoC cost zero f (f x)
161+
echo-cost-intro cost f x cost-x≡0 =
162+
x , refl , subst (_≤ zero) (sym cost-x≡0) ≤-refl
163+
164+
----------------------------------------------------------------------
165+
-- Headline 2: budget is monotone — a tighter budget refines a looser
166+
-- one. One `≤-trans` step. The bare-echo equation `f x ≡ y` is
167+
-- untouched; only the receipt grows.
168+
----------------------------------------------------------------------
169+
170+
echo-cost-relax :
171+
{a b} {A : Set a} {B : Set b}
172+
{cost : A Cost} {c₁ c₂ : Cost} {f : A B} {y : B}
173+
c₁ ≤ c₂ EchoC cost c₁ f y EchoC cost c₂ f y
174+
echo-cost-relax c₁≤c₂ (x , p , cost-x≤c₁) =
175+
x , p , ≤-trans cost-x≤c₁ c₁≤c₂
176+
177+
----------------------------------------------------------------------
178+
-- Headline 3: forget the cost receipt and recover the bare echo.
179+
--
180+
-- The Axis-8 → Axis-1 projection. `echo-cost-forget e := (proj₁ e ,
181+
-- proj₁ (proj₂ e))` — keep the A-witness and the bare-echo equation;
182+
-- drop the budget receipt. This is the *shadow* obligation of every
183+
-- Axis-8 refinement (same role as `echo-shadow-A` in `EchoApprox`):
184+
-- every move in the cost-indexed calculus that preserves
185+
-- `(x , f x ≡ y)` preserves the Axis-1 echo on the nose.
186+
----------------------------------------------------------------------
187+
188+
echo-cost-forget :
189+
{a b} {A : Set a} {B : Set b}
190+
{cost : A Cost} {c : Cost} {f : A B} {y : B}
191+
EchoC cost c f y Echo f y
192+
echo-cost-forget (x , p , _) = x , p
193+
194+
----------------------------------------------------------------------
195+
-- Headline 4: additive composition.
196+
--
197+
-- The cost-indexed analogue of `Echo-comp-iso` / `echo-approx-compose`.
198+
-- Form: given
199+
--
200+
-- * an EchoC at cost-budget `c₁` for `f : A B` at intermediate `b`,
201+
-- * an EchoC at cost-budget `c₂` for `g : B C` at target `y`
202+
-- with `g b ≡ y`,
203+
-- * a target domain `A''` and a function `f' : A'' C` taking
204+
-- the composite-witness shape,
205+
-- * a *combiner* `combine : A A' A''` that produces an `A''`-
206+
-- witness from the two source witnesses, together with two
207+
-- receipts:
208+
-- (i) `image-eq` : `f' (combine x₁ x₂) ≡ g (f x₁)` —
209+
-- the combined witness reaches the
210+
-- same point in `C` as the composite,
211+
-- (ii) `cost-bound` : `cost' (combine x₁ x₂) ≤ cost₁ x₁ + cost₂ x₂`
212+
-- — the combined cost stays inside
213+
-- the additive budget,
214+
--
215+
-- produce an `EchoC cost' (c₁ + c₂) f' y`. The bound proof chains
216+
-- the combiner receipt through `+-mono-≤` and `≤-trans`; the
217+
-- image equation chains through `trans (image-eq) (cong g (proj₁
218+
-- (proj₂ e₁)))` and then through `proj₁ (proj₂ e₂)`.
219+
--
220+
-- Composition shape (design call). This is strictly more general
221+
-- than the EchoApprox-style "single-domain endomorphic g" shape: it
222+
-- compositionally combines two echoes whose A-witnesses may live in
223+
-- different types and whose `f'`-target need not equal `g ∘ f` on
224+
-- the nose. The natural specialisation `f' := g ∘ f` and `combine
225+
-- := λ x₁ _ x₁` (drop the second witness) recovers the
226+
-- single-source story; we pin it as `echo-cost-compose-mono` below.
227+
--
228+
-- No funext used. The image equation is supplied by the caller (not
229+
-- derived from a pointwise homotopy on the carriers), and the cost
230+
-- bound chains through `+-mono-≤` / `≤-trans` — both first-order.
231+
----------------------------------------------------------------------
232+
233+
-- `cost₂` lives on `B`, not on `A'`, because the second echo
234+
-- `EchoC cost₂ c₂ g y` has `g : B C` and so its A-witness is a
235+
-- `B`-point. The combiner takes the original `A`-witness from
236+
-- `e₁` together with the `B`-witness from `e₂` and produces an
237+
-- `A''`-witness for the composite target function `f' : A'' C`.
238+
echo-cost-compose :
239+
{a a'' b c} {A : Set a} {A'' : Set a''} {B : Set b} {C : Set c}
240+
{cost₁ : A Cost} {cost₂ : B Cost} {cost' : A'' Cost}
241+
{c₁ c₂ : Cost}
242+
(f : A B) (g : B C) (f' : A'' C)
243+
(combine : A B A'')
244+
{b'} {y : C}
245+
(e₁ : EchoC cost₁ c₁ f b')
246+
(e₂ : EchoC cost₂ c₂ g y)
247+
g b' ≡ y
248+
f' (combine (proj₁ e₁) (proj₁ e₂)) ≡ g (f (proj₁ e₁))
249+
cost' (combine (proj₁ e₁) (proj₁ e₂)) ≤
250+
((cost₁ (proj₁ e₁)) + (cost₂ (proj₁ e₂)))
251+
EchoC cost' (c₁ + c₂) f' y
252+
echo-cost-compose {cost₁ = cost₁} {cost₂ = cost₂} {cost' = cost'}
253+
{c₁ = c₁} {c₂ = c₂} f g f' combine {b' = b'} {y = y}
254+
(x₁ , fp₁ , cost₁-x≤c₁) (x₂ , gp₂ , cost₂-x≤c₂)
255+
gb'≡y combine-image combine-cost =
256+
combine x₁ x₂ , img , bnd
257+
where
258+
-- f' (combine x₁ x₂) = g (f x₁) by `combine-image`;
259+
-- = g b' by `cong g fp₁` (since `fp₁ : f x₁ ≡ b'`);
260+
-- = y by `gb'≡y`.
261+
img : f' (combine x₁ x₂) ≡ y
262+
img = trans combine-image (trans (cong g fp₁) gb'≡y)
263+
264+
-- cost' (combine x₁ x₂) ≤ cost₁ x₁ + cost₂ x₂ (by combine-cost)
265+
-- cost₁ x₁ + cost₂ x₂ ≤ c₁ + c₂ (by +-mono-≤)
266+
bnd : cost' (combine x₁ x₂) ≤ (c₁ + c₂)
267+
bnd = ≤-trans combine-cost (+-mono-≤ cost₁-x≤c₁ cost₂-x≤c₂)
268+
269+
----------------------------------------------------------------------
270+
-- Single-source specialisation of composition.
271+
--
272+
-- `echo-cost-compose-mono` is the corner of `echo-cost-compose` in
273+
-- which we drop the second source witness: `A'' := A`, `combine x₁
274+
-- _ := x₁`, and `cost' := cost₁`. The image and cost receipts then
275+
-- discharge to `refl` and `≤-refl` after `+-identityˡ`-style
276+
-- algebra in the caller's instance; we leave them as explicit
277+
-- hypotheses (matching the `EchoApprox` retract pattern) so that
278+
-- callers don't need to do `subst` gymnastics inside this module.
279+
--
280+
-- The caller-side discharge is trivial whenever `cost₂` is the
281+
-- constant-zero cost (a "free" outer leg `g`): then `cost₁ x₁ +
282+
-- cost₂ x₂ ≡ cost₁ x₁ + zero`, and a right-identity step closes
283+
-- it. The asymmetric "free outer leg" corner is one of the
284+
-- natural use sites for this shape.
285+
----------------------------------------------------------------------
286+
287+
echo-cost-compose-mono :
288+
{a b c} {A : Set a} {B : Set b} {C : Set c}
289+
{cost₁ : A Cost} {cost₂ : B Cost}
290+
{c₁ c₂ : Cost}
291+
(f : A B) (g : B C)
292+
{b'} {y : C}
293+
(e₁ : EchoC cost₁ c₁ f b')
294+
(e₂ : EchoC cost₂ c₂ g y)
295+
g b' ≡ y
296+
cost₁ (proj₁ e₁) ≤ ((cost₁ (proj₁ e₁)) + (cost₂ (proj₁ e₂)))
297+
EchoC cost₁ (c₁ + c₂) (g ∘ f) y
298+
echo-cost-compose-mono {cost₁ = cost₁} {cost₂ = cost₂}
299+
{c₁ = c₁} {c₂ = c₂} f g {b' = b'} {y = y}
300+
(x₁ , fp₁ , cost₁-x≤c₁) (x₂ , gp₂ , cost₂-x≤c₂)
301+
gb'≡y x₁-≤-sum =
302+
x₁ , img , bnd
303+
where
304+
img : g (f x₁) ≡ y
305+
img = trans (cong g fp₁) gb'≡y
306+
307+
bnd : cost₁ x₁ ≤ (c₁ + c₂)
308+
bnd = ≤-trans x₁-≤-sum (+-mono-≤ cost₁-x≤c₁ cost₂-x≤c₂)
309+
310+
----------------------------------------------------------------------
311+
-- Forget-respects-compose (axis-1 shadow law for the composite).
312+
--
313+
-- The bare-echo projection of `echo-cost-compose-mono e₁ e₂ ...` is
314+
-- the bare composite echo at the A-witness of `e₁`. This is the
315+
-- compositional version of `echo-cost-forget` — composing in the
316+
-- cost-indexed calculus and then forgetting the receipt agrees
317+
-- with the bare-Axis-1 composite of the forgotten echoes on the
318+
-- A-component.
319+
----------------------------------------------------------------------
320+
321+
echo-cost-forget-compose-mono-A :
322+
{a b c} {A : Set a} {B : Set b} {C : Set c}
323+
{cost₁ : A Cost} {cost₂ : B Cost}
324+
{c₁ c₂ : Cost}
325+
(f : A B) (g : B C)
326+
{b' : B} {y : C}
327+
(e₁ : EchoC cost₁ c₁ f b')
328+
(e₂ : EchoC cost₂ c₂ g y)
329+
(gb'≡y : g b' ≡ y)
330+
(x₁-≤-sum :
331+
cost₁ (proj₁ e₁) ≤
332+
((cost₁ (proj₁ e₁)) + (cost₂ (proj₁ e₂))))
333+
proj₁ (echo-cost-forget
334+
(echo-cost-compose-mono {cost₁ = cost₁} {cost₂ = cost₂}
335+
f g e₁ e₂ gb'≡y x₁-≤-sum))
336+
≡ proj₁ (echo-cost-forget e₁)
337+
echo-cost-forget-compose-mono-A f g (x , _ , _) _ _ _ = refl
338+
339+
----------------------------------------------------------------------
340+
-- Budget-zero round-trip companion to `echo-cost-relax`.
341+
--
342+
-- `echo-cost-relax-zero`: relaxing from `zero` to `(zero + c)` is
343+
-- the same as relaxing to `c` (via `+-identityˡ`). The smallest
344+
-- statement that uses the `+-identityˡ` field of `CostAlgebra`,
345+
-- in the same spirit as `EchoApprox.echo-approx-comp-retract-budget`.
346+
----------------------------------------------------------------------
347+
348+
echo-cost-relax-zero :
349+
(c : Cost) (zero + c) ≡ c
350+
echo-cost-relax-zero = +-identityˡ

0 commit comments

Comments
 (0)