1use crate::array::owned::Array;
6use crate::dimension::{Dimension, Ix1, IxDyn};
7use crate::dtype::Element;
8use crate::error::{FerrayError, FerrayResult};
9
10#[derive(Debug, Clone)]
16pub enum PadMode<T: Element> {
17 Constant(T),
19 Edge,
21 Reflect,
24 Symmetric,
26 Wrap,
28}
29
30pub fn pad_1d<T: Element>(
40 a: &Array<T, Ix1>,
41 pad_width: (usize, usize),
42 mode: &PadMode<T>,
43) -> FerrayResult<Array<T, Ix1>> {
44 let n = a.shape()[0];
45 let (before, after) = pad_width;
46 let new_len = before + n + after;
47 let src: Vec<T> = a.iter().cloned().collect();
48
49 if n == 0 && !matches!(mode, PadMode::Constant(_)) {
50 return Err(FerrayError::invalid_value(
51 "pad: cannot use Edge/Reflect/Symmetric/Wrap mode on empty array",
52 ));
53 }
54
55 let mut data = Vec::with_capacity(new_len);
56
57 for i in 0..before {
65 let logical_idx = -((before - i) as isize);
66 let val = match mode {
67 PadMode::Constant(c) => c.clone(),
68 PadMode::Edge => src[0].clone(),
69 PadMode::Reflect => src[reflect_index(logical_idx, n)].clone(),
70 PadMode::Symmetric => src[symmetric_index(logical_idx, n)].clone(),
71 PadMode::Wrap => {
72 let m = n as isize;
75 let idx = ((logical_idx % m) + m) % m;
76 src[idx as usize].clone()
77 }
78 };
79 data.push(val);
80 }
81
82 data.extend_from_slice(&src);
84
85 for i in 0..after {
87 let val = match mode {
88 PadMode::Constant(c) => c.clone(),
89 PadMode::Edge => src[n - 1].clone(),
90 PadMode::Reflect => {
91 let idx = reflect_index(n as isize + i as isize, n);
92 src[idx].clone()
93 }
94 PadMode::Symmetric => {
95 let idx = symmetric_index(n as isize + i as isize, n);
96 src[idx].clone()
97 }
98 PadMode::Wrap => {
99 let idx = i % n;
100 src[idx].clone()
101 }
102 };
103 data.push(val);
104 }
105
106 Array::from_vec(Ix1::new([new_len]), data)
107}
108
109const fn reflect_index(idx: isize, n: usize) -> usize {
112 if n <= 1 {
113 return 0;
114 }
115 let period = (n - 1) as isize * 2;
116 let mut i = idx % period;
117 if i < 0 {
118 i += period;
119 }
120 if i >= n as isize {
121 i = period - i;
122 }
123 i as usize
124}
125
126fn symmetric_index(idx: isize, n: usize) -> usize {
129 if n == 0 {
130 return 0;
131 }
132 if n == 1 {
133 return 0;
134 }
135 let period = n as isize * 2;
136 let mut i = idx % period;
137 if i < 0 {
138 i += period;
139 }
140 if i >= n as isize {
141 i = period - 1 - i;
142 }
143 i.max(0) as usize
144}
145
146pub fn pad<T: Element, D: Dimension>(
156 a: &Array<T, D>,
157 pad_width: &[(usize, usize)],
158 mode: &PadMode<T>,
159) -> FerrayResult<Array<T, IxDyn>> {
160 if pad_width.is_empty() {
161 return Err(FerrayError::invalid_value("pad: pad_width cannot be empty"));
162 }
163
164 let shape = a.shape();
165 let ndim = shape.len();
166
167 let pads: Vec<(usize, usize)> = (0..ndim)
169 .map(|i| {
170 if i < pad_width.len() {
171 pad_width[i]
172 } else {
173 *pad_width.last().unwrap_or_else(|| unreachable!())
175 }
176 })
177 .collect();
178
179 let mut current_data: Vec<T> = a.iter().cloned().collect();
182 let mut current_shape: Vec<usize> = shape.to_vec();
183
184 for ax in (0..ndim).rev() {
185 let (before, after) = pads[ax];
186 if before == 0 && after == 0 {
187 continue;
188 }
189 let axis_len = current_shape[ax];
190 let new_axis_len = before + axis_len + after;
191
192 let outer: usize = current_shape[..ax].iter().product();
194 let inner: usize = current_shape[ax + 1..].iter().product();
195
196 let new_total = outer * new_axis_len * inner;
197 let mut new_data = Vec::with_capacity(new_total);
198
199 for o in 0..outer {
200 for j in 0..new_axis_len {
201 for k in 0..inner {
202 let val = if j < before {
203 match mode {
205 PadMode::Constant(c) => c.clone(),
206 PadMode::Edge => {
207 let src_j = 0;
208 current_data[o * axis_len * inner + src_j * inner + k].clone()
209 }
210 PadMode::Reflect => {
211 let src_j =
212 reflect_index(before as isize - 1 - j as isize, axis_len);
213 current_data[o * axis_len * inner + src_j * inner + k].clone()
214 }
215 PadMode::Symmetric => {
216 let src_j =
217 symmetric_index(before as isize - 1 - j as isize, axis_len);
218 current_data[o * axis_len * inner + src_j * inner + k].clone()
219 }
220 PadMode::Wrap => {
221 let src_j = ((axis_len as isize
222 - (before as isize - j as isize) % axis_len as isize)
223 % axis_len as isize)
224 as usize;
225 current_data[o * axis_len * inner + src_j * inner + k].clone()
226 }
227 }
228 } else if j < before + axis_len {
229 let src_j = j - before;
231 current_data[o * axis_len * inner + src_j * inner + k].clone()
232 } else {
233 let after_idx = j - before - axis_len;
235 match mode {
236 PadMode::Constant(c) => c.clone(),
237 PadMode::Edge => {
238 let src_j = axis_len - 1;
239 current_data[o * axis_len * inner + src_j * inner + k].clone()
240 }
241 PadMode::Reflect => {
242 let src_j = reflect_index(
243 (axis_len as isize) + after_idx as isize,
244 axis_len,
245 );
246 current_data[o * axis_len * inner + src_j * inner + k].clone()
247 }
248 PadMode::Symmetric => {
249 let src_j = symmetric_index(
250 (axis_len as isize) + after_idx as isize,
251 axis_len,
252 );
253 current_data[o * axis_len * inner + src_j * inner + k].clone()
254 }
255 PadMode::Wrap => {
256 let src_j = after_idx % axis_len;
257 current_data[o * axis_len * inner + src_j * inner + k].clone()
258 }
259 }
260 };
261 new_data.push(val);
262 }
263 }
264 }
265
266 current_data = new_data;
267 current_shape[ax] = new_axis_len;
268 }
269
270 Array::from_vec(IxDyn::new(¤t_shape), current_data)
271}
272
273pub fn tile<T: Element, D: Dimension>(
283 a: &Array<T, D>,
284 reps: &[usize],
285) -> FerrayResult<Array<T, IxDyn>> {
286 if reps.is_empty() {
287 return Err(FerrayError::invalid_value("tile: reps cannot be empty"));
288 }
289
290 let src_shape = a.shape();
291 let src_ndim = src_shape.len();
292 let reps_ndim = reps.len();
293 let out_ndim = src_ndim.max(reps_ndim);
294
295 let mut padded_shape = vec![1usize; out_ndim];
297 for i in 0..src_ndim {
298 padded_shape[out_ndim - src_ndim + i] = src_shape[i];
299 }
300 let mut padded_reps = vec![1usize; out_ndim];
301 for i in 0..reps_ndim {
302 padded_reps[out_ndim - reps_ndim + i] = reps[i];
303 }
304
305 let out_shape: Vec<usize> = padded_shape
306 .iter()
307 .zip(padded_reps.iter())
308 .map(|(&s, &r)| s * r)
309 .collect();
310 let total: usize = out_shape.iter().product();
311
312 let src_data: Vec<T> = a.iter().cloned().collect();
313 let mut data = Vec::with_capacity(total);
314
315 let mut out_strides = vec![1usize; out_ndim];
317 for i in (0..out_ndim.saturating_sub(1)).rev() {
318 out_strides[i] = out_strides[i + 1] * out_shape[i + 1];
319 }
320
321 let mut src_strides = vec![1usize; out_ndim];
322 for i in (0..out_ndim.saturating_sub(1)).rev() {
323 src_strides[i] = src_strides[i + 1] * padded_shape[i + 1];
324 }
325
326 for flat in 0..total {
327 let mut rem = flat;
328 let mut src_flat = 0usize;
329 for i in 0..out_ndim {
330 let idx = rem / out_strides[i];
331 rem %= out_strides[i];
332 let src_idx = idx % padded_shape[i];
333 src_flat += src_idx * src_strides[i];
334 }
335 if src_flat < src_data.len() {
338 data.push(src_data[src_flat].clone());
339 } else {
340 data.push(T::zero());
342 }
343 }
344
345 Array::from_vec(IxDyn::new(&out_shape), data)
346}
347
348pub fn repeat<T: Element, D: Dimension>(
358 a: &Array<T, D>,
359 repeats: usize,
360 axis: Option<usize>,
361) -> FerrayResult<Array<T, IxDyn>> {
362 match axis {
363 None => {
364 let src: Vec<T> = a.iter().cloned().collect();
366 let mut data = Vec::with_capacity(src.len() * repeats);
367 for val in &src {
368 for _ in 0..repeats {
369 data.push(val.clone());
370 }
371 }
372 let n = data.len();
373 Array::from_vec(IxDyn::new(&[n]), data)
374 }
375 Some(ax) => {
376 let shape = a.shape();
377 let ndim = shape.len();
378 if ax >= ndim {
379 return Err(FerrayError::axis_out_of_bounds(ax, ndim));
380 }
381
382 let mut new_shape = shape.to_vec();
383 new_shape[ax] *= repeats;
384 let total: usize = new_shape.iter().product();
385 let src_data: Vec<T> = a.iter().cloned().collect();
386
387 let mut src_strides = vec![1usize; ndim];
389 for i in (0..ndim.saturating_sub(1)).rev() {
390 src_strides[i] = src_strides[i + 1] * shape[i + 1];
391 }
392
393 let mut out_strides = vec![1usize; ndim];
395 for i in (0..ndim.saturating_sub(1)).rev() {
396 out_strides[i] = out_strides[i + 1] * new_shape[i + 1];
397 }
398
399 let mut data = Vec::with_capacity(total);
400 for flat in 0..total {
401 let mut rem = flat;
402 let mut src_flat = 0usize;
403 for i in 0..ndim {
404 let idx = rem / out_strides[i];
405 rem %= out_strides[i];
406 let src_idx = if i == ax { idx / repeats } else { idx };
407 src_flat += src_idx * src_strides[i];
408 }
409 data.push(src_data[src_flat].clone());
410 }
411
412 Array::from_vec(IxDyn::new(&new_shape), data)
413 }
414 }
415}
416
417pub fn delete<T: Element, D: Dimension>(
427 a: &Array<T, D>,
428 indices: &[usize],
429 axis: usize,
430) -> FerrayResult<Array<T, IxDyn>> {
431 let shape = a.shape();
432 let ndim = shape.len();
433 if axis >= ndim {
434 return Err(FerrayError::axis_out_of_bounds(axis, ndim));
435 }
436 let axis_len = shape[axis];
437
438 for &idx in indices {
440 if idx >= axis_len {
441 return Err(FerrayError::IndexOutOfBounds {
442 index: idx as isize,
443 axis,
444 size: axis_len,
445 });
446 }
447 }
448
449 let to_remove: std::collections::HashSet<usize> = indices.iter().copied().collect();
450 let kept: Vec<usize> = (0..axis_len).filter(|i| !to_remove.contains(i)).collect();
451 let new_axis_len = kept.len();
452
453 let mut new_shape = shape.to_vec();
454 new_shape[axis] = new_axis_len;
455 let total: usize = new_shape.iter().product();
456 let src_data: Vec<T> = a.iter().cloned().collect();
457
458 let mut src_strides = vec![1usize; ndim];
460 for i in (0..ndim.saturating_sub(1)).rev() {
461 src_strides[i] = src_strides[i + 1] * shape[i + 1];
462 }
463
464 let mut out_strides = vec![1usize; ndim];
466 for i in (0..ndim.saturating_sub(1)).rev() {
467 out_strides[i] = out_strides[i + 1] * new_shape[i + 1];
468 }
469
470 let mut data = Vec::with_capacity(total);
471 for flat in 0..total {
472 let mut rem = flat;
473 let mut src_flat = 0usize;
474 for i in 0..ndim {
475 let idx = rem / out_strides[i];
476 rem %= out_strides[i];
477 let src_idx = if i == axis { kept[idx] } else { idx };
478 src_flat += src_idx * src_strides[i];
479 }
480 data.push(src_data[src_flat].clone());
481 }
482
483 Array::from_vec(IxDyn::new(&new_shape), data)
484}
485
486pub fn insert<T: Element, D: Dimension>(
497 a: &Array<T, D>,
498 index: usize,
499 values: &Array<T, IxDyn>,
500 axis: usize,
501) -> FerrayResult<Array<T, IxDyn>> {
502 let shape = a.shape();
503 let ndim = shape.len();
504 if axis >= ndim {
505 return Err(FerrayError::axis_out_of_bounds(axis, ndim));
506 }
507 let axis_len = shape[axis];
508 if index > axis_len {
509 return Err(FerrayError::IndexOutOfBounds {
510 index: index as isize,
511 axis,
512 size: axis_len + 1,
513 });
514 }
515
516 let n_insert = values.size();
517 let vals: Vec<T> = values.iter().cloned().collect();
518
519 let mut new_shape = shape.to_vec();
520 new_shape[axis] = axis_len + n_insert;
521 let total: usize = new_shape.iter().product();
522 let src_data: Vec<T> = a.iter().cloned().collect();
523
524 let mut src_strides = vec![1usize; ndim];
526 for i in (0..ndim.saturating_sub(1)).rev() {
527 src_strides[i] = src_strides[i + 1] * shape[i + 1];
528 }
529
530 let mut out_strides = vec![1usize; ndim];
531 for i in (0..ndim.saturating_sub(1)).rev() {
532 out_strides[i] = out_strides[i + 1] * new_shape[i + 1];
533 }
534
535 let inner: usize = shape[axis + 1..].iter().product();
537
538 let mut data = Vec::with_capacity(total);
539 for flat in 0..total {
540 let mut rem = flat;
541 let mut nd_idx = vec![0usize; ndim];
542 for i in 0..ndim {
543 nd_idx[i] = rem / out_strides[i];
544 rem %= out_strides[i];
545 }
546
547 let ax_idx = nd_idx[axis];
548 if ax_idx >= index && ax_idx < index + n_insert {
549 let insert_idx = ax_idx - index;
551 let val_idx = (insert_idx * inner + nd_idx.get(axis + 1).copied().unwrap_or(0))
553 % vals.len().max(1);
554 data.push(vals[val_idx].clone());
555 } else {
556 let src_ax_idx = if ax_idx >= index + n_insert {
558 ax_idx - n_insert
559 } else {
560 ax_idx
561 };
562 let mut src_flat = 0usize;
563 for i in 0..ndim {
564 let idx = if i == axis { src_ax_idx } else { nd_idx[i] };
565 src_flat += idx * src_strides[i];
566 }
567 data.push(src_data[src_flat].clone());
568 }
569 }
570
571 Array::from_vec(IxDyn::new(&new_shape), data)
572}
573
574pub fn append<T: Element, D: Dimension>(
580 a: &Array<T, D>,
581 values: &Array<T, IxDyn>,
582 axis: Option<usize>,
583) -> FerrayResult<Array<T, IxDyn>> {
584 match axis {
585 None => {
586 let mut data: Vec<T> = a.iter().cloned().collect();
587 data.extend(values.iter().cloned());
588 let n = data.len();
589 Array::from_vec(IxDyn::new(&[n]), data)
590 }
591 Some(ax) => {
592 let a_dyn = {
593 let data: Vec<T> = a.iter().cloned().collect();
594 Array::from_vec(IxDyn::new(a.shape()), data)?
595 };
596 let vals_dyn = {
597 let data: Vec<T> = values.iter().cloned().collect();
598 Array::from_vec(IxDyn::new(values.shape()), data)?
599 };
600 super::concatenate(&[a_dyn, vals_dyn], ax)
601 }
602 }
603}
604
605pub fn resize<T: Element, D: Dimension>(
612 a: &Array<T, D>,
613 new_shape: &[usize],
614) -> FerrayResult<Array<T, IxDyn>> {
615 let src: Vec<T> = a.iter().cloned().collect();
616 let new_size: usize = new_shape.iter().product();
617
618 if src.is_empty() {
619 let data = vec![T::zero(); new_size];
621 return Array::from_vec(IxDyn::new(new_shape), data);
622 }
623
624 let mut data = Vec::with_capacity(new_size);
625 for i in 0..new_size {
626 data.push(src[i % src.len()].clone());
627 }
628 Array::from_vec(IxDyn::new(new_shape), data)
629}
630
631pub fn trim_zeros<T: Element + PartialEq>(
640 a: &Array<T, Ix1>,
641 trim: &str,
642) -> FerrayResult<Array<T, Ix1>> {
643 let data: Vec<T> = a.iter().cloned().collect();
644 let zero = T::zero();
645
646 let trim_front = trim.contains('f');
647 let trim_back = trim.contains('b');
648
649 if !trim.chars().all(|c| c == 'f' || c == 'b') {
650 return Err(FerrayError::invalid_value(
651 "trim_zeros: trim must contain only 'f' and/or 'b'",
652 ));
653 }
654
655 let start = if trim_front {
656 data.iter().position(|v| *v != zero).unwrap_or(data.len())
657 } else {
658 0
659 };
660
661 let end = if trim_back {
662 data.iter()
663 .rposition(|v| *v != zero)
664 .map_or(start, |i| i + 1)
665 } else {
666 data.len()
667 };
668
669 let end = end.max(start);
670 let trimmed: Vec<T> = data[start..end].to_vec();
671 let n = trimmed.len();
672 Array::from_vec(Ix1::new([n]), trimmed)
673}
674
675pub fn atleast_1d<T: Element, D: Dimension>(a: &Array<T, D>) -> FerrayResult<Array<T, IxDyn>> {
686 let shape = a.shape();
687 let data: Vec<T> = a.iter().cloned().collect();
688 let new_shape: Vec<usize> = if shape.is_empty() {
689 vec![1]
690 } else {
691 shape.to_vec()
692 };
693 Array::from_vec(IxDyn::new(&new_shape), data)
694}
695
696pub fn atleast_2d<T: Element, D: Dimension>(a: &Array<T, D>) -> FerrayResult<Array<T, IxDyn>> {
703 let shape = a.shape();
704 let data: Vec<T> = a.iter().cloned().collect();
705 let new_shape: Vec<usize> = match shape.len() {
706 0 => vec![1, 1],
707 1 => vec![1, shape[0]],
708 _ => shape.to_vec(),
709 };
710 Array::from_vec(IxDyn::new(&new_shape), data)
711}
712
713pub fn atleast_3d<T: Element, D: Dimension>(a: &Array<T, D>) -> FerrayResult<Array<T, IxDyn>> {
721 let shape = a.shape();
722 let data: Vec<T> = a.iter().cloned().collect();
723 let new_shape: Vec<usize> = match shape.len() {
724 0 => vec![1, 1, 1],
725 1 => vec![1, shape[0], 1],
726 2 => vec![shape[0], shape[1], 1],
727 _ => shape.to_vec(),
728 };
729 Array::from_vec(IxDyn::new(&new_shape), data)
730}
731
732#[cfg(test)]
737mod tests {
738 use super::*;
739
740 fn dyn_arr(shape: &[usize], data: Vec<f64>) -> Array<f64, IxDyn> {
741 Array::from_vec(IxDyn::new(shape), data).unwrap()
742 }
743
744 fn arr1d(data: Vec<f64>) -> Array<f64, Ix1> {
745 let n = data.len();
746 Array::from_vec(Ix1::new([n]), data).unwrap()
747 }
748
749 #[test]
752 fn test_pad_1d_constant() {
753 let a = arr1d(vec![1.0, 2.0, 3.0]);
754 let b = pad_1d(&a, (2, 3), &PadMode::Constant(0.0)).unwrap();
755 assert_eq!(b.shape(), &[8]);
756 let data: Vec<f64> = b.iter().copied().collect();
757 assert_eq!(data, vec![0.0, 0.0, 1.0, 2.0, 3.0, 0.0, 0.0, 0.0]);
758 }
759
760 #[test]
761 fn test_pad_1d_edge() {
762 let a = arr1d(vec![1.0, 2.0, 3.0]);
763 let b = pad_1d(&a, (2, 2), &PadMode::Edge).unwrap();
764 let data: Vec<f64> = b.iter().copied().collect();
765 assert_eq!(data, vec![1.0, 1.0, 1.0, 2.0, 3.0, 3.0, 3.0]);
766 }
767
768 #[test]
769 fn test_pad_1d_wrap() {
770 let a = arr1d(vec![1.0, 2.0, 3.0]);
771 let b = pad_1d(&a, (2, 2), &PadMode::Wrap).unwrap();
772 let data: Vec<f64> = b.iter().copied().collect();
773 assert_eq!(data, vec![2.0, 3.0, 1.0, 2.0, 3.0, 1.0, 2.0]);
774 }
775
776 #[test]
779 fn test_pad_1d_reflect_three_element_array() {
780 let a = arr1d(vec![1.0, 2.0, 3.0]);
783 let b = pad_1d(&a, (2, 2), &PadMode::Reflect).unwrap();
784 let data: Vec<f64> = b.iter().copied().collect();
785 assert_eq!(data, vec![3.0, 2.0, 1.0, 2.0, 3.0, 2.0, 1.0]);
786 }
787
788 #[test]
789 fn test_pad_1d_reflect_two_element_array() {
790 let a = arr1d(vec![1.0, 2.0]);
792 let b = pad_1d(&a, (2, 2), &PadMode::Reflect).unwrap();
793 let data: Vec<f64> = b.iter().copied().collect();
794 assert_eq!(b.shape(), &[6]);
807 for v in &data {
808 assert!(
809 *v == 1.0 || *v == 2.0,
810 "Reflect produced unexpected value {v}"
811 );
812 }
813 }
814
815 #[test]
816 fn test_pad_1d_symmetric_three_element_array() {
817 let a = arr1d(vec![1.0, 2.0, 3.0]);
820 let b = pad_1d(&a, (2, 2), &PadMode::Symmetric).unwrap();
821 let data: Vec<f64> = b.iter().copied().collect();
822 assert_eq!(data, vec![2.0, 1.0, 1.0, 2.0, 3.0, 3.0, 2.0]);
823 }
824
825 #[test]
826 fn test_pad_1d_symmetric_single_element() {
827 let a = arr1d(vec![5.0]);
830 let b = pad_1d(&a, (3, 2), &PadMode::Symmetric).unwrap();
831 let data: Vec<f64> = b.iter().copied().collect();
832 assert_eq!(data, vec![5.0; 6]);
833 }
834
835 #[test]
836 fn test_pad_nd_constant() {
837 let a = dyn_arr(&[2, 2], vec![1.0, 2.0, 3.0, 4.0]);
838 let b = pad(&a, &[(1, 1), (1, 1)], &PadMode::Constant(0.0)).unwrap();
839 assert_eq!(b.shape(), &[4, 4]);
840 let data: Vec<f64> = b.iter().copied().collect();
841 assert_eq!(
842 data,
843 vec![
844 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 0.0, 0.0, 3.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0
845 ]
846 );
847 }
848
849 #[test]
852 fn test_tile_1d() {
853 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
854 let b = tile(&a, &[3]).unwrap();
855 assert_eq!(b.shape(), &[9]);
856 let data: Vec<f64> = b.iter().copied().collect();
857 assert_eq!(data, vec![1.0, 2.0, 3.0, 1.0, 2.0, 3.0, 1.0, 2.0, 3.0]);
858 }
859
860 #[test]
861 fn test_tile_2d() {
862 let a = dyn_arr(&[2], vec![1.0, 2.0]);
863 let b = tile(&a, &[2, 3]).unwrap();
864 assert_eq!(b.shape(), &[2, 6]);
865 }
866
867 #[test]
870 fn test_repeat_flat() {
871 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
872 let b = repeat(&a, 2, None).unwrap();
873 let data: Vec<f64> = b.iter().copied().collect();
874 assert_eq!(data, vec![1.0, 1.0, 2.0, 2.0, 3.0, 3.0]);
875 }
876
877 #[test]
878 fn test_repeat_axis() {
879 let a = dyn_arr(&[2, 2], vec![1.0, 2.0, 3.0, 4.0]);
880 let b = repeat(&a, 2, Some(0)).unwrap();
881 assert_eq!(b.shape(), &[4, 2]);
882 let data: Vec<f64> = b.iter().copied().collect();
883 assert_eq!(data, vec![1.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, 4.0]);
884 }
885
886 #[test]
889 fn test_delete() {
890 let a = dyn_arr(&[5], vec![1.0, 2.0, 3.0, 4.0, 5.0]);
891 let b = delete(&a, &[1, 3], 0).unwrap();
892 let data: Vec<f64> = b.iter().copied().collect();
893 assert_eq!(data, vec![1.0, 3.0, 5.0]);
894 }
895
896 #[test]
897 fn test_delete_2d() {
898 let a = dyn_arr(&[3, 2], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
899 let b = delete(&a, &[1], 0).unwrap();
900 assert_eq!(b.shape(), &[2, 2]);
901 let data: Vec<f64> = b.iter().copied().collect();
902 assert_eq!(data, vec![1.0, 2.0, 5.0, 6.0]);
903 }
904
905 #[test]
908 fn test_insert() {
909 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
910 let vals = dyn_arr(&[2], vec![10.0, 20.0]);
911 let b = insert(&a, 1, &vals, 0).unwrap();
912 let data: Vec<f64> = b.iter().copied().collect();
913 assert_eq!(data, vec![1.0, 10.0, 20.0, 2.0, 3.0]);
914 }
915
916 #[test]
919 fn test_append_flat() {
920 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
921 let vals = dyn_arr(&[2], vec![4.0, 5.0]);
922 let b = append(&a, &vals, None).unwrap();
923 let data: Vec<f64> = b.iter().copied().collect();
924 assert_eq!(data, vec![1.0, 2.0, 3.0, 4.0, 5.0]);
925 }
926
927 #[test]
928 fn test_append_axis() {
929 let a = dyn_arr(&[2, 2], vec![1.0, 2.0, 3.0, 4.0]);
930 let vals = dyn_arr(&[2, 1], vec![5.0, 6.0]);
931 let b = append(&a, &vals, Some(1)).unwrap();
932 assert_eq!(b.shape(), &[2, 3]);
933 }
934
935 #[test]
938 fn test_resize_larger() {
939 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
940 let b = resize(&a, &[5]).unwrap();
941 let data: Vec<f64> = b.iter().copied().collect();
942 assert_eq!(data, vec![1.0, 2.0, 3.0, 1.0, 2.0]);
943 }
944
945 #[test]
946 fn test_resize_smaller() {
947 let a = dyn_arr(&[5], vec![1.0, 2.0, 3.0, 4.0, 5.0]);
948 let b = resize(&a, &[3]).unwrap();
949 let data: Vec<f64> = b.iter().copied().collect();
950 assert_eq!(data, vec![1.0, 2.0, 3.0]);
951 }
952
953 #[test]
954 fn test_resize_2d() {
955 let a = dyn_arr(&[2, 2], vec![1.0, 2.0, 3.0, 4.0]);
956 let b = resize(&a, &[3, 3]).unwrap();
957 assert_eq!(b.shape(), &[3, 3]);
958 }
959
960 #[test]
963 fn test_trim_zeros_both() {
964 let a = arr1d(vec![0.0, 0.0, 1.0, 2.0, 3.0, 0.0, 0.0]);
965 let b = trim_zeros(&a, "fb").unwrap();
966 let data: Vec<f64> = b.iter().copied().collect();
967 assert_eq!(data, vec![1.0, 2.0, 3.0]);
968 }
969
970 #[test]
971 fn test_trim_zeros_front() {
972 let a = arr1d(vec![0.0, 0.0, 1.0, 2.0, 0.0]);
973 let b = trim_zeros(&a, "f").unwrap();
974 let data: Vec<f64> = b.iter().copied().collect();
975 assert_eq!(data, vec![1.0, 2.0, 0.0]);
976 }
977
978 #[test]
979 fn test_trim_zeros_back() {
980 let a = arr1d(vec![0.0, 1.0, 2.0, 0.0, 0.0]);
981 let b = trim_zeros(&a, "b").unwrap();
982 let data: Vec<f64> = b.iter().copied().collect();
983 assert_eq!(data, vec![0.0, 1.0, 2.0]);
984 }
985
986 #[test]
987 fn test_trim_zeros_all_zeros() {
988 let a = arr1d(vec![0.0, 0.0, 0.0]);
989 let b = trim_zeros(&a, "fb").unwrap();
990 assert_eq!(b.shape(), &[0]);
991 }
992
993 #[test]
994 fn test_trim_zeros_bad_mode() {
995 let a = arr1d(vec![1.0, 2.0]);
996 assert!(trim_zeros(&a, "x").is_err());
997 }
998
999 #[test]
1002 fn test_atleast_1d_from_scalar() {
1003 let a = Array::from_vec(IxDyn::new(&[]), vec![42.0]).unwrap();
1004 let b = atleast_1d(&a).unwrap();
1005 assert_eq!(b.shape(), &[1]);
1006 assert_eq!(b.iter().copied().collect::<Vec<_>>(), vec![42.0]);
1007 }
1008
1009 #[test]
1010 fn test_atleast_1d_passthrough_1d() {
1011 let a = arr1d(vec![1.0, 2.0, 3.0]);
1012 let b = atleast_1d(&a).unwrap();
1013 assert_eq!(b.shape(), &[3]);
1014 }
1015
1016 #[test]
1017 fn test_atleast_1d_passthrough_2d() {
1018 let a = dyn_arr(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1019 let b = atleast_1d(&a).unwrap();
1020 assert_eq!(b.shape(), &[2, 3]);
1021 }
1022
1023 #[test]
1024 fn test_atleast_2d_from_scalar() {
1025 let a = Array::from_vec(IxDyn::new(&[]), vec![7.0]).unwrap();
1026 let b = atleast_2d(&a).unwrap();
1027 assert_eq!(b.shape(), &[1, 1]);
1028 }
1029
1030 #[test]
1031 fn test_atleast_2d_from_1d() {
1032 let a = arr1d(vec![1.0, 2.0, 3.0]);
1033 let b = atleast_2d(&a).unwrap();
1034 assert_eq!(b.shape(), &[1, 3]);
1035 }
1036
1037 #[test]
1038 fn test_atleast_2d_passthrough_2d() {
1039 let a = dyn_arr(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1040 let b = atleast_2d(&a).unwrap();
1041 assert_eq!(b.shape(), &[2, 3]);
1042 }
1043
1044 #[test]
1045 fn test_atleast_3d_from_scalar() {
1046 let a = Array::from_vec(IxDyn::new(&[]), vec![7.0]).unwrap();
1047 let b = atleast_3d(&a).unwrap();
1048 assert_eq!(b.shape(), &[1, 1, 1]);
1049 }
1050
1051 #[test]
1052 fn test_atleast_3d_from_1d() {
1053 let a = arr1d(vec![1.0, 2.0, 3.0]);
1054 let b = atleast_3d(&a).unwrap();
1055 assert_eq!(b.shape(), &[1, 3, 1]);
1056 }
1057
1058 #[test]
1059 fn test_atleast_3d_from_2d() {
1060 let a = dyn_arr(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1061 let b = atleast_3d(&a).unwrap();
1062 assert_eq!(b.shape(), &[2, 3, 1]);
1063 }
1064
1065 #[test]
1066 fn test_atleast_3d_passthrough_3d() {
1067 let a = dyn_arr(&[2, 2, 2], (0..8).map(|i| i as f64).collect());
1068 let b = atleast_3d(&a).unwrap();
1069 assert_eq!(b.shape(), &[2, 2, 2]);
1070 }
1071}