#[cfg(test)]
mod tests{
use std::ops::{Index, IndexMut};
use nalgebra::{DMatrix, Matrix};
use ndarray::Array1;
use rand::{random, Rng, thread_rng};
use rayon::prelude::*;
use crate::als::ALS;
const N : usize = 10;
const M : usize = 20;
const K : usize = 6;
#[test]
fn test_basic() {
let mut als = ALS::new(4, 4, 2);
als.add((0, 0, 1.0));
als.add((0, 2, 2.0));
als.add((1, 1, 7.0));
als.add((2, 0, 2.0));
als.add((2, 3, 5.0));
als.add((3, 1, 3.0));
let cost_before = als.cost();
als.train();
let cost_after = als.cost();
assert!(cost_before > cost_after);
}
#[test]
fn test_intermediate() {
let n = 10;
let m = 10;
let k = 5;
let mut als = ALS::new(n, m, k);
for i_n in 0..n {
for i_m in 0..m {
if (i_n + i_m) % 2 == 0 {
als.add((i_n, i_m, (2*i_n + i_m) as f64));
}
}
}
let cost_before = als.cost();
als.train();
let cost_after = als.cost();
assert!(cost_before > cost_after);
}
#[test]
fn test_rand_big() {
let m = 1000;
let n = 20_000;
let k = 10;
let mut als = ALS::new(m, n, k);
for n in 0..N {
for m in 0..M {
if random::<f64>() < 0.1 {
let val = thread_rng().gen_range(1.0..10.0);
als.add((n, m, val));
}
}
}
let cost_before = als.cost();
als.train();
let cost_after = als.cost();
assert!(cost_before > cost_after);
}
fn bm25(data : &mut Vec<(usize, usize, f64)>, n: usize, m :usize, b : f64, k1 : f64) {
let mut idf = Array1::<f64>::zeros((m));
data.iter().for_each(|(_, c, _)| { *idf.index_mut((*c)) += 1.0;});
let doc_amounts_ln = (n as f64).ln();
idf.par_map_inplace(|e| {*e = doc_amounts_ln - e.ln_1p();});
let mut length_norm = Array1::<f64>::zeros((n));
data.iter().for_each(|(r, _, _)| { *length_norm.index_mut((*r)) += 1.0;});
let ave_len : f64 = length_norm.par_iter().sum::<f64>() / (n as f64);
length_norm.par_map_inplace(|e| {*e = (1.0 - b) + b * *e / ave_len;});
data.par_iter_mut().for_each(|(r, c, val)|
{*val = *val * (k1 + 1.0) / (k1 * *length_norm.index(*r) + *val) * *idf.index(*c);});
}
fn test_singular() {
let n = 10;
let m = 10;
let k = 6;
let mut als = ALS::new(n, m, k);
let mut sparse:DMatrix<f64> = DMatrix::zeros(n, m);
let mut coo = vec![];
for i_n in 0..n {
for i_m in 0..m {
if thread_rng().gen_bool(0.2) {
coo.push((i_n, i_m,1.0));
}
}
}
for (i_n, i_m, val) in coo {
als.add((i_n, i_m, val));
sparse[(i_n, i_m)] = val;
}
let cost_before = als.cost();
als.train_for_fill_missing(50);
let cost_after = als.cost();
let trained_r = DMatrix::from_fn(n, m, |i_n, i_m| als.predict_r_val(i_n, i_m));
println!("{}", sparse);
println!("{}", trained_r);
assert!(cost_before > cost_after);
}
}