#[cfg(test)]
mod test;
use super::{
super::{Hessian, Tensor, TensorRank0},
Dirichlet, Neumann, OptimizeError, SecondOrder,
};
use crate::ABS_TOL;
use std::ops::Div;
#[derive(Debug)]
pub struct NewtonRaphson {
pub abs_tol: TensorRank0,
pub check_minimum: bool,
pub max_steps: usize,
}
impl Default for NewtonRaphson {
fn default() -> Self {
Self {
abs_tol: ABS_TOL,
check_minimum: true,
max_steps: 250,
}
}
}
impl<H: Hessian, J: Tensor, X: Tensor> SecondOrder<H, J, X> for NewtonRaphson
where
J: Div<H, Output = X>,
{
fn minimize(
&self,
jacobian: impl Fn(&X) -> Result<J, OptimizeError>,
hessian: impl Fn(&X) -> Result<H, OptimizeError>,
initial_guess: X,
_dirichlet: Option<Dirichlet>,
_neumann: Option<Neumann>,
) -> Result<X, OptimizeError> {
let mut residual;
let mut solution = initial_guess;
let mut tangent;
for _ in 0..self.max_steps {
residual = jacobian(&solution)?;
tangent = hessian(&solution)?;
if residual.norm() < self.abs_tol {
if self.check_minimum && !tangent.is_positive_definite() {
return Err(OptimizeError::NotMinimum(
format!("{}", solution),
format!("{:?}", &self),
));
} else {
return Ok(solution);
}
} else {
solution -= residual / tangent;
}
}
Err(OptimizeError::MaximumStepsReached(
self.max_steps,
format!("{:?}", &self),
))
}
}