Skip to main content

Crate faer

Crate faer 

Source
Expand description

faer is a general-purpose linear algebra library for rust, with a focus on high performance for algebraic operations on medium/large matrices, as well as matrix decompositions

most of the high-level functionality in this library is provided through associated functions in its vocabulary types: Mat/MatRef/MatMut

faer is recommended for applications that handle medium to large dense matrices, and its design is not well suited for applications that operate mostly on low dimensional vectors and matrices such as computer graphics or game development. for such applications, nalgebra and cgmath may be better suited

§basic usage

Mat is a resizable matrix type with dynamic capacity, which can be created using [Mat::new] to produce an empty $0\times 0$ matrix, [Mat::zeros] to create a rectangular matrix filled with zeros, [Mat::identity] to create an identity matrix, or [Mat::from_fn] for the more general case

Given a &Mat<T> (resp. &mut Mat<T>), a MatRef<'_, T> (resp. MatMut<'_, T>) can be created by calling [Mat::as_ref] (resp. [Mat::as_mut]), which allow for more flexibility than Mat in that they allow slicing ([MatRef::get]) and splitting ([MatRef::split_at])

MatRef and MatMut are lightweight view objects. the former can be copied freely while the latter has move and reborrow semantics, as described in its documentation

most of the matrix operations can be used through the corresponding math operators: + for matrix addition, - for subtraction, * for either scalar or matrix multiplication depending on the types of the operands.

§example

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)];

§matrix decompositions

faer provides a variety of matrix factorizations, each with its own advantages and drawbacks:

§$LL^\top$ decomposition

[Mat::llt] decomposes a self-adjoint positive definite matrix $A$ such that $$A = LL^H,$$ where $L$ is a lower triangular matrix. this decomposition is highly efficient and has good stability properties

an implementation for sparse matrices is also available

§$LBL^\top$ decomposition

[Mat::lblt] decomposes a self-adjoint (possibly indefinite) matrix $A$ such that $$P A P^\top = LBL^H,$$ where $P$ is a permutation matrix, $L$ is a lower triangular matrix, and $B$ is a block diagonal matrix, with $1 \times 1$ or $2 \times 2$ diagonal blocks. this decomposition is efficient and has good stability properties

§$LU$ decomposition with partial pivoting

[Mat::partial_piv_lu] decomposes a square invertible matrix $A$ into a lower triangular matrix $L$, a unit upper triangular matrix $U$, and a permutation matrix $P$, such that $$PA = LU$$ it is used by default for computing the determinant, and is generally the recommended method for solving a square linear system or computing the inverse of a matrix (although we generally recommend using a faer::linalg::solvers::Solve instead of computing the inverse explicitly)

an implementation for sparse matrices is also available

§$LU$ decomposition with full pivoting

[Mat::full_piv_lu] decomposes a generic rectangular matrix $A$ into a lower triangular matrix $L$, a unit upper triangular matrix $U$, and permutation matrices $P$ and $Q$, such that $$PAQ^\top = LU$$ it can be more stable than the LU decomposition with partial pivoting, in exchange for being more computationally expensive

§$QR$ decomposition

[Mat::qr] decomposes a matrix $A$ into the product $$A = QR,$$ where $Q$ is a unitary matrix, and $R$ is an upper trapezoidal matrix. it is often used for solving least squares problems

an implementation for sparse matrices is also available

§$QR$ decomposition with column pivoting

([Mat::col_piv_qr]) decomposes a matrix $A$ into the product $$AP^\top = QR,$$ where $P$ is a permutation matrix, $Q$ is a unitary matrix, and $R$ is an upper trapezoidal matrix

it is slower than the version with no pivoting, in exchange for being more numerically stable for rank-deficient matrices

§singular value decomposition

