13. Kernel Overflow Bounds
The kernel chapter states the exact-execution obligation as kernelPrefixFits:
every prefix sum that can enter the accumulator must fit the signed accumulator
width. That obligation is left abstract there because it depends on the operands.
This chapter discharges it from concrete magnitude bounds, so a quantized
block-float kernel with bounded weights and streamed operands satisfies the
no-overflow condition automatically, without reasoning about the individual
products.
The argument is a magnitude bound. Each operand has a bounded absolute value, so
each product is bounded by the product of the bounds, a prefix of n products
is bounded by n times that, and adding a bounded initial accumulator keeps the
whole running value inside the signed range whenever the arithmetic bound is
below 2 ^ (accBits - 1).
namespace Janus
-- A signed value fits its width if its magnitude is below the signed bound. The
-- magnitude is carried as an `Int`-cast `natAbs`, which `omega` understands.
theorem signedFits_of_natAbs_lt (bits : Nat) (x : Int)
(h : (x.natAbs : Int) < 2 ^ (bits - 1)) : signedFits bits x := bits:Natx:Inth:↑x.natAbs < 2 ^ (bits - 1)⊢ signedFits bits x
bits:Natx:Inth:↑x.natAbs < 2 ^ (bits - 1)⊢ -2 ^ (bits - 1) ≤ x ∧ x < 2 ^ (bits - 1)
All goals completed! 🐙
theorem prod_natAbs_le (x y : Int) (Wn An : Nat)
(hx : x.natAbs ≤ Wn) (hy : y.natAbs ≤ An) :
(x * y).natAbs ≤ Wn * An := x:Inty:IntWn:NatAn:Nathx:x.natAbs ≤ Wnhy:y.natAbs ≤ An⊢ (x * y).natAbs ≤ Wn * An
x:Inty:IntWn:NatAn:Nathx:x.natAbs ≤ Wnhy:y.natAbs ≤ An⊢ x.natAbs * y.natAbs ≤ Wn * An
exact Nat.mul_le_mul hx hy All goals completed! 🐙
The dot-product prefix is bounded by its length times the per-product bound. The proof shifts the two pointers as it peels one product off the front, so the bound holds for every starting offset.
theorem fsumFrom_natAbs_le (w a : Nat -> Int) (Wn An : Nat)
(hw : forall i, (w i).natAbs ≤ Wn) (ha : forall i, (a i).natAbs ≤ An) :
forall (wp sp k : Nat),
(fsumFrom w a wp sp k).natAbs ≤ k * (Wn * An) := by w:Nat → Inta:Nat → IntWn:NatAn:Nathw:∀ (i : Nat), (w i).natAbs ≤ Wnha:∀ (i : Nat), (a i).natAbs ≤ An⊢ ∀ (wp sp k : Nat), (fsumFrom w a wp sp k).natAbs ≤ k * (Wn * An)
intro wp sp k w:Nat → Inta:Nat → IntWn:NatAn:Nathw:∀ (i : Nat), (w i).natAbs ≤ Wnha:∀ (i : Nat), (a i).natAbs ≤ Anwp:Natsp:Natk:Nat⊢ (fsumFrom w a wp sp k).natAbs ≤ k * (Wn * An)
induction k generalizing wp sp with
| zero => zero w:Nat → Inta:Nat → IntWn:NatAn:Nathw:∀ (i : Nat), (w i).natAbs ≤ Wnha:∀ (i : Nat), (a i).natAbs ≤ Anwp:Natsp:Nat⊢ (fsumFrom w a wp sp 0).natAbs ≤ 0 * (Wn * An) simp [fsumFrom] All goals completed! 🐙
| succ k ih => succ w:Nat → Inta:Nat → IntWn:NatAn:Nathw:∀ (i : Nat), (w i).natAbs ≤ Wnha:∀ (i : Nat), (a i).natAbs ≤ Ank:Natih:∀ (wp sp : Nat), (fsumFrom w a wp sp k).natAbs ≤ k * (Wn * An)wp:Natsp:Nat⊢ (fsumFrom w a wp sp (k + 1)).natAbs ≤ (k + 1) * (Wn * An)
have hstep : fsumFrom w a wp sp (k + 1)
= w wp * a sp + fsumFrom w a (wp + 1) (sp + 1) k := rfl succ w:Nat → Inta:Nat → IntWn:NatAn:Nathw:∀ (i : Nat), (w i).natAbs ≤ Wnha:∀ (i : Nat), (a i).natAbs ≤ Ank:Natih:∀ (wp sp : Nat), (fsumFrom w a wp sp k).natAbs ≤ k * (Wn * An)wp:Natsp:Nathstep:fsumFrom w a wp sp (k + 1) = w wp * a sp + fsumFrom w a (wp + 1) (sp + 1) k⊢ (fsumFrom w a wp sp (k + 1)).natAbs ≤ (k + 1) * (Wn * An)
have h2 : (w wp * a sp).natAbs ≤ Wn * An :=
prod_natAbs_le (w wp) (a sp) Wn An (hw wp) (ha sp) succ w:Nat → Inta:Nat → IntWn:NatAn:Nathw:∀ (i : Nat), (w i).natAbs ≤ Wnha:∀ (i : Nat), (a i).natAbs ≤ Ank:Natih:∀ (wp sp : Nat), (fsumFrom w a wp sp k).natAbs ≤ k * (Wn * An)wp:Natsp:Nathstep:fsumFrom w a wp sp (k + 1) = w wp * a sp + fsumFrom w a (wp + 1) (sp + 1) kh2:(w wp * a sp).natAbs ≤ Wn * An⊢ (fsumFrom w a wp sp (k + 1)).natAbs ≤ (k + 1) * (Wn * An)
have h3 : (fsumFrom w a (wp + 1) (sp + 1) k).natAbs ≤ k * (Wn * An) :=
ih (wp + 1) (sp + 1) succ w:Nat → Inta:Nat → IntWn:NatAn:Nathw:∀ (i : Nat), (w i).natAbs ≤ Wnha:∀ (i : Nat), (a i).natAbs ≤ Ank:Natih:∀ (wp sp : Nat), (fsumFrom w a wp sp k).natAbs ≤ k * (Wn * An)wp:Natsp:Nathstep:fsumFrom w a wp sp (k + 1) = w wp * a sp + fsumFrom w a (wp + 1) (sp + 1) kh2:(w wp * a sp).natAbs ≤ Wn * Anh3:(fsumFrom w a (wp + 1) (sp + 1) k).natAbs ≤ k * (Wn * An)⊢ (fsumFrom w a wp sp (k + 1)).natAbs ≤ (k + 1) * (Wn * An)
have htri : (fsumFrom w a wp sp (k + 1)).natAbs
≤ (w wp * a sp).natAbs
+ (fsumFrom w a (wp + 1) (sp + 1) k).natAbs := by w:Nat → Inta:Nat → IntWn:NatAn:Nathw:∀ (i : Nat), (w i).natAbs ≤ Wnha:∀ (i : Nat), (a i).natAbs ≤ An⊢ ∀ (wp sp k : Nat), (fsumFrom w a wp sp k).natAbs ≤ k * (Wn * An)
rw [hstep w:Nat → Inta:Nat → IntWn:NatAn:Nathw:∀ (i : Nat), (w i).natAbs ≤ Wnha:∀ (i : Nat), (a i).natAbs ≤ Ank:Natih:∀ (wp sp : Nat), (fsumFrom w a wp sp k).natAbs ≤ k * (Wn * An)wp:Natsp:Nathstep:fsumFrom w a wp sp (k + 1) = w wp * a sp + fsumFrom w a (wp + 1) (sp + 1) kh2:(w wp * a sp).natAbs ≤ Wn * Anh3:(fsumFrom w a (wp + 1) (sp + 1) k).natAbs ≤ k * (Wn * An)⊢ (w wp * a sp + fsumFrom w a (wp + 1) (sp + 1) k).natAbs ≤
(w wp * a sp).natAbs + (fsumFrom w a (wp + 1) (sp + 1) k).natAbs] w:Nat → Inta:Nat → IntWn:NatAn:Nathw:∀ (i : Nat), (w i).natAbs ≤ Wnha:∀ (i : Nat), (a i).natAbs ≤ Ank:Natih:∀ (wp sp : Nat), (fsumFrom w a wp sp k).natAbs ≤ k * (Wn * An)wp:Natsp:Nathstep:fsumFrom w a wp sp (k + 1) = w wp * a sp + fsumFrom w a (wp + 1) (sp + 1) kh2:(w wp * a sp).natAbs ≤ Wn * Anh3:(fsumFrom w a (wp + 1) (sp + 1) k).natAbs ≤ k * (Wn * An)⊢ (w wp * a sp + fsumFrom w a (wp + 1) (sp + 1) k).natAbs ≤
(w wp * a sp).natAbs + (fsumFrom w a (wp + 1) (sp + 1) k).natAbs; exact Int.natAbs_add_le _ _ succ w:Nat → Inta:Nat → IntWn:NatAn:Nathw:∀ (i : Nat), (w i).natAbs ≤ Wnha:∀ (i : Nat), (a i).natAbs ≤ Ank:Natih:∀ (wp sp : Nat), (fsumFrom w a wp sp k).natAbs ≤ k * (Wn * An)wp:Natsp:Nathstep:fsumFrom w a wp sp (k + 1) = w wp * a sp + fsumFrom w a (wp + 1) (sp + 1) kh2:(w wp * a sp).natAbs ≤ Wn * Anh3:(fsumFrom w a (wp + 1) (sp + 1) k).natAbs ≤ k * (Wn * An)htri:(fsumFrom w a wp sp (k + 1)).natAbs ≤ (w wp * a sp).natAbs + (fsumFrom w a (wp + 1) (sp + 1) k).natAbs⊢ (fsumFrom w a wp sp (k + 1)).natAbs ≤ (k + 1) * (Wn * An)
have hsm : (k + 1) * (Wn * An) = Wn * An + k * (Wn * An) := by w:Nat → Inta:Nat → IntWn:NatAn:Nathw:∀ (i : Nat), (w i).natAbs ≤ Wnha:∀ (i : Nat), (a i).natAbs ≤ An⊢ ∀ (wp sp k : Nat), (fsumFrom w a wp sp k).natAbs ≤ k * (Wn * An)
rw [Nat.succ_mul w:Nat → Inta:Nat → IntWn:NatAn:Nathw:∀ (i : Nat), (w i).natAbs ≤ Wnha:∀ (i : Nat), (a i).natAbs ≤ Ank:Natih:∀ (wp sp : Nat), (fsumFrom w a wp sp k).natAbs ≤ k * (Wn * An)wp:Natsp:Nathstep:fsumFrom w a wp sp (k + 1) = w wp * a sp + fsumFrom w a (wp + 1) (sp + 1) kh2:(w wp * a sp).natAbs ≤ Wn * Anh3:(fsumFrom w a (wp + 1) (sp + 1) k).natAbs ≤ k * (Wn * An)htri:(fsumFrom w a wp sp (k + 1)).natAbs ≤ (w wp * a sp).natAbs + (fsumFrom w a (wp + 1) (sp + 1) k).natAbs⊢ k * (Wn * An) + Wn * An = Wn * An + k * (Wn * An)] w:Nat → Inta:Nat → IntWn:NatAn:Nathw:∀ (i : Nat), (w i).natAbs ≤ Wnha:∀ (i : Nat), (a i).natAbs ≤ Ank:Natih:∀ (wp sp : Nat), (fsumFrom w a wp sp k).natAbs ≤ k * (Wn * An)wp:Natsp:Nathstep:fsumFrom w a wp sp (k + 1) = w wp * a sp + fsumFrom w a (wp + 1) (sp + 1) kh2:(w wp * a sp).natAbs ≤ Wn * Anh3:(fsumFrom w a (wp + 1) (sp + 1) k).natAbs ≤ k * (Wn * An)htri:(fsumFrom w a wp sp (k + 1)).natAbs ≤ (w wp * a sp).natAbs + (fsumFrom w a (wp + 1) (sp + 1) k).natAbs⊢ k * (Wn * An) + Wn * An = Wn * An + k * (Wn * An); omega succ w:Nat → Inta:Nat → IntWn:NatAn:Nathw:∀ (i : Nat), (w i).natAbs ≤ Wnha:∀ (i : Nat), (a i).natAbs ≤ Ank:Natih:∀ (wp sp : Nat), (fsumFrom w a wp sp k).natAbs ≤ k * (Wn * An)wp:Natsp:Nathstep:fsumFrom w a wp sp (k + 1) = w wp * a sp + fsumFrom w a (wp + 1) (sp + 1) kh2:(w wp * a sp).natAbs ≤ Wn * Anh3:(fsumFrom w a (wp + 1) (sp + 1) k).natAbs ≤ k * (Wn * An)htri:(fsumFrom w a wp sp (k + 1)).natAbs ≤ (w wp * a sp).natAbs + (fsumFrom w a (wp + 1) (sp + 1) k).natAbshsm:(k + 1) * (Wn * An) = Wn * An + k * (Wn * An)⊢ (fsumFrom w a wp sp (k + 1)).natAbs ≤ (k + 1) * (Wn * An)
omega All goals completed! 🐙
The main theorem discharges kernelPrefixFits from three magnitude bounds and
one arithmetic side condition. Wn and An bound the weight and stream
operands, Cn bounds the initial accumulator, and the side condition keeps the
worst-case running value inside the signed accumulator range.
theorem kernelPrefixFits_of_bounds (cfg : Config) (s : KernelState) (n : Nat)
(Wn An Cn : Nat)
(hw : forall i, (s.weights i).natAbs ≤ Wn)
(ha : forall i, (s.stream i).natAbs ≤ An)
(hacc : s.acc.natAbs ≤ Cn)
(hb : Cn + n * (Wn * An) < 2 ^ (cfg.accBits - 1)) :
kernelPrefixFits cfg s n := by cfg:Configs:KernelStaten:NatWn:NatAn:NatCn:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ Wnha:∀ (i : Nat), (s.stream i).natAbs ≤ Anhacc:s.acc.natAbs ≤ Cnhb:Cn + n * (Wn * An) < 2 ^ (cfg.accBits - 1)⊢ kernelPrefixFits cfg s n
intro k hk cfg:Configs:KernelStaten:NatWn:NatAn:NatCn:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ Wnha:∀ (i : Nat), (s.stream i).natAbs ≤ Anhacc:s.acc.natAbs ≤ Cnhb:Cn + n * (Wn * An) < 2 ^ (cfg.accBits - 1)k:Nathk:k ≤ n⊢ signedFits cfg.accBits (s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k)
apply signedFits_of_natAbs_lt cfg:Configs:KernelStaten:NatWn:NatAn:NatCn:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ Wnha:∀ (i : Nat), (s.stream i).natAbs ≤ Anhacc:s.acc.natAbs ≤ Cnhb:Cn + n * (Wn * An) < 2 ^ (cfg.accBits - 1)k:Nathk:k ≤ n⊢ ↑(s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs < 2 ^ (cfg.accBits - 1)
have hsum := fsumFrom_natAbs_le s.weights s.stream Wn An hw ha s.wptr s.sptr k cfg:Configs:KernelStaten:NatWn:NatAn:NatCn:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ Wnha:∀ (i : Nat), (s.stream i).natAbs ≤ Anhacc:s.acc.natAbs ≤ Cnhb:Cn + n * (Wn * An) < 2 ^ (cfg.accBits - 1)k:Nathk:k ≤ nhsum:(fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs ≤ k * (Wn * An)⊢ ↑(s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs < 2 ^ (cfg.accBits - 1)
have htri : (s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs
≤ s.acc.natAbs
+ (fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs :=
Int.natAbs_add_le _ _ cfg:Configs:KernelStaten:NatWn:NatAn:NatCn:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ Wnha:∀ (i : Nat), (s.stream i).natAbs ≤ Anhacc:s.acc.natAbs ≤ Cnhb:Cn + n * (Wn * An) < 2 ^ (cfg.accBits - 1)k:Nathk:k ≤ nhsum:(fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs ≤ k * (Wn * An)htri:(s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs ≤
s.acc.natAbs + (fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs⊢ ↑(s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs < 2 ^ (cfg.accBits - 1)
have hk' : k * (Wn * An) ≤ n * (Wn * An) := Nat.mul_le_mul hk (Nat.le_refl _) cfg:Configs:KernelStaten:NatWn:NatAn:NatCn:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ Wnha:∀ (i : Nat), (s.stream i).natAbs ≤ Anhacc:s.acc.natAbs ≤ Cnhb:Cn + n * (Wn * An) < 2 ^ (cfg.accBits - 1)k:Nathk:k ≤ nhsum:(fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs ≤ k * (Wn * An)htri:(s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs ≤
s.acc.natAbs + (fsumFrom s.weights s.stream s.wptr s.sptr k).natAbshk':k * (Wn * An) ≤ n * (Wn * An)⊢ ↑(s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs < 2 ^ (cfg.accBits - 1)
have hnat : (s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs
≤ Cn + n * (Wn * An) := by cfg:Configs:KernelStaten:NatWn:NatAn:NatCn:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ Wnha:∀ (i : Nat), (s.stream i).natAbs ≤ Anhacc:s.acc.natAbs ≤ Cnhb:Cn + n * (Wn * An) < 2 ^ (cfg.accBits - 1)⊢ kernelPrefixFits cfg s n
have hadd := Nat.add_le_add hacc hsum cfg:Configs:KernelStaten:NatWn:NatAn:NatCn:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ Wnha:∀ (i : Nat), (s.stream i).natAbs ≤ Anhacc:s.acc.natAbs ≤ Cnhb:Cn + n * (Wn * An) < 2 ^ (cfg.accBits - 1)k:Nathk:k ≤ nhsum:(fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs ≤ k * (Wn * An)htri:(s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs ≤
s.acc.natAbs + (fsumFrom s.weights s.stream s.wptr s.sptr k).natAbshk':k * (Wn * An) ≤ n * (Wn * An)hadd:s.acc.natAbs + (fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs ≤ Cn + k * (Wn * An)⊢ (s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs ≤ Cn + n * (Wn * An)
omega cfg:Configs:KernelStaten:NatWn:NatAn:NatCn:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ Wnha:∀ (i : Nat), (s.stream i).natAbs ≤ Anhacc:s.acc.natAbs ≤ Cnhb:Cn + n * (Wn * An) < 2 ^ (cfg.accBits - 1)k:Nathk:k ≤ nhsum:(fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs ≤ k * (Wn * An)htri:(s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs ≤
s.acc.natAbs + (fsumFrom s.weights s.stream s.wptr s.sptr k).natAbshk':k * (Wn * An) ≤ n * (Wn * An)hnat:(s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs ≤ Cn + n * (Wn * An)⊢ ↑(s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs < 2 ^ (cfg.accBits - 1)
have h1 : (s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs
< 2 ^ (cfg.accBits - 1) := Nat.lt_of_le_of_lt hnat hb cfg:Configs:KernelStaten:NatWn:NatAn:NatCn:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ Wnha:∀ (i : Nat), (s.stream i).natAbs ≤ Anhacc:s.acc.natAbs ≤ Cnhb:Cn + n * (Wn * An) < 2 ^ (cfg.accBits - 1)k:Nathk:k ≤ nhsum:(fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs ≤ k * (Wn * An)htri:(s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs ≤
s.acc.natAbs + (fsumFrom s.weights s.stream s.wptr s.sptr k).natAbshk':k * (Wn * An) ≤ n * (Wn * An)hnat:(s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs ≤ Cn + n * (Wn * An)h1:(s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs < 2 ^ (cfg.accBits - 1)⊢ ↑(s.acc + fsumFrom s.weights s.stream s.wptr s.sptr k).natAbs < 2 ^ (cfg.accBits - 1)
exact_mod_cast h1 All goals completed! 🐙
The concrete corollary is the intended use: an int8-quantized block-float
kernel. Weights and streamed operands are signed eight-bit values, so their
magnitudes are at most 127; the accumulator starts cleared; and the default
64-bit accumulator absorbs any block up to 2 ^ 40 MACs with room to spare
(2 ^ 40 * 127 * 127 is far below 2 ^ 63). Such a kernel discharges its
no-overflow obligation with no further arithmetic reasoning.
theorem kernelPrefixFits_int8_block (s : KernelState) (n : Nat)
(hw : forall i, (s.weights i).natAbs ≤ 127)
(ha : forall i, (s.stream i).natAbs ≤ 127)
(hacc : s.acc = 0)
(hn : n ≤ 2 ^ 40) :
kernelPrefixFits defaultConfig s n := by s:KernelStaten:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ 127ha:∀ (i : Nat), (s.stream i).natAbs ≤ 127hacc:s.acc = 0hn:n ≤ 2 ^ 40⊢ kernelPrefixFits defaultConfig s n
apply kernelPrefixFits_of_bounds defaultConfig s n 127 127 0 hw ha hacc s:KernelStaten:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ 127ha:∀ (i : Nat), (s.stream i).natAbs ≤ 127hacc:s.acc = 0hn:n ≤ 2 ^ 40⊢ s.acc.natAbs ≤ 0hb s:KernelStaten:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ 127ha:∀ (i : Nat), (s.stream i).natAbs ≤ 127hacc:s.acc = 0hn:n ≤ 2 ^ 40⊢ 0 + n * (127 * 127) < 2 ^ (defaultConfig.accBits - 1)
· hacc s:KernelStaten:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ 127ha:∀ (i : Nat), (s.stream i).natAbs ≤ 127hacc:s.acc = 0hn:n ≤ 2 ^ 40⊢ s.acc.natAbs ≤ 0 simp [hacc] All goals completed! 🐙
· hb s:KernelStaten:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ 127ha:∀ (i : Nat), (s.stream i).natAbs ≤ 127hacc:s.acc = 0hn:n ≤ 2 ^ 40⊢ 0 + n * (127 * 127) < 2 ^ (defaultConfig.accBits - 1) show 0 + n * (127 * 127) < 2 ^ 63 hb s:KernelStaten:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ 127ha:∀ (i : Nat), (s.stream i).natAbs ≤ 127hacc:s.acc = 0hn:n ≤ 2 ^ 40⊢ 0 + n * (127 * 127) < 2 ^ 63
have hmul : n * (127 * 127) ≤ 2 ^ 40 * (127 * 127) :=
Nat.mul_le_mul hn (Nat.le_refl _) hb s:KernelStaten:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ 127ha:∀ (i : Nat), (s.stream i).natAbs ≤ 127hacc:s.acc = 0hn:n ≤ 2 ^ 40hmul:n * (127 * 127) ≤ 2 ^ 40 * (127 * 127)⊢ 0 + n * (127 * 127) < 2 ^ 63
have hlt : 2 ^ 40 * (127 * 127) < 2 ^ 63 := by s:KernelStaten:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ 127ha:∀ (i : Nat), (s.stream i).natAbs ≤ 127hacc:s.acc = 0hn:n ≤ 2 ^ 40⊢ kernelPrefixFits defaultConfig s n native_decide hb s:KernelStaten:Nathw:∀ (i : Nat), (s.weights i).natAbs ≤ 127ha:∀ (i : Nat), (s.stream i).natAbs ≤ 127hacc:s.acc = 0hn:n ≤ 2 ^ 40hmul:n * (127 * 127) ≤ 2 ^ 40 * (127 * 127)hlt:2 ^ 40 * (127 * 127) < 2 ^ 63⊢ 0 + n * (127 * 127) < 2 ^ 63
omega All goals completed! 🐙
-- A fully concrete smoke check: a 1024-length int8 block cannot overflow.
theorem kernelPrefixFits_int8_1024 (s : KernelState)
(hw : forall i, (s.weights i).natAbs ≤ 127)
(ha : forall i, (s.stream i).natAbs ≤ 127)
(hacc : s.acc = 0) :
kernelPrefixFits defaultConfig s 1024 :=
kernelPrefixFits_int8_block s 1024 hw ha hacc (by s:KernelStatehw:∀ (i : Nat), (s.weights i).natAbs ≤ 127ha:∀ (i : Nat), (s.stream i).natAbs ≤ 127hacc:s.acc = 0⊢ 1024 ≤ 2 ^ 40 native_decide All goals completed! 🐙)
end Janus
Combined with kernel_accumulator_exact_when_prefixFits from the kernel
chapter, this gives an end-to-end statement for quantized kernels: a bounded
int8 block up to the stated length both computes the exact integer dot product
and never wraps the fixed-width accumulator. The overflow obligation is no
longer a proof the caller must supply; it follows from the block's quantization
and length.