use crate::HisabError;
#[must_use = "contains the computed root or an error"]
pub fn newton_raphson(
f: impl Fn(f64) -> f64,
df: impl Fn(f64) -> f64,
x0: f64,
tol: f64,
max_iter: usize,
) -> Result<f64, HisabError> {
let mut x = x0;
for _ in 0..max_iter {
let fx = f(x);
if fx.abs() < tol {
return Ok(x);
}
let dfx = df(x);
if dfx.abs() < crate::EPSILON_F64 {
return Err(HisabError::InvalidInput("derivative is zero".to_string()));
}
x -= fx / dfx;
}
Err(HisabError::NoConvergence(max_iter))
}
#[must_use = "contains the computed root or an error"]
pub fn bisection(
f: impl Fn(f64) -> f64,
a: f64,
b: f64,
tol: f64,
max_iter: usize,
) -> Result<f64, HisabError> {
let mut lo = a;
let mut hi = b;
let f_lo = f(lo);
let f_hi = f(hi);
if f_lo * f_hi > 0.0 {
return Err(HisabError::InvalidInput(
"f(a) and f(b) must have opposite signs".to_string(),
));
}
if f_lo > 0.0 {
std::mem::swap(&mut lo, &mut hi);
}
for _ in 0..max_iter {
let mid = (lo + hi) * 0.5;
let f_mid = f(mid);
if f_mid.abs() < tol || (hi - lo).abs() < tol {
return Ok(mid);
}
if f_mid < 0.0 {
lo = mid;
} else {
hi = mid;
}
}
Ok((lo + hi) * 0.5)
}
#[must_use = "contains the solution vector or an error"]
pub fn gaussian_elimination(matrix: &mut [Vec<f64>]) -> Result<Vec<f64>, HisabError> {
let n = matrix.len();
if n == 0 {
return Err(HisabError::InvalidInput("empty matrix".to_string()));
}
for row in matrix.iter() {
if row.len() != n + 1 {
return Err(HisabError::InvalidInput(format!(
"expected {} columns, got {}",
n + 1,
row.len()
)));
}
}
for col in 0..n {
let mut max_row = col;
let mut max_val = matrix[col][col].abs();
for (row, matrix_row) in matrix.iter().enumerate().skip(col + 1) {
let val = matrix_row[col].abs();
if val > max_val {
max_val = val;
max_row = row;
}
}
if max_val < crate::EPSILON_F64 {
return Err(HisabError::SingularPivot);
}
if max_row != col {
matrix.swap(col, max_row);
}
let pivot = matrix[col][col];
#[allow(clippy::needless_range_loop)]
for row in (col + 1)..n {
let factor = matrix[row][col] / pivot;
for j in col..=n {
let val = matrix[col][j];
matrix[row][j] -= factor * val;
}
}
}
let mut x = vec![0.0; n];
for i in (0..n).rev() {
let mut sum = matrix[i][n];
for j in (i + 1)..n {
sum -= matrix[i][j] * x[j];
}
x[i] = sum / matrix[i][i];
}
Ok(x)
}