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}