Skip to main content

Crate rlumod

Crate rlumod 

Source
Expand description

The C ABI is exported for linking, not as a Rust raw-pointer API.

ⓘ
let _ = rlumod::ffi::one_based::LUmod;

The checked C ABI is exported for linking, not as a Rust raw-pointer API.

ⓘ
let _ = rlumod::ffi::zero_based::rlumod_storage_lengths;

A safe, allocation-free Rust adaptation of the LUmod numerical software made available by Stanford’s Systems Optimization Laboratory.

rlumod incrementally constructs and updates a dense square matrix while maintaining the LUmod representation L A = U, where L is a product of stabilized elementary transformations and U is upper triangular.

§Scope and non-goals

rlumod does not compute a conventional LU decomposition A = L U from an arbitrary completed matrix. In particular:

  • LuMod represents dense square matrices only;
  • L is not the lower-triangular factor from a conventional LU decomposition;
  • there is no one-shot factorization function; construct a new matrix with repeated calls to LuMod::push; and
  • there is no sparse matrix storage or sparse safe API.

The optional lumod_c module provides low-level dense operations with the original LUmod names. It does not add sparse support.

§Quick start

use rlumod::{LuMod, Workspace, storage_lengths};

let capacity = 2;
let lengths = storage_lengths(capacity).unwrap();
let mut l = vec![0.0_f64; lengths.l];
let mut u = vec![0.0_f64; lengths.u];
let mut y = vec![0.0; capacity];
let mut z = vec![0.0; capacity];
let mut w = vec![0.0; capacity];

let mut workspace = Workspace::new(&mut y, &mut z, &mut w).unwrap();
let mut factors = LuMod::from_storage(0, capacity, &mut l, &mut u).unwrap();
factors.push(&[], &[], 2.0, &mut workspace).unwrap();
factors.push(&[3.0], &[5.0], 7.0, &mut workspace).unwrap();

// The represented matrix is [[2, 5], [3, 7]].
let mut rhs = [12.0, 17.0];
factors.solve_in_place(&mut rhs).unwrap();
assert!((rhs[0] - 1.0).abs() < 1.0e-12);
assert!((rhs[1] - 2.0).abs() < 1.0e-12);

The example uses Vec only to choose the capacity at run time. LuMod does not allocate, and fixed arrays or static buffers may be used instead; see examples/static_storage.rs in the source distribution. For a compile-time capacity, stack_storage! creates the zero-initialized factor and workspace arrays from the same checked storage-length calculation.

§Building a matrix

For a new matrix, normally call LuMod::from_storage with a dimension of zero and then append its rows and columns. To construct

A = [[a00, a01, a02],
     [a10, a11, a12],
     [a20, a21, a22]],

make these calls in order:

push([],         [],         a00)
push([a10],      [a01],      a11)
push([a20, a21], [a02, a12], a22)

Each row and column slice contains the entries that precede the new diagonal. After construction, LuMod::replace_row and LuMod::replace_column accept a complete row or column of length LuMod::dimension.

§Storage lifecycle and no_std

storage_lengths returns the required factor-buffer lengths for a fixed capacity. The L buffer contains capacity * capacity factor entries plus capacity entries used internally by solves. The U buffer uses packed upper-triangular storage. Workspace wraps three equally sized buffers used by updates.

LuMod::from_storage adopts the buffers without initializing them. A zero dimension starts a new representation. With a nonzero dimension, the required prefixes must already contain factors previously produced for the same capacity; this mathematical precondition cannot be validated. This is useful when dropping a LuMod to release its borrows and later adopting the retained buffers again.

The crate is no_std and performs no heap allocation. Storage may still be supplied by Vec in applications that have an allocator, or by fixed and static arrays in allocation-free applications. stack_storage! creates fixed local array values without a heap allocation, but does not guarantee physical stack placement; a valid large capacity can still overflow the stack when those values are used as locals.

§Updates and removal

