use mathru::algebra::linear::{Vector, Matrix};
use mathru::algebra::abstr::Sign;
use crate::SupervisedLearn;
use rand::Rng;
#[derive(Debug)]
pub struct SVM
{
alpha: Option<Vector<f64>>,
lambda: f64,
iter: usize
}
impl SVM
{
pub fn new(lambda: f64, iter: usize) -> SVM
{
SVM
{
alpha: None,
lambda: lambda,
iter: iter,
}
}
pub fn get_parameter(self: &Self) -> Vector<f64>
{
if self.alpha == None
{
panic!("Model is not trained");
}
return self.alpha.clone().unwrap();
}
}
impl SupervisedLearn<Matrix<f64>, Vector<f64>> for SVM
{
fn predict(self: &Self, input: &Matrix<f64>) -> Vector<f64> {
let (m, n) : (usize, usize) = input.dim();
if self.alpha == None
{
panic!("Model is not trained");
}
let ones: Matrix<f64> = Matrix::<f64>::ones(m, n + 1);
let full_input: Matrix<f64> = ones.set_slice(input, 0, 0);
return (full_input * self.alpha.clone().unwrap()).sgn();
}
fn train(self: &mut Self, input: &Matrix<f64>, target: &Vector<f64>) {
let mut rng = rand::thread_rng();
let (m, n): (usize, usize) = input.dim();
let ones: Matrix<f64> = Matrix::<f64>::ones(m, n + 1);
let full_input: Matrix<f64> = ones.set_slice( input, 0, 0);
let mut alpha: Vector<f64> = Vector::zero(n + 1);
for t in 0..self.iter
{
let i_t: usize = rng.gen_range(0, m);
let n_t: f64 = 1.0f64 / (self.lambda * (t as f64 + 1.0f64));
let x_i_t: Vector<f64> = full_input.get_row(&i_t).transpose();
let y_i_t: f64 = *target.get(&i_t);
if y_i_t * alpha.dotp(&x_i_t) < 1.0
{
alpha = alpha * (1.0f64 - n_t * self.lambda) + x_i_t * y_i_t * n_t;
}
else
{
if y_i_t * alpha.dotp(&x_i_t) >= 1.0
{
alpha = alpha * (1.0 - n_t * self.lambda);
}
}
}
self.alpha = Some(alpha);
}
}