the SVD of a matrix $A$ of shape $(m, n)$ is a decomposition into three components $U$, $S$, and $V$, such that:

  • $U$ has shape $(m, m)$ and is a unitary matrix,
  • $V$ has shape $(n, n)$ and is a unitary matrix,
  • $S$ has shape $(m, n)$ and is zero everywhere except the main diagonal, with nonnegative diagonal values in nonincreasing order,
  • and finally:

$$A = U S V^H$$

the SVD is provided in two forms: either the full matrices $U$ and $V$ are computed, using [Mat::svd], or only their first $\min(m, n)$ columns are computed, using [Mat::thin_svd]

if only the singular values (elements of $S$) are desired, they can be obtained in nonincreasing order using [Mat::singular_values]

§eigendecomposition

note: the order of the eigenvalues is currently unspecified and may be changed in a future release

the eigenvalue decomposition of a square matrix $A$ of shape $(n, n)$ is a decomposition into two components $U$, $S$:

  • $U$ has shape $(n, n)$ and is invertible,
  • $S$ has shape $(n, n)$ and is a diagonal matrix,
  • and finally:

$$A = U S U^{-1}$$

if $A$ is self-adjoint, then $U$ can be made unitary ($U^{-1} = U^H$), and $S$ is real valued. additionally, the eigenvalues are sorted in nondecreasing order

Depending on the domain of the input matrix and whether it is self-adjoint, multiple methods are provided to compute the eigendecomposition:

  • [Mat::self_adjoint_eigen] can be used with either real or complex matrices, producing an eigendecomposition of the same type,
  • [Mat::eigen] can be used with real or complex matrices, but always produces complex values.

if only the eigenvalues (elements of $S$) are desired, they can be obtained using [Mat::self_adjoint_eigenvalues] (nondecreasing order), [Mat::eigenvalues] with the same conditions described above.

§parallelism

there is no process wide parallelism setting and no global threadpool. Every function that can run in parallel takes a Par argument, the high level ones included ([Mat::svd], [Mat::llt], [Mat::singular_values], the solve family of linalg::solvers::Solve, …). Pass Par::Seq for sequential execution, or own a team for the calls that should use one:

use faer::{Accum, Mat};
let a = Mat::<f64>::from_fn(16, 16, |i, j| (i == j) as u8 as f64 + 0.5);
let mut dst = Mat::<f64>::zeros(16, 16);
faer::team::with_team(4, |par| {
    faer::linalg::matmul::matmul(
        dst.as_mut(),
        Accum::Replace,
        a.as_ref(),
        a.as_ref(),
        1.0,
        par,
    );
});

The operator overloads (&a * &b, &a + &b, …) have no room for the argument and always run sequentially; use linalg::matmul::matmul for a parallel product.

with the threadteam feature (on by default) a team is a reservation the caller owns: its members spin while the reservation is held, instead of being woken for every region, and the token hands each region the authority to place work on them. That is what makes a sequence of short regions cheap: the bidiagonalization behind the SVD issues two vector products per step, and at n = 512 on eight threads it costs 25.5 ms with the members woken per region and 19.2 ms with the team held (docs/worklogs/2026-10-23-blocked-bidiag.md), which is where the values-only SVD reaches the vendor’s time. with_team takes the reservation once, so a caller with a thread budget wraps its work rather than handing a number to every call:

use faer::dyn_stack::{MemBuffer, MemStack};
use faer::{Mat, Par};
let a = Mat::<f64>::from_fn(64, 64, |i, j| ((i * 7 + j * 13) % 11) as f64 + 0.5);
let mut s = Mat::<f64>::zeros(64, 1);
let mut mem = MemBuffer::new(faer::linalg::svd::svd_scratch::<f64>(
    64,
    64,
    faer::linalg::svd::ComputeSvdVectors::No,
    faer::linalg::svd::ComputeSvdVectors::No,
    faer::ParShape::team(4),
    Default::default(),
));
faer::team::with_team(4, |par| {
    // every faer call in here with `par` runs its regions on 4 participants: the calling
    // thread and 3 reserved workers
    faer::linalg::svd::svd(
        a.as_ref(),
        s.as_mut().col_mut(0).as_diagonal_mut(),
        None,
        None,
        par,
        MemStack::new(&mut mem),
        Default::default(),
    )
    .unwrap();
});

