Skip to content

Commit baf5db7

Browse files
committed
feat(abi): close TacticRecord round-trip lemmas (closes #152)
Discharges the two round-trip lemmas deferred at lines 88-93 and 187-196 of `src/abi/EchidnaABI/TacticRecord.idr`: natToFinToNat : Nat → 0 LT n (S MaxConfidence) → finToNat (natToFinLT n) = n clampRoundtripInRange: Nat → LT n (S MaxConfidence) → finToNat (clampConfidence n) = n Approach — what the original deferral comment got nearly right: The note "requires careful LTE-weakening that has not yet been spelled out structurally" identified a real symptom but mis-located the cause. The trap is a unification artefact, not a missing weakening lemma: specialising the round-trip at `S MaxConfidence` forces the recursive call to discharge `LTE (S k) (S MaxConfidence)` while the LTESucc pattern only hands you `LTE (S k) MaxConfidence` — the same proposition off-by-one. Explicit weakening with `lteSuccRight` works but is inelegant. Cleaner shape: introduce a polymorphic helper finToNatNatToFinLT : (n : Nat) -> {m : Nat} -> (0 prf : LT n m) -> finToNat (natToFinLT n {prf}) = n with `m` implicit so the recursive call's `m` is structurally inferred to the predecessor — the LTESucc constraint then matches exactly, no glue. The `S MaxConfidence` instance specialises in one line. `clampRoundtripInRange` closes by `with`-abstracting on the same `isLT n (S MaxConfidence)` that `clampConfidence` inspects: the Yes branch reduces and discharges via `natToFinToNat`, the No branch is contradicted by the in-range hypothesis via `absurd`. Verification: - Module type-checks clean on Idris2 0.8.0 `idris2 --check EchidnaABI/TacticRecord.idr` → 1/1: Building OK - All three new lemmas confirmed total via `:total` REPL - Constraint preserved: zero believe_me, zero postulates, zero admits, zero assert_total. Only standard-library inhabitants used. Refs the deferred proof debt called out in commit 4118893 (the introducing change for TacticRecord.idr).
1 parent 78a65dc commit baf5db7

1 file changed

Lines changed: 44 additions & 12 deletions

File tree

src/abi/EchidnaABI/TacticRecord.idr

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,38 @@ clampConfidence n = case isLT n (S MaxConfidence) of
8585
Yes prf => natToFinLT n
8686
No _ => last -- saturate to MaxConfidence
8787

88-
-- Round-trip lemma `natToFinToNat` is desirable but requires careful
89-
-- LTE-weakening that has not yet been spelled out structurally. The
90-
-- absence of this lemma here is INTENTIONAL: the file ships with the
91-
-- comparison total order proven and the round-trip property captured
92-
-- as a Wave-3 sub-issue rather than a believe-me hole. See issue
93-
-- breadcrumb at the top of this file.
88+
------------------------------------------------------------------------
89+
-- natToFinLT / finToNat Round-Trip
90+
------------------------------------------------------------------------
91+
92+
-- The LTE-weakening worry recorded in the original deferral comment was
93+
-- a unification trap, not a missing lemma. Specialising on
94+
-- `S MaxConfidence` directly forces the recursive call to see
95+
-- `LTE (S k) MaxConfidence`, but the recursive obligation needs
96+
-- `LTE (S k) (S MaxConfidence)` — the same proposition off-by-one.
97+
-- The polymorphic helper sidesteps the trap: with `m` implicit the
98+
-- recursive `m` is inferred to the structural predecessor, so the
99+
-- LTESucc pattern matches without explicit weakening. The
100+
-- `S MaxConfidence` instance is then a one-line specialisation.
101+
102+
||| Generic round-trip: every nat strictly below `m` is faithfully
103+
||| recovered by `finToNat . natToFinLT`. Polymorphic in `m` so the
104+
||| recursion's implicit upper bound shrinks structurally and the
105+
||| LTESucc pattern can be unpacked without `lteSuccRight` glue.
106+
public export
107+
finToNatNatToFinLT :
108+
(n : Nat) -> {m : Nat} -> (0 prf : LT n m) ->
109+
finToNat (natToFinLT n {prf}) = n
110+
finToNatNatToFinLT 0 (LTESucc _) = Refl
111+
finToNatNatToFinLT (S k) (LTESucc lt) = cong S (finToNatNatToFinLT k lt)
112+
113+
||| In-range nat ↔ ConfidenceFP round-trip. Discharges the round-trip
114+
||| obligation flagged at lines 88-93 of the original file.
115+
public export
116+
natToFinToNat :
117+
(n : Nat) -> (0 prf : LT n (S MaxConfidence)) ->
118+
finToNat (natToFinLT n {prf}) = n
119+
natToFinToNat n prf = finToNatNatToFinLT n prf
94120

95121
------------------------------------------------------------------------
96122
-- Comparison: by confidence, descending
@@ -188,9 +214,15 @@ confidenceFloatZero = Refl
188214
-- ABI Roundtrip Invariant
189215
------------------------------------------------------------------------
190216

191-
-- clampRoundtripInRange is deferred along with natToFinToNat above;
192-
-- the constructive round-trip proof requires the in-range
193-
-- nat-fin-nat lemma which is the Wave-3 sub-issue. The clamp
194-
-- operation itself is total and that totality is verified by
195-
-- Idris2's pattern-matching exhaustiveness on the `with` of
196-
-- `isLT n (S MaxConfidence)`.
217+
||| Clamp is the identity on in-range inputs. The `with`-abstraction
218+
||| pivots on the very `isLT n (S MaxConfidence)` that `clampConfidence`
219+
||| inspects, so the `Yes` branch reduces the case and we discharge it
220+
||| via the round-trip lemma; the `No` branch is contradicted by the
221+
||| in-range hypothesis, closed by `absurd`. Total, no admits.
222+
public export
223+
clampRoundtripInRange :
224+
(n : Nat) -> (prf : LT n (S MaxConfidence)) ->
225+
finToNat (clampConfidence n) = n
226+
clampRoundtripInRange n prf with (isLT n (S MaxConfidence))
227+
_ | Yes prf' = natToFinToNat n prf'
228+
_ | No nlt = absurd (nlt prf)

0 commit comments

Comments
 (0)