Tasks / sorter / Properties.lean
Properties.lean
The trusted statement of sorter as named properties: proved, not trusted.
- Properties
- 10
- Lines
- 192
Each definition below is one property of the trusted statement (Statement). The theorem statement_iff_properties proves that the statement holds exactly when they all do, and Lean's kernel checks it, so this file adds nothing to what is trusted.
| property | Lean name | line | on the task page |
|---|---|---|---|
PARAMS_IN_RANGE | ParamsInRange | 27 | the card |
INTERFACE | Interface | 31 | the card |
CLOCK_DISCIPLINE | ClockDiscipline | 36 | the card |
TERMINATES | Terminates | 45 | the card |
LATENCY_AT_LEAST_ONE | LatencyAtLeastOne | 50 | the card |
MOORE_OUTPUTS | MooreOutputs | 54 | the card |
NO_X_CREATING | NoXCreating | 68 | the card |
OUT_VALID_KNOWN | OutValidKnown | 73 | the card |
SILENT_BEFORE_FIRST_START | SilentBeforeFirstStart | 78 | the card |
EMITS_SORTED | EmitsSorted | 95 | the card |
SILENT_AFTER_LATENCY | SilentAfterLatency | 103 | the card |
statement_iff_properties | the theorem | 176 |
- file
svgolf/tasks/sorter/Properties.lean- module
tasks.sorter.Properties- sha256
de7054a478aaefb6713b742380a4616f5bdfa640de254fad8b6f985c87d4311b
svgolf/tasks/sorter/Properties.leanProperties.lean
import tasks.sorter.Spec
/-!
# Task `sorter`: the statement as named properties (proved, not trusted)
`Spec.lean`'s `Statement` is one formula. This file gives each part of it a name, one definition
per thing a design must satisfy, and proves `statement_iff_properties`: the statement holds
exactly when, at every `(N, W)` in range, every property holds. The theorem is checked by Lean's
kernel, so the properties cover the whole statement and nothing else; this file adds nothing to
the trusted base. `properties.json` explains each property in plain words.
The statement's guarantee (`StreamTask.Guar`) is one conjunction under the protocol; here it is
four properties, each under the same protocol (`UnderProtocol`): `OutValidKnown`,
`SilentBeforeFirstStart`, `EmitsSorted` and `SilentAfterLatency`. The last two split the
statement's per-transaction claim (one list of observations that emits the sorted values and is
silent after the latency) in two; they are equivalent to it because the snapshots fix the
`out_valid` bit of every observation. Under txtask-v2 (2026-11-05; final, decided 2026-11-08) every run is
from a power-up state: `Terminates` and `UnderProtocol` quantify over every power-up state and every
known stimulus (rule 2); rules 1 and 3 are two more properties, `MooreOutputs` and `NoXCreating`,
each the trusted conjunct verbatim.
-/
namespace SvGolf.Tasks.Sorter.Properties
open SvGolf LeanModels.Sv
/-- The parameters the statement covers: `N, W ≥ 1` and `N·W` below `2^31`. -/
def ParamsInRange (N W : Nat) : Prop :=
1 ≤ N ∧ 1 ≤ W ∧ N * W < 2 ^ 31
/-- Exactly these ports, in this order, with these widths; no two declarations share a name. -/
def Interface (W : Nat) (d : Design2) : Prop :=
inputPorts d = [("clk", 1), ("rst", 1), ("start", 1), ("in_valid", 1), ("in_data", W)] ∧
outputPorts d = [("out_valid", 1), ("out_data", W)] ∧ (d.decls.toList.map Decl.name).Nodup
/-- `clk` is an input; every process that runs at a clock edge is clocked by `clk`; no process
has an asynchronous reset (`rst` is synchronous); no process reads `clk` as data. -/
def ClockDiscipline (d : Design2) : Prop :=
"clk" ∈ d.inputNames.toList ∧
∀ p ∈ d.processes.toList,
(p.isEdgePhase = true → edgeClock p = some "clk") ∧
asyncReset p = none ∧
"clk" ∉ processDataNames p
/-- From every power-up state, under every schedule and every known stimulus, the run completes. -/
def Terminates (d : Design2) : Prop :=
∀ st0, PowerUp d st0 → ∀ (σ : ScheduleOracle) (stim : List SvState), KnownStim d stim →
∃ tr, RunsAt d σ st0 stim tr
/-- The declared latency is at least one cycle. -/
def LatencyAtLeastOne (lat : Nat) : Prop :=
1 ≤ lat
/-- No combinational path leads from an input port, `rst` included, to an output port
(`MooreOutDep` with nothing exempt, txtask-v2 rule 1): `out_valid` and `out_data` are functions of
the registers, so every snapshot is what the wires show for the whole next period. -/
def MooreOutputs (d : Design2) : Prop :=
MooreOutDep d []
/-- `G` holds in every completed run from every power-up state on every known stimulus, from every
release `c1` of the reset, up to every horizon `h` before which the environment kept the protocol
(`StreamTask.Rely`). -/
def UnderProtocol (N W : Nat) (d : Design2)
(G : List SvState → List SvState → Nat → Nat → Prop) : Prop :=
ModelsPU d fun stim tr =>
∀ c1 h, Released "rst" stim c1 h → task.Rely (N, W) stim tr c1 h → G stim tr c1 h
/-- No construct of the design can create an `x` or `z` from known operands (`XSafe`, txtask-v2
rule 3): with the power-up rule, every value of every run is known. -/
def NoXCreating (d : Design2) : Prop :=
XSafe d
/-- `out_valid` is a known bit at every cycle from the release. -/
def OutValidKnown (N W : Nat) (d : Design2) : Prop :=
UnderProtocol N W d fun _ tr c1 h =>
∀ c, c1 ≤ c → c < h → ∃ b, TraceBit tr c "out_valid" b
/-- `out_valid` is 0 at every cycle from the release up to the first start. -/
def SilentBeforeFirstStart (N W : Nat) (d : Design2) : Prop :=
UnderProtocol N W d fun stim tr c1 h =>
∀ c, c1 ≤ c → c < h → (∀ s, c1 ≤ s → s ≤ c → ¬ StimBit stim s "start" true) →
TraceBit tr c "out_valid" false
/-- `Transaction N W stim c1 h s xs e`: `s` is a start after the release `c1`, `xs` are the `N`
values on `in_data` in the cycles after it, and `e` is the next start, or the horizon `h` if
there is none before it. -/
def Transaction (N W : Nat) (stim : List SvState) (c1 h s : Nat) (xs : List (BitVec W))
(e : Nat) : Prop :=
c1 ≤ s ∧ StimBit stim s "start" true ∧ xs.length = N ∧
(∀ j v, xs[j]? = some v → ∃ en, stim[s + 1 + j]? = some en ∧
SvState.lookup en "in_data" = some (LVec.ofBitVec v)) ∧
s < e ∧ e ≤ h ∧ (∀ s', s < s' → s' < e → ¬ StimBit stim s' "start" true) ∧
(e < h → StimBit stim e "start" true)
/-- From each start to the next, the values shown on `out_data` while `out_valid` is 1 are, in
order, the transaction's input values sorted ascending. -/
def EmitsSorted (N W lat : Nat) (d : Design2) : Prop :=
UnderProtocol N W d fun stim tr c1 h =>
∀ s xs e, s + lat < h → Transaction N W stim c1 h s xs e →
∃ obs : List (Bool × BitVec W), obs.length = e - s ∧ task.Shows (N, W) tr s obs ∧
task.emitted (N, W) obs = sortAsc xs
/-- From each start to the next, `out_valid` is 0 at every cycle more than `lat` cycles after
the start. -/
def SilentAfterLatency (N W lat : Nat) (d : Design2) : Prop :=
UnderProtocol N W d fun stim tr c1 h =>
∀ s xs e, s + lat < h → Transaction N W stim c1 h s xs e →
∀ c, s + lat < c → c < e → TraceBit tr c "out_valid" false
theorem clockDiscipline_iff (d : Design2) : ClockDiscipline d ↔ task.Disciplined d := by
constructor
· rintro ⟨hk, hp⟩
refine ⟨hk, fun p hmem => ?_⟩
obtain ⟨h1, h2, h3⟩ := hp p hmem
exact ⟨h1, fun r hr => (by rw [h2] at hr; cases hr), h3⟩
· rintro ⟨hk, hp⟩
refine ⟨hk, fun p hmem => ?_⟩
obtain ⟨h1, h2, h3⟩ := hp p hmem
refine ⟨h1, ?_, h3⟩
cases h : asyncReset p with
| none => rfl
| some r => cases h2 r h
/-- A snapshot shows one value of a 1-bit signal. -/
private theorem bitIs_unique {st : SvState} {n : String} {a b : Bool} (ha : BitIs st n a)
(hb : BitIs st n b) : a = b := by
unfold BitIs at ha hb
rw [ha] at hb
cases a <;> cases b <;> first | rfl | exact absurd hb (by decide)
/-- The guarantee is the four properties. -/
theorem follows_iff (N W lat : Nat) (d : Design2) :
task.FollowsPU (N, W) lat d ↔
OutValidKnown N W d ∧ SilentBeforeFirstStart N W d ∧ EmitsSorted N W lat d ∧
SilentAfterLatency N W lat d := by
constructor
· intro hF
refine ⟨?_, ?_, ?_, ?_⟩
· intro st0 h0 σ stim tr hks hr c1 h hrel hrely
exact (hF st0 h0 σ stim tr hks hr c1 h hrel hrely).1
· intro st0 h0 σ stim tr hks hr c1 h hrel hrely
exact (hF st0 h0 σ stim tr hks hr c1 h hrel hrely).2.1
· intro st0 h0 σ stim tr hks hr c1 h hrel hrely s xs e hlat htx
obtain ⟨hs, hst, hlen, hdata, hse, heh, hno, hnext⟩ := htx
obtain ⟨obs, hl, hsh, hem, _⟩ :=
(hF st0 h0 σ stim tr hks hr c1 h hrel hrely).2.2 s xs hs hlat hst hlen hdata e hse heh hno hnext
exact ⟨obs, hl, hsh, hem⟩
· intro st0 h0 σ stim tr hks hr c1 h hrel hrely s xs e hlat htx c hc hce
obtain ⟨hs, hst, hlen, hdata, hse, heh, hno, hnext⟩ := htx
obtain ⟨obs, hl, hsh, _, hq⟩ :=
(hF st0 h0 σ stim tr hks hr c1 h hrel hrely).2.2 s xs hs hlat hst hlen hdata e hse heh hno hnext
have hk : c - s < obs.length := by omega
obtain ⟨o, ho⟩ : ∃ o, obs[c - s]? = some o := ⟨_, List.getElem?_eq_getElem hk⟩
obtain ⟨st, hst', hb, _⟩ := hsh (c - s) o ho
have hc' : s + (c - s) = c := by omega
rw [hc'] at hst'
refine ⟨st, hst', ?_⟩
rw [hq (c - s) o ho (by omega)] at hb
exact hb
· rintro ⟨hK, hS, hE, hQ⟩ st0 h0 σ stim tr hks hr c1 h hrel hrely
refine ⟨hK st0 h0 σ stim tr hks hr c1 h hrel hrely, hS st0 h0 σ stim tr hks hr c1 h hrel hrely,
fun s xs hs hlat hst hlen hdata e hse heh hno hnext => ?_⟩
have htx : Transaction N W stim c1 h s xs e := ⟨hs, hst, hlen, hdata, hse, heh, hno, hnext⟩
obtain ⟨obs, hl, hsh, hem⟩ := hE st0 h0 σ stim tr hks hr c1 h hrel hrely s xs e hlat htx
refine ⟨obs, hl, hsh, hem, fun k o hk hlk => ?_⟩
obtain ⟨st, hst', hb, _⟩ := hsh k o hk
have hkl : k < obs.length := by
obtain ⟨hkl, _⟩ := List.getElem?_eq_some_iff.1 hk
exact hkl
obtain ⟨st', hst'', hb'⟩ := hQ st0 h0 σ stim tr hks hr c1 h hrel hrely s xs e hlat htx (s + k)
(by omega) (by omega)
rw [hst'] at hst''
cases hst''
exact bitIs_unique hb hb'
/-- **The statement is exactly the properties.** -/
theorem statement_iff_properties (sem : Nat → Nat → Design2) (lat : Nat → Nat → Nat) :
Statement sem lat ↔ ∀ N W, ParamsInRange N W →
Interface W (sem N W) ∧ ClockDiscipline (sem N W) ∧ Terminates (sem N W) ∧
LatencyAtLeastOne (lat N W) ∧ MooreOutputs (sem N W) ∧ NoXCreating (sem N W) ∧
OutValidKnown N W (sem N W) ∧
SilentBeforeFirstStart N W (sem N W) ∧ EmitsSorted N W (lat N W) (sem N W) ∧
SilentAfterLatency N W (lat N W) (sem N W) := by
constructor
· intro h N W hp
obtain ⟨hi, ⟨hd, ht⟩, hl, hf, hm, hk⟩ := h (N, W) hp
exact ⟨hi, (clockDiscipline_iff _).2 hd, ht, hl, hm, hk, (follows_iff N W _ _).1 hf⟩
· rintro h ⟨N, W⟩ hp
obtain ⟨hi, hd, ht, hl, hm, hk, hf⟩ := h N W hp
exact ⟨hi, ⟨(clockDiscipline_iff _).1 hd, ht⟩, hl, (follows_iff N W _ _).2 hf, hm, hk⟩
end SvGolf.Tasks.Sorter.Properties