extern crate rand;
extern crate libc;
use self::rand::{thread_rng, Rng};
use std::iter::repeat;
use matrix::*;
use ops::{MatrixVectorMul, MatrixVectorOps};
pub struct Hypothesis {
thetas: Vec<f64>
}
impl Hypothesis {
pub fn random(n: usize) -> Hypothesis {
Hypothesis {
thetas: thread_rng().gen_iter::<f64>().take(n).collect()
}
}
pub fn from_params(params: &[f64]) -> Hypothesis {
Hypothesis {
thetas: params.to_vec()
}
}
pub fn params(&self) -> Vec<f64> {
self.thetas.clone()
}
pub fn eval(&self, x: &Matrix<f64>) -> Vec<f64> {
x.mul_vec(&self.thetas)
}
pub fn error(&self, x: &Matrix<f64>, y: &[f64]) -> f64 {
x.mul_vec_minus_vec(&self.thetas, y)
.iter()
.fold(0.0, |acc, &x| acc + x*x) / 2.0 / (x.rows() as f64)
}
pub fn derivatives(&self, x: &Matrix<f64>, y: &[f64]) -> Vec<f64> {
let v = x.mul_vec_minus_vec(&self.thetas, &y);
x.mul_scalar_vec(
true,
1.0 / (x.rows() as f64),
&v
)
}
}
pub trait DesignMatrix<T> {
fn design_matrix(&self) -> Self;
}
impl DesignMatrix<f64> for Matrix<f64> {
fn design_matrix(&self) -> Self {
self.insert_column(0,
&repeat(1.0).take(self.rows()).collect::<Vec<f64>>()
)
}
}
impl DesignMatrix<f32> for Matrix<f32> {
fn design_matrix(&self) -> Self {
self.insert_column(0,
&repeat(1.0).take(self.rows()).collect::<Vec<f32>>()
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use matrix::*;
#[test]
fn test_hypothesis() {
let h = Hypothesis::random(5);
assert!(h.thetas.iter().all(|&x| x < 1.0));
let i = Hypothesis::from_params(&[0.1, 0.2, 0.3, 0.4]);
assert_eq!(i.params(), vec![0.1, 0.2, 0.3, 0.4]);
}
#[test]
fn test_eval() {
let x = mat![1.0, 2.0, 3.0; 4.0, 2.0, 5.0];
let h = Hypothesis::from_params(&[2.0, 6.0, 3.0]);
let y = h.eval(&x);
assert_eq!(y, vec![23.0, 35.0]);
}
#[test]
fn test_design_matrix() {
let x = mat![
7.0, 2.0, 3.0;
4.0, 8.0, 5.0
];
let y = x.design_matrix();
assert_eq!(
y.buf(),
&[1.0, 7.0, 2.0, 3.0, 1.0, 4.0, 8.0, 5.0]
);
}
#[test]
fn test_error() {
let x = mat![
1.0, 2.0, 3.0;
4.0, 2.0, 5.0
];
let h = Hypothesis::from_params(&[2.0, 6.0, 3.0]);
let y = [7.0, 2.0];
assert_eq!(
h.error(&x, &y),
336.25
);
}
#[test]
fn test_derivatives() {
let x = mat![
1.0, 2.0, 3.0;
4.0, 2.0, 5.0
];
let h = Hypothesis::from_params(&[2.0, 6.0, 3.0]);
let y = [7.0, 2.0];
assert_eq!(
h.derivatives(&x, &y),
vec![74.0, 49.0, 106.5]
);
}
}