//! Story 1.5 comparative benchmark: nalgebra vs faer dense LU backends. //! //! Measures factorization (`set_linearisation`) and per-RHS solve //! (`solve_in_place`) on the mock-cycle Jacobian (9×9) and a synthetic 50×50 //! dense Jacobian — the sizes Entropyk Newton actually sees. use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; use entropyk_solver::linear::NalgebraLuSolver; use entropyk_solver::linear_faer::FaerLuSolver; use entropyk_solver::LinearSolver; mod common; fn dense_entries(n: usize) -> Vec<(usize, usize, f64)> { let mut entries = Vec::with_capacity(n * n); for i in 0..n { for j in 0..n { let v = if i == j { 4.0 + 0.01 * (i as f64) } else { 1.0 / (1.0 + (i as f64 - j as f64).abs()) }; entries.push((i, j, v)); } } entries } fn bench_pair(c: &mut Criterion, label: &str, entries: &[(usize, usize, f64)], n: usize) { let mut group = c.benchmark_group(label); let rhs: Vec = (0..n) .map(|i| (i as f64 * 0.7 - 1.3).sin() * 100.0) .collect(); let mut nal = NalgebraLuSolver::new(); nal.set_problem(n, n).unwrap(); let mut faer = FaerLuSolver::new(); faer.set_problem(n, n).unwrap(); group.bench_function(BenchmarkId::new("factor", "nalgebra"), |b| { b.iter(|| { black_box(nal.set_linearisation(black_box(entries))).unwrap(); }); }); group.bench_function(BenchmarkId::new("factor", "faer"), |b| { b.iter(|| { black_box(faer.set_linearisation(black_box(entries))).unwrap(); }); }); nal.set_linearisation(entries).unwrap(); faer.set_linearisation(entries).unwrap(); group.bench_function(BenchmarkId::new("solve", "nalgebra"), |b| { b.iter(|| { let mut rhs = rhs.clone(); let _ = black_box(nal.solve_in_place(black_box(&mut rhs))); }); }); group.bench_function(BenchmarkId::new("solve", "faer"), |b| { b.iter(|| { let mut rhs = rhs.clone(); let _ = black_box(faer.solve_in_place(black_box(&mut rhs))); }); }); group.finish(); } fn bench_lu_backends(c: &mut Criterion) { let (system, state) = common::build_mock_system(); let jacobian = common::assemble_jacobian(&system, &state); let n = jacobian.nrows(); let jm = jacobian.as_matrix(); let entries: Vec<(usize, usize, f64)> = (0..n) .flat_map(|i| (0..n).map(move |j| (i, j, jm[(i, j)]))) .collect(); bench_pair(c, "lu_mock_9x9", &entries, n); let entries50 = dense_entries(50); bench_pair(c, "lu_dense_50x50", &entries50, 50); let _ = state; } criterion_group!(benches, bench_lu_backends); criterion_main!(benches);