pub(crate) struct MonoQueue {
buf: Vec<usize>,
mask: usize, head: usize, tail: usize, len: usize,
}
impl MonoQueue {
#[inline]
pub(crate) fn with_capacity(period: usize) -> Self {
let cap = period.next_power_of_two().max(1);
MonoQueue {
buf: vec![0usize; cap],
mask: cap - 1,
head: 0,
tail: 0,
len: 0,
}
}
#[inline]
pub(crate) fn push_back(&mut self, v: usize) {
self.buf[self.tail & self.mask] = v;
self.tail += 1;
self.len += 1;
}
#[inline]
pub(crate) fn pop_back(&mut self) {
self.tail -= 1;
self.len -= 1;
}
#[inline]
pub(crate) fn pop_front(&mut self) {
self.head += 1;
self.len -= 1;
}
#[inline]
pub(crate) fn front(&self) -> usize {
self.buf[self.head & self.mask]
}
#[inline]
pub(crate) fn back(&self) -> usize {
self.buf[(self.tail - 1) & self.mask]
}
#[inline]
pub(crate) fn is_empty(&self) -> bool {
self.len == 0
}
}
#[inline]
pub(crate) fn rolling_extreme(values: &[f64], period: usize, take_max: bool) -> Vec<f64> {
debug_assert!(period >= 1);
let n = values.len();
let mut out = vec![f64::NAN; n];
if n < period {
return out;
}
let mut dq = MonoQueue::with_capacity(period);
for i in 0..n {
while !dq.is_empty() && dq.front() + period <= i {
dq.pop_front();
}
if take_max {
while !dq.is_empty() && values[dq.back()] <= values[i] {
dq.pop_back();
}
} else {
while !dq.is_empty() && values[dq.back()] >= values[i] {
dq.pop_back();
}
}
dq.push_back(i);
if i >= period - 1 {
out[i] = values[dq.front()];
}
}
out
}
#[allow(dead_code)]
pub(crate) fn rolling_extreme_naive(values: &[f64], period: usize, take_max: bool) -> Vec<f64> {
debug_assert!(period >= 1);
let n = values.len();
let mut out = vec![f64::NAN; n];
if n < period {
return out;
}
for i in (period - 1)..n {
let mut acc = values[i];
for j in 1..period {
let v = values[i - j];
if take_max {
if v > acc {
acc = v;
}
} else if v < acc {
acc = v;
}
}
out[i] = acc;
}
out
}
#[inline]
pub(crate) fn rolling_minmax(values: &[f64], period: usize) -> (Vec<f64>, Vec<f64>) {
debug_assert!(period >= 1);
let n = values.len();
let mut max_out = vec![f64::NAN; n];
let mut min_out = vec![f64::NAN; n];
if n < period {
return (max_out, min_out);
}
let mut max_dq = MonoQueue::with_capacity(period);
let mut min_dq = MonoQueue::with_capacity(period);
for i in 0..n {
while !max_dq.is_empty() && max_dq.front() + period <= i {
max_dq.pop_front();
}
while !min_dq.is_empty() && min_dq.front() + period <= i {
min_dq.pop_front();
}
while !max_dq.is_empty() && values[max_dq.back()] <= values[i] {
max_dq.pop_back();
}
while !min_dq.is_empty() && values[min_dq.back()] >= values[i] {
min_dq.pop_back();
}
max_dq.push_back(i);
min_dq.push_back(i);
if i >= period - 1 {
max_out[i] = values[max_dq.front()];
min_out[i] = values[min_dq.front()];
}
}
(max_out, min_out)
}
pub(crate) fn rolling_extreme_index(values: &[f64], period: usize, take_max: bool) -> Vec<f64> {
debug_assert!(period >= 1);
let n = values.len();
let mut out = vec![f64::NAN; n];
if n < period {
return out;
}
let mut dq = MonoQueue::with_capacity(period);
for i in 0..n {
while !dq.is_empty() && dq.front() + period <= i {
dq.pop_front();
}
if take_max {
while !dq.is_empty() && values[dq.back()] < values[i] {
dq.pop_back();
}
} else {
while !dq.is_empty() && values[dq.back()] > values[i] {
dq.pop_back();
}
}
dq.push_back(i);
if i >= period - 1 {
out[i] = dq.front() as f64;
}
}
out
}
#[inline]
pub fn rolling_max(values: &[f64], period: usize) -> Vec<f64> {
rolling_extreme(values, period, true)
}
#[inline]
pub fn rolling_min(values: &[f64], period: usize) -> Vec<f64> {
rolling_extreme(values, period, false)
}