#[derive(Debug)]
pub struct MovingMin<T> {
push_stack: Vec<(T, T)>,
pop_stack: Vec<(T, T)>,
}
impl<T: Clone + PartialOrd> Default for MovingMin<T> {
fn default() -> Self {
Self {
push_stack: Vec::new(),
pop_stack: Vec::new(),
}
}
}
impl<T: Clone + PartialOrd> MovingMin<T> {
#[inline]
pub fn new() -> Self {
Self::default()
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
push_stack: Vec::with_capacity(capacity),
pop_stack: Vec::with_capacity(capacity),
}
}
#[inline]
pub fn min(&self) -> Option<&T> {
match (self.push_stack.last(), self.pop_stack.last()) {
(None, None) => None,
(Some((_, min)), None) => Some(min),
(None, Some((_, min))) => Some(min),
(Some((_, a)), Some((_, b))) => Some(if a < b { a } else { b }),
}
}
#[inline]
pub fn push(&mut self, val: T) {
self.push_stack.push(match self.push_stack.last() {
Some((_, min)) => {
if val > *min {
(val, min.clone())
} else {
(val.clone(), val)
}
}
None => (val.clone(), val),
});
}
#[inline]
pub fn pop(&mut self) -> Option<T> {
if self.pop_stack.is_empty() {
match self.push_stack.pop() {
Some((val, _)) => {
let mut last = (val.clone(), val);
self.pop_stack.push(last.clone());
while let Some((val, _)) = self.push_stack.pop() {
let min = if last.1 < val {
last.1.clone()
} else {
val.clone()
};
last = (val.clone(), min);
self.pop_stack.push(last.clone());
}
}
None => return None,
}
}
self.pop_stack.pop().map(|(val, _)| val)
}
#[inline]
pub fn len(&self) -> usize {
self.push_stack.len() + self.pop_stack.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[derive(Debug)]
pub struct MovingMax<T> {
push_stack: Vec<(T, T)>,
pop_stack: Vec<(T, T)>,
}
impl<T: Clone + PartialOrd> Default for MovingMax<T> {
fn default() -> Self {
Self {
push_stack: Vec::new(),
pop_stack: Vec::new(),
}
}
}
impl<T: Clone + PartialOrd> MovingMax<T> {
#[inline]
pub fn new() -> Self {
Self::default()
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
push_stack: Vec::with_capacity(capacity),
pop_stack: Vec::with_capacity(capacity),
}
}
#[inline]
pub fn max(&self) -> Option<&T> {
match (self.push_stack.last(), self.pop_stack.last()) {
(None, None) => None,
(Some((_, max)), None) => Some(max),
(None, Some((_, max))) => Some(max),
(Some((_, a)), Some((_, b))) => Some(if a > b { a } else { b }),
}
}
#[inline]
pub fn push(&mut self, val: T) {
self.push_stack.push(match self.push_stack.last() {
Some((_, max)) => {
if val < *max {
(val, max.clone())
} else {
(val.clone(), val)
}
}
None => (val.clone(), val),
});
}
#[inline]
pub fn pop(&mut self) -> Option<T> {
if self.pop_stack.is_empty() {
match self.push_stack.pop() {
Some((val, _)) => {
let mut last = (val.clone(), val);
self.pop_stack.push(last.clone());
while let Some((val, _)) = self.push_stack.pop() {
let max = if last.1 > val {
last.1.clone()
} else {
val.clone()
};
last = (val.clone(), max);
self.pop_stack.push(last.clone());
}
}
None => return None,
}
}
self.pop_stack.pop().map(|(val, _)| val)
}
#[inline]
pub fn len(&self) -> usize {
self.push_stack.len() + self.pop_stack.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[cfg(test)]
mod tests {
use super::*;
use datafusion_common::Result;
use rand::Rng;
fn get_random_vec_i32(len: usize) -> Vec<i32> {
let mut rng = rand::thread_rng();
let mut input = Vec::with_capacity(len);
for _i in 0..len {
input.push(rng.gen_range(0..100));
}
input
}
fn moving_min_i32(len: usize, n_sliding_window: usize) -> Result<()> {
let data = get_random_vec_i32(len);
let mut expected = Vec::with_capacity(len);
let mut moving_min = MovingMin::<i32>::new();
let mut res = Vec::with_capacity(len);
for i in 0..len {
let start = i.saturating_sub(n_sliding_window);
expected.push(*data[start..i + 1].iter().min().unwrap());
moving_min.push(data[i]);
if i > n_sliding_window {
moving_min.pop();
}
res.push(*moving_min.min().unwrap());
}
assert_eq!(res, expected);
Ok(())
}
fn moving_max_i32(len: usize, n_sliding_window: usize) -> Result<()> {
let data = get_random_vec_i32(len);
let mut expected = Vec::with_capacity(len);
let mut moving_max = MovingMax::<i32>::new();
let mut res = Vec::with_capacity(len);
for i in 0..len {
let start = i.saturating_sub(n_sliding_window);
expected.push(*data[start..i + 1].iter().max().unwrap());
moving_max.push(data[i]);
if i > n_sliding_window {
moving_max.pop();
}
res.push(*moving_max.max().unwrap());
}
assert_eq!(res, expected);
Ok(())
}
#[test]
fn moving_min_tests() -> Result<()> {
moving_min_i32(100, 10)?;
moving_min_i32(100, 20)?;
moving_min_i32(100, 50)?;
moving_min_i32(100, 100)?;
Ok(())
}
#[test]
fn moving_max_tests() -> Result<()> {
moving_max_i32(100, 10)?;
moving_max_i32(100, 20)?;
moving_max_i32(100, 50)?;
moving_max_i32(100, 100)?;
Ok(())
}
}