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

```console
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:

```toml
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:

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

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

[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"
```

```rust
#![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](https://docs.rs/rlumod/latest/rlumod/) 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](examples/README.md).

Build and open the documentation locally with:

```console
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](https://web.stanford.edu/group/SOL/software/lumod/)
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](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](LICENSES/SOL-LUMOD-MIT.txt).