linalg
linear algebra (graphics + dense + AI base)
use linalgNot “gamedev linalg”; it is the mathematical library that underpins everything from graphics to AI. There are three layers: fixed types (graphics),
Matrix[M,N]/dynamic (general dense), and BLAS-style dense algebra (multiplication, decompositions, solve). Dual backend (mirrors the multi-engine ofregex): the portable own implementation is the floor, and the system BLAS/LAPACK is the opt-in accelerator (via the C-FFI we already have). Tier 1. Arbitrary-rank tensors and autograd/NN are left to the AI lib (tier 2/3) on top; here is the numerical foundation.
Fixed types (graphics)
Section titled “Fixed types (graphics)”Size known at compile time; operations are by value, no allocation:
decl Vec2 { pub x: f32; pub y: f32 }decl Vec3 { pub x: f32; pub y: f32; pub z: f32 }decl Vec4 { pub x: f32; pub y: f32; pub z: f32; pub w: f32 }decl Mat2 { ... } decl Mat3 { ... } decl Mat4 { ... }decl Quat { pub x: f32; pub y: f32; pub z: f32; pub w: f32 } // quaternion
fn (a: Vec3) dot(b: Vec3) -> f32 // dot product (+ via operator where numeric)fn (a: Vec3) cross(b: Vec3) -> Vec3 // cross productfn (a: Vec3) length() -> f32fn (a: Vec3) normalized() -> Vec3fn (a: Vec3) add(b: Vec3) -> Vec3 // + also via operator (numeric)fn (m: Mat4) mul(n: Mat4) -> Mat4fn (m: Mat4) mul_vec(v: Vec4) -> Vec4fn (m: Mat4) inverse() -> Optional[Mat4] // none if singularfn (m: Mat4) transpose() -> Mat4fn (q: Quat) mul(r: Quat) -> Quatfn (q: Quat) to_mat4() -> Mat4
// common transformations (constructors):fn Mat4.identity() -> Mat4fn Mat4.translation(v: Vec3) -> Mat4fn Mat4.rotation(axis: Vec3, angle: f32) -> Mat4fn Mat4.scale(v: Vec3) -> Mat4fn Mat4.perspective(fovy: f32, aspect: f32, near: f32, far: f32) -> Mat4fn Mat4.look_at(eye: Vec3, center: Vec3, up: Vec3) -> Mat4f32 generic where it makes sense: Vec3[T] over any float (f32/f64); the bare names (Vec3) are
the f32 alias (the graphics case). In practice, alias Vec3 = Vec3f.
Dynamic and dense matrix (Matrix[T])
Section titled “Dynamic and dense matrix (Matrix[T])”Dimensions at runtime; allocates via the context’s @mm. It is the general numerical base, and what AI pulls:
decl Matrix[T] { pub rows: usize; pub cols: usize; ... } // T = f32/f64fn (Matrix[T]) zeros(rows: usize, cols: usize) -> Matrix[T]fn (Matrix[T]) from(rows: usize, cols: usize, data: []T) -> Matrix[T] // row-majorfn (Matrix[T]) identity(n: usize) -> Matrix[T]
fn (m: Matrix[T]) get(i: usize, j: usize) -> Optional[T] // SAFE (none out of bounds)@requires(i < m.rows && j < m.cols)fn (m: Matrix[T]) at(i: usize, j: usize) -> T // contracted (no Optional)fn (m: *Matrix[T]) set(i: usize, j: usize, v: T) -> error{OutOfBounds}fn (m: Matrix[T]) mul(n: Matrix[T]) -> Result[Matrix[T], error{ShapeMismatch}] // matrix productfn (m: Matrix[T]) add(n: Matrix[T]) -> Result[Matrix[T], error{ShapeMismatch}]fn (m: Matrix[T]) transpose() -> Matrix[T]fn (m: Matrix[T]) slice(r0: usize, r1: usize, c0: usize, c1: usize) -> Matrix[T] // submatrix (view)fn (m: Matrix[T]) row(i: usize) -> []T // viewfn (m: Matrix[T]) col(j: usize) -> List[T]Access is at/get (no [] overload), same as collections/containers: safe from the outside, with the raw index
contained.
Dense algebra (decompositions): dual backend
Section titled “Dense algebra (decompositions): dual backend”The decompositions and the solve, the heart of the dense part. Portable own one by default; BLAS/LAPACK opt-in when
linked (the compiler chooses the backend at comptime according to how linalg is configured, the way arch.has_feature
chooses the SIMD path):
fn (m: Matrix[T]) lu() -> Result[(l: Matrix[T], u: Matrix[T], p: Permutation), error{Singular}]fn (m: Matrix[T]) qr() -> (q: Matrix[T], r: Matrix[T])fn (m: Matrix[T]) svd() -> (u: Matrix[T], s: List[T], vt: Matrix[T])fn (m: Matrix[T]) cholesky() -> Result[Matrix[T], error{NotPositiveDefinite}]fn (m: Matrix[T]) solve(b: Matrix[T]) -> Result[Matrix[T], error{Singular, ShapeMismatch}] // solves Mx=bfn (m: Matrix[T]) det() -> Tfn (m: Matrix[T]) inverse() -> Result[Matrix[T], error{Singular}]fn (m: Matrix[T]) eig() -> Result[(values: List[T], vectors: Matrix[T]), error{NoConverge}]The own implementation is the floor (portable, always present); the BLAS/LAPACK binding (via C-FFI, §17) is the
accelerator, with the same API and a swappable backend. Enabling BLAS is declaring the C dep (cdeps, §17) + a build
flag; without that, it runs the own one.
Curation
Section titled “Curation”- Dual backend (own + BLAS opt-in): mirrors the multi-engine of
regex: portable is the floor (zero dependency), BLAS is the accelerator when you link it. Same API; comptime chooses. - Three layers, one package: fixed (graphics, zero-alloc, by value),
Matrix[T](general dense), decompositions (serious dense). They grow together because they share the types. - Tensors (rank > 2) and autograd/NN are the AI lib (tier 2/3):
linalgis the foundation; broadcasting andTensor[rank]enter the layer above, not here. A big piece, deliberately out. at/get, no[]overload: consistent withcollections/containers; colorless (allocates via the context).