arr_rs/math/operations/
extrema.rs

1use crate::{
2    core::prelude::*,
3    errors::prelude::*,
4    extensions::prelude::*,
5    numeric::prelude::*,
6};
7
8/// `ArrayTrait` - Array Extrema functions
9pub trait ArrayExtrema<N: Numeric> where Self: Sized + Clone {
10
11    /// Element-wise maximum of array elements
12    ///
13    /// # Arguments
14    ///
15    /// * `other` - array to perform the operation with
16    ///
17    /// # Examples
18    ///
19    /// ```
20    /// use arr_rs::prelude::*;
21    ///
22    /// let arr = Array::flat(vec![1., 2., 3., 4.]);
23    /// assert_eq!(
24    /// format!("{:#}", Array::flat(vec![2., f64::NAN, 3., 10.]).unwrap()),
25    /// format!("{:#}", arr.maximum(&Array::flat(vec![2., f64::NAN, 2., 10.]).unwrap()).unwrap())
26    /// );
27    /// ```
28    ///
29    /// # Errors
30    ///
31    /// may returns `ArrayError`
32    fn maximum(&self, other: &Array<N>) -> Result<Array<N>, ArrayError>;
33
34    /// Return the maximum of an array or maximum along an axis
35    ///
36    /// # Arguments
37    ///
38    /// * `axis` - axis along which to operate. optional, if None, input is flattened
39    ///
40    /// # Examples
41    ///
42    /// ```
43    /// use arr_rs::prelude::*;
44    ///
45    /// let arr = Array::flat(vec![1., 2., 3., 4.]);
46    /// assert_eq!(Array::single(4.), arr.max(None));
47    /// ```
48    ///
49    /// # Errors
50    ///
51    /// may returns `ArrayError`
52    fn max(&self, axis: Option<isize>) -> Result<Array<N>, ArrayError>;
53
54    /// Return the maximum of an array or maximum along an axis
55    /// alias on `max`
56    ///
57    /// # Arguments
58    ///
59    /// * `axis` - axis along which to operate. optional, if None, input is flattened
60    ///
61    /// # Examples
62    ///
63    /// ```
64    /// use arr_rs::prelude::*;
65    ///
66    /// let arr = Array::flat(vec![1., 2., 3., 4.]);
67    /// assert_eq!(Array::single(4.), arr.amax(None));
68    /// ```
69    ///
70    /// # Errors
71    ///
72    /// may returns `ArrayError`
73    fn amax(&self, axis: Option<isize>) -> Result<Array<N>, ArrayError>;
74
75    /// Element-wise maximum of array elements
76    ///
77    /// # Arguments
78    ///
79    /// * `other` - array to perform the operation with
80    ///
81    /// # Examples
82    ///
83    /// ```
84    /// use arr_rs::prelude::*;
85    ///
86    /// let arr = Array::flat(vec![1., 2., 3., 4.]);
87    /// assert_eq!(
88    /// format!("{:#}", Array::flat(vec![2., 2., 3., 10.]).unwrap()),
89    /// format!("{:#}", arr.fmax(&Array::flat(vec![2., f64::NAN, 2., 10.]).unwrap()).unwrap())
90    /// );
91    /// ```
92    ///
93    /// # Errors
94    ///
95    /// may returns `ArrayError`
96    fn fmax(&self, other: &Array<N>) -> Result<Array<N>, ArrayError>;
97
98    /// Return the maximum of an array or maximum along an axis, ignoring NAN
99    ///
100    /// # Arguments
101    ///
102    /// * `axis` - axis along which to operate. optional, if None, input is flattened
103    //
104    /// # Examples
105    ///
106    /// ```
107    /// use arr_rs::prelude::*;
108    ///
109    /// let arr = Array::flat(vec![1., 2., 3., 4., f64::NAN]);
110    /// assert_eq!(Array::single(4.), arr.nanmax(None));
111    /// ```
112    ///
113    /// # Errors
114    ///
115    /// may returns `ArrayError`
116    fn nanmax(&self, axis: Option<isize>) -> Result<Array<N>, ArrayError>;
117
118    /// Element-wise minimum of array elements
119    ///
120    /// # Arguments
121    ///
122    /// * `other` - array to perform the operation with
123    ///
124    /// # Examples
125    ///
126    /// ```
127    /// use arr_rs::prelude::*;
128    ///
129    /// let arr = Array::flat(vec![1., 2., 3., 4.]);
130    /// assert_eq!(
131    /// format!("{:#}", Array::flat(vec![1., f64::NAN, 2., 4.]).unwrap()),
132    /// format!("{:#}", arr.minimum(&Array::flat(vec![2., f64::NAN, 2., 10.]).unwrap()).unwrap())
133    /// );
134    /// ```
135    ///
136    /// # Errors
137    ///
138    /// may returns `ArrayError`
139    fn minimum(&self, other: &Array<N>) -> Result<Array<N>, ArrayError>;
140
141    /// Return the minimum of an array or minimum along an axis
142    ///
143    /// # Arguments
144    ///
145    /// * `axis` - axis along which to operate. optional, if None, input is flattened
146    ///
147    /// # Examples
148    ///
149    /// ```
150    /// use arr_rs::prelude::*;
151    ///
152    /// let arr = Array::flat(vec![1., 2., 3., 4.]);
153    /// assert_eq!(Array::single(1.), arr.min(None));
154    /// ```
155    ///
156    /// # Errors
157    ///
158    /// may returns `ArrayError`
159    fn min(&self, axis: Option<isize>) -> Result<Array<N>, ArrayError>;
160
161    /// Return the minimum of an array or minimum along an axis
162    /// alias on `min`
163    ///
164    /// # Arguments
165    ///
166    /// * `axis` - axis along which to operate. optional, if None, input is flattened
167    ///
168    /// # Examples
169    ///
170    /// ```
171    /// use arr_rs::prelude::*;
172    ///
173    /// let arr = Array::flat(vec![1., 2., 3., 4.]);
174    /// assert_eq!(Array::single(1.), arr.amin(None));
175    /// ```
176    ///
177    /// # Errors
178    ///
179    /// may returns `ArrayError`
180    fn amin(&self, axis: Option<isize>) -> Result<Array<N>, ArrayError>;
181
182    /// Element-wise maximum of array elements
183    ///
184    /// # Arguments
185    ///
186    /// * `other` - array to perform the operation with
187    ///
188    /// # Examples
189    ///
190    /// ```
191    /// use arr_rs::prelude::*;
192    ///
193    /// let arr = Array::flat(vec![1., 2., 3., 4.]);
194    /// assert_eq!(
195    /// format!("{:#}", Array::flat(vec![1., 2., 2., 4.]).unwrap()),
196    /// format!("{:#}", arr.fmin(&Array::flat(vec![2., f64::NAN, 2., 10.]).unwrap()).unwrap())
197    /// );
198    /// ```
199    ///
200    /// # Errors
201    ///
202    /// may returns `ArrayError`
203    fn fmin(&self, other: &Array<N>) -> Result<Array<N>, ArrayError>;
204
205    /// Return the minimum of an array or minimum along an axis, ignoring NAN
206    ///
207    /// # Arguments
208    ///
209    /// * `axis` - axis along which to operate. optional, if None, input is flattened
210    //
211    /// # Examples
212    ///
213    /// ```
214    /// use arr_rs::prelude::*;
215    ///
216    /// let arr = Array::flat(vec![1., 2., 3., 4., f64::NAN]);
217    /// assert_eq!(Array::single(1.), arr.nanmin(None));
218    /// ```
219    ///
220    /// # Errors
221    ///
222    /// may returns `ArrayError`
223    fn nanmin(&self, axis: Option<isize>) -> Result<Array<N>, ArrayError>;
224}
225
226impl <N: Numeric> ArrayExtrema<N> for Array<N> {
227
228    fn maximum(&self, other: &Self) -> Result<Self, ArrayError> {
229        self.zip(other)?
230            .map(|item| {
231                if item.0.to_f64().is_nan() || item.1.to_f64().is_nan() { N::from(f64::NAN) }
232                else { N::from(f64::max(item.0.to_f64(), item.1.to_f64())) }
233            })
234    }
235
236    fn max(&self, axis: Option<isize>) -> Result<Self, ArrayError> {
237        match axis {
238            Some(axis) => {
239                let axis = self.normalize_axis(axis);
240                let result = self.apply_along_axis(axis, |arr| arr.max(None));
241                result.reshape(&result.get_shape()?.remove_at_if(axis, result.ndim()? > 1))
242            },
243            None => {
244                if self.to_array_f64().get_elements()?.iter().any(ArrayElement::is_nan) {
245                    Self::single(N::from(f64::NAN))
246                } else {
247                    let result = self.into_iter().fold(self[0], |a, &b| if a < b { b } else { a });
248                    Self::single(result)
249                }
250            }
251        }
252    }
253
254    fn amax(&self, axis: Option<isize>) -> Result<Self, ArrayError> {
255        self.max(axis)
256    }
257
258    fn fmax(&self, other: &Self) -> Result<Self, ArrayError> {
259        self.zip(other)?
260            .map(|item| N::from(f64::max(item.0.to_f64(), item.1.to_f64())))
261    }
262
263    fn nanmax(&self, axis: Option<isize>) -> Result<Self, ArrayError> {
264        match axis {
265            Some(axis) => {
266                let axis = self.normalize_axis(axis);
267                let result = self.apply_along_axis(axis, |arr| arr.nanmax(None));
268                result.reshape(&result.get_shape()?.remove_at_if(axis, result.ndim()? > 1))
269            },
270            None => {
271                if self.to_array_f64().get_elements()?.iter().all(ArrayElement::is_nan) {
272                    Self::single(N::from(f64::NAN))
273                } else {
274                    let filtered = self.get_elements()?.into_iter().filter(|i| !i.to_f64().is_nan()).collect::<Self>();
275                    let result = filtered.fold(filtered[0], |&a, &b| if a < b { b } else { a })?;
276                    Self::single(result)
277                }
278            }
279        }
280    }
281
282    fn minimum(&self, other: &Self) -> Result<Self, ArrayError> {
283        self.zip(other)?
284            .map(|item| {
285                if item.0.to_f64().is_nan() || item.1.to_f64().is_nan() { N::from(f64::NAN) }
286                else { N::from(f64::min(item.0.to_f64(), item.1.to_f64())) }
287            })
288    }
289
290    fn min(&self, axis: Option<isize>) -> Result<Self, ArrayError> {
291        if let Some(axis) = axis {
292            let axis = self.normalize_axis(axis);
293            let result = self.apply_along_axis(axis, |arr| arr.min(None));
294            result.reshape(&result.get_shape()?.remove_at_if(axis, result.ndim()? > 1))
295        } else {
296            if self.to_array_f64().get_elements()?.iter().any(ArrayElement::is_nan) { return Self::single(N::from(f64::NAN)) }
297            let result = self.into_iter().fold(self[0], |a, &b| if a > b { b } else { a });
298            Self::single(result)
299        }
300    }
301
302    fn amin(&self, axis: Option<isize>) -> Result<Self, ArrayError> {
303        self.min(axis)
304    }
305
306    fn fmin(&self, other: &Self) -> Result<Self, ArrayError> {
307        self.zip(other)?
308            .map(|item| N::from(f64::min(item.0.to_f64(), item.1.to_f64())))
309    }
310
311    fn nanmin(&self, axis: Option<isize>) -> Result<Self, ArrayError> {
312        match axis {
313            Some(axis) => {
314                let axis = self.normalize_axis(axis);
315                let result = self.apply_along_axis(axis, |arr| arr.nanmin(None));
316                result.reshape(&result.get_shape()?.remove_at_if(axis, result.ndim()? > 1))
317            },
318            None => {
319                if self.to_array_f64().get_elements()?.iter().all(ArrayElement::is_nan) {
320                    Self::single(N::from(f64::NAN))
321                } else {
322                    let filtered = self.get_elements()?.into_iter().filter(|i| !i.to_f64().is_nan()).collect::<Self>();
323                    let result = filtered.fold(filtered[0], |&a, &b| if a > b { b } else { a })?;
324                    Self::single(result)
325                }
326            }
327        }
328    }
329}
330
331impl <N: Numeric> ArrayExtrema<N> for Result<Array<N>, ArrayError> {
332
333    fn maximum(&self, other: &Array<N>) -> Self {
334        self.clone()?.maximum(other)
335    }
336
337    fn max(&self, axis: Option<isize>) -> Self {
338        self.clone()?.max(axis)
339    }
340
341    fn amax(&self, axis: Option<isize>) -> Self {
342        self.clone()?.amax(axis)
343    }
344
345    fn fmax(&self, other: &Array<N>) -> Self {
346        self.clone()?.fmax(other)
347    }
348
349    fn nanmax(&self, axis: Option<isize>) -> Self {
350        self.clone()?.nanmax(axis)
351    }
352
353    fn minimum(&self, other: &Array<N>) -> Self {
354        self.clone()?.minimum(other)
355    }
356
357    fn min(&self, axis: Option<isize>) -> Self {
358        self.clone()?.min(axis)
359    }
360
361    fn amin(&self, axis: Option<isize>) -> Self {
362        self.clone()?.amin(axis)
363    }
364
365    fn fmin(&self, other: &Array<N>) -> Self {
366        self.clone()?.fmin(other)
367    }
368
369    fn nanmin(&self, axis: Option<isize>) -> Self {
370        self.clone()?.nanmin(axis)
371    }
372}