### Run rlumod examples Source: https://docs.rs/rlumod/latest/rlumod/index.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Use these commands to execute the provided examples from the source distribution. ```bash cargo run --example basic_lifecycle cargo run --example static_storage cargo run --example remove_with_ids ``` -------------------------------- ### Handle capacity overflow Source: https://docs.rs/rlumod/latest/rlumod/macro.stack_storage.html Example of a capacity that causes a compilation error due to overflow. ```rust const _: ([f64; 0], [f64; 0], [f64; 0], [f64; 0], [f64; 0]) = rlumod::stack_storage!(f64; usize::MAX); ``` -------------------------------- ### Initialize and solve with LuMod Source: https://docs.rs/rlumod/latest/rlumod/index.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Demonstrates setting up storage, initializing the workspace, pushing matrix elements, and solving a linear system. ```rust 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); ``` -------------------------------- ### Perform LU factorization and solve Source: https://docs.rs/rlumod/latest/rlumod/lumod_c/index.html Demonstrates the usage of LUmod, Lprod, and Usolve to update factors and solve a system. ```rust use rlumod::lumod_c::{LUmod, Lprod, Usolve}; let (mut l, mut u) = ([0.0; 1], [0.0; 1]); let (mut y, mut z, mut w) = ([2.0], [2.0], [0.0]); LUmod(1, 1, 1, 0, 0, &mut l, &mut u, &mut y, &mut z, &mut w); let (mut rhs, mut work) = ([6.0], [0.0]); Lprod(1, 1, 1, &mut l, &mut rhs, &mut work); Usolve(1, 1, 1, &mut u, &mut work); assert_eq!(work, [3.0]); ``` -------------------------------- ### LuMod::from_storage Source: https://docs.rs/rlumod/latest/rlumod/struct.LuMod.html?search=std%3A%3Avec Initializes a new LuMod instance by adopting existing factor storage buffers. ```APIDOC ## pub fn from_storage(dimension: usize, capacity: usize, l: &'a mut [T], u: &'a mut [T]) -> Result ### Description Adopts existing factor storage without changing its contents. The buffers l and u must meet specific size requirements based on the capacity. ### Parameters - **dimension** (usize) - The current matrix dimension. - **capacity** (usize) - The maximum matrix dimension supported. - **l** (&'a mut [T]) - Buffer for L-factor and solve-work elements. - **u** (&'a mut [T]) - Buffer for packed upper-triangular U-factor elements. ``` -------------------------------- ### Workspace Initialization Source: https://docs.rs/rlumod/latest/src/rlumod/api.rs.html?search=u32+-%3E+bool Creates a reusable workspace from three equally sized buffers. Returns an error if the buffer lengths do not match. ```rust pub fn new(y: &'a mut [T], z: &'a mut [T], w: &'a mut [T]) -> Result { if y.len() != z.len() || y.len() != w.len() { return Err(StorageError::InsufficientStorage); } Ok(Self { y, z, w }) } ``` -------------------------------- ### Initialize LuMod from storage Source: https://docs.rs/rlumod/latest/src/rlumod/api.rs.html?search= Creates an LuMod instance by adopting existing factor storage. Validates that buffers meet capacity requirements for the given dimension. ```rust pub fn from_storage( dimension: usize, capacity: usize, l: &'a mut [T], u: &'a mut [T], ) -> Result { if dimension > capacity { return Err(StorageError::InvalidDimension); } let lengths = storage_lengths(capacity)?; let factor_len = lengths.l - capacity; if l.len() < lengths.l || u.len() < lengths.u { return Err(StorageError::InsufficientStorage); } let (l, remainder) = l.split_at_mut(factor_len); let solve_work = Cell::from_mut(&mut remainder[..capacity]).as_slice_of_cells(); Ok(Self { n: dimension, capacity, l, u: &mut u[..lengths.u], solve_work, }) } ``` -------------------------------- ### Workspace::new Source: https://docs.rs/rlumod/latest/rlumod/struct.Workspace.html Creates a new reusable update workspace from three equally sized buffers. The buffers act as scratch storage and their contents are not preserved. ```APIDOC ## pub fn new(y: &'a mut [T], z: &'a mut [T], w: &'a mut [T]) -> Result ### Description Creates a reusable update workspace from three equally sized buffers. The buffers are used as scratch storage for factor updates. ### Parameters - **y** (&'a mut [T]) - Required - First buffer for scratch storage. - **z** (&'a mut [T]) - Required - Second buffer for scratch storage. - **w** (&'a mut [T]) - Required - Third buffer for scratch storage. ### Errors Returns `StorageError::InsufficientStorage` if the provided buffers have different lengths. ``` -------------------------------- ### Implement Workspace structure Source: https://docs.rs/rlumod/latest/src/rlumod/api.rs.html?search= Manages reusable scratch buffers for factor updates. Requires three equally sized buffers to be initialized. ```rust pub struct Workspace<'a, T> { y: &'a mut [T], z: &'a mut [T], w: &'a mut [T], } impl<'a, T> Workspace<'a, T> { /// Creates reusable update workspace from three equally sized buffers. /// /// The buffers are scratch storage and their contents are not preserved by /// successful updates. /// /// # Errors /// /// Returns [`StorageError::InsufficientStorage`] if the lengths differ. pub fn new(y: &'a mut [T], z: &'a mut [T], w: &'a mut [T]) -> Result { if y.len() != z.len() || y.len() != w.len() { return Err(StorageError::InsufficientStorage); } Ok(Self { y, z, w }) } fn has_capacity(&self, required: usize) -> bool { self.y.len() >= required } } ``` -------------------------------- ### Initialize stack storage Source: https://docs.rs/rlumod/latest/rlumod/macro.stack_storage.html Basic usage of the macro to initialize storage arrays for a LuMod instance. ```rust const CAPACITY: usize = 2; let (l, u, y, z, w) = rlumod::stack_storage!(f64; CAPACITY); assert_eq!(l.len(), 6); assert_eq!(u.len(), 3); assert_eq!(y.len(), CAPACITY); assert_eq!(z.len(), CAPACITY); assert_eq!(w.len(), CAPACITY); ``` -------------------------------- ### Workspace::new Source: https://docs.rs/rlumod/latest/rlumod/struct.Workspace.html?search=std%3A%3Avec Creates a new reusable update workspace from three equally sized mutable buffers. ```APIDOC ## pub fn new<'a, T>(y: &'a mut [T], z: &'a mut [T], w: &'a mut [T]) -> Result ### Description Creates a reusable update workspace from three equally sized buffers. The buffers serve as scratch storage and their contents are not preserved by successful updates. ### Parameters - **y** (&'a mut [T]) - Required - The first buffer. - **z** (&'a mut [T]) - Required - The second buffer. - **w** (&'a mut [T]) - Required - The third buffer. ### Errors Returns `StorageError::InsufficientStorage` if the lengths of the provided buffers differ. ``` -------------------------------- ### Construct a matrix via push calls Source: https://docs.rs/rlumod/latest/rlumod/index.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Shows the sequence of push calls required to build a 3x3 matrix. ```rust push([], [], a00) push([a10], [a01], a11) push([a20, a21], [a02, a12], a22) ``` -------------------------------- ### Calculate storage lengths and initialize LuMod Source: https://docs.rs/rlumod/latest/rlumod/fn.storage_lengths.html Computes buffer sizes for a capacity of 4 and uses them to initialize an LuMod instance. ```rust let lengths = rlumod::storage_lengths(4).unwrap(); let mut l = vec![0.0; lengths.l]; let mut u = vec![0.0; lengths.u]; let factor = rlumod::LuMod::from_storage(0, 4, &mut l, &mut u).unwrap(); assert_eq!(factor.capacity(), 4); ``` -------------------------------- ### from_storage Source: https://docs.rs/rlumod/latest/rlumod/struct.LuMod.html?search=u32+-%3E+bool Adopts existing factor storage without changing its contents. ```APIDOC ### pub fn from_storage(dimension: usize, capacity: usize, l: &'a mut [T], u: &'a mut [T]) -> Result Adopts existing factor storage without changing its contents. `l` needs `capacity * capacity` factor elements followed by `capacity` solve-work elements. `u` uses packed upper-triangular storage and needs `capacity * (capacity + 1) / 2` elements. ``` -------------------------------- ### stack_storage!(scalar; capacity) Source: https://docs.rs/rlumod/latest/rlumod/macro.stack_storage.html Creates zero-initialized fixed-size storage for a LuMod instance, returning a tuple of arrays (L, U, Y, Z, W). ```APIDOC ## stack_storage!(scalar; capacity) ### Description Creates zero-initialized fixed-size storage for a `LuMod` instance. The macro returns a tuple of arrays ordered as `(L, U, Y, Z, W)`, representing the factor buffers followed by the three update-workspace buffers. ### Parameters - **scalar** (type) - The scalar type for the storage, must be `f32` or `f64`. - **capacity** (expr) - A literal or constant expression defining the capacity of the workspace buffers. ### Usage Example ```rust const CAPACITY: usize = 2; let (l, u, y, z, w) = rlumod::stack_storage!(f64; CAPACITY); ``` ``` -------------------------------- ### pub fn Usolve(mode: i32, maxmod: i32, n: i32, u: &mut [f64], y: &mut [f64]) Source: https://docs.rs/rlumod/latest/rlumod/lumod_c/fn.Usolve.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Solves an upper-triangular system in place. With mode == 1, replaces y with the solution of U * x = y; every other mode solves Uᵀ * x = y. ```APIDOC ## Function: Usolve ### Description Solves an upper-triangular system in place. The diagonal is not validated, so zero or non-finite entries can produce infinite or NaN output. ### Signature `pub fn Usolve(mode: i32, maxmod: i32, n: i32, u: &mut [f64], y: &mut [f64])` ### Parameters - **mode** (i32) - If 1, solves U * x = y; otherwise, solves Uᵀ * x = y. - **maxmod** (i32) - The maximum module capacity. - **n** (i32) - The dimension of the system. - **u** (&mut [f64]) - The U factor encoded according to the module storage contract. - **y** (&mut [f64]) - The input vector to be solved, replaced by the solution. ### Preconditions - 0 <= n <= maxmod - u must satisfy the module storage contract - y must contain at least n elements ### Panics May panic if a required slice is too short or the dimension and capacity relationships are invalid. ``` -------------------------------- ### Use stack_storage without implicit prelude Source: https://docs.rs/rlumod/latest/rlumod/macro.stack_storage.html Demonstrates that the macro expansion functions correctly in downstream crates without the implicit prelude. ```rust #![no_implicit_prelude] extern crate rlumod; const STORAGE: ([f64; 2], [f64; 1], [f64; 1], [f64; 1], [f64; 1]) = rlumod::stack_storage!(f64; 1); ``` -------------------------------- ### Initialize Workspace Descriptor Source: https://docs.rs/rlumod/latest/src/rlumod/ffi/zero_based.rs.html Initializes a workspace descriptor after verifying that all provided memory regions are disjoint. ```rust unsafe fn workspace_init_impl( output: *mut WorkspaceDescriptor, y: *mut T, y_len: usize, z: *mut T, z_len: usize, w: *mut T, w_len: usize, ) -> StatusResult { let output_region = required_region(output)?; let descriptor = WorkspaceDescriptor { y, y_len, z, z_len, w, w_len, }; let (y_region, z_region, w_region) = workspace_regions(descriptor)?; ensure_disjoint([Some(output_region), y_region, z_region, w_region])?; // SAFETY: All descriptor regions and aliases have been validated. unsafe { borrow_workspace(descriptor)? }; // SAFETY: `output` is valid, aligned, and disjoint from workspace buffers. unsafe { output.write(descriptor) }; Ok(()) } ``` -------------------------------- ### Solver Implementation Source: https://docs.rs/rlumod/latest/src/rlumod/ffi/zero_based.rs.html Internal implementation for solving linear systems, handling memory region validation and error mapping for FFI. ```rust #[derive(Clone, Copy)] enum SolveKind { Normal, Transpose, } unsafe fn solve_impl( factor_pointer: *const FactorDescriptor, rhs: *mut T, rhs_len: usize, error_index: *mut usize, kind: SolveKind, ) -> StatusResult { // SAFETY: Descriptor is read only after null/alignment validation. let (factor_descriptor, factor_descriptor_region) = unsafe { read_descriptor(factor_pointer) }?; let (l_region, u_region) = factor_regions(factor_descriptor)?; let rhs_region = region(rhs, rhs_len)?; let error_region = optional_region(error_index)?; ensure_disjoint([ Some(factor_descriptor_region), l_region, u_region, rhs_region, error_region, ])?; let result = { // SAFETY: Every region and conflicting alias was validated above. let factor = unsafe { borrow_factor(factor_descriptor) }?; // SAFETY: The mutable RHS region was validated above. let rhs = unsafe { mutable_slice(rhs, rhs_len) }; match kind { SolveKind::Normal => factor.solve_in_place(rhs), SolveKind::Transpose => factor.solve_transpose_in_place(rhs), } }; match result { Ok(()) => Ok(()), Err(SolveError::LengthMismatch) => Err(RLUMOD_STATUS_LENGTH_MISMATCH), Err(SolveError::Singular { index }) => { if !error_index.is_null() { // SAFETY: Optional output was validated and factor references are dropped. unsafe { error_index.write(index) }; } Err(RLUMOD_STATUS_SINGULAR) } Err(SolveError::NonFiniteDiagonal { index }) => { if !error_index.is_null() { // SAFETY: Optional output was validated and factor references are dropped. unsafe { error_index.write(index) }; } Err(RLUMOD_STATUS_NON_FINITE_DIAGONAL) } } } ``` -------------------------------- ### Dense One-Based C Compatibility ABI Implementation Source: https://docs.rs/rlumod/latest/src/rlumod/ffi/one_based.rs.html?search=u32+-%3E+bool Internal helper functions and FFI wrappers for managing one-based memory buffers and LU decomposition operations. ```rust fn element_count_fits_slice(length: usize) -> bool { length <= isize::MAX as usize / size_of::() } fn storage_lengths(maxmod: c_int) -> Option<(usize, usize)> { let capacity = usize::try_from(maxmod).ok().filter(|&value| value > 0)?; let l = capacity.checked_mul(capacity)?; let next = capacity.checked_add(1)?; let u = if capacity % 2 == 0 { (capacity / 2).checked_mul(next)? } else { capacity.checked_mul(next / 2)? }; element_count_fits_slice(l) .then_some(()) .and_then(|()| element_count_fits_slice(u).then_some((l, u))) } fn dimension(value: c_int, capacity: usize) -> Option { usize::try_from(value) .ok() .filter(|&value| value > 0 && value <= capacity) } fn index(value: c_int, dimension: usize) -> Option { usize::try_from(value) .ok() .filter(|&value| value > 0 && value <= dimension) .and_then(|value| c_int::try_from(value - 1).ok()) } fn pointer_is_aligned(pointer: *mut c_double) -> bool { !pointer.is_null() && (pointer as usize) % align_of::() == 0 } fn pointers_are_aligned(pointers: [*mut c_double; N]) -> bool { pointers.into_iter().all(pointer_is_aligned) } unsafe fn one_based_slice<'a>(pointer: *mut c_double, length: usize) -> Option<&'a mut [c_double]> { let allocation_length = length.checked_add(1)?; if !pointer_is_aligned(pointer) || !element_count_fits_slice(allocation_length) { return None; } // SAFETY: The caller guarantees an additional writable dummy element at index zero. let first = unsafe { pointer.add(1) }; // SAFETY: The caller guarantees that the elements after the dummy form the // required writable, initialized, non-overlapping region. Some(unsafe { slice::from_raw_parts_mut(first, length) }) } /// Updates dense one-based LUmod factor storage. /// /// # Safety /// /// All pointers must satisfy the storage, alignment, and non-aliasing contract /// declared in `lumod_dense.h`. #[unsafe(no_mangle)] unsafe extern "C" fn LUmod( mode: c_int, maxmod: c_int, n: c_int, krow: c_int, kcol: c_int, l: *mut c_double, u: *mut c_double, y: *mut c_double, z: *mut c_double, w: *mut c_double, ) { if !(1..=4).contains(&mode) { return; } let Some((l_len, u_len)) = storage_lengths(maxmod) else { return; }; let capacity = maxmod as usize; let Some(n_len) = dimension(n, capacity) else { return; }; let (krow, kcol) = match mode { 1 => (0, 0), 2 => { let Some(kcol) = index(kcol, n_len) else { return; }; (0, kcol) } 3 => { let Some(krow) = index(krow, n_len) else { return; }; (krow, 0) } 4 => { let (Some(krow), Some(kcol)) = (index(krow, n_len), index(kcol, n_len)) else { return; }; (krow, kcol) } _ => return, }; if !pointers_are_aligned([l, u, y, z, w]) { return; } // SAFETY: This function's contract requires all five one-based buffers to // be valid and mutually non-overlapping for their computed lengths. let (Some(l), Some(u), Some(y), Some(z), Some(w)) = (unsafe { ( one_based_slice(l, l_len), one_based_slice(u, u_len), one_based_slice(y, n_len), one_based_slice(z, n_len), one_based_slice(w, n_len), ) }) else { return; }; lumod_c::LUmod(mode, maxmod, n, krow, kcol, l, u, y, z, w); } /// Multiplies a vector by a dense one-based L factor. /// /// # Safety /// /// All pointers must satisfy the storage, alignment, and non-aliasing contract /// declared in `lumod_dense.h`. #[unsafe(no_mangle)] unsafe extern "C" fn Lprod( mode: c_int, maxmod: c_int, n: c_int, l: *mut c_double, y: *mut c_double, z: *mut c_double, ) { ``` -------------------------------- ### Create new Workspace Source: https://docs.rs/rlumod/latest/rlumod/struct.Workspace.html Constructor for creating a new Workspace instance from three mutable slices. Returns an error if the provided buffers do not have identical lengths. ```rust pub fn new( y: &'a mut [T], z: &'a mut [T], w: &'a mut [T], ) -> Result ``` -------------------------------- ### storage_lengths Source: https://docs.rs/rlumod/latest/src/rlumod/lib.rs.html Macro to create zero-initialized fixed-size storage for a LuMod instance, returning arrays ordered as (L, U, Y, Z, W). ```APIDOC ## storage_lengths ### Description Creates zero-initialized fixed-size storage for a LuMod instance. The returned arrays are ordered as (L, U, Y, Z, W): the factor buffers followed by the three update-workspace buffers. ### Usage `storage_lengths!(capacity, T)` ### Parameters - **capacity** (constant) - Required - The maximum dimension capacity for the LU factors. - **T** (type) - Required - The scalar type, must be f32 or f64. ``` -------------------------------- ### rlumod::stack_storage! Source: https://docs.rs/rlumod/latest/rlumod/macro.stack_storage.html?search=std%3A%3Avec Creates zero-initialized fixed-size storage for a LuMod instance. The macro returns a tuple of arrays ordered as (L, U, Y, Z, W). ```APIDOC ## macro rlumod::stack_storage!(scalar, capacity) ### Description Creates zero-initialized fixed-size storage for a `LuMod` instance without heap allocation. The macro returns a tuple of arrays representing the factor buffers (L, U) and update-workspace buffers (Y, Z, W). ### Parameters - **scalar** (type) - The scalar type for the storage, must be `f32` or `f64`. - **capacity** (expr) - A literal or constant expression defining the capacity of the workspace buffers. ### Usage Example ```rust const CAPACITY: usize = 2; let (l, u, y, z, w) = rlumod::stack_storage!(f64; CAPACITY); ``` ``` -------------------------------- ### One-based C FFI implementation Source: https://docs.rs/rlumod/latest/src/rlumod/ffi/one_based.rs.html The module provides safe wrappers for C-compatible functions, handling pointer alignment and slice conversion for one-based indexing. ```rust 1// SPDX-FileCopyrightText: 2026 Daisuke Nagao 2// SPDX-License-Identifier: MIT 3 4//! Dense, one-based C compatibility ABI for `LUmod`, `Lprod`, and `Usolve`. 5//! 6//! Enable this module with the `c-ffi-one-based` Cargo feature. 7 8#![deny(unsafe_op_in_unsafe_fn)] 9#![allow(non_snake_case, clippy::too_many_arguments)] 10 11use core::ffi::{c_double, c_int}; 12use core::mem::{align_of, size_of}; 13use core::slice; 14 15use crate::lumod_c; 16 17fn element_count_fits_slice(length: usize) -> bool { 18 length <= isize::MAX as usize / size_of::() 19} 20 21fn storage_lengths(maxmod: c_int) -> Option<(usize, usize)> { 22 let capacity = usize::try_from(maxmod).ok().filter(|&value| value > 0)?; 23 let l = capacity.checked_mul(capacity)?; 24 let next = capacity.checked_add(1)?; 25 let u = if capacity % 2 == 0 { 26 (capacity / 2).checked_mul(next)? 27 } else { 28 capacity.checked_mul(next / 2)? 29 }; 30 element_count_fits_slice(l) 31 .then_some(()) 32 .and_then(|()| element_count_fits_slice(u).then_some((l, u))) 33} 34 35fn dimension(value: c_int, capacity: usize) -> Option { 36 usize::try_from(value) 37 .ok() 38 .filter(|&value| value > 0 && value <= capacity) 39} 40 41fn index(value: c_int, dimension: usize) -> Option { 42 usize::try_from(value) 43 .ok() 44 .filter(|&value| value > 0 && value <= dimension) 45 .and_then(|value| c_int::try_from(value - 1).ok()) 46} 47 48fn pointer_is_aligned(pointer: *mut c_double) -> bool { 49 !pointer.is_null() && (pointer as usize) % align_of::() == 0 50} 51 52fn pointers_are_aligned(pointers: [*mut c_double; N]) -> bool { 53 pointers.into_iter().all(pointer_is_aligned) 54} 55 56unsafe fn one_based_slice<'a>(pointer: *mut c_double, length: usize) -> Option<&'a mut [c_double]> { 57 let allocation_length = length.checked_add(1)?; 58 if !pointer_is_aligned(pointer) || !element_count_fits_slice(allocation_length) { 59 return None; 60 } 61 // SAFETY: The caller guarantees an additional writable dummy element at index zero. 62 let first = unsafe { pointer.add(1) }; 63 // SAFETY: The caller guarantees that the elements after the dummy form the 64 // required writable, initialized, non-overlapping region. 65 Some(unsafe { slice::from_raw_parts_mut(first, length) }) 66} 67 68/// Updates dense one-based LUmod factor storage. 69/// 70/// # Safety 71/// 72/// All pointers must satisfy the storage, alignment, and non-aliasing contract 73/// declared in `lumod_dense.h`. 74#[unsafe(no_mangle)] 75unsafe extern "C" fn LUmod( 76 mode: c_int, 77 maxmod: c_int, 78 n: c_int, 79 krow: c_int, 80 kcol: c_int, 81 l: *mut c_double, 82 u: *mut c_double, 83 y: *mut c_double, 84 z: *mut c_double, 85 w: *mut c_double, 86) { 87 if !(1..=4).contains(&mode) { 88 return; 89 } 90 let Some((l_len, u_len)) = storage_lengths(maxmod) else { 91 return; 92 }; 93 let capacity = maxmod as usize; 94 let Some(n_len) = dimension(n, capacity) else { 95 return; 96 }; 97 let (krow, kcol) = match mode { 98 1 => (0, 0), 99 2 => { 100 let Some(kcol) = index(kcol, n_len) else { 101 return; 102 }; 103 (0, kcol) 104 } 105 3 => { 106 let Some(krow) = index(krow, n_len) else { 107 return; 108 }; 109 (krow, 0) 110 } 111 4 => { 112 let (Some(krow), Some(kcol)) = (index(krow, n_len), index(kcol, n_len)) else { 113 return; 114 }; 115 (krow, kcol) 116 } 117 _ => return, 118 }; 119 if !pointers_are_aligned([l, u, y, z, w]) { 120 return; 121 } 122 // SAFETY: This function's contract requires all five one-based buffers to 123 // be valid and mutually non-overlapping for their computed lengths. 124 let (Some(l), Some(u), Some(y), Some(z), Some(w)) = (unsafe { 125 ( 126 one_based_slice(l, l_len), 127 one_based_slice(u, u_len), 128 one_based_slice(y, n_len), 129 one_based_slice(z, n_len), 130 one_based_slice(w, n_len), 131 ) 132 }) else { 133 return; 134 }; 135 lumod_c::LUmod(mode, maxmod, n, krow, kcol, l, u, y, z, w); 136} 137 138/// Multiplies a vector by a dense one-based L factor. 139/// 140/// # Safety 141/// 142/// All pointers must satisfy the storage, alignment, and non-aliasing contract 143/// declared in `lumod_dense.h`. 144#[unsafe(no_mangle)] 145unsafe extern "C" fn Lprod( 146 mode: c_int, 147 maxmod: c_int, 148 n: c_int, 149 l: *mut c_double, 150 y: *mut c_double, 151 z: *mut c_double, 152) { ``` -------------------------------- ### Usolve Source: https://docs.rs/rlumod/latest/src/rlumod/lumod_c/mod.rs.html Solves a system using the U factor. ```APIDOC ## Usolve(maxmod, n, k, u, work) ### Description Performs a back-substitution solve using the U factor. This is part of the compatibility surface for LUmod operations. ``` -------------------------------- ### Workspace and Factor Initialization Source: https://docs.rs/rlumod/latest/src/rlumod/ffi/zero_based.rs.html?search=std%3A%3Avec Functions for initializing workspace and factor descriptors while ensuring memory safety through region validation and disjointness checks. ```rust unsafe fn borrow_workspace<'a, T: Copy>( descriptor: WorkspaceDescriptor, ) -> StatusResult> { // SAFETY: Descriptor regions and aliases were validated by the caller. let y = unsafe { mutable_slice(descriptor.y, descriptor.y_len) }; // SAFETY: Descriptor regions and aliases were validated by the caller. let z = unsafe { mutable_slice(descriptor.z, descriptor.z_len) }; // SAFETY: Descriptor regions and aliases were validated by the caller. let w = unsafe { mutable_slice(descriptor.w, descriptor.w_len) }; Workspace::new(y, z, w).map_err(storage_status) } ``` ```rust unsafe fn factor_init_impl( output: *mut FactorDescriptor, dimension: usize, capacity: usize, l: *mut T, l_len: usize, u: *mut T, u_len: usize, ) -> StatusResult { let output_region = required_region(output)?; let descriptor = FactorDescriptor { dimension, capacity, l, l_len, u, u_len, }; let (l_region, u_region) = factor_regions(descriptor)?; ensure_disjoint([Some(output_region), l_region, u_region])?; // SAFETY: All descriptor regions and aliases have been validated. unsafe { borrow_factor(descriptor)? }; // SAFETY: `output` is valid, aligned, and disjoint from adopted storage. unsafe { output.write(descriptor) }; Ok(()) } ``` ```rust unsafe fn workspace_init_impl( output: *mut WorkspaceDescriptor, y: *mut T, y_len: usize, z: *mut T, z_len: usize, w: *mut T, w_len: usize, ) -> StatusResult { let output_region = required_region(output)?; let descriptor = WorkspaceDescriptor { y, y_len, z, z_len, w, w_len, }; let (y_region, z_region, w_region) = workspace_regions(descriptor)?; ensure_disjoint([Some(output_region), y_region, z_region, w_region])?; // SAFETY: All descriptor regions and aliases have been validated. unsafe { borrow_workspace(descriptor)? }; // SAFETY: `output` is valid, aligned, and disjoint from workspace buffers. unsafe { output.write(descriptor) }; Ok(()) } ``` -------------------------------- ### FFI Solve Operations Source: https://docs.rs/rlumod/latest/src/rlumod/ffi/zero_based.rs.html Internal macro implementation for exposing standard and transpose solve operations via FFI. ```rust #[unsafe(no_mangle)] unsafe extern "C" fn $solve( factor: *const $factor, rhs: *mut $ty, rhs_len: usize, error_index: *mut usize, ) -> Status { status(unsafe { solve_impl(factor, rhs, rhs_len, error_index, SolveKind::Normal) }) } #[unsafe(no_mangle)] unsafe extern "C" fn $solve_transpose( factor: *const $factor, rhs: *mut $ty, rhs_len: usize, error_index: *mut usize, ) -> Status { status(unsafe { solve_impl(factor, rhs, rhs_len, error_index, SolveKind::Transpose) }) } ``` -------------------------------- ### rlumod::stack_storage! Source: https://docs.rs/rlumod/latest/src/rlumod/lib.rs.html?search= Allocates a tuple of five arrays on the stack based on the provided scalar type and capacity. The macro calculates the required storage lengths and initializes the arrays with the zero value of the scalar type. ```APIDOC ## macro rlumod::stack_storage! ### Description Allocates a tuple of five arrays on the stack for use in rlumod computations. The macro takes a scalar type and a capacity, returning a tuple of arrays sized according to the internal requirements of the library. ### Syntax `rlumod::stack_storage!(scalar_type; capacity)` ### Parameters - **scalar_type** (type) - The numeric type (e.g., f64) to be stored in the arrays. - **capacity** (usize) - The capacity for the storage arrays. ### Returns - **( [scalar; l], [scalar; u], [scalar; capacity], [scalar; capacity], [scalar; capacity] )** - A tuple containing five arrays initialized to the zero value of the scalar type. ### Example ```rust const CAPACITY: usize = 2; let (l, u, y, z, w) = rlumod::stack_storage!(f64; CAPACITY); assert_eq!(l.len(), 6); assert_eq!(u.len(), 3); assert_eq!(y.len(), CAPACITY); assert_eq!(z.len(), CAPACITY); assert_eq!(w.len(), CAPACITY); ``` ``` -------------------------------- ### Usolve Source: https://docs.rs/rlumod/latest/rlumod/lumod_c/index.html?search= Solves an upper-triangular system in place. ```APIDOC ## Usolve ### Description Solves an upper-triangular system in place. ### Signature `pub fn Usolve(maxmod: usize, n: usize, k: usize, u: &mut [f64], work: &mut [f64])` ``` -------------------------------- ### Implement DenseL Matrix Storage Source: https://docs.rs/rlumod/latest/src/rlumod/algorithm.rs.html?search= Provides a dense matrix implementation for the MatrixRead and Matrix traits. ```rust 99pub(crate) struct DenseL { 100 storage: S, 101 stride: usize, 102} 103 104impl DenseL { 105 pub(crate) fn new(storage: S, stride: usize) -> Self { 106 Self { storage, stride } 107 } 108} 109 110impl> MatrixRead for DenseL { 111 fn get(&self, row: usize, column: usize) -> T { 112 self.storage.as_ref()[row * self.stride + column] 113 } 114} 115 116impl + AsMut<[T]>> Matrix for DenseL { 117 fn set(&mut self, row: usize, column: usize, value: T) { 118 self.storage.as_mut()[row * self.stride + column] = value; 119 } 120 121 fn transform_rows( 122 &mut self, 123 x_row: usize, 124 y_row: usize, 125 first: usize, 126 end: usize, 127 transform: Transform, 128 ) { 129 let matrix = self.storage.as_mut(); 130 for column in first..end { 131 let x = x_row * self.stride + column; 132 let y = y_row * self.stride + column; 133 if transform.swap { 134 matrix.swap(x, y); 135 } 136 if transform.multiplier != T::ZERO { 137 matrix[y] += transform.multiplier * matrix[x]; 138 } 139 } 140 } 141} ``` -------------------------------- ### Configure WASM test environment Source: https://docs.rs/rlumod/latest/src/rlumod/lib.rs.html?search= Conditional configuration for running tests in a browser environment when targeting WASM. ```rust #[cfg(all(test, target_arch = "wasm32", target_os = "unknown"))] use wasm_bindgen_test::wasm_bindgen_test_configure; #[cfg(all(test, target_arch = "wasm32", target_os = "unknown"))] wasm_bindgen_test_configure!(run_in_browser); ``` -------------------------------- ### FFI Lprod Wrapper Source: https://docs.rs/rlumod/latest/src/rlumod/ffi/one_based.rs.html?search= Wraps the Lprod C function with pointer alignment checks and one-based slice conversion. ```rust let Some((l_len, _)) = storage_lengths(maxmod) else { return; }; let Some(n_len) = dimension(n, maxmod as usize) else { return; }; if !pointers_are_aligned([l, y, z]) { return; } // SAFETY: Required by this function's pointer contract. let (Some(l), Some(y), Some(z)) = (unsafe { ( one_based_slice(l, l_len), one_based_slice(y, n_len), one_based_slice(z, n_len), ) }) else { return; }; lumod_c::Lprod(mode, maxmod, n, l, y, z); } ``` -------------------------------- ### Usolve Source: https://docs.rs/rlumod/latest/src/rlumod/ffi/one_based.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Solves a dense one-based upper-triangular system in place. This function is exposed via FFI and requires adherence to specific pointer safety contracts. ```APIDOC ## Usolve ### Description Solves a dense one-based upper-triangular system in place. Both pointers must satisfy the storage, alignment, and non-aliasing contract declared in `lumod_dense.h`. ### Signature `unsafe extern "C" fn Usolve(mode: c_int, maxmod: c_int, n: c_int, u: *mut c_double, y: *mut c_double)` ### Parameters - **mode** (c_int) - The operation mode. - **maxmod** (c_int) - The maximum module size. - **n** (c_int) - The dimension of the system. - **u** (*mut c_double) - Pointer to the upper-triangular matrix data. - **y** (*mut c_double) - Pointer to the vector data to be solved in place. ``` -------------------------------- ### Workspace Capacity Check Source: https://docs.rs/rlumod/latest/src/rlumod/api.rs.html?search=u32+-%3E+bool Checks if the workspace has sufficient capacity for a required size. ```rust fn has_capacity(&self, required: usize) -> bool { self.y.len() >= required } ``` -------------------------------- ### Manage Workspace Buffers Source: https://docs.rs/rlumod/latest/src/rlumod/api.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Defines the Workspace structure for holding reusable buffers and provides a constructor to ensure all buffers have equal length. ```rust /// Caller-owned work buffers used by factor updates. /// /// All three buffers always have the same length. An operation may require /// more capacity than a successfully constructed workspace currently has. pub struct Workspace<'a, T> { y: &'a mut [T], z: &'a mut [T], w: &'a mut [T], } impl<'a, T> Workspace<'a, T> { /// Creates reusable update workspace from three equally sized buffers. /// /// The buffers are scratch storage and their contents are not preserved by /// successful updates. /// /// # Errors /// /// Returns [`StorageError::InsufficientStorage`] if the lengths differ. pub fn new(y: &'a mut [T], z: &'a mut [T], w: &'a mut [T]) -> Result { if y.len() != z.len() || y.len() != w.len() { return Err(StorageError::InsufficientStorage); } Ok(Self { y, z, w }) } fn has_capacity(&self, required: usize) -> bool { self.y.len() >= required } } ``` -------------------------------- ### Update Context Management Source: https://docs.rs/rlumod/latest/src/rlumod/ffi/zero_based.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Handles the creation and validation of update contexts for RLU operations. ```rust impl UpdateContext { unsafe fn from_raw( factor_pointer: *mut FactorDescriptor, workspace_pointer: *const WorkspaceDescriptor, ) -> StatusResult { // SAFETY: Descriptors are read only after null/alignment validation. let (factor, factor_descriptor_region) = unsafe { read_descriptor(factor_pointer) }?; // SAFETY: Descriptors are read only after null/alignment validation. let (workspace, workspace_descriptor_region) = unsafe { read_descriptor(workspace_pointer) }?; let (l_region, u_region) = factor_regions(factor)?; let (y_region, z_region, w_region) = workspace_regions(workspace)?; Ok(Self { factor, workspace, regions: UpdateRegions { factor_descriptor: factor_descriptor_region, workspace_descriptor: workspace_descriptor_region, l: l_region, u: u_region, y: y_region, z: z_region, w: w_region, }, }) } fn validate_update_region(&self, additional_region: Option) -> StatusResult { ensure_disjoint([ Some(self.regions.factor_descriptor), Some(self.regions.workspace_descriptor), self.regions.l, self.regions.u, self.regions.y, self.regions.z, self.regions.w, additional_region, ]) } fn validate_push_inputs( &self, row_region: Option, column_region: Option, ) -> StatusResult { self.validate_update_region(row_region)?; self.validate_update_region(column_region) } fn validate_replace_input(&self, values_region: Option) -> StatusResult { self.validate_update_region(values_region) } } ``` -------------------------------- ### Export Float ABI Macros Source: https://docs.rs/rlumod/latest/src/rlumod/ffi/zero_based.rs.html Macro invocations to export the FFI interface for f32 and f64 types. ```rust export_float_abi!( f32, FactorDescriptor, WorkspaceDescriptor, rlumod_f32_factor_init, rlumod_f32_workspace_init, rlumod_f32_push, rlumod_f32_replace_row, rlumod_f32_replace_column, rlumod_f32_remove, rlumod_f32_solve_in_place, rlumod_f32_solve_transpose_in_place ); export_float_abi!( f64, FactorDescriptor, WorkspaceDescriptor, rlumod_f64_factor_init, rlumod_f64_workspace_init, rlumod_f64_push, rlumod_f64_replace_row, rlumod_f64_replace_column, rlumod_f64_remove, rlumod_f64_solve_in_place, rlumod_f64_solve_transpose_in_place ); ``` -------------------------------- ### Initialize Factor Descriptor Source: https://docs.rs/rlumod/latest/src/rlumod/ffi/zero_based.rs.html Initializes a factor descriptor by validating memory regions and ensuring they are disjoint. ```rust unsafe fn factor_init_impl( output: *mut FactorDescriptor, dimension: usize, capacity: usize, l: *mut T, l_len: usize, u: *mut T, u_len: usize, ) -> StatusResult { let output_region = required_region(output)?; let descriptor = FactorDescriptor { dimension, capacity, l, l_len, u, u_len, }; let (l_region, u_region) = factor_regions(descriptor)?; ensure_disjoint([Some(output_region), l_region, u_region])?; // SAFETY: All descriptor regions and aliases have been validated. unsafe { borrow_factor(descriptor)? }; // SAFETY: `output` is valid, aligned, and disjoint from adopted storage. unsafe { output.write(descriptor) }; Ok(()) } ``` -------------------------------- ### Usolve Source: https://docs.rs/rlumod/latest/src/rlumod/lumod_c/mod.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Solves an upper-triangular system using the U factor. ```APIDOC ## Usolve(maxmod, n, k, u, work) ### Description Solves the system Ux = b where U is the upper-triangular factor. ### Parameters - **maxmod** (i32) - Maximum dimension capacity. - **n** (i32) - Current dimension. - **k** (i32) - Operation parameter. - **u** (&mut [f64]) - Packed upper-triangular storage for U factor. - **work** (&mut [f64]) - Workspace buffer containing the right-hand side and receiving the solution. ``` -------------------------------- ### Matrix Product Operations Source: https://docs.rs/rlumod/latest/src/rlumod/algorithm.rs.html?search= Utility functions for computing products involving the L matrix. ```rust pub(crate) fn l_product>( transpose: bool, n: usize, l: &L, input: &[T], output: &mut [T], ) { let result_len = n.min(output.len()); output[..result_len].fill(T::ZERO); for index in 0..n { output[index] = l_product_value(transpose, n, l, input, index); } } ``` ```rust pub(crate) fn l_product_value>( transpose: bool, n: usize, l: &L, input: &[T], index: usize, ) -> T { let mut value = T::ZERO; for (other, &input_value) in input.iter().enumerate().take(n) { value += if transpose { l.get(other, index) } else { l.get(index, other) } * input_value; } value } ``` -------------------------------- ### solve_in_place Source: https://docs.rs/rlumod/latest/rlumod/struct.LuMod.html?search=u32+-%3E+bool Solves A * x = rhs and overwrites rhs with x. ```APIDOC ### pub fn solve_in_place(&self, rhs: &mut [T]) -> Result<(), SolveError> Solves the linear system A * x = rhs and overwrites `rhs` with the solution `x`. ```