#![allow(non_snake_case)]
#![allow(clippy::too_many_arguments)]
#![allow(clippy::needless_range_loop)]
#[cfg(test)]
use crate::algorithm::Transform;
use crate::algorithm::{self, DenseL, Numerics, PackedU};
#[cfg(test)]
mod tests;
const MACHINE_PRECISION: f64 = 2.22e-16;
const TINY_NUMBER: f64 = 1.0e-4;
fn numerics(epsilon: f64) -> Numerics<f64> {
Numerics {
epsilon,
update_tiny: TINY_NUMBER,
}
}
pub fn LUmod(
mode: i32,
maxmod: i32,
n: i32,
krow: i32,
kcol: i32,
l: &mut [f64],
u: &mut [f64],
y: &mut [f64],
z: &mut [f64],
w: &mut [f64],
) {
let stride = maxmod.max(1) as usize;
let n = n.max(0) as usize;
if n == 0 {
return;
}
let mut l = DenseL::new(l, stride);
let mut u = PackedU::new(u, stride);
let numerics = numerics(MACHINE_PRECISION);
match mode {
1 => algorithm::push(n, &mut l, &mut u, y, z, w, numerics),
2 => {
let Some(column) = usize::try_from(kcol).ok().filter(|&value| value < n) else {
return;
};
algorithm::replace_column(column, n, &mut l, &mut u, y, z, w, numerics);
}
3 => {
let Some(row) = usize::try_from(krow).ok().filter(|&value| value < n) else {
return;
};
algorithm::replace_row(row, n, &mut l, &mut u, y, z, w, numerics);
}
4 => {
let Some(row) = usize::try_from(krow).ok().filter(|&value| value < n) else {
return;
};
let Some(column) = usize::try_from(kcol).ok().filter(|&value| value < n) else {
return;
};
algorithm::remove(row, column, n, &mut l, &mut u, y, z, w, numerics);
}
_ => {}
}
}
pub fn Lprod(mode: i32, maxmod: i32, n: i32, l: &mut [f64], y: &mut [f64], z: &mut [f64]) {
let n = n.max(0) as usize;
let l = DenseL::new(l, maxmod.max(1) as usize);
algorithm::l_product(mode != 1, n, &l, y, z);
}
pub fn LUforw(
first: i32,
last: i32,
n: i32,
nu: i32,
maxmod: i32,
eps: f64,
l: &mut [f64],
u: &mut [f64],
y: &mut [f64],
) {
let mut l = DenseL::new(l, maxmod.max(1) as usize);
let mut u = PackedU::new(u, maxmod.max(1) as usize);
algorithm::forward(
first.max(0) as usize,
last.max(0) as usize,
n.max(0) as usize,
nu.max(0) as usize,
&mut l,
&mut u,
y,
numerics(eps),
);
}
pub fn LUback(
first: i32,
last: &mut i32,
n: i32,
nu: i32,
maxmod: i32,
eps: f64,
l: &mut [f64],
u: &mut [f64],
y: &mut [f64],
z: &mut [f64],
) {
let n = n.max(0) as usize;
if n == 0 {
*last = 0;
return;
}
let (selected, trim_trailing_zeros) = if *last >= 0 {
((*last as usize).min(n - 1), true)
} else {
(
(last.unsigned_abs() as usize).saturating_sub(1).min(n - 1),
false,
)
};
let mut l = DenseL::new(l, maxmod.max(1) as usize);
let mut u = PackedU::new(u, maxmod.max(1) as usize);
*last = algorithm::backward(
first.max(0) as usize,
selected,
trim_trailing_zeros,
n,
nu.max(0) as usize,
&mut l,
&mut u,
y,
z,
numerics(eps),
) as i32;
}
pub fn Usolve(mode: i32, maxmod: i32, n: i32, u: &mut [f64], y: &mut [f64]) {
let u = PackedU::new(u, maxmod.max(1) as usize);
algorithm::u_solve(mode != 1, n.max(0) as usize, &u, y);
}
#[cfg(test)]
pub(crate) fn elmgen(x: &mut f64, y: &mut f64, eps: f64, cs: &mut f64, sn: &mut f64) {
let transform = algorithm::elementary(x, y, numerics(eps));
*cs = if transform.swap { -1.0 } else { 0.0 };
*sn = transform.multiplier;
}
#[cfg(test)]
fn u_index(row: usize, column: usize, stride: usize) -> usize {
algorithm::u_index(row, column, stride)
}
#[cfg(test)]
pub(crate) fn apply_pair(x: &mut f64, y: &mut f64, cs: f64, sn: f64) {
algorithm::apply_pair(
x,
y,
Transform {
swap: cs < 0.0,
multiplier: sn,
},
);
}