Skip to main content

SparseLdlt

Struct SparseLdlt 

Source
pub struct SparseLdlt { /* private fields */ }
Expand description

An L D Lᵀ factorization of a symmetric matrix.

L is stored in CSC by column with an implicit unit diagonal (only the strictly lower entries are kept); d is the signed diagonal of D.

Implementations§

Source§

impl SparseLdlt

Source

pub fn factor( n: usize, col_ptr: &[usize], row_idx: &[usize], values: &[f64], ) -> Result<Self, LdltError>

Factor a symmetric n x n matrix supplied in CSC form.

  • col_ptr has length n + 1; column k occupies col_ptr[k]..col_ptr[k+1].
  • row_idx and values are parallel arrays of the nonzeros (any row order).

Only the upper triangle (entries with row ≤ col) is read; a fully symmetric matrix works too. No fill-reducing reordering is applied - permute the matrix first if you want one (RCM, AMD, nested dissection, …).

Source

pub fn factor_reporting_collapse( n: usize, col_ptr: &[usize], row_idx: &[usize], values: &[f64], ) -> Result<(Self, Vec<usize>), LdltError>

Like SparseLdlt::factor, but a near-zero pivot is RECORDED and the factorization continues, instead of aborting at the first one.

This exists for RANK CHECKS, not for solves. A caller asking “which directions of this matrix are null” needs the elimination to run to the end and name every column that collapsed - a structure with fifteen mechanisms has fifteen of them, and stopping at the first would report one. The returned factor is NOT fit to solve or to sign-count with: every collapsed column’s pivot is rounding noise, exactly the value SparseLdlt::factor refuses to return. Use the column list; discard d() for anything but structure.

An exact zero pivot still aborts, as it must: the elimination cannot proceed through it.

Source

pub fn factor_perm( n: usize, col_ptr: &[usize], row_idx: &[usize], values: &[f64], order: &[usize], ) -> Result<Self, LdltError>

Factor P A Pᵀ for a symmetric permutation P given as order, where order[k] is the original index eliminated k-th (e.g. the output of amd).

The returned factorization solves A x = b DIRECTLY - the permutation is stored and solve maps the right-hand side in and the solution back out, so callers that just want answers use it exactly like SparseLdlt::factor. Fill-in drops because the elimination order follows the ordering: on a random 2%-dense 1024 matrix the plain factor carries ~9x the nonzeros of the AMD-ordered one.

Inertia is untouched by a symmetric permutation (Sylvester’s law: P A Pᵀ is a congruence of A), so Sturm counts are identical with or without ordering.

§Errors

LdltError::InvalidInput if order is not a permutation of 0..n, plus everything SparseLdlt::factor can return.

Source

pub fn factor_shifted( n: usize, col_ptr: &[usize], row_idx: &[usize], values: &[f64], ) -> Result<Self, LdltError>

Like SparseLdlt::factor, but on a breakdown it retries with a positive diagonal shift instead of giving up.

The unshifted factorization is tried first, so a well-conditioned matrix costs nothing extra and comes back with SparseLdlt::shift == 0.0. On LdltError::ZeroPivot or LdltError::NearZeroPivot the matrix is refactored as A + shift * I, starting from the suggested shift and multiplying by 8 each attempt, at most 8 attempts; if none succeeds the last error is returned.

THE RESULT IS AN EXACT FACTORIZATION OF A NEARBY MATRIX, NOT OF A. Its pivots are the pivots of A + shift * I, so its inertia is that matrix’s inertia and a Sturm count taken from it is a count at a sigma moved by shift. A solve against it is a solve of the shifted system. Ignoring SparseLdlt::shift is a bug in the caller.

Source

pub fn factor_perm_shifted( n: usize, col_ptr: &[usize], row_idx: &[usize], values: &[f64], order: &[usize], ) -> Result<Self, LdltError>

SparseLdlt::factor_perm with the shifted-retry behaviour of SparseLdlt::factor_shifted. The same warning applies: a non-zero SparseLdlt::shift means this factored A + shift * I, not A.

Source

pub fn shift(&self) -> f64

The diagonal shift actually applied. 0.0 for SparseLdlt::factor / SparseLdlt::factor_perm, which never shift. Non-zero means this is an exact factorization of A + shift * I, NOT of A: its inertia is the inertia of the shifted matrix, so a Sturm count taken from it is a count for the caller’s sigma moved by this much, and the caller must correct for it.

Source

pub fn dim(&self) -> usize

The order of the factored matrix.

Source

pub fn d(&self) -> &[f64]

The signed diagonal D. The count of negative entries is the matrix inertia (number of negative eigenvalues), e.g. for a Sturm eigenvalue count.

Source

pub fn nnz(&self) -> usize

Number of stored off-diagonal nonzeros in L (the fill-in).

Source

pub fn flops(&self) -> u64

Floating-point operation count of the factorization: for each column of L with c stored entries, c*c + 3*c (the column-update arithmetic). Deterministic, so two factorizations of the same sparsity pattern report identical counts - callers (e.g. the supernodal equivalence gates in FEM Studio) assert on exactly that.

Source

pub fn solve(&self, b: &[f64]) -> Result<Vec<f64>, LdltError>

Solve A x = b for a single right-hand side, returning x.

Works for both SparseLdlt::factor and SparseLdlt::factor_perm - the stored elimination order is applied to the right-hand side and inverted on the solution, so the caller never sees the permutation.

§Errors

Returns LdltError::SizeMismatch if b.len() != self.dim().

Trait Implementations§

Source§

impl Clone for SparseLdlt

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for SparseLdlt

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.