use mathru::algebra::linear::{Vector, Matrix};
use mathru::optimization::{Optim};
use mathru::optimization::Gradient;
use mathru::algebra::abstr::Real;
use crate::model::SupervisedLearn;
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(())
}
}
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
{
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)]);
}
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);
}
fn hessian(&self, _x: &Vector<T>) -> Matrix<T>
{
unimplemented!();
}
}