the members busy-wait for a bounded time between regions, then sleep; the width is the one the caller asked with_team for, and there is no process-wide setting to override it.

with_team is for a one-off call: each call builds a new pool, spawning its worker threads and joining them again at the end. Code that runs parallel work repeatedly should build a threadteam::Pool and threadteam::Team once and lend a Par from the team to each call (see the example on team::with_team).

§crate features

  • std: enabled by default. links with the standard library to enable additional features such as cpu feature detection at runtime
  • rayon: enabled by default. selects the rayon backend of the gemm dependency; the parallel route itself (Par::Team, team::with_team) always uses rayon’s iterator plumbing, so the dependency is not optional
  • threadteam: enabled by default. the name the consumers pass; it pulls in rayon
  • npy: enables conversions to/from numpy’s matrix file format
  • perf-warn: produces performance warnings when matrix operations are called with suboptimal data layout
  • nightly: requires the nightly compiler. enables experimental simd features such as avx512

Re-exports§

pub extern crate num_complex as complex;
pub extern crate dyn_stack;
pub extern crate rand;
pub extern crate reborrow;
pub extern crate faer_traits as traits;

Re-exports§

pub use utils::team;
pub use col::Col;
pub use col::ColMut;
pub use col::ColRef;
pub use mat::Mat;
pub use mat::MatMut;
pub use mat::MatRef;
pub use mat::MatUninitMut;
pub use row::Row;
pub use row::RowMut;
pub use row::RowRef;

Modules§

col
column vector
diag
diagonal matrix
io
de-serialization from common matrix file formats
linalg
linear algebra module
mat
rectangular matrix
matrix_free
matrix-free linear operator traits and algorithms
perm
permutation matrix
prelude
useful imports for general usage of the library
row
row vector
sparse
sparse matrix data structures
stats
statistics and randomness functionality
utils
helper utilities

Macros§

Zip
expands to the type of zipped items.
auto
shorthand for <_ as Auto::<T>>::auto()
col
creates a col::Col containing the arguments
concat
concatenates the matrices in each row horizontally, then concatenates the results vertically
make_guard
see: generativity::make_guard
mat
creates a Mat containing the arguments.
row
creates a row::Row containing the arguments
unzip
used to undo the zipping by the zip! macro.
zip
zips together matrix of the same size, so that coefficient-wise operations can be performed on their elements.

Structs§

ContiguousBwd
contiguous stride equal to -1
ContiguousFwd
contiguous stride equal to +1
Scale
scaling factor for multiplying matrices.
Spec
implements Default based on Config’s Auto implementation for the type T.

Enums§

Accum
determines whether to replace or add to the result of a matmul operatio
Conj
determines whether the input should be implicitly conjugated or not
Par
determines the parallelization configuration, and carries the right to execute with it
ParShape
the shape of a Par: which kind of parallelism and how many threads, without the right to run anything. Copy, so workspace queries and thresholds can use it freely; it cannot be passed to any function that executes work.
Side
determines which side of a self-adjoint matrix should be accessed
TryReserveError
memory allocation error

Traits§

Auto
like Default, but with an extra type parameter so that algorithm hyperparameters can be tuned per scalar type.
Index
native unsigned integer type
Shape
matrix dimension
ShapeIdx
base trait for Shape
Stride
stride distance between two consecutive elements along a given dimension
Unbind
sealed trait for types that can be created from “unbound” values, as long as their struct preconditions are upheld

Type Aliases§

Idx
type that can be used to index into a range
IdxInc
type that can be used to partition a range
MaybeIdx
either an index or a negative value
c32
Complex<f32>
c64
Complex<f64>
cx128
Complex<f64>
fx128
Complex<f64>