arr_rs/core/operations/
reorder.rs1use std::collections::HashMap;
2
3use crate::{
4 core::prelude::*,
5 errors::prelude::*,
6 extensions::prelude::*,
7 validators::prelude::*,
8};
9use crate::prelude::Numeric;
10
11pub trait ArrayReorder<T: ArrayElement> where Self: Sized + Clone {
13
14 fn flip(&self, axes: Option<Vec<isize>>) -> Result<Array<T>, ArrayError>;
33
34 fn flipud(&self) -> Result<Array<T>, ArrayError>;
49
50 fn fliplr(&self) -> Result<Array<T>, ArrayError>;
65
66 fn roll(&self, shift: Vec<isize>, axes: Option<Vec<isize>>) -> Result<Array<T>, ArrayError>;
88
89 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}