argmin/solver/newton/newton_method.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
// Copyright 2018-2020 argmin developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! # References:
//!
//! [0] Jorge Nocedal and Stephen J. Wright (2006). Numerical Optimization.
//! Springer. ISBN 0-387-30303-0.
use crate::prelude::*;
use serde::{Deserialize, Serialize};
use std::default::Default;
/// Newton's method iteratively finds the stationary points of a function f by using a second order
/// approximation of f at the current point.
///
/// [Example](https://github.com/argmin-rs/argmin/blob/master/examples/newton.rs)
///
/// # References:
///
/// [0] Jorge Nocedal and Stephen J. Wright (2006). Numerical Optimization.
/// Springer. ISBN 0-387-30303-0.
#[derive(Clone, Serialize, Deserialize)]
pub struct Newton<F> {
/// gamma
gamma: F,
}
impl<F: ArgminFloat> Newton<F> {
/// Constructor
pub fn new() -> Self {
Newton {
gamma: F::from_f64(1.0).unwrap(),
}
}
/// set gamma
pub fn set_gamma(mut self, gamma: F) -> Result<Self, Error> {
if gamma <= F::from_f64(0.0).unwrap() || gamma > F::from_f64(1.0).unwrap() {
return Err(ArgminError::InvalidParameter {
text: "Newton: gamma must be in (0, 1].".to_string(),
}
.into());
}
self.gamma = gamma;
Ok(self)
}
}
impl<F: ArgminFloat> Default for Newton<F> {
fn default() -> Newton<F> {
Newton::new()
}
}
impl<O, F> Solver<O> for Newton<F>
where
O: ArgminOp<Float = F>,
O::Param: ArgminScaledSub<O::Param, O::Float, O::Param>,
O::Hessian: ArgminInv<O::Hessian> + ArgminDot<O::Param, O::Param>,
F: ArgminFloat,
{
const NAME: &'static str = "Newton method";
fn next_iter(
&mut self,
op: &mut OpWrapper<O>,
state: &IterState<O>,
) -> Result<ArgminIterData<O>, Error> {
let param = state.get_param();
let grad = op.gradient(¶m)?;
let hessian = op.hessian(¶m)?;
let new_param = param.scaled_sub(&self.gamma, &hessian.inv()?.dot(&grad));
Ok(ArgminIterData::new().param(new_param))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_trait_impl;
test_trait_impl!(newton_method, Newton<f64>);
}