diff --git a/fastsim-core/src/traits.rs b/fastsim-core/src/traits.rs index 042e880c..656b13f3 100644 --- a/fastsim-core/src/traits.rs +++ b/fastsim-core/src/traits.rs @@ -31,14 +31,57 @@ impl Min for &[f64] { } impl Min for Vec { fn min(&self) -> anyhow::Result { - Ok(self.iter().fold(f64::INFINITY, |acc, curr| acc.min(*curr))) + self.as_slice().min() } } -impl Min for Vec<&f64> { +impl Min for &[&f64] { fn min(&self) -> anyhow::Result { Ok(self.iter().fold(f64::INFINITY, |acc, curr| acc.min(**curr))) } } +impl Min for Vec<&f64> { + fn min(&self) -> anyhow::Result { + self.as_slice().min() + } +} +impl Min for &[Vec] { + fn min(&self) -> anyhow::Result { + self.iter() + .map(|v| v.min()) + .try_fold(f64::INFINITY, |acc, x| Ok(acc.min(x?))) + } +} +impl Min for Vec> { + fn min(&self) -> anyhow::Result { + self.as_slice().min() + } +} +impl Min for &[Vec>] { + fn min(&self) -> anyhow::Result { + self.iter() + .map(|v| v.min()) + .try_fold(f64::INFINITY, |acc, x| Ok(acc.min(x?))) + } +} +impl Min for Vec>> { + fn min(&self) -> anyhow::Result { + self.as_slice().min() + } +} +impl Min for Interpolator { + fn min(&self) -> anyhow::Result { + match self { + Interpolator::Interp0D(value) => Ok(*value), + Interpolator::Interp1D(interp) => interp.f_x().min(), + Interpolator::Interp2D(interp) => interp.f_xy().min(), + Interpolator::Interp3D(interp) => interp.f_xyz().min(), + Interpolator::InterpND(interp) => Ok(interp + .values() + .iter() + .fold(f64::INFINITY, |acc, x| acc.min(*x))), + } + } +} pub trait Max { fn max(&self) -> anyhow::Result; @@ -52,18 +95,59 @@ impl Max for &[f64] { } impl Max for Vec { fn max(&self) -> anyhow::Result { - Ok(self - .iter() - .fold(f64::NEG_INFINITY, |acc, curr| acc.max(*curr))) + self.as_slice().max() } } -impl Max for Vec<&f64> { +impl Max for &[&f64] { fn max(&self) -> anyhow::Result { Ok(self .iter() .fold(f64::NEG_INFINITY, |acc, curr| acc.max(**curr))) } } +impl Max for Vec<&f64> { + fn max(&self) -> anyhow::Result { + self.as_slice().max() + } +} +impl Max for &[Vec] { + fn max(&self) -> anyhow::Result { + self.iter() + .map(|v| v.max()) + .try_fold(f64::NEG_INFINITY, |acc, x| Ok(acc.max(x?))) + } +} +impl Max for Vec> { + fn max(&self) -> anyhow::Result { + self.as_slice().max() + } +} +impl Max for &[Vec>] { + fn max(&self) -> anyhow::Result { + self.iter() + .map(|v| v.max()) + .try_fold(f64::NEG_INFINITY, |acc, x| Ok(acc.max(x?))) + } +} +impl Max for Vec>> { + fn max(&self) -> anyhow::Result { + self.as_slice().max() + } +} +impl Max for Interpolator { + fn max(&self) -> anyhow::Result { + match self { + Interpolator::Interp0D(value) => Ok(*value), + Interpolator::Interp1D(interp) => interp.f_x().max(), + Interpolator::Interp2D(interp) => interp.f_xy().max(), + Interpolator::Interp3D(interp) => interp.f_xyz().max(), + Interpolator::InterpND(interp) => Ok(interp + .values() + .iter() + .fold(f64::NEG_INFINITY, |acc, x| acc.max(*x))), + } + } +} pub trait Init { /// Specialized code to execute upon initialization. For any struct with fields diff --git a/fastsim-core/src/utils/interp.rs b/fastsim-core/src/utils/interp.rs new file mode 100644 index 00000000..265b43db --- /dev/null +++ b/fastsim-core/src/utils/interp.rs @@ -0,0 +1,107 @@ +use crate::imports::*; + +/// Methods for proportionally scaling interpolator function data +pub trait InterpolatorMethods { + fn set_min(&mut self, min: f64) -> anyhow::Result<()>; + fn set_max(&mut self, max: f64) -> anyhow::Result<()>; + fn set_range(&mut self, range: f64) -> anyhow::Result<()>; +} + +impl InterpolatorMethods for Interpolator { + fn set_min(&mut self, min: f64) -> anyhow::Result<()> { + let old_min = self.min()?; + match self { + Interpolator::Interp0D(value) => Ok(*value = min), + Interpolator::Interp1D(interp) => { + todo!() + } + Interpolator::Interp2D(interp) => { + todo!() + } + Interpolator::Interp3D(interp) => { + todo!() + } + Interpolator::InterpND(interp) => { + todo!() + } + } + } + + fn set_max(&mut self, max: f64) -> anyhow::Result<()> { + let old_max = self.max()?; + match self { + Interpolator::Interp0D(value) => Ok(*value = max), + Interpolator::Interp1D(interp) => { + Ok(interp.set_f_x(interp.f_x().iter().map(|x| x * max / old_max).collect())?) + } + Interpolator::Interp2D(interp) => Ok(interp.set_f_xy( + interp + .f_xy() + .iter() + .map(|v| v.iter().map(|x| x * max / old_max).collect()) + .collect(), + )?), + Interpolator::Interp3D(interp) => Ok(interp.set_f_xyz( + interp + .f_xyz() + .iter() + .map(|v0| { + v0.iter() + .map(|v1| v1.iter().map(|x| x * max / old_max).collect()) + .collect() + }) + .collect(), + )?), + Interpolator::InterpND(interp) => { + Ok(interp.set_values(interp.values().map(|x| x * max / old_max))?) + } + } + } + + fn set_range(&mut self, range: f64) -> anyhow::Result<()> { + let old_max = self.max()?; + let old_range = old_max - self.min()?; + ensure!(old_range != 0., "Cannot modify range when min == max"); + match self { + Interpolator::Interp0D(_value) => unreachable!("The above `ensure` should trigger"), + Interpolator::Interp1D(interp) => Ok(interp.set_f_x( + interp + .f_x() + .iter() + .map(|x| old_max + (x - old_max) * range / old_range) + .collect(), + )?), + Interpolator::Interp2D(interp) => Ok(interp.set_f_xy( + interp + .f_xy() + .iter() + .map(|v| { + v.iter() + .map(|x| old_max + (x - old_max) * range / old_range) + .collect() + }) + .collect(), + )?), + Interpolator::Interp3D(interp) => Ok(interp.set_f_xyz( + interp + .f_xyz() + .iter() + .map(|v0| { + v0.iter() + .map(|v1| { + v1.iter() + .map(|x| old_max + (x - old_max) * range / old_range) + .collect() + }) + .collect() + }) + .collect(), + )?), + Interpolator::InterpND(interp) => Ok(interp.set_values( + interp + .values() + .map(|x| old_max + (x - old_max) * range / old_range), + )?), + } + } +} diff --git a/fastsim-core/src/utils/mod.rs b/fastsim-core/src/utils/mod.rs index 7c161c76..409f98c6 100755 --- a/fastsim-core/src/utils/mod.rs +++ b/fastsim-core/src/utils/mod.rs @@ -2,6 +2,9 @@ use crate::imports::*; use paste::paste; use regex::Regex; +pub mod interp; +pub use interp::*; + impl Init for ninterp::Interpolator {} impl SerdeAPI for ninterp::Interpolator { const RESOURCE_PREFIX: &'static str = "interpolators";