lsph 0.1.9

Learned Spatial HashMap
Documentation
use core::iter::Sum;
use num_traits::{cast::FromPrimitive, float::Float};

/// Calculates mean of a slice of values
pub fn mean<F>(values: &[F]) -> F
where
    F: Float + Sum,
{
    if values.is_empty() {
        return F::zero();
    }
    let sum: F = values.iter().cloned().map(Into::into).sum();
    sum / F::from(values.len()).unwrap()
}

/// Calculates variance of a slice of values
pub fn variance<F>(values: &[F]) -> F
where
    F: Float + Sum,
{
    if values.is_empty() {
        return F::zero();
    }
    let mean = mean(values);

    let diff_sum: F = values
        .iter()
        .cloned()
        .map(|x| (x - mean).powf(F::from(2.0).unwrap()))
        .sum();
    diff_sum / F::from(values.len()).unwrap()
}

/// Calculates covariance over two slices of values
pub fn covariance<F>(x_values: &[F], y_values: &[F]) -> F
where
    F: Float + Sum,
{
    if x_values.len() != y_values.len() {
        panic!("x_values and y_values must be of equal length.");
    }
    let length: usize = x_values.len();
    if length == 0usize {
        return F::zero();
    }
    let mean_x = mean(x_values);
    let mean_y = mean(y_values);

    x_values
        .iter()
        .zip(y_values.iter())
        .fold(F::zero(), |covariance, (&x, &y)| {
            covariance + (x - mean_x) * (y - mean_y)
        })
        / F::from(length).unwrap()
}

/// Calculates mean squared error between actual and predict values
pub fn mean_squared_error<F>(actual: &[F], predict: &[F]) -> F
where
    F: Float + FromPrimitive,
{
    if actual.len() != predict.len() {
        panic!("actual and predict must be of equal length.");
    }

    actual
        .iter()
        .zip(predict.iter())
        .fold(F::from_f64(0.0).unwrap(), |sum, (&x, &y)| {
            sum + (x - y).powf(F::from_f64(2.0).unwrap())
        })
        / F::from_usize(actual.len()).unwrap()
}

/// Calculates root mean squared error between actual and predict values
pub fn root_mean_squared_error<F>(actual: &[F], predict: &[F]) -> F
where
    F: Float + FromPrimitive,
{
    mean_squared_error::<F>(actual, predict).sqrt()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn mean_empty_vec() {
        let values: Vec<f64> = vec![];
        assert_delta!(0., mean(&values), 0.00001);
    }

    #[test]
    fn mean_empty_vec_f32() {
        let values: Vec<f32> = vec![];
        assert_delta!(0., mean(&values), 0.00001);
    }

    #[test]
    fn mean_1_to_5() {
        let values = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        assert_delta!(3., mean(&values), 0.00001);
    }

    #[test]
    fn mean_1_to_5_f32() {
        let values: Vec<f32> = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        assert_delta!(3., mean(&values), 0.00001);
    }

    #[test]
    fn variance_empty_vec() {
        let values: Vec<f64> = vec![];
        assert_delta!(0., variance(&values), 0.00001);
    }

    #[test]
    fn variance_empty_vec_f32() {
        let values: Vec<f32> = vec![];
        assert_delta!(0., variance(&values), 0.00001);
    }

    #[test]
    fn variance_1_to_5() {
        let values = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        assert_delta!(2., variance(&values), 0.00001);
    }

    #[test]
    fn variance_1_to_5_f32() {
        let values: Vec<f32> = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        assert_delta!(2., variance(&values), 0.00001);
    }

    #[test]
    fn covariance_empty_vec() {
        let x_values: Vec<f64> = vec![];
        let y_values: Vec<f64> = vec![];
        assert_delta!(0., covariance(&x_values, &y_values), 0.00001);
    }

    #[test]
    fn covariance_empty_vec_f32() {
        let x_values: Vec<f32> = vec![];
        let y_values: Vec<f32> = vec![];
        assert_delta!(0., covariance(&x_values, &y_values), 0.00001);
    }

    #[test]
    fn covariance_1_to_5() {
        let x_values = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        let y_values = vec![1.0, 3.0, 2.0, 3.0, 5.0];
        assert_delta!(1.6, covariance(&x_values, &y_values), 0.00001);
    }

    #[test]
    fn covariance_1_to_5_f32() {
        let x_values: Vec<f32> = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        let y_values: Vec<f32> = vec![1.0, 3.0, 2.0, 3.0, 5.0];
        assert_delta!(1.6, covariance(&x_values, &y_values), 0.00001);
    }

    #[test]
    fn negative_covariance_1_to_5() {
        let x_values = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        let y_values = vec![0.5, 4.0, 1.0, -5.0, 4.0];
        assert_delta!(-0.4, covariance(&x_values, &y_values), 0.00001);
    }

    #[test]
    fn negative_covariance_1_to_5_f32() {
        let x_values: Vec<f32> = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        let y_values: Vec<f32> = vec![0.5, 4.0, 1.0, -5.0, 4.0];
        assert_delta!(-0.4, covariance(&x_values, &y_values), 0.00001);
    }

    #[test]
    fn mean_squared_error_test() {
        let actual = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        let predict = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        assert_delta!(0., mean_squared_error(&actual, &predict), 0.00001);
    }

    #[test]
    fn mean_squared_error_test_f32() {
        let actual: Vec<f32> = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        let predict: Vec<f32> = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        assert_delta!(0., mean_squared_error(&actual, &predict), 0.00001);
    }

    #[test]
    fn mean_squared_error_test_2() {
        let actual = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        let predict = vec![1.0, 1.6, 3.0, 4.0, 5.0];
        assert_delta!(0.032, mean_squared_error(&actual, &predict), 0.00001);
    }

    #[test]
    fn mean_squared_error_test_2_f32() {
        let actual: Vec<f32> = vec![1.0, 2.0, 3.0, 4.0, 5.0];
        let predict: Vec<f32> = vec![1.0, 1.6, 3.0, 4.0, 5.0];
        assert_delta!(0.032, mean_squared_error(&actual, &predict), 0.00001);
    }
}