use std::fmt;
#[derive(Debug, Clone, Copy)]
pub struct CholUpdateConfig {
pub check_positive_definite: bool,
pub tolerance: f64,
}
impl Default for CholUpdateConfig {
fn default() -> Self {
Self {
check_positive_definite: true,
tolerance: 1e-14,
}
}
}
#[derive(Debug, Clone)]
pub struct CholUpdateResult {
pub factor: Vec<Vec<f64>>,
pub successful: bool,
pub condition_estimate: f64,
}
impl fmt::Display for CholUpdateResult {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"CholUpdateResult {{ n={}, successful={}, cond_est={:.6e} }}",
self.factor.len(),
self.successful,
self.condition_estimate,
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum UpdateType {
RankOneUpdate,
RankOneDowndate,
LowRankUpdate,
}
impl fmt::Display for UpdateType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UpdateType::RankOneUpdate => write!(f, "Rank-1 Update"),
UpdateType::RankOneDowndate => write!(f, "Rank-1 Downdate"),
UpdateType::LowRankUpdate => write!(f, "Low-Rank Update"),
#[allow(unreachable_patterns)]
_ => write!(f, "Unknown Update Type"),
}
}
}
pub(crate) fn estimate_condition(l: &[Vec<f64>], tol: f64) -> f64 {
let n = l.len();
if n == 0 {
return 1.0;
}
let mut min_diag = f64::INFINITY;
let mut max_diag = 0.0_f64;
for i in 0..n {
let d = l[i][i].abs();
if d < tol {
return f64::INFINITY;
}
if d < min_diag {
min_diag = d;
}
if d > max_diag {
max_diag = d;
}
}
if min_diag <= 0.0 {
f64::INFINITY
} else {
max_diag / min_diag
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let cfg = CholUpdateConfig::default();
assert!(cfg.check_positive_definite);
assert!(cfg.tolerance > 0.0);
assert!(cfg.tolerance < 1e-10);
}
#[test]
fn test_update_type_display() {
assert_eq!(format!("{}", UpdateType::RankOneUpdate), "Rank-1 Update");
assert_eq!(
format!("{}", UpdateType::RankOneDowndate),
"Rank-1 Downdate"
);
assert_eq!(format!("{}", UpdateType::LowRankUpdate), "Low-Rank Update");
}
#[test]
fn test_estimate_condition_identity() {
let l = vec![vec![1.0, 0.0], vec![0.0, 1.0]];
let cond = estimate_condition(&l, 1e-14);
assert!((cond - 1.0).abs() < 1e-14);
}
#[test]
fn test_estimate_condition_singular() {
let l = vec![vec![1.0, 0.0], vec![0.5, 0.0]];
let cond = estimate_condition(&l, 1e-14);
assert!(cond.is_infinite());
}
#[test]
fn test_result_display() {
let res = CholUpdateResult {
factor: vec![vec![1.0]],
successful: true,
condition_estimate: 1.0,
};
let s = format!("{}", res);
assert!(s.contains("successful=true"));
}
}