diff --git a/src/core/xseries.rs b/src/core/xseries.rs new file mode 100644 index 0000000..d655900 --- /dev/null +++ b/src/core/xseries.rs @@ -0,0 +1,163 @@ +use std::ops::{Add, Div, Mul, Sub}; + +// +// 1) Define a float series: FSeries +// + +#[derive(Debug, Clone)] +pub struct FSeries { + data: Vec, +} + +impl FSeries { + /// Create a new FSeries from a vector of f64 values. + pub fn new(data: Vec) -> Self { + Self { data } + } + + pub fn len(&self) -> usize { + self.data.len() + } + + /// Element‑wise helper applying an operation between two FSeries. + pub fn apply(&self, other: &Self, op: F) -> Self + where + F: Fn(f64, f64) -> f64, + { + assert!( + self.len() == other.len(), + "FSeries must have the same length to apply operations." + ); + let data = self + .data + .iter() + .zip(other.data.iter()) + .map(|(&a, &b)| op(a, b)) + .collect(); + FSeries { data } + } + + /// Access to the underlying data + pub fn data(&self) -> &[f64] { + &self.data + } +} + +// Macros for float series arithmetic (element‑wise) +macro_rules! impl_fseries_bin_op { + ($trait:ident, $method:ident, $op:tt) => { + impl $trait for FSeries { + type Output = Self; + + fn $method(self, rhs: Self) -> Self::Output { + self.apply(&rhs, |a, b| a $op b) + } + } + }; +} + +impl_fseries_bin_op!(Add, add, +); +impl_fseries_bin_op!(Sub, sub, -); +impl_fseries_bin_op!(Mul, mul, *); +impl_fseries_bin_op!(Div, div, /); + +macro_rules! impl_fseries_scalar_op { + ($trait:ident, $method:ident, $op:tt) => { + impl $trait for FSeries { + type Output = Self; + + fn $method(mut self, scalar: f64) -> Self::Output { + for x in self.data.iter_mut() { + *x = *x $op scalar; + } + self + } + } + }; +} + +impl_fseries_scalar_op!(Add, add, +); +impl_fseries_scalar_op!(Sub, sub, -); +impl_fseries_scalar_op!(Mul, mul, *); +impl_fseries_scalar_op!(Div, div, /); + +// +// 2) Define an integer series: ISeries +// + +#[derive(Debug, Clone)] +pub struct ISeries { + data: Vec, +} + +impl ISeries { + /// Create an ISeries from a vector of i64 values. + pub fn new(data: Vec) -> Self { + Self { data } + } + + pub fn len(&self) -> usize { + self.data.len() + } + + pub fn data(&self) -> &[i64] { + &self.data + } + + /// Element‑wise helper for integer series. + pub fn apply(&self, other: &Self, op: F) -> Self + where + F: Fn(i64, i64) -> i64, + { + assert!( + self.len() == other.len(), + "ISeries must have the same length to apply operations." + ); + let data = self + .data + .iter() + .zip(other.data.iter()) + .map(|(&a, &b)| op(a, b)) + .collect(); + ISeries { data } + } +} + +// Macros for integer series arithmetic (element‑wise) +macro_rules! impl_iseries_bin_op { + ($trait:ident, $method:ident, $op:tt) => { + impl $trait for ISeries { + type Output = Self; + + fn $method(self, rhs: Self) -> Self::Output { + self.apply(&rhs, |a, b| a $op b) + } + } + }; +} + +impl_iseries_bin_op!(Add, add, +); +impl_iseries_bin_op!(Sub, sub, -); +impl_iseries_bin_op!(Mul, mul, *); +impl_iseries_bin_op!(Div, div, /); // integer division (floor trunc) + +// Optional scalar operations (for i64) +macro_rules! impl_iseries_scalar_op { + ($trait:ident, $method:ident, $op:tt) => { + impl $trait for ISeries { + type Output = Self; + + fn $method(mut self, scalar: i64) -> Self::Output { + for x in self.data.iter_mut() { + *x = *x $op scalar; + } + self + } + } + }; +} + +impl_iseries_scalar_op!(Add, add, +); +impl_iseries_scalar_op!(Sub, sub, -); +impl_iseries_scalar_op!(Mul, mul, *); +impl_iseries_scalar_op!(Div, div, /); // floor/trunc division by scalar