#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use core::ops::{Deref, DerefMut};
use num_traits::{One, Zero};
#[cfg(feature = "std")]
use std::vec::Vec;
#[derive(Debug, Clone)]
pub struct Slot<T>(Vec<T>);
impl<T> Slot<T> {
#[inline]
pub fn new(capacity: usize) -> Self {
Self(Vec::with_capacity(capacity))
}
#[inline]
pub fn clear(&mut self) {
self.0.clear();
}
#[inline]
pub fn as_vec(&self) -> &Vec<T> {
&self.0
}
#[inline]
pub fn as_vec_mut(&mut self) -> &mut Vec<T> {
&mut self.0
}
}
impl<T> Default for Slot<T> {
fn default() -> Self {
Self(Vec::new())
}
}
impl<T> Deref for Slot<T> {
type Target = Vec<T>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for Slot<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> From<Vec<T>> for Slot<T> {
fn from(v: Vec<T>) -> Self {
Self(v)
}
}
#[derive(Debug, Clone)]
pub struct CVBuffer<T> {
pub train_x: Vec<T>,
pub train_y: Vec<T>,
pub test_x: Vec<T>,
pub test_y: Vec<T>,
pub sorted_train_x: Vec<T>,
pub sorted_train_y: Vec<T>,
}
impl<T> Default for CVBuffer<T> {
fn default() -> Self {
Self {
train_x: Vec::new(),
train_y: Vec::new(),
test_x: Vec::new(),
test_y: Vec::new(),
sorted_train_x: Vec::new(),
sorted_train_y: Vec::new(),
}
}
}
impl<T: Clone> CVBuffer<T> {
pub fn new() -> Self {
Self {
train_x: Vec::new(),
train_y: Vec::new(),
test_x: Vec::new(),
test_y: Vec::new(),
sorted_train_x: Vec::new(),
sorted_train_y: Vec::new(),
}
}
pub fn ensure_capacity(&mut self, n_total: usize, dims: usize) {
if self.train_x.capacity() < n_total * dims {
self.train_x.reserve(n_total * dims);
}
if self.train_y.capacity() < n_total {
self.train_y.reserve(n_total);
}
if self.test_x.capacity() < (n_total / 2 + 1) * dims {
self.test_x.reserve((n_total / 2 + 1) * dims);
}
if self.test_y.capacity() < (n_total / 2 + 1) {
self.test_y.reserve(n_total / 2 + 1);
}
if self.sorted_train_x.capacity() < n_total * dims {
self.sorted_train_x.reserve(n_total * dims);
}
if self.sorted_train_y.capacity() < n_total {
self.sorted_train_y.reserve(n_total);
}
}
}
#[derive(Debug, Clone)]
pub struct LowessBuffer<T> {
pub y_smooth: Slot<T>,
pub y_prev: Slot<T>,
pub robustness_weights: Slot<T>,
pub residuals: Slot<T>,
pub weights: Slot<T>,
}
impl<T> Default for LowessBuffer<T> {
fn default() -> Self {
Self {
y_smooth: Slot::default(),
y_prev: Slot::default(),
robustness_weights: Slot::default(),
residuals: Slot::default(),
weights: Slot::default(),
}
}
}
impl<T: Clone> LowessBuffer<T> {
pub fn with_capacity(n: usize) -> Self {
Self {
y_smooth: Slot::new(n),
y_prev: Slot::new(n),
robustness_weights: Slot::new(n),
residuals: Slot::new(n),
weights: Slot::new(n),
}
}
pub fn prepare(&mut self, n: usize, use_convergence: bool)
where
T: Zero + One + Clone,
{
self.y_smooth.as_vec_mut().assign(n, T::zero());
if use_convergence {
self.y_prev.as_vec_mut().assign(n, T::zero());
} else {
self.y_prev.clear();
}
self.robustness_weights.as_vec_mut().assign(n, T::one());
self.residuals.as_vec_mut().assign(n, T::zero());
self.weights.as_vec_mut().assign(n, T::zero());
}
}
pub trait VecExt<T> {
fn assign(&mut self, n: usize, val: T);
fn assign_slice(&mut self, slice: &[T]);
}
impl<T: Clone> VecExt<T> for Vec<T> {
fn assign(&mut self, n: usize, val: T) {
if self.len() != n {
self.clear();
self.resize(n, val);
} else {
self.fill(val);
}
}
fn assign_slice(&mut self, slice: &[T]) {
self.clear();
self.extend_from_slice(slice);
}
}
#[derive(Debug, Clone)]
pub struct OnlineBuffer<T> {
pub scratch_x: Slot<T>,
pub scratch_y: Slot<T>,
pub weights: Slot<T>,
pub robustness_weights: Slot<T>,
}
impl<T> Default for OnlineBuffer<T> {
fn default() -> Self {
Self {
scratch_x: Slot::default(),
scratch_y: Slot::default(),
weights: Slot::default(),
robustness_weights: Slot::default(),
}
}
}
impl<T: Clone> OnlineBuffer<T> {
pub fn with_capacity(capacity: usize) -> Self {
Self {
scratch_x: Slot::new(capacity),
scratch_y: Slot::new(capacity),
weights: Slot::new(capacity),
robustness_weights: Slot::new(capacity),
}
}
pub fn clear(&mut self) {
self.scratch_x.clear();
self.scratch_y.clear();
self.weights.clear();
self.robustness_weights.clear();
}
}
#[derive(Debug, Clone)]
pub struct StreamingBuffer<T> {
pub overlap_x: Slot<T>,
pub overlap_y: Slot<T>,
pub overlap_smoothed: Slot<T>,
pub overlap_robustness_weights: Slot<T>,
pub work_buffer: LowessBuffer<T>,
}
impl<T> Default for StreamingBuffer<T> {
fn default() -> Self {
Self {
overlap_x: Slot::default(),
overlap_y: Slot::default(),
overlap_smoothed: Slot::default(),
overlap_robustness_weights: Slot::default(),
work_buffer: LowessBuffer::default(),
}
}
}
impl<T: Clone> StreamingBuffer<T> {
pub fn with_capacity(overlap: usize, chunk_size: usize) -> Self {
Self {
overlap_x: Slot::new(overlap),
overlap_y: Slot::new(overlap),
overlap_smoothed: Slot::new(overlap),
overlap_robustness_weights: Slot::new(overlap),
work_buffer: LowessBuffer::with_capacity(chunk_size),
}
}
pub fn clear(&mut self) {
self.overlap_x.clear();
self.overlap_y.clear();
self.overlap_smoothed.clear();
self.overlap_robustness_weights.clear();
}
}