use std::collections::VecDeque;
pub fn sum(real: &[f64], timeperiod: usize) -> Vec<f64> {
let n = real.len();
let mut result = vec![f64::NAN; n];
if timeperiod < 1 || n < timeperiod {
return result;
}
let mut win: f64 = real[..timeperiod].iter().sum();
result[timeperiod - 1] = win;
for i in timeperiod..n {
win += real[i] - real[i - timeperiod];
result[i] = win;
}
result
}
pub fn max(real: &[f64], timeperiod: usize) -> Vec<f64> {
sliding_max(real, timeperiod)
}
pub fn min(real: &[f64], timeperiod: usize) -> Vec<f64> {
sliding_min(real, timeperiod)
}
pub fn sliding_max(real: &[f64], timeperiod: usize) -> Vec<f64> {
let n = real.len();
let mut result = vec![f64::NAN; n];
if timeperiod < 1 || n < timeperiod {
return result;
}
let mut dq: VecDeque<usize> = VecDeque::new();
for i in 0..n {
while dq.front().map(|&j| j + timeperiod <= i).unwrap_or(false) {
dq.pop_front();
}
while dq.back().map(|&j| real[j] <= real[i]).unwrap_or(false) {
dq.pop_back();
}
dq.push_back(i);
if i + 1 >= timeperiod {
result[i] = real[*dq.front().unwrap()];
}
}
result
}
pub fn sliding_min(real: &[f64], timeperiod: usize) -> Vec<f64> {
let n = real.len();
let mut result = vec![f64::NAN; n];
if timeperiod < 1 || n < timeperiod {
return result;
}
let mut dq: VecDeque<usize> = VecDeque::new();
for i in 0..n {
while dq.front().map(|&j| j + timeperiod <= i).unwrap_or(false) {
dq.pop_front();
}
while dq.back().map(|&j| real[j] >= real[i]).unwrap_or(false) {
dq.pop_back();
}
dq.push_back(i);
if i + 1 >= timeperiod {
result[i] = real[*dq.front().unwrap()];
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sum_basic() {
let v = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let r = sum(&v, 3);
assert!(r[0].is_nan());
assert!((r[2] - 6.0).abs() < 1e-10);
assert!((r[4] - 12.0).abs() < 1e-10);
}
#[test]
fn max_basic() {
let v = vec![3.0, 1.0, 4.0, 1.0, 5.0];
let r = max(&v, 3);
assert!((r[2] - 4.0).abs() < 1e-10);
assert!((r[4] - 5.0).abs() < 1e-10);
}
#[test]
fn sliding_max_matches_naive() {
let v = vec![3.0, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0, 6.0];
let naive = max(&v, 3);
let fast = sliding_max(&v, 3);
for i in 0..v.len() {
assert_eq!(naive[i].is_nan(), fast[i].is_nan());
if !naive[i].is_nan() {
assert!((naive[i] - fast[i]).abs() < 1e-10);
}
}
}
#[test]
fn sliding_min_matches_naive() {
let v = vec![3.0, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0, 6.0];
let naive = min(&v, 3);
let fast = sliding_min(&v, 3);
for i in 0..v.len() {
assert_eq!(naive[i].is_nan(), fast[i].is_nan());
if !naive[i].is_nan() {
assert!((naive[i] - fast[i]).abs() < 1e-10);
}
}
}
}