1use crate::error::Error;
2use crate::imports::*;
3pub mod serde_api;
4pub use serde_api::*;
5
6use ninterp::num_traits::{Num, Zero};
7
8pub trait Linspace {
9 fn linspace(start: f64, stop: f64, n_elements: usize) -> Vec<f64> {
15 let n_steps = n_elements - 1;
16 let step_size = (stop - start) / n_steps as f64;
17 let v_norm: Vec<f64> = (0..=n_steps)
18 .collect::<Vec<usize>>()
19 .iter()
20 .map(|x| *x as f64)
21 .collect();
22 let v = v_norm.iter().map(|x| (x * step_size) + start).collect();
23 v
24 }
25}
26
27impl Linspace for Vec<f64> {}
28
29pub trait Min<T: PartialOrd> {
30 fn min(&self) -> anyhow::Result<&T>;
31}
32impl<T: PartialOrd> Min<T> for [T] {
33 fn min(&self) -> anyhow::Result<&T> {
34 self.iter()
35 .min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
36 .ok_or_else(|| anyhow!("Empty slice has no minimum"))
37 }
38}
39impl<T: PartialOrd> Min<T> for Vec<T> {
40 fn min(&self) -> anyhow::Result<&T> {
41 self.as_slice().min()
42 }
43}
44impl<S, D> Min<S::Elem> for ArrayBase<S, D>
45where
46 S: ndarray::Data,
47 S::Elem: PartialOrd,
48 D: ndarray::Dimension,
49{
50 fn min(&self) -> anyhow::Result<&S::Elem> {
51 self.iter()
52 .min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
53 .ok_or_else(|| anyhow!("Empty slice has no minimum"))
54 }
55}
56impl<T> Min<T> for Interp0D<T>
57where
58 T: PartialOrd,
59{
60 fn min(&self) -> anyhow::Result<&T> {
61 Ok(&self.0)
62 }
63}
64impl<D, S> Min<D::Elem> for Interp1D<D, S>
65where
66 D: ndarray::Data + ndarray::RawDataClone + Clone,
67 D::Elem: PartialOrd + std::fmt::Debug,
68 S: strategy::traits::Strategy1D<D> + Clone,
69{
70 fn min(&self) -> anyhow::Result<&D::Elem> {
71 self.data.values.min()
72 }
73}
74impl<D, S> Min<D::Elem> for Interp2D<D, S>
75where
76 D: ndarray::Data + ndarray::RawDataClone + Clone,
77 D::Elem: PartialOrd + std::fmt::Debug,
78 S: strategy::traits::Strategy2D<D> + Clone,
79{
80 fn min(&self) -> anyhow::Result<&D::Elem> {
81 self.data.values.min()
82 }
83}
84impl<D, S> Min<D::Elem> for Interp3D<D, S>
85where
86 D: ndarray::Data + ndarray::RawDataClone + Clone,
87 D::Elem: PartialOrd + std::fmt::Debug,
88 S: strategy::traits::Strategy3D<D> + Clone,
89{
90 fn min(&self) -> anyhow::Result<&D::Elem> {
91 self.data.values.min()
92 }
93}
94impl<D, S> Min<D::Elem> for InterpND<D, S>
95where
96 D: ndarray::Data + ndarray::RawDataClone + Clone,
97 D::Elem: PartialOrd + std::fmt::Debug,
98 S: strategy::traits::StrategyND<D> + Clone,
99{
100 fn min(&self) -> anyhow::Result<&D::Elem> {
101 self.data.values.min()
102 }
103}
104impl<S> Min<S::Elem> for InterpolatorEnum<S>
105where
106 S: ndarray::Data + ndarray::RawDataClone + Clone,
107 S::Elem: Num + PartialOrd + Copy + std::fmt::Debug,
108{
109 fn min(&self) -> anyhow::Result<&S::Elem> {
110 match self {
111 Self::Interp0D(interp) => interp.min(),
112 Self::Interp1D(interp) => interp.min(),
113 Self::Interp2D(interp) => interp.min(),
114 Self::Interp3D(interp) => interp.min(),
115 Self::InterpND(interp) => interp.min(),
116 }
117 }
118}
119
120pub trait Max<T: PartialOrd> {
121 fn max(&self) -> anyhow::Result<&T>;
122}
123impl<T: PartialOrd> Max<T> for [T] {
124 fn max(&self) -> anyhow::Result<&T> {
125 self.iter()
126 .max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
127 .ok_or_else(|| anyhow!("Empty slice has no maximum"))
128 }
129}
130impl<T: PartialOrd> Max<T> for Vec<T> {
131 fn max(&self) -> anyhow::Result<&T> {
132 self.as_slice().max()
133 }
134}
135impl<S, D> Max<S::Elem> for ArrayBase<S, D>
136where
137 S: ndarray::Data,
138 S::Elem: PartialOrd,
139 D: ndarray::Dimension,
140{
141 fn max(&self) -> anyhow::Result<&S::Elem> {
142 self.iter()
143 .max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
144 .ok_or_else(|| anyhow!("Empty slice has no maximum"))
145 }
146}
147impl<T> Max<T> for Interp0D<T>
148where
149 T: PartialOrd,
150{
151 fn max(&self) -> anyhow::Result<&T> {
152 Ok(&self.0)
153 }
154}
155impl<D, S> Max<D::Elem> for Interp1D<D, S>
156where
157 D: ndarray::Data + ndarray::RawDataClone + Clone,
158 D::Elem: PartialOrd + std::fmt::Debug,
159 S: strategy::traits::Strategy1D<D> + Clone,
160{
161 fn max(&self) -> anyhow::Result<&D::Elem> {
162 self.data.values.max()
163 }
164}
165impl<D, S> Max<D::Elem> for Interp2D<D, S>
166where
167 D: ndarray::Data + ndarray::RawDataClone + Clone,
168 D::Elem: PartialOrd + std::fmt::Debug,
169 S: strategy::traits::Strategy2D<D> + Clone,
170{
171 fn max(&self) -> anyhow::Result<&D::Elem> {
172 self.data.values.max()
173 }
174}
175impl<D, S> Max<D::Elem> for Interp3D<D, S>
176where
177 D: ndarray::Data + ndarray::RawDataClone + Clone,
178 D::Elem: PartialOrd + std::fmt::Debug,
179 S: strategy::traits::Strategy3D<D> + Clone,
180{
181 fn max(&self) -> anyhow::Result<&D::Elem> {
182 self.data.values.max()
183 }
184}
185impl<D, S> Max<D::Elem> for InterpND<D, S>
186where
187 D: ndarray::Data + ndarray::RawDataClone + Clone,
188 D::Elem: PartialOrd + std::fmt::Debug,
189 S: strategy::traits::StrategyND<D> + Clone,
190{
191 fn max(&self) -> anyhow::Result<&D::Elem> {
192 self.data.values.max()
193 }
194}
195impl<S> Max<S::Elem> for InterpolatorEnum<S>
196where
197 S: ndarray::Data + ndarray::RawDataClone + Clone,
198 S::Elem: Num + PartialOrd + Copy + std::fmt::Debug,
199{
200 fn max(&self) -> anyhow::Result<&S::Elem> {
201 match self {
202 Self::Interp0D(interp) => interp.max(),
203 Self::Interp1D(interp) => interp.max(),
204 Self::Interp2D(interp) => interp.max(),
205 Self::Interp3D(interp) => interp.max(),
206 Self::InterpND(interp) => interp.max(),
207 }
208 }
209}
210
211pub trait Range<T: PartialOrd + Sub<Output = T>>: Min<T> + Max<T> {
212 fn range(&self) -> anyhow::Result<T>;
213}
214impl<T> Range<T> for [T]
215where
216 Self: Min<T> + Max<T>,
217 T: PartialOrd + Sub<Output = T> + Copy,
218{
219 fn range(&self) -> anyhow::Result<T> {
220 Ok(*self.max()? - *self.min()?)
221 }
222}
223impl<T> Range<T> for Vec<T>
224where
225 Self: Min<T> + Max<T>,
226 T: PartialOrd + Sub<Output = T> + Copy,
227{
228 fn range(&self) -> anyhow::Result<T> {
229 self.as_slice().range()
230 }
231}
232impl<S, D> Range<S::Elem> for ArrayBase<S, D>
233where
234 S: ndarray::Data,
235 S::Elem: PartialOrd + Sub<Output = S::Elem> + Copy,
236 D: ndarray::Dimension,
237 Self: Min<S::Elem> + Max<S::Elem>,
238{
239 fn range(&self) -> anyhow::Result<S::Elem> {
240 Ok(*self.max()? - *self.min()?)
241 }
242}
243impl<T> Range<T> for Interp0D<T>
244where
245 T: Zero + PartialOrd + Sub<Output = T>,
246{
247 fn range(&self) -> anyhow::Result<T> {
248 Ok(T::zero())
249 }
250}
251impl<D, S> Range<D::Elem> for Interp1D<D, S>
252where
253 D: ndarray::Data + ndarray::RawDataClone + Clone,
254 D::Elem: PartialOrd + Sub<Output = D::Elem> + Copy + std::fmt::Debug,
255 S: strategy::traits::Strategy1D<D> + Clone,
256{
257 fn range(&self) -> anyhow::Result<D::Elem> {
258 self.data.values.range()
259 }
260}
261impl<D, S> Range<D::Elem> for Interp2D<D, S>
262where
263 D: ndarray::Data + ndarray::RawDataClone + Clone,
264 D::Elem: PartialOrd + Sub<Output = D::Elem> + Copy + std::fmt::Debug,
265 S: strategy::traits::Strategy2D<D> + Clone,
266{
267 fn range(&self) -> anyhow::Result<D::Elem> {
268 self.data.values.range()
269 }
270}
271impl<D, S> Range<D::Elem> for Interp3D<D, S>
272where
273 D: ndarray::Data + ndarray::RawDataClone + Clone,
274 D::Elem: PartialOrd + Sub<Output = D::Elem> + Copy + std::fmt::Debug,
275 S: strategy::traits::Strategy3D<D> + Clone,
276{
277 fn range(&self) -> anyhow::Result<D::Elem> {
278 self.data.values.range()
279 }
280}
281impl<D, S> Range<D::Elem> for InterpND<D, S>
282where
283 D: ndarray::Data + ndarray::RawDataClone + Clone,
284 D::Elem: PartialOrd + Sub<Output = D::Elem> + Copy + std::fmt::Debug,
285 S: strategy::traits::StrategyND<D> + Clone,
286{
287 fn range(&self) -> anyhow::Result<D::Elem> {
288 self.data.values.range()
289 }
290}
291impl<S> Range<S::Elem> for InterpolatorEnum<S>
292where
293 S: ndarray::Data + ndarray::RawDataClone + Clone,
294 S::Elem: Num + PartialOrd + Copy + std::fmt::Debug,
295 ArrayBase<S, Ix1>: Range<S::Elem>,
296{
297 fn range(&self) -> anyhow::Result<S::Elem> {
298 match self {
299 Self::Interp0D(interp) => interp.range(),
300 Self::Interp1D(interp) => interp.range(),
301 Self::Interp2D(interp) => interp.range(),
302 Self::Interp3D(interp) => interp.range(),
303 Self::InterpND(interp) => interp.range(),
304 }
305 }
306}
307
308pub trait Init {
309 fn init(&mut self) -> Result<(), Error> {
312 Ok(())
313 }
314}
315
316pub trait Diff<T> {
317 fn diff(&self) -> Vec<T>;
320}
321
322impl<T: Clone + Sub<T, Output = T> + Default> Diff<T> for Vec<T> {
323 fn diff(&self) -> Vec<T> {
324 let mut v_diff: Vec<T> = vec![Default::default()];
325 v_diff.extend::<Vec<T>>(
326 self.windows(2)
327 .map(|vs| {
328 let x = &vs[0];
329 let y = &vs[1];
330 y.clone() - x.clone()
331 })
332 .collect(),
333 );
334 v_diff
335 }
336}
337
338pub trait StateMethods: SetCumulative + SaveState + Step + TrackedStateMethods {}
340
341pub trait SetCumulative {
343 fn set_cumulative<F: Fn() -> String>(&mut self, dt: si::Time, loc: F) -> anyhow::Result<()>;
345}
346
347pub trait SaveState {
350 fn save_state<F: Fn() -> String>(&mut self, loc: F) -> anyhow::Result<()>;
354}
355
356pub trait Step {
359 fn step<F: Fn() -> String>(&mut self, loc: F) -> anyhow::Result<()>;
363
364 fn reset_step<F: Fn() -> String>(&mut self, loc: F) -> anyhow::Result<()>;
368}
369
370pub trait HistoryMethods: SaveState {
372 fn set_save_interval(&mut self, save_interval: Option<usize>) -> anyhow::Result<()>;
376 fn save_interval(&self) -> anyhow::Result<Option<usize>>;
379 fn clear(&mut self);
381}
382
383pub trait EqDefault: std::default::Default + PartialEq {
385 fn eq_default(&self) -> bool {
387 *self == Self::default()
388 }
389}
390
391impl<T: Default + PartialEq> EqDefault for T {}
392
393#[cfg(test)]
394mod tests {
395 use super::*;
396
397 #[test]
398 fn test_linspace() {
399 assert_eq!(Vec::linspace(0., 2., 3), vec![0., 1., 2.]);
400 }
401
402 #[test]
403 fn test_max_for_vec_f64() {
404 assert_eq!(Vec::linspace(-10., 12., 5).max().unwrap(), &12.);
405 }
406 #[test]
407 fn test_min_for_vec_f64() {
408 assert_eq!(Vec::linspace(-10., 12., 5).min().unwrap(), &-10.);
409 }
410
411 #[test]
412 fn test_diff() {
413 let diff = Vec::linspace(0., 2., 3).diff();
414 let ref_diff = vec![0., 1., 1.];
415 assert_eq!(diff, ref_diff);
416 }
417}