Sparse Matrix Public API Shape
Summary
Sparse matrix operations (COO, CSR, CSC) are exposed as free functions rather than methods, COO is a build-only format with no arithmetic of its own, shape failures across every sparse operation share one error type, matvec/matmat return owned allocations, and a narrow trait lets iterative solvers call into any sparse format without knowing which one they’re holding.
Scope
Applies to the three sparse storage formats — coordinate (COO), compressed sparse row (CSR), and compressed sparse column (CSC) — and to every operation defined over them: construction, conversion between formats, matrix-vector and matrix-matrix products, addition, scaling, and the interface iterative solvers use to call into a sparse matrix without depending on its concrete format.
Decision
Free functions, not methods. All sparse operations are free functions, following the same convention used throughout the algorithm layer elsewhere in the crate. This keeps operation logic decoupled from the format type definitions, so operations can be added incrementally without reopening format modules — and stays consistent with the crate’s avoidance of trait-object-based dynamic dispatch, which a method surface on the types themselves would not by itself require, but which the free-function convention sidesteps entirely regardless.
COO is build-only. COO is the natural way to build a sparse matrix incrementally — it requires no ordering invariant, and duplicate entries at the same position are valid and expected while building. Arithmetic directly on COO is either expensive or semantically ambiguous (adding two COO matrices without first sorting both has no efficient implementation, and naively concatenating entry lists produces a result with unresolved duplicate positions that behaves differently from the equivalent CSR operation). COO supports construction and entry-by-entry manipulation; arithmetic requires converting to CSR or CSC first.
One shared shape-mismatch error. Every sparse operation that can fail due to
incompatible dimensions — matvec’s vector-length-versus-column-count check, binary
operations’ equal-dimension check, matmat’s inner-dimension-agreement check — returns the
same single error type rather than a module-specific one. All of these failures represent
the same underlying fact from a caller’s perspective, and a single type means one import and
one ?-target regardless of which sparse operation is being called.
Owned output. Matrix-vector and matrix-matrix products return an owned, newly allocated
vector or matrix. Every sparse format already requires an allocator to exist at all, so
there is no no_std-without-alloc path through this API to preserve, and an owned return
keeps call sites simple.
Solver interface without dynamic dispatch. Iterative solvers need only a matrix-vector
product and the operand dimensions, and should not be forced to pick a specific format at
the call site. A trait exposing rows, cols, and an apply-style matrix-vector product
provides this indirection through generic, monomorphized dispatch — no trait objects, no
heap allocation for the indirection itself. Every sparse format type implements it, and
solver functions are written generically against it rather than against any one format.
CSR/CSC parity. Both formats expose the same operation set (scale, matvec, add, matmat), because a caller who receives a matrix in one format should not be forced to convert before using it just because an operation happened to be implemented for the other format first.
Constraints
- A shape-mismatch failure anywhere in the sparse module must surface through the same error type, regardless of which operation detected it.
- The solver-facing trait must add no heap allocation of its own beyond what the concrete sparse format already requires, and must not rely on trait objects.
- Any per-iteration matrix-vector product called from inside a solver’s loop must be able to write into a caller-supplied output buffer rather than allocate fresh on every call — a per-iteration allocation is both a throughput cost and, on real-time embedded targets, a determinism problem.
- COO must never be extended with arithmetic operations that produce ambiguous results (such as unresolved duplicate entries after an add); any operation with that risk requires converting to CSR or CSC first.
Status
Implemented. All sparse operations are free functions; COO supports construction and conversion only; a single shared error type covers every shape mismatch; the solver-facing trait writes into a caller-supplied buffer for its matrix-vector product; CSR and CSC expose matching operation sets.