LuMod::remove has swap-remove semantics: it moves the last row into the removed row position and the last column into the removed column position, then decreases the dimension. The returned Removal reports the original last indices that moved. External row and column identities should be updated with the same semantics, for example with Vec::swap_remove. See examples/remove_with_ids.rs in the source distribution.

§Error and numerical behavior

The safe API validates dimensions, indices, slice lengths, and workspace capacity. A structural update error leaves the factors and dimension unchanged. A solve error leaves the right-hand side unchanged.

“Safe” does not mean numerically nonsingular or well-conditioned. Updates accept singular and non-finite matrix values, and a successful update does not assess conditioning. Solves reject zero or non-finite U-factor diagonal entries, but do not classify a small finite diagonal as nearly singular or compute a condition number.

§Migrating from dense C LUmod

The safe API replaces integer modes and raw buffers with explicit methods, typed zero-based indices, and validated slices:

Dense C operationSafe Rust operation
LUmod(mode = 1, n = new_dimension, ...)LuMod::push with row and column slices of length new_dimension - 1 plus a separate diagonal
LUmod(mode = 2, kcol, ...)LuMod::replace_column with ColumnIndex
LUmod(mode = 3, krow, ...)LuMod::replace_row with RowIndex
LUmod(mode = 4, krow, kcol, ...)LuMod::remove, which also decreases the stored dimension
Lprod(mode = 1, ...) then Usolve(mode = 1, ...)LuMod::solve_in_place
Usolve(mode = 2, ...) then Lprod(mode = 2, ...)LuMod::solve_transpose_in_place

Original C LUmod uses one-based row and column numbers and caller-managed dimension changes. The safe API uses zero-based RowIndex and ColumnIndex values and owns the logical dimension. Allocate factor storage with storage_lengths rather than reproducing the C formulas: unlike the C L array, the safe L buffer also contains private solve work. Construct Workspace separately for update work. Safe operations support f32 and f64 and return structural or solve errors instead of relying on unchecked preconditions.

For a closer Rust port, enable the lumod-c feature. The lumod_c module keeps the original names and mode arguments as a zero-based Rust slice API. Enable c-ffi-zero-based for the checked, zero-based C ABI corresponding to the safe API. It supports f32 and f64 and is independent of lumod-c and c-ffi-one-based. Enable c-ffi-one-based for the dense, one-based C ABI; it also enables lumod-c. This crate remains an rlib; a final C-linkable crate must provide its own panic handler, select staticlib, and reference rlumod so the C ABI is retained. New Rust code should normally prefer LuMod. The sparse C implementation has no corresponding API in this crate.

§Runnable examples

The source distribution includes small examples for the complete safe API lifecycle, fixed storage, and external identity tracking:

cargo run --example basic_lifecycle
cargo run --example static_storage
cargo run --example remove_with_ids

rlumod is licensed under the MIT License; see LICENSE. The original LUmod is used under SOL’s MIT license option; its copyright and license notice are retained separately in LICENSES/SOL-LUMOD-MIT.txt.

Modules§

lumod_c
Low-level API compatible with the original LUmod calling conventions.

Macros§

stack_storage
Creates zero-initialized fixed-size storage for a LuMod instance.

Structs§

ColumnIndex
A zero-based column index in the represented matrix.
LuMod
An updatable square-matrix representation backed by caller-owned factor storage.
Removal
Describes which last row and column were moved by LuMod::remove.
RowIndex
A zero-based row index in the represented matrix.
StorageLengths
Required lengths of the caller-owned factor buffers.
Workspace
Caller-owned work buffers used by factor updates.

Enums§

SolveError
An error that prevents solving with the current factors.
StorageError
An error in caller-owned storage or its requested dimensions.
UpdateError
An error that prevents a structural factor update.

Traits§

Real
A floating-point type supported by LuMod.

Functions§

storage_lengths
Computes the factor-buffer lengths required for capacity.