rlumod 1.0.0

Safe, no_std matrix updates and linear solves using the LUmod algorithm
Documentation

rlumod

rlumod is a safe, no_std Rust adaptation of LUmod, Michael A. Saunders' software for incrementally updating a dense square matrix and solving systems with the updated matrix. It maintains the LUmod representation L A = U; it does not compute a conventional A = LU decomposition of an arbitrary completed matrix.

The crate provides:

  • row-and-column insertion, row replacement, column replacement, and row-and-column removal;
  • in-place solution of A x = b and A^T x = b;
  • safe, zero-based APIs for both f32 and f64;
  • caller-owned factor and workspace storage, with no heap allocation during updates or solves; and
  • an optional lumod-c feature exposing a lower-level Rust slice API with the original LUmod names and mode arguments; and
  • an optional c-ffi-zero-based feature exposing a checked, zero-based C ABI corresponding to the safe Rust lifecycle; and
  • an optional c-ffi-one-based feature exposing one-based C entry points for LUmod, Lprod, and Usolve.

rlumod supports dense square matrices only. It does not provide sparse matrix storage or a one-shot factorization API.

Installation

cargo add rlumod

C FFI

The optional c-ffi-zero-based feature exports the checked, zero-based API in include/rlumod/rlumod.h. It supports both float and double, uses caller-owned factor and workspace storage, reports errors with stable numeric status values, and exposes push, row and column replacement, removal, and normal and transpose solves. It is independent of both lumod-c and c-ffi-one-based.

The zero-based L buffer needs capacity * (capacity + 1) elements, including private solve work. U needs capacity * (capacity + 1) / 2 elements, and each workspace buffer should normally have capacity elements. Use rlumod_storage_lengths instead of reproducing these formulas. Empty buffers may use a null pointer with length zero.

This is a checked unsafe ABI, not a memory-safe C API. It validates dimensions, lengths, alignment, representable address ranges, and detectable overlap before forming Rust slices. The caller remains responsible for pointer lifetime, actual allocation size, initialization, and external synchronization. Even solves require exclusive access to a factor because L contains mutable scratch storage. Descriptor fields may be read but must not be changed by the caller.

Enable the feature in the final static-library crate as follows:

rlumod = { version = "1.0.0", features = ["c-ffi-zero-based"] }

The descriptor layout, function signatures, and documented status numbers in this header form the target-specific ABI. size_t fields follow the pointer width of the target C ABI.

Original one-based compatibility ABI

The optional c-ffi-one-based feature includes dense, one-based C entry points for LUmod, Lprod, and Usolve, as declared by lumod-c/lumod_dense.h. It automatically enables the lower-level lumod-c Rust API. rlumod remains an rlib; the final no_std crate is responsible for its panic handler and for selecting staticlib when a C-linkable archive is needed. The header is include/lumod-c/lumod_dense.h.

The final crate must also reference rlumod so the linker retains the C ABI:

[lib]
crate-type = ["staticlib"]

[dependencies]
rlumod = { version = "1.0.0", features = ["c-ffi-one-based"] }

[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"
#![no_std]

extern crate rlumod; // Force-link the exported C ABI.

#[panic_handler]
fn panic(_info: &core::panic::PanicInfo<'_>) -> ! {
    loop {
        core::hint::spin_loop();
    }
}

// Stock core may retain this reference even when the final crate aborts on panic.
#[cfg(not(target_env = "msvc"))]
#[unsafe(no_mangle)]
extern "C" fn rust_eh_personality(
    _version: i32,
    _actions: i32,
    _exception_class: u64,
    _exception_object: *mut (),
    _context: *mut (),
) -> i32 {
    loop {
        core::hint::spin_loop();
    }
}

This compatibility ABI uses caller-owned, one-based buffers. Element zero is an unused dummy; L needs maxmod * maxmod + 1 doubles and U needs maxmod * (maxmod + 1) / 2 + 1 doubles. Callers must provide initialized, aligned, writable, sufficiently large, non-overlapping buffers. The ABI cannot verify those C pointer properties. Sparse storage and a dynamic library are not provided.

Documentation and examples

The crate documentation is the main user guide. It covers matrix construction, storage lifetime, update and removal semantics, numerical behavior, and migration from the C LUmod API.

Small runnable programs and the larger validation drivers are listed in the examples guide.

Build and open the documentation locally with:

cargo doc --all-features --open

About LUmod and SOL

The original LUmod was written by Michael A. Saunders at Stanford University's Systems Optimization Laboratory (SOL). It maintains the factorization L A = U, where L is a product of stabilized elementary transformations and U is upper triangular.

See the official LUmod page at SOL for the algorithm's provenance, original distributions, and references.

The rlumod project is an independent Rust adaptation and is not affiliated with, endorsed by, or maintained by Michael A. Saunders or SOL.

License

This Rust adaptation is distributed under the MIT License. The original LUmod is used under SOL's MIT license option. Its copyright and license notice are retained in LICENSES/SOL-LUMOD-MIT.txt.