From 176f60665d9d7683c72397161e9dd7d5af74ba62 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 28 Mar 2026 14:29:50 -0700 Subject: [PATCH] Increased transform flexibility --- README.md | 2 +- src/transforms.rs | 39 ++++++++++++++++++++++++++++++++------- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 5a21259..2acf60a 100644 --- a/README.md +++ b/README.md @@ -376,7 +376,7 @@ let bad_and_silly_prediction = fit.y(150.0); // This is outside the range of the // Violating that is called extrapolation, which we generally want to avoid // This will return an error! -let bad_prediction_probably = fit.as_polynomial().y(150.0); // This is outside the range of the data, but you asked for it specifically +let bad_prediction_probably = fit.as_polynomial().y(150.0); // This is outside the range of the data, but you asked for it specifically // Unlike a CurveFit, a Polynomial is just a mathematical function - no seatbelts // This will return a value, but it is probably nonsense diff --git a/src/transforms.rs b/src/transforms.rs index 149c158..1cbea59 100644 --- a/src/transforms.rs +++ b/src/transforms.rs @@ -61,6 +61,8 @@ //! - Z-Score Normalization: [`NormalizationTransform::ZScore`] //! - Normalizes the dataset to zero mean and unit variance. //! - [`ApplyNormalization::apply_z_score_normalization`] allows you to apply it to the Y channel of an (X, Y) dataset +use std::borrow::BorrowMut; + use crate::value::Value; mod noise; @@ -87,24 +89,35 @@ pub trait Transform { } } +/// Allow passing an `&impl Transform` to anything that wants `impl Transform`. +/// +/// This way if you don't need to re-use a transform, you can pass it directly, +/// but you can still pass large ones by reference where that's helpful. +impl> Transform for &R { + fn apply<'a>(&self, data: impl Iterator) { + >::apply(*self, data); + } +} + /// Trait for transforming data. pub trait Transformable { /// Transforms the data in place. - fn transform>(&mut self, transform: &R); + fn transform>(&mut self, transform: R); /// Returns a transformed copy of the data. #[must_use] - fn transformed>(&self, transform: &R) -> Self + fn transformed>(&self, transform: R) -> Self::Owned where - Self: Sized + Clone, + Self: ToOwned, + Self::Owned: BorrowMut, { - let mut new_data = self.clone(); - new_data.transform(transform); + let mut new_data = self.to_owned(); + new_data.borrow_mut().transform(transform); new_data } } -impl Transformable for Vec<(T, T)> { - fn transform>(&mut self, transform: &R) { +impl Transformable for [(T, T)] { + fn transform>(&mut self, transform: R) { transform.apply(self.iter_mut().map(|(_, y)| y)); } } @@ -228,3 +241,15 @@ impl SeedSource { Some(out) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_transformed_slice_gives_vec() { + let points = [(-0.5, -4.0), (1.0, 3.0), (5.0, 4.0)]; + let new_points: Vec<_> = points[1..].transformed(ScaleTransform::Quadratic(0.5)); + assert_eq!(new_points, [(1.0, 4.5), (5.0, 8.0)]); + } +}