use anyhow::Result;
use num::Float;
use rayon::prelude::*;
use std::cmp;
use std::convert::From;
use std::ops::{Add, AddAssign, Div};
pub fn acf<T: Float + From<u32> + From<f64> + Copy + Add + AddAssign + Div>(
x: &[T],
max_lag: Option<usize>,
covariance: bool,
) -> Result<Vec<T>> {
let max_lag = match max_lag {
Some(max_lag) => cmp::min(max_lag, x.len() - 1),
None => x.len() - 1,
};
if x.len() <= max_lag {
return Err(anyhow::anyhow!(
"acf-max-lag ({}) must be less than the number of m6A observations ({}).",
max_lag,
x.len()
));
}
let m = max_lag + 1;
let len_x_usize = x.len();
let len_x: T = From::from(len_x_usize as u32);
let sum: T = From::from(0.0);
let sum_x: T = x.iter().fold(sum, |sum, &xi| sum + xi);
let mean_x: T = sum_x / len_x;
let mut y: Vec<T> = vec![From::from(0.0); m];
for t in 0..m {
for i in 0..len_x_usize - t {
let xi = x[i] - mean_x;
let xi_t = x[i + t] - mean_x;
y[t] += (xi * xi_t) / len_x;
}
if !covariance && t > 0 {
y[t] = y[t] / y[0];
}
}
if !covariance {
y[0] = From::from(1.0);
}
Ok(y)
}
pub fn acf_par<
T: Float
+ From<u32>
+ From<f64>
+ Copy
+ Add
+ AddAssign
+ Div
+ Send
+ std::iter::Sum
+ std::marker::Sync,
>(
x: &[T],
max_lag: Option<usize>,
covariance: bool,
) -> Result<Vec<T>> {
let max_lag = match max_lag {
Some(max_lag) => cmp::min(max_lag, x.len() - 1),
None => x.len() - 1,
};
if x.len() <= max_lag {
return Err(anyhow::anyhow!(
"acf-max-lag ({}) must be less than the number of m6A observations ({}).",
max_lag,
x.len()
));
}
let m = max_lag + 1;
let len_x_usize = x.len();
let len_x: T = From::from(len_x_usize as u32);
let sum: T = From::from(0.0);
let sum_x: T = x.iter().fold(sum, |sum, &xi| sum + xi);
let mean_x: T = sum_x / len_x;
let mut y: Vec<T> = vec![From::from(0.0); m];
for t in 0..m {
y[t] = x
.into_par_iter()
.enumerate()
.take(len_x_usize - t)
.map(|(i, xi)| {
let xi = *xi - mean_x;
let xi_t = x[i + t] - mean_x;
(xi * xi_t) / len_x
})
.sum();
if !covariance && t > 0 {
y[t] = y[t] / y[0];
}
}
if !covariance {
y[0] = From::from(1.0);
}
Ok(y)
}