|
| 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 | +||| Structural invariants for Anvomidaviser (Idris2 ABI Layer 3). |
| 5 | +||| |
| 6 | +||| The Layer-2 flagship (`Anvomidaviser.ABI.Semantics`) proves the ISU |
| 7 | +||| element-count UPPER bound: a well-formed short program has at most seven |
| 8 | +||| elements (`WellFormed p = LTE (length p) 7`). This module proves two |
| 9 | +||| genuinely DIFFERENT and DEEPER properties over the SAME `Program` model: |
| 10 | +||| |
| 11 | +||| 1. DOWNWARD-CLOSURE (monotonicity) of well-formedness under deletion. |
| 12 | +||| If a program is well-formed, then removing the element at ANY position |
| 13 | +||| leaves it well-formed. This is a structural law about how the predicate |
| 14 | +||| behaves under a program transformation — not a restatement of the count |
| 15 | +||| bound. The core is an exact length lemma |
| 16 | +||| `removeAtLen : length (removeAt xs i) = length xs` ... after a `S`, |
| 17 | +||| i.e. deleting one element drops the length by exactly one, which is then |
| 18 | +||| transported through `LTE` via `lteSuccLeft`. |
| 19 | +||| |
| 20 | +||| 2. A SECOND ISU rule, distinct from the count limit: the MINIMUM-CONTENT |
| 21 | +||| rule. A real program must contain at least one element; the empty |
| 22 | +||| program is not a valid program. This is given as a decidable |
| 23 | +||| proposition `HasContent` with a sound+complete `Dec`, a certifier into |
| 24 | +||| the ABI `Result`, and a non-vacuity (negative) control: the empty |
| 25 | +||| program is provably rejected. |
| 26 | +||| |
| 27 | +||| FORBIDDEN constructs (believe_me, idris_crash, assert_total, postulate, |
| 28 | +||| sorry, %hint hacks, asserted equalities) appear NOWHERE below. |
| 29 | + |
| 30 | +module Anvomidaviser.ABI.Invariants |
| 31 | + |
| 32 | +import Anvomidaviser.ABI.Types |
| 33 | +import Anvomidaviser.ABI.Semantics |
| 34 | +import Data.Nat |
| 35 | +import Data.Fin |
| 36 | + |
| 37 | +%default total |
| 38 | + |
| 39 | +-------------------------------------------------------------------------------- |
| 40 | +-- Deletion at a position |
| 41 | +-------------------------------------------------------------------------------- |
| 42 | + |
| 43 | +||| Remove the element at position `i` from a list. The position is a `Fin` |
| 44 | +||| indexed by the list length, so it is always in range — there is no failure |
| 45 | +||| case and no need for `Maybe`. |
| 46 | +public export |
| 47 | +removeAt : (xs : List a) -> Fin (length xs) -> List a |
| 48 | +removeAt (_ :: xs) FZ = xs |
| 49 | +removeAt (x :: xs) (FS k) = x :: removeAt xs k |
| 50 | + |
| 51 | +-------------------------------------------------------------------------------- |
| 52 | +-- Exact length lemma: deletion drops the length by exactly one |
| 53 | +-------------------------------------------------------------------------------- |
| 54 | + |
| 55 | +||| Removing one element at any position yields a list whose length, plus one, |
| 56 | +||| equals the original length. Stated this way (rather than with `pred`) so the |
| 57 | +||| original `length xs` stays in `S` form for transport through `LTE`. |
| 58 | +export |
| 59 | +removeAtLen : (xs : List a) -> (i : Fin (length xs)) -> |
| 60 | + S (length (removeAt xs i)) = length xs |
| 61 | +removeAtLen (_ :: xs) FZ = Refl |
| 62 | +removeAtLen (x :: xs) (FS k) = cong S (removeAtLen xs k) |
| 63 | + |
| 64 | +-------------------------------------------------------------------------------- |
| 65 | +-- Downward-closure (monotonicity) of WellFormed under deletion |
| 66 | +-------------------------------------------------------------------------------- |
| 67 | + |
| 68 | +||| THEOREM (downward-closure / monotonicity). If a program is well-formed |
| 69 | +||| (at most seven elements) then deleting the element at any position keeps it |
| 70 | +||| well-formed. Deeper than the Layer-2 count bound: it is a closure law about |
| 71 | +||| the predicate under a structural transformation. |
| 72 | +||| |
| 73 | +||| Proof: from `WellFormed p` we have `LTE (length p) 7`. By `removeAtLen`, |
| 74 | +||| `S (length (removeAt p i)) = length p`, so rewriting gives |
| 75 | +||| `LTE (S (length (removeAt p i))) 7`, and `lteSuccLeft` weakens this to |
| 76 | +||| `LTE (length (removeAt p i)) 7` — exactly `WellFormed (removeAt p i)`. |
| 77 | +export |
| 78 | +wellFormedDownClosed : (p : Program) -> (i : Fin (length p)) -> |
| 79 | + WellFormed p -> WellFormed (removeAt p i) |
| 80 | +wellFormedDownClosed p i (WF prf) = |
| 81 | + let prfS : LTE (S (length (removeAt p i))) 7 |
| 82 | + = rewrite removeAtLen p i in prf |
| 83 | + in WF (lteSuccLeft prfS) |
| 84 | + |
| 85 | +||| Specialisation to the head: dropping the first element preserves |
| 86 | +||| well-formedness (the `tail` corollary). `p` is required non-empty so that a |
| 87 | +||| first element exists; the position is `FZ`. |
| 88 | +export |
| 89 | +wellFormedTail : (x : SkateElement) -> (xs : Program) -> |
| 90 | + WellFormed (x :: xs) -> WellFormed xs |
| 91 | +wellFormedTail x xs wf = wellFormedDownClosed (x :: xs) FZ wf |
| 92 | + |
| 93 | +-------------------------------------------------------------------------------- |
| 94 | +-- Second ISU rule: the minimum-content rule (a non-empty program) |
| 95 | +-------------------------------------------------------------------------------- |
| 96 | + |
| 97 | +||| The minimum-content rule: a valid program contains at least one element. |
| 98 | +||| Distinct from the count limit — this is a LOWER bound on content. |
| 99 | +public export |
| 100 | +data HasContent : Program -> Type where |
| 101 | + HC : {0 x : SkateElement} -> {0 xs : Program} -> HasContent (x :: xs) |
| 102 | + |
| 103 | +||| The empty program has no content. Used as the refutation for the `Dec` |
| 104 | +||| (top-level `impossible` clause, per the Idris2 0.7.0 idiom). |
| 105 | +export |
| 106 | +Uninhabited (HasContent []) where |
| 107 | + uninhabited HC impossible |
| 108 | + |
| 109 | +||| Sound + complete decision procedure for the minimum-content rule. |
| 110 | +public export |
| 111 | +decHasContent : (p : Program) -> Dec (HasContent p) |
| 112 | +decHasContent [] = No uninhabited |
| 113 | +decHasContent (_ :: _) = Yes HC |
| 114 | + |
| 115 | +-------------------------------------------------------------------------------- |
| 116 | +-- Certifier into the ABI Result, proven sound |
| 117 | +-------------------------------------------------------------------------------- |
| 118 | + |
| 119 | +||| Certify the minimum-content rule into the shared ABI `Result`. A violation |
| 120 | +||| is reported as `RuleViolation` (the dedicated ISU-rule failure code). |
| 121 | +public export |
| 122 | +certifyContent : Program -> Result |
| 123 | +certifyContent p = case decHasContent p of |
| 124 | + Yes _ => Ok |
| 125 | + No _ => RuleViolation |
| 126 | + |
| 127 | +||| Soundness: an `Ok` verdict really does witness the minimum-content rule. |
| 128 | +export |
| 129 | +certifyContentSound : (p : Program) -> certifyContent p = Ok -> HasContent p |
| 130 | +certifyContentSound p prf with (decHasContent p) |
| 131 | + certifyContentSound p prf | Yes hc = hc |
| 132 | + certifyContentSound p Refl | No _ impossible |
| 133 | + |
| 134 | +-------------------------------------------------------------------------------- |
| 135 | +-- Positive controls (inhabited witnesses) |
| 136 | +-------------------------------------------------------------------------------- |
| 137 | + |
| 138 | +||| A concrete deletion: removing the middle element of a three-element program. |
| 139 | +public export |
| 140 | +trimmedProgram : Program |
| 141 | +trimmedProgram = removeAt Semantics.goodProgram (FS FZ) |
| 142 | + |
| 143 | +||| Positive control for downward-closure: the well-formed `goodProgram` stays |
| 144 | +||| well-formed after deleting its middle element. This is a real transport of |
| 145 | +||| the Layer-2 witness through the Layer-3 theorem. |
| 146 | +export |
| 147 | +trimmedWellFormed : WellFormed Invariants.trimmedProgram |
| 148 | +trimmedWellFormed = |
| 149 | + wellFormedDownClosed Semantics.goodProgram (FS FZ) goodWellFormed |
| 150 | + |
| 151 | +||| Positive control for the minimum-content rule. |
| 152 | +export |
| 153 | +goodHasContent : certifyContent Semantics.goodProgram = Ok |
| 154 | +goodHasContent = Refl |
| 155 | + |
| 156 | +-------------------------------------------------------------------------------- |
| 157 | +-- Negative / non-vacuity controls |
| 158 | +-------------------------------------------------------------------------------- |
| 159 | + |
| 160 | +||| Non-vacuity for the minimum-content rule: the empty program is rejected. |
| 161 | +export |
| 162 | +emptyRejected : certifyContent [] = RuleViolation |
| 163 | +emptyRejected = Refl |
| 164 | + |
| 165 | +||| Stronger negative control: the empty program provably has no content. This |
| 166 | +||| rules out a vacuously-true `HasContent`. |
| 167 | +export |
| 168 | +emptyNoContent : Not (HasContent []) |
| 169 | +emptyNoContent = uninhabited |
| 170 | + |
| 171 | +||| Non-vacuity for downward-closure: the theorem genuinely constrains length. |
| 172 | +||| Deleting one element from a maximal (7-element) program yields a 6-element |
| 173 | +||| program — and that length is exactly what `removeAtLen` reports, machine |
| 174 | +||| checked here against the concrete `6`. |
| 175 | +public export |
| 176 | +fullProgram : Program |
| 177 | +fullProgram = [Jump, Spin, StepSequence, Jump, Spin, StepSequence, Jump] |
| 178 | + |
| 179 | +export |
| 180 | +fullLenIs7 : length Invariants.fullProgram = 7 |
| 181 | +fullLenIs7 = Refl |
| 182 | + |
| 183 | +||| After one deletion the length is exactly 6 (a concrete witness that the |
| 184 | +||| length lemma is not vacuous on a non-trivial instance). |
| 185 | +export |
| 186 | +trimFullLenIs6 : length (removeAt Invariants.fullProgram FZ) = 6 |
| 187 | +trimFullLenIs6 = Refl |
0 commit comments