Operations
StaticMatrix and DynamicMatrix support the same core set of operations: element-wise
addition and subtraction, scalar scaling, matrix-vector and matrix-matrix products,
transpose, rank, and the LU, QR, Cholesky, and SVD decompositions, plus condition number.
The example below runs each of them on a StaticMatrix.
#![allow(unused)]
fn main() {
use rustebra::matrix::StaticMatrix;
use rustebra::vector::StaticVector;
pub(crate) fn run() {
println!("== StaticMatrix ==");
let a = StaticMatrix::new([[1.0, 2.0], [3.0, 4.0]]);
let b = StaticMatrix::new([[5.0, 6.0], [7.0, 8.0]]);
let v = StaticVector::new([1.0, 1.0]);
println!("a = {a:?}");
println!("b = {b:?}");
println!("a + b = {:?}", a.add(&b));
println!("a - b = {:?}", a.sub(&b));
println!("a scaled by 2 = {:?}", a.mul_scalar(2.0));
println!("a * v = {:?}", a.mul_vector(&v));
println!("a * b = {:?}", a.mul_matrix(&b));
println!("a^T = {:?}", a.transpose());
println!("det(a) = {:?}", a.determinant());
println!("rank(a) = {:?}", a.rank());
let (l, u, swap_count) = a.lu();
println!("lu(a) = (l = {l:?}, u = {u:?}, swap_count = {swap_count})");
let (q, r) = a.qr().expect("a has at least as many rows as columns");
println!("qr(a) = (q = {q:?}, r = {r:?})");
let spd = StaticMatrix::new([[4.0, 2.0], [2.0, 2.0]]);
println!("cholesky(spd) = {:?}", spd.cholesky());
let mut svd_scratch = [0.0; 5 * 2 * 2 + 2 + 2];
let (svd_u, sigma, v) = a.svd(&mut svd_scratch).expect("scratch is correctly sized");
println!("svd(a) = (u = {svd_u:?}, sigma = {sigma:?}, v = {v:?})");
let mut condition_scratch = [0.0; 7 * 2 * 2 + 3 * 2];
println!(
"condition_number(a) = {:?}",
a.condition_number(&mut condition_scratch)
);
}
}
Gotchas
- On
StaticMatrix, operations between two matrices (add,sub,mul_matrix,mul_vector) return a plain value, not aResult— the const generics guarantee compatible shapes at compile time. TheDynamicMatrixequivalents returnResult<_, DimensionMismatch>instead, since twoDynamicMatrixs aren’t guaranteed to match in shape. qrreturnsResult<_, DimensionMismatch>on both types, becauseR >= Cisn’t something the type system can enforce even forStaticMatrix— stable Rust has no way to bound one const generic against another.svdandcondition_numberonStaticMatrixtake a caller-providedscratchbuffer sized by an explicit formula (5 * C * C + C + Rforsvd,7 * N * N + 3 * Nforcondition_number) — get the size wrong and you getErr(DimensionMismatch)back rather than a panic.DynamicMatrix’ssvd/condition_numberallocate their own scratch space internally and don’t take this parameter.determinantonStaticMatrix<T, N, N>returnsErr(DeterminantError::MatrixTooLargeWithoutAlloc)if theallocfeature is disabled andN > 4— for larger matrices withoutalloc, userustebra::algorithm::matrix::determinant_ludirectly with your own scratch buffer.choleskyrequiresselfto be symmetric positive-definite; it returnsErr(CholeskyError::NotPositiveDefinite)rather than a garbage result or a panic when that doesn’t hold.