arr_rs/core/operations/
reorder.rs

1use std::collections::HashMap;
2
3use crate::{
4    core::prelude::*,
5    errors::prelude::*,
6    extensions::prelude::*,
7    validators::prelude::*,
8};
9use crate::prelude::Numeric;
10
11/// `ArrayTrait` - Array Reordering functions
12pub trait ArrayReorder<T: ArrayElement> where Self: Sized + Clone {
13
14    /// Reverse the order of elements in an array along the given axis
15    ///
16    /// # Arguments
17    ///
18    /// * `axes` - axes along which to flip over. if None, will flip over all of the axes.
19    ///
20    /// # Examples
21    ///
22    /// ```
23    /// use arr_rs::prelude::*;
24    ///
25    /// let arr = array_arange!(i32, 0, 7).reshape(&[2, 2, 2]);
26    /// assert_eq!(array!(i32, [[[1, 0], [3, 2]], [[5, 4], [7, 6]]]), arr.flip(Some(vec![2])));
27    /// ```
28    ///
29    /// # Errors
30    ///
31    /// may returns `ArrayError`
32    fn flip(&self, axes: Option<Vec<isize>>) -> Result<Array<T>, ArrayError>;
33
34    /// Reverse the order of elements along axis 0 (up/down)
35    ///
36    /// # Examples
37    ///
38    /// ```
39    /// use arr_rs::prelude::*;
40    ///
41    /// let arr = array_arange!(i32, 0, 7).reshape(&[2, 2, 2]);
42    /// assert_eq!(array!(i32, [[[4, 5], [6, 7]], [[0, 1], [2, 3]]]), arr.flipud());
43    /// ```
44    ///
45    /// # Errors
46    ///
47    /// may returns `ArrayError`
48    fn flipud(&self) -> Result<Array<T>, ArrayError>;
49
50    /// Reverse the order of elements along axis 1 (left/right)
51    ///
52    /// # Examples
53    ///
54    /// ```
55    /// use arr_rs::prelude::*;
56    ///
57    /// let arr = array_arange!(i32, 0, 7).reshape(&[2, 2, 2]);
58    /// assert_eq!(array!(i32, [[[2, 3], [0, 1]], [[6, 7], [4, 5]]]), arr.fliplr());
59    /// ```
60    ///
61    /// # Errors
62    ///
63    /// may returns `ArrayError`
64    fn fliplr(&self) -> Result<Array<T>, ArrayError>;
65
66    /// Roll array elements along a given axis
67    ///
68    /// # Arguments
69    ///
70    /// * `shift` - number of places by which elements are shifted.
71    /// if a tuple, then axis must be a tuple of the same size, and each of the given axes is shifted by the corresponding number.
72    /// if an int while axis is a tuple of ints, then the same value is used for all given axes.
73    /// * `axes` - axes along which to roll over. if None, will flip over all of the axes.
74    ///
75    /// # Examples
76    ///
77    /// ```
78    /// use arr_rs::prelude::*;
79    ///
80    /// let arr = array_arange!(i32, 0, 7).reshape(&[2, 2, 2]);
81    /// assert_eq!(array!(i32, [[[4, 5], [6, 7]], [[0, 1], [2, 3]]]), arr.roll(vec![1], Some(vec![0])));
82    /// ```
83    ///
84    /// # Errors
85    ///
86    /// may returns `ArrayError`
87    fn roll(&self, shift: Vec<isize>, axes: Option<Vec<isize>>) -> Result<Array<T>, ArrayError>;
88
89    /// Rotate an array by 90 degrees in the plane specified by axes.
90    /// Rotation direction is from the first towards the second axis.
91    ///
92    /// # Arguments
93    ///
94    /// * `k` - number of times the array is rotated by 90 degrees.
95    /// * `axes` - the array is rotated in the plane defined by the axes. axes must be different.
96    ///
97    /// # Examples
98    ///
99    /// ```
100    /// use arr_rs::prelude::*;
101    ///
102    /// let arr = array_arange!(i32, 0, 7).reshape(&[2, 4]);
103    /// assert_eq!(array!(i32, [[3, 7], [2, 6], [1, 5], [0, 4]]), arr.rot90(1, vec![0, 1]));
104    /// ```
105    ///
106    /// # Errors
107    ///
108    /// may returns `ArrayError`
109    fn rot90(&self, k: usize, axes: Vec<isize>) -> Result<Array<T>, ArrayError>;
110}
111
112impl <T: ArrayElement> ArrayReorder<T> for Array<T> {
113
114    fn flip(&self, axes: Option<Vec<isize>>) -> Result<Self, ArrayError> {
115        match axes {
116            None => Self::new(self.get_elements()?.reverse_ext(), self.get_shape()?),
117            Some(axes) => {
118                let self_shape = self.shape.clone();
119                let axes = axes.into_iter().map(|i| self.normalize_axis(i)).collect::<Vec<usize>>();
120
121                let mut elements = self.elements.clone();
122                for ax in axes {
123                    let flatten = Self::flat(elements);
124                    elements =
125                        if ax == 0 { flatten
126                            .split(self_shape[0], Some(0))?.reverse_ext().into_iter()
127                            .flatten().collect::<Vec<T>>()
128                        } else if ax == self.ndim()? - 1 { flatten
129                            .split(self_shape[0..ax].iter().product(), None)?.iter_mut()
130                            .flat_map(|arr| arr.elements.reverse_ext())
131                            .collect::<Vec<T>>()
132                        } else { flatten
133                            .split(self_shape[ax], None)?.into_iter()
134                            .map(|i| i.reshape(&self.shape.clone().remove_at(ax)))
135                            .map(|i| i.flip(Some(vec![ax.to_isize() - 1])))
136                            .collect::<Vec<Result<Self, _>>>()
137                            .has_error()?.into_iter()
138                            .flat_map(Result::unwrap)
139                            .collect::<Vec<T>>()
140                        }
141                };
142
143                Self::flat(elements).reshape(&self_shape)
144            }
145        }
146    }
147
148    fn flipud(&self) -> Result<Self, ArrayError> {
149        self.is_dim_unsupported(&[0])?;
150        self.clone().flip(Some(vec![0]))
151    }
152
153    fn fliplr(&self) -> Result<Self, ArrayError> {
154        self.is_dim_unsupported(&[0, 1])?;
155        self.clone().flip(Some(vec![1]))
156    }
157
158    fn roll(&self, shift: Vec<isize>, axes: Option<Vec<isize>>) -> Result<Self, ArrayError> {
159        let array = if axes.is_none() { self.ravel()? } else { self.clone() };
160        let axes = axes.unwrap_or_else(|| vec![0]);
161
162        let broadcasted = Array::flat(shift).broadcast(&Array::flat(axes)?)?;
163        if broadcasted.ndim()? > 1 { return Err(ArrayError::ParameterError { param: "'shift' and 'axis'", message: "should be 1D" }); }
164        let broadcasted = broadcasted.into_iter().map(|a| (
165            self.normalize_axis(a.1),
166            a.0,
167        )).collect::<Vec<(usize, isize)>>();
168
169        let mut shifts: HashMap<usize, isize> = HashMap::new();
170        for (a, b) in &broadcasted {
171            *shifts.entry(*a).or_insert(0) += *b;
172        }
173
174
175        let mut elements = array.get_elements()?;
176        match array.ndim()? {
177            0 => Self::empty(),
178            1 => {
179                for &sh in shifts.values() {
180                    if sh >= 0 { elements.rotate_right(sh.to_usize()); }
181                    else { elements.rotate_left(sh.unsigned_abs()); }
182                }
183                Self::flat(elements).reshape(&self.shape)
184            },
185            _ => {
186                for (ax, sh) in shifts.clone() {
187                    let flatten = Self::flat(elements.clone());
188                    elements = if ax == 0 {
189                        let mut split = flatten.split(self.shape[0], Some(0))?;
190                        if sh >= 0 { split.rotate_right(sh.to_usize()); }
191                        else { split.rotate_left(sh.unsigned_abs()); }
192                        split.into_iter().flatten().collect()
193                    } else if ax == array.ndim()? - 1 { flatten
194                        .split(self.shape[0..ax].iter().product(), None)?.iter()
195                        .flat_map(|item| {
196                            let mut tmp_item = item.elements.clone();
197                            if sh >= 0 { tmp_item.rotate_right(sh.to_usize()); }
198                            else { tmp_item.rotate_left(sh.unsigned_abs()); }
199                            tmp_item
200                        }).collect()
201                    } else { flatten
202                        .split(self.shape[ax], None)?.into_iter()
203                        .map(|i| i.reshape(&self.shape.clone().remove_at(ax)))
204                        .map(|i| i.roll(vec![shifts[&ax]], Some(vec![ax.to_isize() - 1])))
205                        .collect::<Vec<Result<Self, _>>>()
206                        .has_error()?.into_iter()
207                        .flat_map(Result::unwrap)
208                        .collect::<Vec<T>>()
209                    }
210                }
211                Self::new(elements, self.shape.clone())
212            }
213        }
214    }
215
216    fn rot90(&self, k: usize, axes: Vec<isize>) -> Result<Self, ArrayError> {
217        self.is_dim_unsupported(&[0, 1])?;
218        if axes.len() != 2 {
219            return Err(ArrayError::ParameterError { param: "axes", message: "axes length must be 2" })
220        }
221        let self_ndim = self.ndim()?.to_isize();
222        if axes[0] >= self_ndim || axes[0] < -self_ndim || axes[1] >= self_ndim || axes[1] < -self_ndim {
223            return Err(ArrayError::ParameterError { param: "axes", message: "out of range" })
224        }
225
226        let k = k % 4;
227        if k == 0 { return Ok(self.clone()) }
228        if k == 2 { return self.flip(Some(vec![axes[1]])).flip(Some(vec![axes[0]])) }
229
230        let axes = axes.into_iter().map(|i| self.normalize_axis(i)).collect::<Vec<usize>>();
231        let mut axes_list = (0..self_ndim).collect::<Vec<isize>>();
232        (axes_list[axes[0]], axes_list[axes[1]]) = (axes_list[axes[1]], axes_list[axes[0]]);
233
234        if k == 1 { self.flip(Some(vec![axes[1].to_isize()])).transpose(Some(axes_list)) }
235        else { self.transpose(Some(axes_list)).flip(Some(vec![axes[1].to_isize()])) }
236    }
237}
238
239impl <T: ArrayElement> ArrayReorder<T> for Result<Array<T>, ArrayError> {
240
241    fn flip(&self, axes: Option<Vec<isize>>) -> Self {
242        self.clone()?.flip(axes)
243    }
244
245    fn flipud(&self) -> Self {
246        self.clone()?.flipud()
247    }
248
249    fn fliplr(&self) -> Self {
250        self.clone()?.fliplr()
251    }
252
253    fn roll(&self, shift: Vec<isize>, axes: Option<Vec<isize>>) -> Self {
254        self.clone()?.roll(shift, axes)
255    }
256
257    fn rot90(&self, k: usize, axes: Vec<isize>) -> Self {
258        self.clone()?.rot90(k, axes)
259    }
260}