Materializing the top-left quadrant view is Matrix.toBlocks₁₁ of the
materialized parent.
Materializing the top-right quadrant view is Matrix.toBlocks₁₂ of the parent.
Materializing the bottom-left quadrant view is Matrix.toBlocks₂₁ of the parent.
Materializing the bottom-right quadrant view is Matrix.toBlocks₂₂ of the parent.
Configuration for mulStrassen: the recursion cutoff below which a block is
handed to the base kernel, and the pluggable baseMul base kernel itself. Data
only — baseMul is a bare function and the record carries no algebraic instances,
so a caller can supply a hand-tuned small-matrix kernel without touching the
recursion.
- cutoff : Nat
The recursion stops splitting and calls
baseMulonce any of the three dimensions is below this cutoff. The base kernel run on small blocks. Polymorphic over the dimensions because the recursion reaches its base case at a range of (possibly rectangular) shapes.
Instances For
A configuration is valid when its base kernel agrees with the reference
mul on every input. The correctness theorem mulStrassen_eq_mul is stated under
this hypothesis, keeping the proof out of the StrassenConfig data record.
Equations
- cfg.Valid = ∀ {n m k : Nat} (X : Hex.Matrix R n m) (Y : Hex.Matrix R m k), cfg.baseMul X Y = X.mul Y
Instances For
The default configuration: naive mulImpl as the base kernel and a measured
cutoff of 96.
Measured by the Strassen bench driver (bench/HexMatrix/Bench.lean) on Int
coefficients with GMP arithmetic, sweeping the cutoff τ against dimension n
on host chungus2 (AMD EPYC 9455), Lean toolchain 4.32.0-rc1. An extra
Strassen level below a 64×64 block loses to the naive base kernel, while a
128×128 block splits profitably. Any cutoff in (64, 128] therefore recurses
down to a 64×64 naive leaf; that leaf class wins from the first splitting
dimension (n = 128) and stays within ~4% of the 128×128-leaf class at
n = 512 (which edges ahead there), so 96 is shipped as its representative,
extending Strassen to non-power-of-two blocks in [96, 128) as well. The value
has been re-measured twice: on the flat row-major backing with materialized
quadrants and again on the
Submatrix-view recursion, both within noise of the original sweep (the
quadrant copies the views remove are O(n²) per level against the O(n^2.81)
multiply work, so they never dominated at benched sizes) — the crossover
stayed put and 96 stands.
Equations
- Hex.Matrix.strassenDefault = { cutoff := 96, baseMul := fun {n m k : Nat} => Hex.Matrix.mulImpl }
Instances For
The default configuration is valid: its base kernel mulImpl equals mul by
mul_eq_mulImpl.
The internal Strassen-Winograd recursion over copy-free Submatrix views.
Recurses on the runtime dimensions following the Winograd schedule.
Base case: when any of n, m, k is ≤ 1 or below cfg.cutoff, materialize
the current view blocks (toMatrix) and call cfg.baseMul — the only leaf
allocation. The ≤ 1 disjuncts are config-independent, so cutoff = 0 cannot
defeat termination.
Recursive step: widen each operand view to even dimensions (h + h, w + w,
d + d with h := (n+1)/2 etc.) — a zero-fill reshape with no copy — split into
2×2 quadrant views (offset arithmetic — small view records, no buffer copies),
materialize only the fifteen
Sᵢ/Tᵢ/Uᵢ operand sums and the seven recursive products, assemble with
fromBlocks, and crop back to n × k. Termination is well-founded on n + m + k:
the recursion fires only when n, m, k ≥ 2, and each halved dimension is then
strictly smaller.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Write a square Strassen result into a backing-free region of one owned output
matrix. Even recursive nodes use the Boyer–Dumas–Pernet–Zhou schedule: X and
Y are the only half-size matrix buffers, while products and Uᵢ values are
written directly into the four output quadrants. Base and odd nodes retain the
reference view recursion as a shape-safe fallback.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The region writer returns the reference result in its destination and preserves every disjoint region.
Strassen-Winograd multiplication. The public entry point wraps the operands
as full-matrix Submatrix views and runs the view recursion mulStrassenView;
the quadrant splitting inside never materializes or copies a quadrant buffer —
only O(1) view records.
Equations
- Hex.Matrix.mulStrassen cfg M N = Hex.Matrix.mulStrassenView cfg (Hex.Submatrix.ofMatrix M) (Hex.Submatrix.ofMatrix N)
Instances For
Storage-scheduled implementation of mulStrassen. Square inputs run the
two-buffer writer; all other shapes retain the reference view recursion.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The storage-scheduled implementation is extensionally equal to the reference
entry point. This transfers the implementation without changing
mulStrassen's statement or its ring-level correctness theorem.
The view recursion computes the same matrix as the reference mul of the
materialized operands, for every valid configuration. Proved by functional
induction over mulStrassenView, reducing each quadrant view to its toBlocks
materialization (toMatrix_toBlocks…, toMatrix_pad_view) and composing the
three wave-1 lemmas exactly as the Matrix-level recursion did.
Correctness of Strassen-Winograd multiplication. For every valid
configuration, mulStrassen computes the same matrix as the reference mul.