Skip to content

Commit f4d6a44

Browse files
ABI Layer 2: prove array-rewrite semantics preservation (+´⌽ ⇒ +´) — flagship Idris2 proof (#33)
## Summary Raises bqniser's Idris2 ABI to **Layer 2** with its first flagship semantic proof. bqniser's headline is detecting array patterns and rewriting them as optimised BQN primitives; the correctness obligation is that a rewrite is **semantics-preserving**. This proves a concrete BQN rewrite — `+´⌽𝕩 ⇒ +´𝕩` (drop the reverse before a fold-sum) — via `sumRev : bsum (brev xs) = bsum xs` (summation is reverse-invariant), proven by induction. Mirrors the estate flagship-proof pattern: array model, the equivalence proven by induction, certifier proven sound, non-vacuous negative control. ## Changes - Adds `src/interface/abi/Bqniser/ABI/Semantics.idr` — `bsum`/`brev`, `sumSnoc`, `sumRev` (the rewrite equivalence), `certifyRewriteSound`, and negative control `revChangesOrder`. - Registers the module in `bqniser-abi.ipkg`. ## RSR Quality Checklist ### Required - [x] Tests pass — ABI builds clean (see Testing) - [x] Linter clean — zero warnings - [x] No banned language patterns - [x] No banned functions — genuine proof - [x] SPDX headers present - [x] No secrets ### As Applicable - [x] ABI/FFI changes validated — additive proof; FFI untouched ## Testing Verified with **Idris2 0.7.0**: `idris2 --build bqniser-abi.ipkg` → exit 0, zero warnings. **Adversarial check**: a deliberately-false proof (`brev [1,2] = [1,2]`) was rejected. `build/` removed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01A6PSzJWpRxtzGDjUCEh7Mx --- _Generated by [Claude Code](https://claude.ai/code/session_01A6PSzJWpRxtzGDjUCEh7Mx)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8fc1ddf commit f4d6a44

2 files changed

Lines changed: 96 additions & 0 deletions

File tree

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
-- SPDX-License-Identifier: MPL-2.0
2+
-- Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
--
4+
||| Flagship semantic proof for Bqniser (Idris2 ABI Layer 2).
5+
|||
6+
||| Bqniser's headline is "detect array patterns and rewrite as optimised BQN
7+
||| primitives". The correctness obligation for any such rewrite is that it is
8+
||| *semantics-preserving*. This module proves a concrete, real BQN rewrite:
9+
|||
10+
||| +´⌽𝕩 ==> +´𝕩 (sum-of-reverse ==> sum)
11+
|||
12+
||| i.e. detecting a fold-sum applied to a reversed array and dropping the
13+
||| reverse, because summation is invariant under reversal. The equivalence
14+
||| `sumRev : bsum (brev xs) = bsum xs` is proven by induction; a certifier is
15+
||| proven sound against it; and a negative control machine-checks that the
16+
||| rewrite is non-trivial (reversal genuinely changes the array).
17+
|||
18+
||| (`bsum`/`brev` are named to avoid clashing with Prelude `sum`.)
19+
20+
module Bqniser.ABI.Semantics
21+
22+
import Bqniser.ABI.Types
23+
import Data.Nat
24+
25+
%default total
26+
27+
--------------------------------------------------------------------------------
28+
-- A minimal array model with the two primitives the rewrite touches
29+
--------------------------------------------------------------------------------
30+
31+
||| Fold-sum (`+´`).
32+
public export
33+
bsum : List Nat -> Nat
34+
bsum [] = 0
35+
bsum (x :: xs) = x + bsum xs
36+
37+
||| Reverse (`⌽`), defined directly so it is convenient to induct over.
38+
public export
39+
brev : List Nat -> List Nat
40+
brev [] = []
41+
brev (x :: xs) = brev xs ++ [x]
42+
43+
--------------------------------------------------------------------------------
44+
-- Semantics-preservation of the rewrite
45+
--------------------------------------------------------------------------------
46+
47+
||| Sum distributes over a snoc: bsum (xs ++ [y]) = bsum xs + y.
48+
export
49+
sumSnoc : (xs : List Nat) -> (y : Nat) -> bsum (xs ++ [y]) = bsum xs + y
50+
sumSnoc [] y = plusZeroRightNeutral y
51+
sumSnoc (x :: xs) y =
52+
trans (cong (x +) (sumSnoc xs y))
53+
(plusAssociative x (bsum xs) y)
54+
55+
||| The headline equivalence: summing a reversed array equals summing it, so the
56+
||| `+´⌽ ==> +´` rewrite preserves semantics for all inputs.
57+
export
58+
sumRev : (xs : List Nat) -> bsum (brev xs) = bsum xs
59+
sumRev [] = Refl
60+
sumRev (x :: xs) =
61+
trans (sumSnoc (brev xs) x)
62+
(trans (cong (+ x) (sumRev xs))
63+
(plusCommutative (bsum xs) x))
64+
65+
--------------------------------------------------------------------------------
66+
-- Certifier into the ABI Result, proven sound against the equivalence
67+
--------------------------------------------------------------------------------
68+
69+
||| The rewrite is unconditionally valid, so the certifier always reports `Ok`.
70+
public export
71+
certifyRewrite : List Nat -> Result
72+
certifyRewrite _ = Ok
73+
74+
||| Soundness: whenever the certifier reports `Ok`, the rewrite genuinely
75+
||| preserves the computed result for that input.
76+
export
77+
certifyRewriteSound : (xs : List Nat) -> certifyRewrite xs = Ok -> bsum (brev xs) = bsum xs
78+
certifyRewriteSound xs _ = sumRev xs
79+
80+
--------------------------------------------------------------------------------
81+
-- Positive control
82+
--------------------------------------------------------------------------------
83+
84+
export
85+
rewritePreservesConcrete : bsum (brev [1, 2, 3]) = bsum [1, 2, 3]
86+
rewritePreservesConcrete = sumRev [1, 2, 3]
87+
88+
--------------------------------------------------------------------------------
89+
-- Negative control: the rewrite is non-trivial — reversal really changes the
90+
-- array, so the equivalence is a genuine theorem, not reverse = id.
91+
--------------------------------------------------------------------------------
92+
93+
export
94+
revChangesOrder : Not (brev [1, 2] = [1, 2])
95+
revChangesOrder Refl impossible

src/interface/abi/bqniser-abi.ipkg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ modules = Bqniser.ABI.Types
99
, Bqniser.ABI.Layout
1010
, Bqniser.ABI.Foreign
1111
, Bqniser.ABI.Proofs
12+
, Bqniser.ABI.Semantics

0 commit comments

Comments
 (0)