#[derive(Debug, Clone, Default)]
pub struct LinearSolverSummary {
pub solver_name: String,
pub requested: Option<String>,
pub n_factors: u64,
pub n_pattern_reuse: u64,
pub n_pattern_changes: u64,
pub max_fill_ratio: Option<f64>,
pub min_abs_pivot: Option<f64>,
pub max_abs_pivot: Option<f64>,
pub last_inertia: Option<(usize, usize, usize)>,
pub last_inertia_unregularized: Option<(usize, usize, usize)>,
pub last_nnz_a: Option<usize>,
pub last_nnz_l: Option<usize>,
pub total_factor_secs: f64,
pub total_factor_flops: f64,
pub total_delayed_cols: u64,
pub total_two_by_two: u64,
pub total_n_tiny: u64,
pub last_factor_flops: Option<f64>,
pub last_peak_bytes: Option<usize>,
pub last_n_supernodes: Option<usize>,
pub last_max_front_rows: Option<usize>,
pub last_delayed_cols: Option<usize>,
pub last_two_by_two: Option<usize>,
pub last_n_tiny: Option<usize>,
pub last_ordering: Option<String>,
pub last_ordering_preprocess: Option<String>,
pub blocks: Option<BlockSummary>,
pub schur: Option<SchurSummary>,
pub restoration: Option<Box<LinearSolverSummary>>,
}
#[derive(Debug, Clone, Default)]
pub struct BlockSummary {
pub n_blocks: usize,
pub border_dim: usize,
pub largest_block: usize,
pub n_factors: u64,
pub factor_secs: f64,
}
#[derive(Debug, Clone, Default)]
pub struct SchurSummary {
pub n_eliminated: usize,
pub n_schur: usize,
pub n_factors: u64,
pub eliminated_factor_secs: f64,
pub form_schur_secs: f64,
pub schur_factor_secs: f64,
}
#[derive(Debug, Clone, Default)]
pub struct FactorRecord {
pub pattern_reused: bool,
pub fill_ratio: f64,
pub min_abs_pivot: f64,
pub max_abs_pivot: f64,
pub inertia: (usize, usize, usize),
pub nnz_a: usize,
pub nnz_l: usize,
pub factor_secs: f64,
pub factor_flops: Option<f64>,
pub peak_bytes: Option<usize>,
pub n_supernodes: Option<usize>,
pub max_front_rows: Option<usize>,
pub delayed_cols: Option<usize>,
pub two_by_two: Option<usize>,
pub n_tiny: Option<usize>,
pub ordering: Option<String>,
pub ordering_preprocess: Option<String>,
}
impl LinearSolverSummary {
pub fn is_empty(&self) -> bool {
self.n_factors == 0
}
pub fn record(&mut self, r: &FactorRecord) {
self.n_factors += 1;
if r.pattern_reused {
self.n_pattern_reuse += 1;
} else {
self.n_pattern_changes += 1;
}
self.max_fill_ratio = Some(
self.max_fill_ratio
.map_or(r.fill_ratio, |p| p.max(r.fill_ratio)),
);
self.min_abs_pivot = Some(
self.min_abs_pivot
.map_or(r.min_abs_pivot, |p| p.min(r.min_abs_pivot)),
);
self.max_abs_pivot = Some(
self.max_abs_pivot
.map_or(r.max_abs_pivot, |p| p.max(r.max_abs_pivot)),
);
self.last_inertia = Some(r.inertia);
self.last_nnz_a = Some(r.nnz_a);
self.last_nnz_l = Some(r.nnz_l);
self.total_factor_secs += r.factor_secs;
self.total_factor_flops += r.factor_flops.unwrap_or(0.0);
self.total_delayed_cols += r.delayed_cols.unwrap_or(0) as u64;
self.total_two_by_two += r.two_by_two.unwrap_or(0) as u64;
self.total_n_tiny += r.n_tiny.unwrap_or(0) as u64;
self.last_factor_flops = r.factor_flops;
self.last_peak_bytes = r.peak_bytes;
self.last_n_supernodes = r.n_supernodes;
self.last_max_front_rows = r.max_front_rows;
self.last_delayed_cols = r.delayed_cols;
self.last_two_by_two = r.two_by_two;
self.last_n_tiny = r.n_tiny;
self.last_ordering = r.ordering.clone();
self.last_ordering_preprocess = r.ordering_preprocess.clone();
}
}
#[cfg(test)]
mod tests {
use super::*;
fn rec(fill: f64, secs: f64, delayed: usize) -> FactorRecord {
FactorRecord {
pattern_reused: true,
fill_ratio: fill,
min_abs_pivot: fill,
max_abs_pivot: fill,
inertia: (3, 2, 0),
nnz_a: 10,
nnz_l: 20,
factor_secs: secs,
factor_flops: Some(100.0),
delayed_cols: Some(delayed),
two_by_two: Some(1),
n_tiny: Some(0),
ordering: Some("amd".into()),
..Default::default()
}
}
#[test]
fn record_accumulates_totals_and_keeps_last() {
let mut s = LinearSolverSummary::default();
s.record(&rec(2.0, 0.5, 3));
s.record(&rec(1.5, 0.25, 4));
assert_eq!(s.n_factors, 2);
assert_eq!(s.n_pattern_reuse, 2);
assert_eq!(s.max_fill_ratio, Some(2.0));
assert_eq!(s.min_abs_pivot, Some(1.5));
assert_eq!(s.total_factor_secs, 0.75);
assert_eq!(s.total_factor_flops, 200.0);
assert_eq!(s.total_delayed_cols, 7);
assert_eq!(s.total_two_by_two, 2);
assert_eq!(s.last_delayed_cols, Some(4));
assert_eq!(s.last_ordering.as_deref(), Some("amd"));
}
#[test]
fn two_writers_fold_rather_than_overwrite() {
let mut shared = LinearSolverSummary::default();
let mut a = LinearSolverSummary::default();
let mut b = LinearSolverSummary::default();
for (mine, r) in [(&mut a, rec(1.0, 1.0, 1)), (&mut b, rec(1.0, 1.0, 1))] {
mine.record(&r);
shared.record(&r);
}
a.record(&rec(1.0, 1.0, 1));
shared.record(&rec(1.0, 1.0, 1));
assert_eq!(a.n_factors, 2);
assert_eq!(b.n_factors, 1);
assert_eq!(shared.n_factors, 3);
assert_eq!(shared.total_delayed_cols, 3);
}
}