pub mod dense_factor;
pub mod dense_matrix;
pub mod dense_solve;
pub mod dense_update;
pub mod scaling;
pub mod sparse_factor;
pub mod sparse_matrix;
pub mod sparse_solve;
pub mod sparse_symbolic;
pub mod sparse_update;
pub use dense_factor::DenseLu;
pub use dense_matrix::GeneralMatrix;
pub use sparse_factor::SparseLu;
pub use sparse_matrix::SparseColMatrix;
pub use sparse_symbolic::SparseLuSymbolic;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LuSingularAction {
Fail,
PerturbToEps {
abs_floor: f64,
},
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LuScaling {
None,
InfNorm,
Mc64,
Mc64ThenInfNorm,
}
#[derive(Debug, Clone)]
pub struct LuParams {
pub pivot_threshold: f64,
pub zero_pivot_tol: f64,
pub on_singular: LuSingularAction,
pub max_growth: f64,
pub max_updates: usize,
pub dense_threshold: usize,
pub scaling: LuScaling,
pub refine_steps: usize,
pub refine_tol: f64,
}
impl LuParams {
pub(crate) fn validate(&self) -> Result<(), crate::error::FeralError> {
use crate::error::FeralError;
if !(self.pivot_threshold > 0.0 && self.pivot_threshold <= 1.0) {
return Err(FeralError::InvalidInput(format!(
"LuParams::pivot_threshold must be in (0, 1], got {}",
self.pivot_threshold
)));
}
if !(self.zero_pivot_tol >= 0.0 && self.zero_pivot_tol < 1.0) {
return Err(FeralError::InvalidInput(format!(
"LuParams::zero_pivot_tol must be in [0, 1), got {}",
self.zero_pivot_tol
)));
}
Ok(())
}
}
impl Default for LuParams {
fn default() -> Self {
LuParams {
pivot_threshold: 1.0,
zero_pivot_tol: 1e-13,
on_singular: LuSingularAction::Fail,
max_growth: 1e8,
max_updates: 64,
dense_threshold: 128,
scaling: LuScaling::None,
refine_steps: 0,
refine_tol: 1e-12,
}
}
}
pub fn should_use_dense_lu(m: usize, nnz: usize, params: &LuParams) -> bool {
const M_TINY: usize = 16;
if m == 0 {
return false;
}
if m <= M_TINY {
return true;
}
if m > params.dense_threshold {
return false;
}
let cells = m.saturating_mul(m);
nnz.saturating_mul(4) >= cells
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn router_tiny_is_dense() {
let p = LuParams::default();
assert!(should_use_dense_lu(8, 0, &p));
assert!(should_use_dense_lu(16, 0, &p));
}
#[test]
fn router_large_is_sparse() {
let p = LuParams::default();
assert!(!should_use_dense_lu(1000, 1000 * 1000, &p));
}
#[test]
fn router_density_gate() {
let p = LuParams::default();
assert!(!should_use_dense_lu(64, 1023, &p));
assert!(should_use_dense_lu(64, 1024, &p));
}
}