use std::borrow::Borrow;
pub trait Function {
fn value(&self, position: &[f64]) -> f64;
}
pub struct Func<F: Fn(&[f64]) -> f64>(pub F);
impl<F: Fn(&[f64]) -> f64> Function for Func<F> {
fn value(&self, position: &[f64]) -> f64 {
self.0(position)
}
}
pub trait Function1: Function {
fn gradient(&self, position: &[f64]) -> Vec<f64>;
}
pub trait Summation: Function {
fn terms(&self) -> usize;
fn term_value(&self, position: &[f64], term: usize) -> f64;
fn partial_value<T: IntoIterator<Item=I>, I: Borrow<usize>>(&self, position: &[f64], terms: T) -> f64 {
let mut value = 0.0;
for term in terms {
value += self.term_value(position, *term.borrow());
}
value
}
}
impl<S: Summation> Function for S {
fn value(&self, position: &[f64]) -> f64 {
self.partial_value(position, 0..self.terms())
}
}
pub trait Summation1: Summation + Function1 {
fn term_gradient(&self, position: &[f64], term: usize) -> Vec<f64>;
fn partial_gradient<T: IntoIterator<Item=I>, I: Borrow<usize>>(&self, position: &[f64], terms: T) -> Vec<f64> {
let mut gradient = vec![0.0; position.len()];
for term in terms {
for (g, gi) in gradient.iter_mut().zip(self.term_gradient(position, *term.borrow())) {
*g += gi;
}
}
gradient
}
}
impl<S: Summation1> Function1 for S {
fn gradient(&self, position: &[f64]) -> Vec<f64> {
self.partial_gradient(position, 0..self.terms())
}
}
pub trait Minimizer<F: ?Sized> {
type Solution: Evaluation;
fn minimize(&self, function: &F, initial_position: Vec<f64>) -> Self::Solution;
}
pub trait Evaluation {
fn position(&self) -> &[f64];
fn value(&self) -> f64;
}
#[derive(Debug, Clone)]
pub struct Solution {
pub position: Vec<f64>,
pub value: f64
}
impl Solution {
pub fn new(position: Vec<f64>, value: f64) -> Solution {
Solution {
position,
value
}
}
}
impl Evaluation for Solution {
fn position(&self) -> &[f64] {
&self.position
}
fn value(&self) -> f64 {
self.value
}
}