faer Linear Algebra Library

repository·main·Indexed 25 days ago

https://github.com/sarah-quinones/faer-rs

A high-performance, pure Rust linear algebra library providing low-level routines and high-level abstractions. It includes the faer-ffi crate for C/C++ interfacing, supporting operations such as matrix multiplication, triangular system solving, and various factorizations including Cholesky (LLT, LDLT, LBLT), QR, LU, SVD, and Eigenvalue Decomposition (EVD). Minimum supported rust version (MSRV) is 1.84.0.

Tokens
16.8K
Snippets
25
Records
115
Agent score
82%

What's inside faer

  1. Overview of faer: High-performance dense linear algebra in Rust

    main

    faer is a portable, high-performance dense linear algebra library written in Rust. It provides a high-level API for matrix decompositions and solving linear systems, built upon a lower-level API that allows fine-grained control over memory allocation and multithreading.

    Key Features

    • Matrix Types: Provides the Mat type for simple matrix construction and manipulation, alongside lightweight view types MatRef and MatMut for building memory views over existing data.
    • Supported Scalars: Supports native floating-point types f32, f64, c32, and c64, as well as user-defined types (e.g., extended precision, complex numbers, dual/hyper-dual numbers) that satisfy the required interface.
    • Decompositions: Implements state-of-the-art algorithms for:
      • Cholesky (LLT, LDLT, and Bunch-Kaufman LDLT)
      • QR (with and without column pivoting)
      • LU (with partial and full pivoting)
      • SVD (with or without singular vectors, thin or full)
      • Eigenvalue decomposition (with or without eigenvectors)
    • Performance: Uses explicit SIMD instructions (x86-64 and Aarch64/NEON) and the Rayon library for high-performance parallelism.
    • Platform Support: Supports all platforms supported by Rust.
  2. Overview of the faer library

    main
    faer is a pure Rust crate providing both low-level linear algebra routines and a high-level wrapper for ease of use. It is designed to be a fully featured linear algebra library with a focus on portability, correctness, and performance.
  3. Use Mat, MatRef, and MatMut for matrix manipulation

    main

    faer uses three primary types to handle matrix data:

    1. Mat<T>: A high-level type used for quick and simple construction and manipulation of matrices. It owns its data.
    2. MatRef<T>: A lightweight, read-only view type used to represent a matrix view over existing data.
    3. MatMut<T>: A lightweight, mutable view type used to represent a mutable matrix view over existing data.

    These views can represent various matrix structures, including generic rectangular matrices and symmetric, Hermitian, or triangular matrices (where only half of the matrix is stored).

  4. Permutation types: Perm and PermRef

    main

    Faer provides two primary types for representing permutations:

    • Perm<I, N>: An owned permutation matrix.
    • PermRef<'a, I, N>: An immutable view of a permutation.

    Both types wrap an inner representation and can be used to define how rows or columns should be reordered in permutation routines.

  5. Understand the core matrix types: Mat, MatRef, and MatMut

    main

    The faer library provides three primary matrix abstractions depending on ownership and mutability:

    1. Mat<T, Rows, Cols>: A heap-allocated, resizable, owned matrix. It is stored in column-major order. While individual columns are contiguous, the matrix as a whole may contain padding for alignment.
    2. MatRef<'a, T, Rows, Cols, RStride, CStride>: An immutable view over a matrix (similar to a 2D strided slice). Note that data may be partially uninitialized; avoid reading uninitialized values.
    3. MatMut<'a, T, Rows, Cols, RStride, CStride>: A mutable view over a matrix.

    Important: Move Semantics and Reborrowing MatMut cannot be Copy because it mutably borrows data. If you pass a MatMut to a function by value or use a consuming method (like transpose_mut), the original variable becomes unusable. To use a MatMut multiple times, use the reborrow pattern via .rb() (for immutable reborrow) or .rb_mut() (for mutable reborrow).

    use faer::{Mat, MatMut, MatRef};
    use reborrow::ReborrowMut;
    
    let mut matrix = Mat::<f64>::zeros(3, 4);
    let mut view = matrix.as_mut();
    
    // Use .rb_mut() to reborrow so 'view' remains usable
    takes_matmut(view.rb_mut());
    takes_matmut(view.rb_mut());
    
    // Use .rb() to get an immutable view from a mutable one
    takes_matref(view.rb());
    use faer::{Mat, MatMut, MatRef};
    use reborrow::ReborrowMut;
    
    fn takes_matmut(view: MatMut<'_, f64>) {}
    fn takes_matref(view: MatRef<'_, f64>) {}
    
    let mut matrix = Mat::new();
    let mut view = matrix.as_mut();
    takes_matmut(view.rb_mut());
    takes_matmut(view.rb_mut());
    // view is still usable here
    takes_matref(view.rb());
    // view is still usable here
  6. Control factorization type with SupernodalThreshold

    main

    The SupernodalThreshold type controls whether the sparse factorization uses a simplicial or supernodal approach. This is a non-negative threshold where:

    • Increasing the value makes it more likely to use simplicial factorization.
    • Decreasing the value makes it more likely to use supernodal factorization.

    Available constants:

    • SupernodalThreshold::AUTO: Uses the default value of 1.0 to determine the variant automatically.
    • SupernodalThreshold::FORCE_SIMPLICIAL: Uses f64::INFINITY to ensure simplicial factorization is always selected.
    • SupernodalThreshold::FORCE_SUPERNODAL: Uses 0.0 to ensure supernodal factorization is always selected.
  7. Understand the RealField trait

    main

    The RealField trait is a specialization of ComplexField for types that represent real numbers. A type implementing RealField must satisfy ComplexField<Real = Self, Conj = Self> and provide additional mathematical properties like PartialOrd and num_traits::Num.

    It includes methods for retrieving field-specific constants and properties:

    • epsilon_impl(): Returns the machine epsilon.
    • nbits_impl(): Returns the number of mantissa bits.
    • min_positive_impl() / max_positive_impl(): Returns the smallest and largest positive representable values.
    • sqrt_min_positive_impl() / sqrt_max_positive_impl(): Returns the square roots of the min/max positive values.
  8. Understand the ComplexField trait

    main

    The ComplexField trait defines the interface for complex number types in faer. It provides both scalar operations (like conj_impl, sqrt_impl, abs_impl) and SIMD-accelerated operations (like simd_add, simd_mul, simd_reduce_sum).

    Key associated types include:

    • type Real: The underlying real field type.
    • type Arch: The SIMD architecture.
    • type SimdVec<S: Simd>: The SIMD vector type for a given SIMD instruction set.
    • type SimdMask<S: Simd>: The SIMD mask type.

    Implementations are provided for primitive types like f32 and f64 (which act as RealField) and for the Complex<T> struct.

  9. Matrix decompositions in faer

    main

    faer provides several matrix factorization methods via associated functions on Mat:

    • $LL^\top$ decomposition: Mat::llt() decomposes a self-adjoint positive definite matrix $A$ into $A = LL^H$. Highly efficient and stable.
    • $LBL^\top$ decomposition: Mat::lblt() decomposes a self-adjoint (possibly indefinite) matrix $A$ into $P A P^\top = LBL^H$, where $P$ is a permutation matrix, $L$ is lower triangular, and $B$ is block diagonal.
    • $LU$ decomposition (Partial Pivoting): Mat::partial_piv_lu() decomposes a square invertible matrix $A$ into $PA = LU$. Recommended for solving square linear systems or computing determinants.
    • $LU$ decomposition (Full Pivoting): Mat::full_piv_lu() decomposes a generic rectangular matrix $A$ into $PAQ^\top = LU$. More stable than partial pivoting but more expensive.
    • $QR$ decomposition: Mat::qr() decomposes $A$ into $A = QR$ (unitary $Q$, upper trapezoidal $R$). Used for least squares problems.
    • $QR$ decomposition (Column Pivoting): Mat::col_piv_qr() decomposes $AP^\top = QR$. More stable for rank-deficient matrices.
    • Singular Value Decomposition (SVD):
      • Mat::svd(): Computes full matrices $U$, $S$, and $V$ such that $A = U S V^H$.
      • Mat::thin_svd(): Computes only the first $\min(m, n)$ columns of $U$ and $V$.
      • Mat::singular_values(): Returns only the singular values in nonincreasing order.
    • Eigendecomposition:
      • Mat::self_adjoint_eigen(): For self-adjoint matrices (real or complex). Eigenvalues are sorted in nondecreasing order.
      • Mat::eigen(): For real or complex matrices; always produces complex values.
  10. Basic usage of faer matrices

    main

    The faer library provides high-performance linear algebra operations. The primary way to interact with matrices is through the Mat, MatRef, and MatMut types.

    • Mat<T>: A resizable matrix type with dynamic capacity.
    • MatRef<'_, T>: A lightweight, copyable view of a matrix (created via Mat::as_ref).
    • MatMut<'_, T>: A lightweight view of a matrix with move and reborrow semantics (created via Mat::as_mut).

    Common creation methods for Mat include:

    • Mat::new(): Creates an empty $0\times 0$ matrix.
    • Mat::zeros(nrows, ncols): Creates a rectangular matrix filled with zeros.
    • Mat::identity(n): Creates an identity matrix.
    • Mat::from_fn(nrows, ncols, |i, j| ...): Creates a matrix using a generator function.
    • mat![...]: A macro for convenient matrix initialization.

    Matrix operations can be performed using standard math operators: + (addition), - (subtraction), and * (scalar or matrix multiplication).

    use faer::{Mat, Scale, mat};
    let a = mat![
    	[1.0, 5.0, 9.0],
    	[2.0, 6.0, 10.0],
    	[3.0, 7.0, 11.0],
    	[4.0, 8.0, 12.0f64],
    ];
    let b = Mat::from_fn(4, 3, |i, j| (i + j) as f64);
    let add = &a + &b;
    let sub = &a - &b;
    let scale = Scale(3.0) * &a;
    let mul = &a * b.transpose();
    let a00 = a[(0, 0)];
  11. Configure faer crate features

    main

    faer can be configured via Cargo features:

    • std: (Default) Enables standard library support, including runtime CPU feature detection.
    • rayon: (Default) Enables the rayon parallel backend and global parallelism.
    • npy: Enables conversions to/from NumPy's matrix file format.
    • perf-warn: Produces performance warnings when operations are called with suboptimal data layouts.
    • nightly: Requires the nightly Rust compiler; enables experimental SIMD features like avx512.