tinguely 0.1.1

Machine learning library
Documentation
use mathru::algebra::linear::{Vector, Matrix};
use mathru::optimization::{Optim};
use mathru::optimization::Gradient;
use mathru::algebra::abstr::Real;
use crate::model::SupervisedLearn;

/// Linear regression
///
/// For more information: <br>
/// <a href="https://en.wikipedia.org/wiki/Linear_regression">https://en.wikipedia.org/wiki/Linear_regression</a>
///
///
pub struct LinearRegression<T>
{
	beta: Option<Vector<T>>,

	optim: Gradient<T>,
}

impl<T> LinearRegression<T>
	where T: Real
{
	pub fn new(optim: Gradient<T>) -> LinearRegression<T>
	{
		LinearRegression
		{
			beta: None,
			optim: optim
		}
	}

  	pub fn parameters(self: &Self) -> Option<Vector<T>>
  	{
        self.beta.clone()
	}
}


impl<T> SupervisedLearn<Matrix<T>, Vector<T>> for LinearRegression<T>
	where T: Real
{
	fn predict(self: &Self, x: &Matrix<T>) -> Result<Vector<T>, ()>
	{
		let (m, n) : (usize, usize) = x.dim();

		let ones: Matrix<T> = Matrix::<T>::ones(m, n + 1);

		let full_input: Matrix<T> = ones.set_slice( x, 0, 1);

		return match self.beta.clone()
		{
			Some(beta) => Ok(&full_input * &beta),
			None => Err(())
		}

	}

	/// Train the linear regression model.
    ///
    /// # Examples
    ///
    /// ```
    /// //use tinguely::regression::LinearRegression;
    /// //use mathru::algebra::linear::{Vector, Matrix};
    /// //use mathru::optimization::Gradient;
    /// //use tinguely::SupervisedLearn;
    ///
    /// //let optimizer = Gradient::new(0.1, 200);
    /// //let mut lin_mod: LinearRegression<f64> = LinearRegression::new(optimizer);
    /// //let inputs: Matrix<f64> = Matrix::new(3, 1, vec![2.0, 3.0, 4.0]);
    /// //let targets: Vector<f64> = Vector::new_column(3, vec![5.0, 6.0, 7.0]);
    ///
    /// //lin_mod.train(&inputs, &targets);
    /// ```
    fn train(self: &mut Self, x: &Matrix<T>, y: &Vector<T>)
	{
		let (x_m, x_n): (usize, usize) = x.dim();
		let (y_m, _y_n): (usize, usize) = x.dim();

		if x_m != y_m
		{
			panic!("Dimension mismatch")
		}

        let ones: Matrix<T> = Matrix::<T>::ones(x_m, x_n + 1);
        let full_input: Matrix<T> = ones.set_slice( x, 0, 1);

		let beta_0: Vector<T> = Vector::new_column(x_n + 1, vec![T::from_f64(0.1), T::from_f64(1.0)]);

		let base: LeastMeanSquare<T> = LeastMeanSquare::new(y, &full_input);

		let beta: Vector<T> = self.optim.minimize(&base, &beta_0).arg();

		self.beta = Some(beta);
	}
}

pub struct LeastMeanSquare<'a, T>
{
	pub x: &'a Matrix<T>,
	pub y: &'a Vector<T>,
}

impl<'a, T> LeastMeanSquare<'a, T>
	where T: Real
{
	fn new(y: &'a Vector<T>, x: &'a Matrix<T>) -> LeastMeanSquare<'a, T>
	{
		LeastMeanSquare
		{
				y: y,
				x: x
		}
	}
}

impl<'a, T> Optim<T> for LeastMeanSquare<'a, T>
	where T: Real
{
	///
	/// ```math
	/// J(\theta) = X^{T}\theta X - X^{T}\theta
	/// ```
	fn eval(&self, beta: &Vector<T>) -> Vector<T>
	{
		let y_hat: Vector<T> = self.x * &beta.clone();

		let diff: Vector<T> = &y_hat - self.y;

		let k: Vector<T> =  diff.apply(&|&x| {return x * x / T::from(2.0)});

		return Vector::new_column(1, vec![k.dotp(&k)]);
	}

	///
	/// ```math
	/// \nabla J(\theta) = X^T X \theta - X^T y = X^T(X \theta - y)
	///
	/// ```
	fn jacobian(&self, beta: &Vector<T>) -> Matrix<T>
	{
		let y_hat: Vector<T> = self.x * beta;

		let diff: Vector<T> = (&y_hat - self.y).transpose();
		return Matrix::from( &diff * self.x);
	}

	/// Computes the Hessian at the given value x
	fn hessian(&self, _x: &Vector<T>) -> Matrix<T>
	{
		unimplemented!();
	}
}