use crate::error::KError;
#[derive(Clone, Debug)]
pub struct PivotPolicy {
pub mode: PivotMode,
pub tau: f64,
pub scale: PivotScale,
pub sign: PivotSignPolicy,
pub deterministic: bool,
}
impl Default for PivotPolicy {
fn default() -> Self {
Self {
mode: PivotMode::AdditiveFloor,
tau: 1e-12,
scale: PivotScale::RowGershgorin,
sign: PivotSignPolicy::Positive,
deterministic: true,
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum PivotMode {
Strict,
AdditiveFloor,
ThresholdFloor,
PivotingAllowed,
}
#[derive(Clone, Copy, Debug)]
pub enum PivotScale {
MaxDiagA,
LocalDiagA,
RowInfA,
RowGershgorin,
RunningMaxU,
}
#[derive(Clone, Copy, Debug)]
pub enum PivotSignPolicy {
Preserve,
Positive,
}
#[derive(Clone, Debug)]
pub struct PivotStats {
pub num_floors: usize,
pub max_abs_shift: f64,
pub sum_abs_shift: f64,
pub num_strict_fail: usize,
pub last_floor_value: f64,
}
impl Default for PivotStats {
fn default() -> Self {
Self {
num_floors: 0,
max_abs_shift: 0.0,
sum_abs_shift: 0.0,
num_strict_fail: 0,
last_floor_value: 0.0,
}
}
}
fn record_pivot_shift(stats: &mut PivotStats, old: f64, new: f64) {
let sh: f64 = (new - old).abs();
stats.num_floors += 1;
if sh > stats.max_abs_shift {
stats.max_abs_shift = sh;
}
stats.sum_abs_shift += sh;
stats.last_floor_value = new.abs();
}
pub fn stabilize_pivot_in_place(
u_ii: &mut f64,
s_i: f64,
tau: f64,
sign_policy: PivotSignPolicy,
mode: PivotMode,
stats: &mut PivotStats,
row: usize,
) -> Result<(), KError> {
let floor = tau * s_i;
let abs: f64 = (*u_ii).abs();
match mode {
PivotMode::Strict => {
if abs < floor {
stats.num_strict_fail += 1;
stats.last_floor_value = floor;
return Err(KError::ZeroPivot(row));
}
}
PivotMode::AdditiveFloor | PivotMode::ThresholdFloor => {
if abs >= floor {
return Ok(());
}
let magnitude = floor;
let new_value = match sign_policy {
PivotSignPolicy::Preserve => {
let sign: f64 = if *u_ii >= 0.0 { 1.0 } else { -1.0 };
sign * magnitude
}
PivotSignPolicy::Positive => magnitude,
};
let old = *u_ii;
*u_ii = new_value;
record_pivot_shift(stats, old, *u_ii);
}
PivotMode::PivotingAllowed => {
unimplemented!("Pivoting path not yet implemented");
}
}
Ok(())
}