newton-faer
Why another Newton solver?
Most Rust numerical computing is still young. The existing options:
- roots — great for 1D, but not systems
- argmin — focused on optimization (line searches, trust regions), not sparse Newton for general nonlinear systems
- nalgebra — has solvers, but not a sparse-aware Newton–Raphson with reusable symbolic factorizations
This crate is a thin, reusable Newton core that leans on faer for world-class sparse linear algebra, while keeping all domain logic (residual/Jacobian) outside the engine. You get:
- Separation of concerns: engine = iteration policy + linear solves; models = residual/Jacobian.
- Sparse-first: symbolic LU reused across solves when the sparsity pattern is unchanged.
- Production knobs: adaptive damping, divergence guard + backtracking, cancellation, and progress callbacks.
- Parallelism control: slam all cores for big single cases, or run many small cases in parallel with single-threaded LU (no oversubscription).
Architecture at a glance
- linalg: adapters over faer (sparse LU) and dense LU; keeps symbolic factorization cached per pattern.
- solver: Newton loop, damping policy, divergence guard, callbacks, and thread init.
Your model implements NonlinearSystem (residual + Jacobian/refresh), optionally with its own Jacobian cache.
Parallelism
Parallelism is a policy choice: inside LU for one/few huge systems, or over cases for large batches. We auto-init Rayon once; you can override the global thread count via config.
use *;
use crateNewtonCfg;
// batch mode: many cases, maximize throughput
let cfg_batch = default.with_threads; // LU single-thread
let results: = contingencies
.par_iter
.map
.collect;
// big single case mode: few huge systems
let cfg_big = default.with_threads; // use all cores in LU
let mut pf = big_system_pf.clone;
let res = pf.solve_with_cfg?;
Guideline:
- Tons of scenarios? with_threads(1) + par_iter() over cases.
- One gigantic system? with_threads(0) (all cores) + sequential cases.
Adaptive Damping
Divergence guard + backtracking are enabled when adaptive=true and steered by: min_damping, max_damping, grow, shrink, divergence_ratio, ls_backtrack, ls_max_steps.
let cfg = default.with_adaptive;
Reuse LU
Keep a solver instance and reuse the symbolic factorization across solves with the same sparsity. Only the numeric phase is recomputed.
let mut lu = default;
for case in cases
Solver Progress
Stream iteration stats to your UI, support cancellation, and run the solve on a worker thread.
use ;
use crate;
let = ;
let cancel = new;
let cancel_flag = cancel.clone;
let mut system = /* build system */;
spawn;
while let Ok = rx.recv
Performance notes
- Symbolic reuse is the big win in multi-scenario studies (fixed sparsity).
- Preallocated buffers and in-place solves avoid per-iteration allocations.
- Threading: pick one level of parallelism—inside LU or over cases—to avoid oversubscription.
- Ordering (AMD/ND/…) can drastically reduce fill; we expose knobs for faer’s symbolic parameters if you want to tune.
Acknowledgments
Big thanks to the faer team. newton-faer leans on faer’s fast, well-designed sparse linear algebra.