use crate::{
algebra::linear::vector::Vector,
optimization::{Optim, OptimResult},
};
extern crate rand;
use crate::algebra::abstr::Real;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::clone::Clone;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug)]
pub struct Gradient<T> {
sigma: T,
iters: usize,
}
impl<T> Gradient<T>
where
T: Real,
{
pub fn new(sigma: T, iters: usize) -> Gradient<T> {
debug_assert!(sigma <= T::one() && sigma > T::zero());
debug_assert!(iters > 0);
Gradient { sigma, iters }
}
}
impl<T> Gradient<T>
where
T: Real,
{
pub fn minimize<F>(&self, func: &F, x_0: &Vector<T>) -> OptimResult<Vector<T>>
where
F: Optim<T>,
{
let mut x_k: Vector<T> = x_0.clone();
for _k in 0..self.iters {
let mut alpha_k: T = T::one();
let anti_grad: Vector<T> = -func.jacobian(&x_k).get_row(0).transpose();
loop {
let anti_grad_alpha: Vector<T> = &anti_grad * &alpha_k;
let r: Vector<T> = &x_k + &anti_grad_alpha;
let f_r: T = func.eval(&r)[0];
let b: T = self.sigma * anti_grad_alpha.dotp(&anti_grad);
let f_x_k: T = func.eval(&x_k)[0];
if f_r <= f_x_k - b {
break;
}
alpha_k /= T::from_f64(2.0);
}
x_k += anti_grad * alpha_k;
}
OptimResult::new(x_k)
}
}