1pub mod extended;
21
22use crate::array::owned::Array;
23use crate::dimension::{Dimension, Ix1, IxDyn};
24use crate::dtype::Element;
25use crate::error::{FerrayError, FerrayResult};
26
27pub fn reshape<T: Element, D: Dimension>(
45 a: &Array<T, D>,
46 new_shape: &[usize],
47) -> FerrayResult<Array<T, IxDyn>> {
48 let old_size = a.size();
49 let new_size: usize = new_shape.iter().product();
50 if old_size != new_size {
51 return Err(FerrayError::shape_mismatch(format!(
52 "cannot reshape array of size {old_size} into shape {new_shape:?} (size {new_size})",
53 )));
54 }
55 let view = a.inner.view().into_dyn();
56 let reshaped = view
57 .to_shape(ndarray::IxDyn(new_shape))
58 .map_err(|e| FerrayError::shape_mismatch(e.to_string()))?;
59 Ok(Array::from_ndarray(
63 reshaped.as_standard_layout().into_owned(),
64 ))
65}
66
67pub fn ravel<T: Element, D: Dimension>(a: &Array<T, D>) -> FerrayResult<Array<T, Ix1>> {
72 let n = a.size();
73 let view = a.inner.view().into_dyn();
74 let reshaped = view
75 .to_shape(ndarray::IxDyn(&[n]))
76 .expect("1-D reshape always succeeds for a size-preserving target");
77 let standard = reshaped.as_standard_layout().into_owned();
78 let one_d = standard
79 .into_dimensionality::<ndarray::Ix1>()
80 .expect("reshape result has ndim == 1 by construction");
81 Ok(Array::from_ndarray(one_d))
82}
83
84pub fn flatten<T: Element, D: Dimension>(a: &Array<T, D>) -> FerrayResult<Array<T, Ix1>> {
88 ravel(a)
89}
90
91pub fn squeeze<T: Element, D: Dimension>(
102 a: &Array<T, D>,
103 axis: Option<usize>,
104) -> FerrayResult<Array<T, IxDyn>> {
105 let shape = a.shape();
106 if let Some(ax) = axis {
107 if ax >= shape.len() {
108 return Err(FerrayError::axis_out_of_bounds(ax, shape.len()));
109 }
110 if shape[ax] != 1 {
111 return Err(FerrayError::invalid_value(format!(
112 "cannot select axis {} with size {} for squeeze (must be 1)",
113 ax, shape[ax],
114 )));
115 }
116 let new_shape: Vec<usize> = shape
117 .iter()
118 .enumerate()
119 .filter(|&(i, _)| i != ax)
120 .map(|(_, &s)| s)
121 .collect();
122 let data: Vec<T> = a.iter().cloned().collect();
123 Array::from_vec(IxDyn::new(&new_shape), data)
124 } else {
125 let new_shape: Vec<usize> = shape.iter().copied().filter(|&s| s != 1).collect();
132 let data: Vec<T> = a.iter().cloned().collect();
133 Array::from_vec(IxDyn::new(&new_shape), data)
134 }
135}
136
137pub fn expand_dims<T: Element, D: Dimension>(
144 a: &Array<T, D>,
145 axis: usize,
146) -> FerrayResult<Array<T, IxDyn>> {
147 let ndim = a.ndim();
148 if axis > ndim {
149 return Err(FerrayError::axis_out_of_bounds(axis, ndim + 1));
150 }
151 let mut new_shape: Vec<usize> = a.shape().to_vec();
152 new_shape.insert(axis, 1);
153 let data: Vec<T> = a.iter().cloned().collect();
154 Array::from_vec(IxDyn::new(&new_shape), data)
155}
156
157pub fn broadcast_to<T: Element, D: Dimension>(
170 a: &Array<T, D>,
171 new_shape: &[usize],
172) -> FerrayResult<Array<T, IxDyn>> {
173 let src_shape = a.shape();
174 let dyn_view = a.inner.view().into_dyn();
175 let broadcast_view = dyn_view
176 .broadcast(ndarray::IxDyn(new_shape))
177 .ok_or_else(|| FerrayError::BroadcastFailure {
178 shape_a: src_shape.to_vec(),
179 shape_b: new_shape.to_vec(),
180 })?;
181 Ok(Array::from_ndarray(
185 broadcast_view.as_standard_layout().into_owned(),
186 ))
187}
188
189pub fn concatenate<T: Element>(
202 arrays: &[Array<T, IxDyn>],
203 axis: usize,
204) -> FerrayResult<Array<T, IxDyn>> {
205 if arrays.is_empty() {
206 return Err(FerrayError::invalid_value(
207 "concatenate: need at least one array",
208 ));
209 }
210 let ndim = arrays[0].ndim();
211 if axis >= ndim {
212 return Err(FerrayError::axis_out_of_bounds(axis, ndim));
213 }
214 let base_shape = arrays[0].shape();
215
216 let mut total_along_axis = 0usize;
218 for arr in arrays {
219 if arr.ndim() != ndim {
220 return Err(FerrayError::shape_mismatch(format!(
221 "all arrays must have same ndim; got {} and {}",
222 ndim,
223 arr.ndim(),
224 )));
225 }
226 for (i, (&s, &base)) in arr.shape().iter().zip(base_shape.iter()).enumerate() {
227 if i != axis && s != base {
228 return Err(FerrayError::shape_mismatch(format!(
229 "shape mismatch on axis {i}: {s} vs {base}",
230 )));
231 }
232 }
233 total_along_axis += arr.shape()[axis];
234 }
235
236 let mut new_shape = base_shape.to_vec();
238 new_shape[axis] = total_along_axis;
239 let total: usize = new_shape.iter().product();
240 let mut data = Vec::with_capacity(total);
241
242 let src_vecs: Vec<Vec<T>> = arrays.iter().map(|a| a.iter().cloned().collect()).collect();
244
245 let mut out_strides = vec![1usize; ndim];
247 for i in (0..ndim - 1).rev() {
248 out_strides[i] = out_strides[i + 1] * new_shape[i + 1];
249 }
250
251 for flat_idx in 0..total {
253 let mut rem = flat_idx;
255 let mut nd_idx = vec![0usize; ndim];
256 for i in 0..ndim {
257 nd_idx[i] = rem / out_strides[i];
258 rem %= out_strides[i];
259 }
260
261 let concat_idx = nd_idx[axis];
263 let mut offset = 0;
264 let mut src_arr_idx = 0;
265 for (k, arr) in arrays.iter().enumerate() {
266 let len_along = arr.shape()[axis];
267 if concat_idx < offset + len_along {
268 src_arr_idx = k;
269 break;
270 }
271 offset += len_along;
272 }
273 let local_concat_idx = concat_idx - offset;
274
275 let src_shape = arrays[src_arr_idx].shape();
277 let mut src_flat = 0usize;
278 let mut src_mul = 1usize;
279 for i in (0..ndim).rev() {
280 let idx = if i == axis {
281 local_concat_idx
282 } else {
283 nd_idx[i]
284 };
285 src_flat += idx * src_mul;
286 src_mul *= src_shape[i];
287 }
288
289 let elem = src_vecs[src_arr_idx].get(src_flat).ok_or_else(|| {
290 FerrayError::invalid_value(format!(
291 "concatenate: internal index {} out of range for source array of length {}",
292 src_flat,
293 src_vecs[src_arr_idx].len(),
294 ))
295 })?;
296 data.push(elem.clone());
297 }
298
299 Array::from_vec(IxDyn::new(&new_shape), data)
300}
301
302pub fn stack<T: Element>(arrays: &[Array<T, IxDyn>], axis: usize) -> FerrayResult<Array<T, IxDyn>> {
314 if arrays.is_empty() {
315 return Err(FerrayError::invalid_value("stack: need at least one array"));
316 }
317 let base_shape = arrays[0].shape();
318 let ndim = base_shape.len();
319
320 if axis > ndim {
321 return Err(FerrayError::axis_out_of_bounds(axis, ndim + 1));
322 }
323
324 for arr in &arrays[1..] {
325 if arr.shape() != base_shape {
326 return Err(FerrayError::shape_mismatch(format!(
327 "all input arrays must have the same shape; got {:?} and {:?}",
328 base_shape,
329 arr.shape(),
330 )));
331 }
332 }
333
334 let mut expanded = Vec::with_capacity(arrays.len());
336 for arr in arrays {
337 expanded.push(expand_dims(arr, axis)?);
338 }
339 concatenate(&expanded, axis)
340}
341
342pub fn vstack<T: Element>(arrays: &[Array<T, IxDyn>]) -> FerrayResult<Array<T, IxDyn>> {
347 if arrays.is_empty() {
348 return Err(FerrayError::invalid_value(
349 "vstack: need at least one array",
350 ));
351 }
352 let ndim = arrays[0].ndim();
354 if ndim == 1 {
355 let mut reshaped = Vec::with_capacity(arrays.len());
356 for arr in arrays {
357 let n = arr.shape()[0];
358 reshaped.push(reshape(arr, &[1, n])?);
359 }
360 concatenate(&reshaped, 0)
361 } else {
362 concatenate(arrays, 0)
363 }
364}
365
366pub fn hstack<T: Element>(arrays: &[Array<T, IxDyn>]) -> FerrayResult<Array<T, IxDyn>> {
371 if arrays.is_empty() {
372 return Err(FerrayError::invalid_value(
373 "hstack: need at least one array",
374 ));
375 }
376 let ndim = arrays[0].ndim();
377 if ndim == 1 {
378 concatenate(arrays, 0)
379 } else {
380 concatenate(arrays, 1)
381 }
382}
383
384pub fn dstack<T: Element>(arrays: &[Array<T, IxDyn>]) -> FerrayResult<Array<T, IxDyn>> {
392 if arrays.is_empty() {
393 return Err(FerrayError::invalid_value(
394 "dstack: need at least one array",
395 ));
396 }
397 let mut expanded = Vec::with_capacity(arrays.len());
398 for arr in arrays {
399 let shape = arr.shape();
400 match shape.len() {
401 1 => {
402 let n = shape[0];
403 expanded.push(reshape(arr, &[1, n, 1])?);
404 }
405 2 => {
406 let (m, n) = (shape[0], shape[1]);
407 expanded.push(reshape(arr, &[m, n, 1])?);
408 }
409 _ => {
410 let data: Vec<T> = arr.iter().cloned().collect();
412 expanded.push(Array::from_vec(IxDyn::new(shape), data)?);
413 }
414 }
415 }
416 concatenate(&expanded, 2)
417}
418
419pub fn column_stack<T: Element>(arrays: &[Array<T, IxDyn>]) -> FerrayResult<Array<T, IxDyn>> {
430 if arrays.is_empty() {
431 return Err(FerrayError::invalid_value(
432 "column_stack: need at least one array",
433 ));
434 }
435 let first_ndim = arrays[0].ndim();
436 if first_ndim == 1 {
437 let n = arrays[0].shape()[0];
439 let mut reshaped = Vec::with_capacity(arrays.len());
440 for arr in arrays {
441 if arr.ndim() != 1 {
442 return Err(FerrayError::shape_mismatch(
443 "column_stack: all inputs must have the same ndim",
444 ));
445 }
446 if arr.shape()[0] != n {
447 return Err(FerrayError::shape_mismatch(format!(
448 "column_stack: 1-D inputs must have the same length; got {} and {}",
449 n,
450 arr.shape()[0],
451 )));
452 }
453 reshaped.push(reshape(arr, &[n, 1])?);
454 }
455 concatenate(&reshaped, 1)
456 } else {
457 hstack(arrays)
459 }
460}
461
462pub fn row_stack<T: Element>(arrays: &[Array<T, IxDyn>]) -> FerrayResult<Array<T, IxDyn>> {
467 vstack(arrays)
468}
469
470pub fn block<T: Element>(blocks: &[Vec<Array<T, IxDyn>>]) -> FerrayResult<Array<T, IxDyn>> {
480 if blocks.is_empty() {
481 return Err(FerrayError::invalid_value("block: empty input"));
482 }
483 let mut rows = Vec::with_capacity(blocks.len());
484 for row in blocks {
485 if row.is_empty() {
486 return Err(FerrayError::invalid_value("block: empty row"));
487 }
488 let row_arr = if row.len() == 1 {
490 let data: Vec<T> = row[0].iter().cloned().collect();
491 Array::from_vec(IxDyn::new(row[0].shape()), data)?
492 } else {
493 hstack(row)?
494 };
495 rows.push(row_arr);
496 }
497 if rows.len() == 1 {
498 Ok(rows.pop().unwrap_or_else(|| unreachable!()))
500 } else {
501 vstack(&rows)
502 }
503}
504
505pub fn split<T: Element>(
514 a: &Array<T, IxDyn>,
515 n_sections: usize,
516 axis: usize,
517) -> FerrayResult<Vec<Array<T, IxDyn>>> {
518 let shape = a.shape();
519 if axis >= shape.len() {
520 return Err(FerrayError::axis_out_of_bounds(axis, shape.len()));
521 }
522 let axis_len = shape[axis];
523 if n_sections == 0 {
524 return Err(FerrayError::invalid_value("split: n_sections must be > 0"));
525 }
526 if !axis_len.is_multiple_of(n_sections) {
527 return Err(FerrayError::invalid_value(format!(
528 "array of size {axis_len} along axis {axis} cannot be evenly split into {n_sections} sections",
529 )));
530 }
531 let chunk_size = axis_len / n_sections;
532 let indices: Vec<usize> = (1..n_sections).map(|i| i * chunk_size).collect();
533 array_split(a, &indices, axis)
534}
535
536pub fn array_split<T: Element>(
545 a: &Array<T, IxDyn>,
546 indices: &[usize],
547 axis: usize,
548) -> FerrayResult<Vec<Array<T, IxDyn>>> {
549 let shape = a.shape();
550 let ndim = shape.len();
551 if axis >= ndim {
552 return Err(FerrayError::axis_out_of_bounds(axis, ndim));
553 }
554 let axis_len = shape[axis];
555 let src_data: Vec<T> = a.iter().cloned().collect();
556
557 let mut splits = Vec::with_capacity(indices.len() + 2);
559 splits.push(0);
560 for &idx in indices {
561 splits.push(idx.min(axis_len));
562 }
563 splits.push(axis_len);
564
565 let mut src_strides = vec![1usize; ndim];
567 for i in (0..ndim - 1).rev() {
568 src_strides[i] = src_strides[i + 1] * shape[i + 1];
569 }
570
571 let mut result = Vec::with_capacity(splits.len() - 1);
572 for w in splits.windows(2) {
573 let start = w[0];
574 let end = w[1];
575 let chunk_len = end - start;
576
577 let mut sub_shape = shape.to_vec();
578 sub_shape[axis] = chunk_len;
579 let sub_total: usize = sub_shape.iter().product();
580
581 let mut sub_strides = vec![1usize; ndim];
583 for i in (0..ndim - 1).rev() {
584 sub_strides[i] = sub_strides[i + 1] * sub_shape[i + 1];
585 }
586
587 let mut sub_data = Vec::with_capacity(sub_total);
588 for flat in 0..sub_total {
589 let mut rem = flat;
591 let mut src_flat = 0usize;
592 for i in 0..ndim {
593 let idx = rem / sub_strides[i];
594 rem %= sub_strides[i];
595 let src_idx = if i == axis { idx + start } else { idx };
596 src_flat += src_idx * src_strides[i];
597 }
598 sub_data.push(src_data[src_flat].clone());
599 }
600 result.push(Array::from_vec(IxDyn::new(&sub_shape), sub_data)?);
601 }
602
603 Ok(result)
604}
605
606pub fn array_split_n<T: Element>(
616 a: &Array<T, IxDyn>,
617 n: usize,
618 axis: usize,
619) -> FerrayResult<Vec<Array<T, IxDyn>>> {
620 if n == 0 {
621 return Err(FerrayError::invalid_value("array_split_n: n must be > 0"));
622 }
623 let shape = a.shape();
624 if axis >= shape.len() {
625 return Err(FerrayError::axis_out_of_bounds(axis, shape.len()));
626 }
627 let axis_len = shape[axis];
628
629 let base = axis_len / n;
633 let extra = axis_len % n;
634 let mut indices = Vec::with_capacity(n.saturating_sub(1));
635 let mut cum = 0usize;
636 for i in 0..n - 1 {
637 cum += if i < extra { base + 1 } else { base };
638 indices.push(cum);
639 }
640 array_split(a, &indices, axis)
641}
642
643pub fn vsplit<T: Element>(
647 a: &Array<T, IxDyn>,
648 n_sections: usize,
649) -> FerrayResult<Vec<Array<T, IxDyn>>> {
650 split(a, n_sections, 0)
651}
652
653pub fn hsplit<T: Element>(
657 a: &Array<T, IxDyn>,
658 n_sections: usize,
659) -> FerrayResult<Vec<Array<T, IxDyn>>> {
660 split(a, n_sections, 1)
661}
662
663pub fn dsplit<T: Element>(
667 a: &Array<T, IxDyn>,
668 n_sections: usize,
669) -> FerrayResult<Vec<Array<T, IxDyn>>> {
670 split(a, n_sections, 2)
671}
672
673pub fn transpose<T: Element, D: Dimension>(
688 a: &Array<T, D>,
689 axes: Option<&[usize]>,
690) -> FerrayResult<Array<T, IxDyn>> {
691 let ndim = a.ndim();
692 let perm: Vec<usize> = match axes {
693 Some(ax) => {
694 if ax.len() != ndim {
695 return Err(FerrayError::invalid_value(format!(
696 "axes must have length {} but got {}",
697 ndim,
698 ax.len(),
699 )));
700 }
701 let mut seen = vec![false; ndim];
703 for &a in ax {
704 if a >= ndim {
705 return Err(FerrayError::axis_out_of_bounds(a, ndim));
706 }
707 if seen[a] {
708 return Err(FerrayError::invalid_value(format!(
709 "duplicate axis {a} in transpose",
710 )));
711 }
712 seen[a] = true;
713 }
714 ax.to_vec()
715 }
716 None => (0..ndim).rev().collect(),
717 };
718
719 let permuted = a
728 .inner
729 .view()
730 .into_dyn()
731 .permuted_axes(ndarray::IxDyn(&perm));
732 Ok(Array::from_ndarray(
733 permuted.as_standard_layout().into_owned(),
734 ))
735}
736
737pub fn swapaxes<T: Element, D: Dimension>(
744 a: &Array<T, D>,
745 axis1: usize,
746 axis2: usize,
747) -> FerrayResult<Array<T, IxDyn>> {
748 let ndim = a.ndim();
749 if axis1 >= ndim {
750 return Err(FerrayError::axis_out_of_bounds(axis1, ndim));
751 }
752 if axis2 >= ndim {
753 return Err(FerrayError::axis_out_of_bounds(axis2, ndim));
754 }
755 let mut perm: Vec<usize> = (0..ndim).collect();
756 perm.swap(axis1, axis2);
757 transpose(a, Some(&perm))
758}
759
760pub fn moveaxis<T: Element, D: Dimension>(
767 a: &Array<T, D>,
768 source: usize,
769 destination: usize,
770) -> FerrayResult<Array<T, IxDyn>> {
771 let ndim = a.ndim();
772 if source >= ndim {
773 return Err(FerrayError::axis_out_of_bounds(source, ndim));
774 }
775 if destination >= ndim {
776 return Err(FerrayError::axis_out_of_bounds(destination, ndim));
777 }
778 let mut order: Vec<usize> = (0..ndim).filter(|&x| x != source).collect();
780 order.insert(destination, source);
781 transpose(a, Some(&order))
782}
783
784pub fn rollaxis<T: Element, D: Dimension>(
791 a: &Array<T, D>,
792 axis: usize,
793 start: usize,
794) -> FerrayResult<Array<T, IxDyn>> {
795 let ndim = a.ndim();
796 if axis >= ndim {
797 return Err(FerrayError::axis_out_of_bounds(axis, ndim));
798 }
799 if start > ndim {
800 return Err(FerrayError::axis_out_of_bounds(start, ndim + 1));
801 }
802 let dst = if start > axis { start - 1 } else { start };
803 if axis == dst {
804 let data: Vec<T> = a.iter().cloned().collect();
806 return Array::from_vec(IxDyn::new(a.shape()), data);
807 }
808 moveaxis(a, axis, dst)
809}
810
811pub fn flip<T: Element, D: Dimension>(
818 a: &Array<T, D>,
819 axis: usize,
820) -> FerrayResult<Array<T, IxDyn>> {
821 let shape = a.shape();
822 let ndim = shape.len();
823 if axis >= ndim {
824 return Err(FerrayError::axis_out_of_bounds(axis, ndim));
825 }
826 let src_data: Vec<T> = a.iter().cloned().collect();
827 let total = src_data.len();
828
829 let mut strides = vec![1usize; ndim];
831 for i in (0..ndim.saturating_sub(1)).rev() {
832 strides[i] = strides[i + 1] * shape[i + 1];
833 }
834
835 let mut data = Vec::with_capacity(total);
836 for flat in 0..total {
837 let mut rem = flat;
838 let mut src_flat = 0usize;
839 for i in 0..ndim {
840 let idx = rem / strides[i];
841 rem %= strides[i];
842 let src_idx = if i == axis { shape[i] - 1 - idx } else { idx };
843 src_flat += src_idx * strides[i];
844 }
845 data.push(src_data[src_flat].clone());
846 }
847 Array::from_vec(IxDyn::new(shape), data)
848}
849
850pub fn fliplr<T: Element, D: Dimension>(a: &Array<T, D>) -> FerrayResult<Array<T, IxDyn>> {
857 if a.ndim() < 2 {
858 return Err(FerrayError::invalid_value(
859 "fliplr: array must be at least 2-D",
860 ));
861 }
862 flip(a, 1)
863}
864
865pub fn flipud<T: Element, D: Dimension>(a: &Array<T, D>) -> FerrayResult<Array<T, IxDyn>> {
872 if a.ndim() < 1 {
873 return Err(FerrayError::invalid_value(
874 "flipud: array must be at least 1-D",
875 ));
876 }
877 flip(a, 0)
878}
879
880pub fn rot90<T: Element, D: Dimension>(a: &Array<T, D>, k: i32) -> FerrayResult<Array<T, IxDyn>> {
889 if a.ndim() < 2 {
890 return Err(FerrayError::invalid_value(
891 "rot90: array must be at least 2-D",
892 ));
893 }
894 let k = k.rem_euclid(4);
896 let shape = a.shape();
897 let data: Vec<T> = a.iter().cloned().collect();
898
899 let as_dyn = Array::from_vec(IxDyn::new(shape), data)?;
901
902 match k {
903 0 => Ok(as_dyn),
904 1 => {
905 let flipped = flip(&as_dyn, 1)?;
907 swapaxes(&flipped, 0, 1)
908 }
909 2 => {
910 let f1 = flip(&as_dyn, 0)?;
912 flip(&f1, 1)
913 }
914 3 => {
915 let transposed = swapaxes(&as_dyn, 0, 1)?;
917 flip(&transposed, 1)
918 }
919 _ => unreachable!(),
920 }
921}
922
923pub fn roll<T: Element, D: Dimension>(
933 a: &Array<T, D>,
934 shift: isize,
935 axis: Option<usize>,
936) -> FerrayResult<Array<T, IxDyn>> {
937 match axis {
938 None => {
939 let data: Vec<T> = a.iter().cloned().collect();
941 let n = data.len();
942 if n == 0 {
943 return Array::from_vec(IxDyn::new(a.shape()), data);
944 }
945 let shift = ((shift % n as isize) + n as isize) as usize % n;
946 let mut rolled = Vec::with_capacity(n);
947 for i in 0..n {
948 rolled.push(data[(n + i - shift) % n].clone());
949 }
950 Array::from_vec(IxDyn::new(a.shape()), rolled)
951 }
952 Some(ax) => {
953 let shape = a.shape();
954 let ndim = shape.len();
955 if ax >= ndim {
956 return Err(FerrayError::axis_out_of_bounds(ax, ndim));
957 }
958 let axis_len = shape[ax];
959 if axis_len == 0 {
960 let data: Vec<T> = a.iter().cloned().collect();
961 return Array::from_vec(IxDyn::new(shape), data);
962 }
963 let shift = ((shift % axis_len as isize) + axis_len as isize) as usize % axis_len;
964 let src_data: Vec<T> = a.iter().cloned().collect();
965 let total = src_data.len();
966
967 let mut strides = vec![1usize; ndim];
969 for i in (0..ndim.saturating_sub(1)).rev() {
970 strides[i] = strides[i + 1] * shape[i + 1];
971 }
972
973 let mut data = Vec::with_capacity(total);
974 for flat in 0..total {
975 let mut rem = flat;
976 let mut src_flat = 0usize;
977 #[allow(clippy::needless_range_loop)]
978 for i in 0..ndim {
979 let idx = rem / strides[i];
980 rem %= strides[i];
981 let src_idx = if i == ax {
982 (axis_len + idx - shift) % axis_len
983 } else {
984 idx
985 };
986 src_flat += src_idx * strides[i];
987 }
988 data.push(src_data[src_flat].clone());
989 }
990 Array::from_vec(IxDyn::new(shape), data)
991 }
992 }
993}
994
995pub fn r_<T: Element>(arrays: &[Array<T, Ix1>]) -> FerrayResult<Array<T, Ix1>> {
1011 if arrays.is_empty() {
1012 return Err(FerrayError::invalid_value("r_: need at least one array"));
1013 }
1014 let total: usize = arrays.iter().map(|a| a.shape()[0]).sum();
1015 let mut data = Vec::with_capacity(total);
1016 for a in arrays {
1017 data.extend(a.iter().cloned());
1018 }
1019 Array::from_vec(Ix1::new([total]), data)
1020}
1021
1022pub fn c_<T: Element>(arrays: &[Array<T, Ix1>]) -> FerrayResult<Array<T, IxDyn>> {
1033 if arrays.is_empty() {
1034 return Err(FerrayError::invalid_value("c_: need at least one array"));
1035 }
1036 let n = arrays[0].shape()[0];
1037 for a in &arrays[1..] {
1038 if a.shape()[0] != n {
1039 return Err(FerrayError::shape_mismatch(format!(
1040 "c_: all 1-D inputs must have the same length; got {} and {}",
1041 n,
1042 a.shape()[0],
1043 )));
1044 }
1045 }
1046 let k = arrays.len();
1047 let cols: Vec<Vec<T>> = arrays.iter().map(|a| a.iter().cloned().collect()).collect();
1049 let mut data = Vec::with_capacity(n * k);
1050 for i in 0..n {
1051 for col in &cols {
1052 data.push(col[i].clone());
1053 }
1054 }
1055 Array::from_vec(IxDyn::new(&[n, k]), data)
1056}
1057
1058#[cfg(test)]
1063mod tests {
1064 use super::*;
1065
1066 fn dyn_arr(shape: &[usize], data: Vec<f64>) -> Array<f64, IxDyn> {
1067 Array::from_vec(IxDyn::new(shape), data).unwrap()
1068 }
1069
1070 #[test]
1073 fn test_reshape() {
1074 let a = dyn_arr(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1075 let b = reshape(&a, &[3, 2]).unwrap();
1076 assert_eq!(b.shape(), &[3, 2]);
1077 let data: Vec<f64> = b.iter().copied().collect();
1078 assert_eq!(data, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1079 }
1080
1081 #[test]
1082 fn test_reshape_size_mismatch() {
1083 let a = dyn_arr(&[2, 3], vec![1.0; 6]);
1084 assert!(reshape(&a, &[2, 4]).is_err());
1085 }
1086
1087 #[test]
1088 fn test_ravel() {
1089 let a = dyn_arr(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1090 let b = ravel(&a).unwrap();
1091 assert_eq!(b.shape(), &[6]);
1092 assert_eq!(b.as_slice().unwrap(), &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1093 }
1094
1095 #[test]
1096 fn test_flatten() {
1097 let a = dyn_arr(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1098 let b = flatten(&a).unwrap();
1099 assert_eq!(b.shape(), &[6]);
1100 }
1101
1102 #[test]
1103 fn test_squeeze() {
1104 let a = dyn_arr(&[1, 3, 1], vec![1.0, 2.0, 3.0]);
1105 let b = squeeze(&a, None).unwrap();
1106 assert_eq!(b.shape(), &[3]);
1107 }
1108
1109 #[test]
1110 fn test_squeeze_specific_axis() {
1111 let a = dyn_arr(&[1, 3, 1], vec![1.0, 2.0, 3.0]);
1112 let b = squeeze(&a, Some(0)).unwrap();
1113 assert_eq!(b.shape(), &[3, 1]);
1114 }
1115
1116 #[test]
1117 fn test_squeeze_not_size_1() {
1118 let a = dyn_arr(&[2, 3], vec![1.0; 6]);
1119 assert!(squeeze(&a, Some(0)).is_err());
1120 }
1121
1122 #[test]
1123 fn test_expand_dims() {
1124 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
1125 let b = expand_dims(&a, 0).unwrap();
1126 assert_eq!(b.shape(), &[1, 3]);
1127 let c = expand_dims(&a, 1).unwrap();
1128 assert_eq!(c.shape(), &[3, 1]);
1129 }
1130
1131 #[test]
1132 fn test_expand_dims_oob() {
1133 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
1134 assert!(expand_dims(&a, 3).is_err());
1135 }
1136
1137 #[test]
1138 fn test_broadcast_to() {
1139 let a = dyn_arr(&[1, 3], vec![1.0, 2.0, 3.0]);
1140 let b = broadcast_to(&a, &[3, 3]).unwrap();
1141 assert_eq!(b.shape(), &[3, 3]);
1142 let data: Vec<f64> = b.iter().copied().collect();
1143 assert_eq!(data, vec![1.0, 2.0, 3.0, 1.0, 2.0, 3.0, 1.0, 2.0, 3.0]);
1144 }
1145
1146 #[test]
1147 fn test_broadcast_to_1d_to_2d() {
1148 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
1149 let b = broadcast_to(&a, &[2, 3]).unwrap();
1150 assert_eq!(b.shape(), &[2, 3]);
1151 }
1152
1153 #[test]
1154 fn test_broadcast_to_incompatible() {
1155 let a = dyn_arr(&[4], vec![1.0, 2.0, 3.0, 4.0]);
1156 assert!(broadcast_to(&a, &[3]).is_err());
1157 }
1158
1159 #[test]
1160 fn test_broadcast_to_from_non_contiguous_source() {
1161 let a = dyn_arr(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1166 let t = transpose(&a, None).unwrap();
1168 let b = broadcast_to(&t, &[2, 3, 2]).unwrap();
1169 assert_eq!(b.shape(), &[2, 3, 2]);
1170 let data: Vec<f64> = b.iter().copied().collect();
1172 assert_eq!(&data[..6], &data[6..12]);
1173 }
1174
1175 #[test]
1178 fn test_concatenate() {
1179 let a = dyn_arr(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1180 let b = dyn_arr(&[2, 3], vec![7.0, 8.0, 9.0, 10.0, 11.0, 12.0]);
1181 let c = concatenate(&[a, b], 0).unwrap();
1182 assert_eq!(c.shape(), &[4, 3]);
1183 }
1184
1185 #[test]
1186 fn test_concatenate_axis1() {
1187 let a = dyn_arr(&[2, 2], vec![1.0, 2.0, 3.0, 4.0]);
1188 let b = dyn_arr(&[2, 3], vec![5.0, 6.0, 7.0, 8.0, 9.0, 10.0]);
1189 let c = concatenate(&[a, b], 1).unwrap();
1190 assert_eq!(c.shape(), &[2, 5]);
1191 }
1192
1193 #[test]
1194 fn test_concatenate_shape_mismatch() {
1195 let a = dyn_arr(&[2, 3], vec![1.0; 6]);
1196 let b = dyn_arr(&[3, 3], vec![1.0; 9]);
1197 let c = concatenate(&[a, b], 0).unwrap();
1201 assert_eq!(c.shape(), &[5, 3]);
1202 }
1203
1204 #[test]
1205 fn test_concatenate_empty() {
1206 let v: Vec<Array<f64, IxDyn>> = vec![];
1207 assert!(concatenate(&v, 0).is_err());
1208 }
1209
1210 #[test]
1211 fn test_stack() {
1212 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
1213 let b = dyn_arr(&[3], vec![4.0, 5.0, 6.0]);
1214 let c = stack(&[a, b], 0).unwrap();
1215 assert_eq!(c.shape(), &[2, 3]);
1216 let data: Vec<f64> = c.iter().copied().collect();
1217 assert_eq!(data, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1218 }
1219
1220 #[test]
1221 fn test_stack_axis1() {
1222 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
1223 let b = dyn_arr(&[3], vec![4.0, 5.0, 6.0]);
1224 let c = stack(&[a, b], 1).unwrap();
1225 assert_eq!(c.shape(), &[3, 2]);
1226 let data: Vec<f64> = c.iter().copied().collect();
1227 assert_eq!(data, vec![1.0, 4.0, 2.0, 5.0, 3.0, 6.0]);
1228 }
1229
1230 #[test]
1231 fn test_vstack() {
1232 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
1233 let b = dyn_arr(&[3], vec![4.0, 5.0, 6.0]);
1234 let c = vstack(&[a, b]).unwrap();
1235 assert_eq!(c.shape(), &[2, 3]);
1236 }
1237
1238 #[test]
1239 fn test_hstack() {
1240 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
1241 let b = dyn_arr(&[3], vec![4.0, 5.0, 6.0]);
1242 let c = hstack(&[a, b]).unwrap();
1243 assert_eq!(c.shape(), &[6]);
1244 }
1245
1246 #[test]
1247 fn test_hstack_2d() {
1248 let a = dyn_arr(&[2, 2], vec![1.0, 2.0, 3.0, 4.0]);
1249 let b = dyn_arr(&[2, 3], vec![5.0, 6.0, 7.0, 8.0, 9.0, 10.0]);
1250 let c = hstack(&[a, b]).unwrap();
1251 assert_eq!(c.shape(), &[2, 5]);
1252 }
1253
1254 #[test]
1255 fn test_dstack() {
1256 let a = dyn_arr(&[2, 2], vec![1.0, 2.0, 3.0, 4.0]);
1257 let b = dyn_arr(&[2, 2], vec![5.0, 6.0, 7.0, 8.0]);
1258 let c = dstack(&[a, b]).unwrap();
1259 assert_eq!(c.shape(), &[2, 2, 2]);
1260 }
1261
1262 #[test]
1263 fn test_block() {
1264 let a = dyn_arr(&[2, 2], vec![1.0, 2.0, 3.0, 4.0]);
1265 let b = dyn_arr(&[2, 2], vec![5.0, 6.0, 7.0, 8.0]);
1266 let c = dyn_arr(&[2, 2], vec![9.0, 10.0, 11.0, 12.0]);
1267 let d = dyn_arr(&[2, 2], vec![13.0, 14.0, 15.0, 16.0]);
1268 let result = block(&[vec![a, b], vec![c, d]]).unwrap();
1269 assert_eq!(result.shape(), &[4, 4]);
1270 }
1271
1272 #[test]
1273 fn test_split() {
1274 let a = dyn_arr(&[6], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1275 let parts = split(&a, 3, 0).unwrap();
1276 assert_eq!(parts.len(), 3);
1277 assert_eq!(parts[0].shape(), &[2]);
1278 assert_eq!(parts[1].shape(), &[2]);
1279 assert_eq!(parts[2].shape(), &[2]);
1280 }
1281
1282 #[test]
1283 fn test_split_uneven() {
1284 let a = dyn_arr(&[5], vec![1.0, 2.0, 3.0, 4.0, 5.0]);
1285 assert!(split(&a, 3, 0).is_err()); }
1287
1288 #[test]
1289 fn test_array_split() {
1290 let a = dyn_arr(&[5], vec![1.0, 2.0, 3.0, 4.0, 5.0]);
1291 let parts = array_split(&a, &[2, 4], 0).unwrap();
1292 assert_eq!(parts.len(), 3);
1293 assert_eq!(parts[0].shape(), &[2]); assert_eq!(parts[1].shape(), &[2]); assert_eq!(parts[2].shape(), &[1]); }
1297
1298 #[test]
1299 fn test_vsplit() {
1300 let a = dyn_arr(&[4, 2], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);
1301 let parts = vsplit(&a, 2).unwrap();
1302 assert_eq!(parts.len(), 2);
1303 assert_eq!(parts[0].shape(), &[2, 2]);
1304 }
1305
1306 #[test]
1307 fn test_hsplit() {
1308 let a = dyn_arr(&[2, 4], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);
1309 let parts = hsplit(&a, 2).unwrap();
1310 assert_eq!(parts.len(), 2);
1311 assert_eq!(parts[0].shape(), &[2, 2]);
1312 }
1313
1314 #[test]
1317 fn test_transpose_2d() {
1318 let a = dyn_arr(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1319 let b = transpose(&a, None).unwrap();
1320 assert_eq!(b.shape(), &[3, 2]);
1321 let data: Vec<f64> = b.iter().copied().collect();
1322 assert_eq!(data, vec![1.0, 4.0, 2.0, 5.0, 3.0, 6.0]);
1323 }
1324
1325 #[test]
1326 fn test_transpose_explicit() {
1327 let a = dyn_arr(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1328 let b = transpose(&a, Some(&[1, 0])).unwrap();
1329 assert_eq!(b.shape(), &[3, 2]);
1330 }
1331
1332 #[test]
1333 fn test_transpose_bad_axes() {
1334 let a = dyn_arr(&[2, 3], vec![1.0; 6]);
1335 assert!(transpose(&a, Some(&[0])).is_err()); }
1337
1338 #[test]
1339 fn test_swapaxes() {
1340 let a = dyn_arr(&[2, 3, 4], vec![0.0; 24]);
1341 let b = swapaxes(&a, 0, 2).unwrap();
1342 assert_eq!(b.shape(), &[4, 3, 2]);
1343 }
1344
1345 #[test]
1346 fn test_moveaxis() {
1347 let a = dyn_arr(&[2, 3, 4], vec![0.0; 24]);
1348 let b = moveaxis(&a, 0, 2).unwrap();
1349 assert_eq!(b.shape(), &[3, 4, 2]);
1350 }
1351
1352 #[test]
1353 fn test_rollaxis() {
1354 let a = dyn_arr(&[2, 3, 4], vec![0.0; 24]);
1355 let b = rollaxis(&a, 2, 0).unwrap();
1356 assert_eq!(b.shape(), &[4, 2, 3]);
1357 }
1358
1359 #[test]
1360 fn test_flip() {
1361 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
1362 let b = flip(&a, 0).unwrap();
1363 let data: Vec<f64> = b.iter().copied().collect();
1364 assert_eq!(data, vec![3.0, 2.0, 1.0]);
1365 }
1366
1367 #[test]
1368 fn test_flip_2d() {
1369 let a = dyn_arr(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1370 let b = flip(&a, 0).unwrap();
1371 let data: Vec<f64> = b.iter().copied().collect();
1372 assert_eq!(data, vec![4.0, 5.0, 6.0, 1.0, 2.0, 3.0]);
1373
1374 let c = flip(&a, 1).unwrap();
1375 let data2: Vec<f64> = c.iter().copied().collect();
1376 assert_eq!(data2, vec![3.0, 2.0, 1.0, 6.0, 5.0, 4.0]);
1377 }
1378
1379 #[test]
1380 fn test_fliplr() {
1381 let a = dyn_arr(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1382 let b = fliplr(&a).unwrap();
1383 let data: Vec<f64> = b.iter().copied().collect();
1384 assert_eq!(data, vec![3.0, 2.0, 1.0, 6.0, 5.0, 4.0]);
1385 }
1386
1387 #[test]
1388 fn test_flipud() {
1389 let a = dyn_arr(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1390 let b = flipud(&a).unwrap();
1391 let data: Vec<f64> = b.iter().copied().collect();
1392 assert_eq!(data, vec![4.0, 5.0, 6.0, 1.0, 2.0, 3.0]);
1393 }
1394
1395 #[test]
1396 fn test_fliplr_1d_err() {
1397 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
1398 assert!(fliplr(&a).is_err());
1399 }
1400
1401 #[test]
1402 fn test_rot90_once() {
1403 let a = dyn_arr(&[2, 2], vec![1.0, 2.0, 3.0, 4.0]);
1405 let b = rot90(&a, 1).unwrap();
1406 assert_eq!(b.shape(), &[2, 2]);
1407 let data: Vec<f64> = b.iter().copied().collect();
1408 assert_eq!(data, vec![2.0, 4.0, 1.0, 3.0]);
1409 }
1410
1411 #[test]
1412 fn test_rot90_twice() {
1413 let a = dyn_arr(&[2, 2], vec![1.0, 2.0, 3.0, 4.0]);
1414 let b = rot90(&a, 2).unwrap();
1415 let data: Vec<f64> = b.iter().copied().collect();
1416 assert_eq!(data, vec![4.0, 3.0, 2.0, 1.0]);
1417 }
1418
1419 #[test]
1420 fn test_rot90_four_is_identity() {
1421 let a = dyn_arr(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1422 let b = rot90(&a, 4).unwrap();
1423 let data_a: Vec<f64> = a.iter().copied().collect();
1424 let data_b: Vec<f64> = b.iter().copied().collect();
1425 assert_eq!(data_a, data_b);
1426 assert_eq!(a.shape(), b.shape());
1427 }
1428
1429 #[test]
1430 fn test_roll_flat() {
1431 let a = dyn_arr(&[5], vec![1.0, 2.0, 3.0, 4.0, 5.0]);
1432 let b = roll(&a, 2, None).unwrap();
1433 let data: Vec<f64> = b.iter().copied().collect();
1434 assert_eq!(data, vec![4.0, 5.0, 1.0, 2.0, 3.0]);
1435 }
1436
1437 #[test]
1438 fn test_roll_negative() {
1439 let a = dyn_arr(&[5], vec![1.0, 2.0, 3.0, 4.0, 5.0]);
1440 let b = roll(&a, -2, None).unwrap();
1441 let data: Vec<f64> = b.iter().copied().collect();
1442 assert_eq!(data, vec![3.0, 4.0, 5.0, 1.0, 2.0]);
1443 }
1444
1445 #[test]
1446 fn test_roll_axis() {
1447 let a = dyn_arr(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1448 let b = roll(&a, 1, Some(1)).unwrap();
1449 let data: Vec<f64> = b.iter().copied().collect();
1450 assert_eq!(data, vec![3.0, 1.0, 2.0, 6.0, 4.0, 5.0]);
1451 }
1452
1453 #[test]
1458 fn test_column_stack_1d() {
1459 let a = dyn_arr(&[4], vec![1.0, 2.0, 3.0, 4.0]);
1461 let b = dyn_arr(&[4], vec![10.0, 20.0, 30.0, 40.0]);
1462 let c = dyn_arr(&[4], vec![100.0, 200.0, 300.0, 400.0]);
1463 let result = column_stack(&[a, b, c]).unwrap();
1464 assert_eq!(result.shape(), &[4, 3]);
1465 assert_eq!(
1466 result.iter().copied().collect::<Vec<_>>(),
1467 vec![
1468 1.0, 10.0, 100.0, 2.0, 20.0, 200.0, 3.0, 30.0, 300.0, 4.0, 40.0, 400.0, ]
1473 );
1474 }
1475
1476 #[test]
1477 fn test_column_stack_2d_same_as_hstack() {
1478 let a = dyn_arr(&[2, 2], vec![1.0, 2.0, 3.0, 4.0]);
1479 let b = dyn_arr(&[2, 2], vec![5.0, 6.0, 7.0, 8.0]);
1480 let result = column_stack(&[a, b]).unwrap();
1481 assert_eq!(result.shape(), &[2, 4]);
1482 assert_eq!(
1483 result.iter().copied().collect::<Vec<_>>(),
1484 vec![1.0, 2.0, 5.0, 6.0, 3.0, 4.0, 7.0, 8.0]
1485 );
1486 }
1487
1488 #[test]
1489 fn test_column_stack_length_mismatch() {
1490 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
1491 let b = dyn_arr(&[4], vec![1.0, 2.0, 3.0, 4.0]);
1492 assert!(column_stack(&[a, b]).is_err());
1493 }
1494
1495 #[test]
1496 fn test_row_stack_is_vstack() {
1497 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
1498 let b = dyn_arr(&[3], vec![4.0, 5.0, 6.0]);
1499 let row = row_stack(&[a.clone(), b.clone()]).unwrap();
1500 let v = vstack(&[a, b]).unwrap();
1501 assert_eq!(row.shape(), v.shape());
1502 assert_eq!(
1503 row.iter().copied().collect::<Vec<_>>(),
1504 v.iter().copied().collect::<Vec<_>>()
1505 );
1506 }
1507
1508 #[test]
1509 fn test_array_split_n_uneven() {
1510 let a = dyn_arr(&[7], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]);
1512 let parts = array_split_n(&a, 3, 0).unwrap();
1513 assert_eq!(parts.len(), 3);
1514 assert_eq!(
1515 parts[0].iter().copied().collect::<Vec<_>>(),
1516 vec![1.0, 2.0, 3.0]
1517 );
1518 assert_eq!(parts[1].iter().copied().collect::<Vec<_>>(), vec![4.0, 5.0]);
1519 assert_eq!(parts[2].iter().copied().collect::<Vec<_>>(), vec![6.0, 7.0]);
1520 }
1521
1522 #[test]
1523 fn test_array_split_n_even() {
1524 let a = dyn_arr(&[6], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1525 let parts = array_split_n(&a, 3, 0).unwrap();
1526 assert_eq!(parts.len(), 3);
1527 for (i, expected) in [vec![1.0, 2.0], vec![3.0, 4.0], vec![5.0, 6.0]]
1528 .iter()
1529 .enumerate()
1530 {
1531 assert_eq!(&parts[i].iter().copied().collect::<Vec<_>>(), expected);
1532 }
1533 }
1534
1535 #[test]
1536 fn test_array_split_n_more_sections_than_elements() {
1537 let a = dyn_arr(&[3], vec![1.0, 2.0, 3.0]);
1540 let parts = array_split_n(&a, 5, 0).unwrap();
1541 assert_eq!(parts.len(), 5);
1542 assert_eq!(parts[0].iter().copied().collect::<Vec<_>>(), vec![1.0]);
1543 assert_eq!(parts[1].iter().copied().collect::<Vec<_>>(), vec![2.0]);
1544 assert_eq!(parts[2].iter().copied().collect::<Vec<_>>(), vec![3.0]);
1545 assert_eq!(
1546 parts[3].iter().copied().collect::<Vec<_>>(),
1547 Vec::<f64>::new()
1548 );
1549 assert_eq!(
1550 parts[4].iter().copied().collect::<Vec<_>>(),
1551 Vec::<f64>::new()
1552 );
1553 }
1554
1555 #[test]
1556 fn test_to_dyn_from_typed() {
1557 use crate::Array;
1558 use crate::dimension::Ix2;
1559 let typed =
1560 Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
1561 .unwrap();
1562 let dy = typed.to_dyn();
1563 assert_eq!(dy.shape(), &[2, 3]);
1564 assert_eq!(
1565 dy.iter().copied().collect::<Vec<_>>(),
1566 vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
1567 );
1568 }
1569
1570 #[test]
1571 fn test_concatenate_typed_via_to_dyn() {
1572 use crate::Array;
1575 use crate::dimension::Ix2;
1576 let a = Array::<f64, Ix2>::from_vec(Ix2::new([2, 2]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
1577 let b = Array::<f64, Ix2>::from_vec(Ix2::new([2, 2]), vec![5.0, 6.0, 7.0, 8.0]).unwrap();
1578 let result = concatenate(&[a.to_dyn(), b.to_dyn()], 0).unwrap();
1579 assert_eq!(result.shape(), &[4, 2]);
1580 assert_eq!(
1581 result.iter().copied().collect::<Vec<_>>(),
1582 vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]
1583 );
1584 }
1585
1586 #[test]
1587 fn test_r_concatenates_1d() {
1588 use crate::Array;
1589 let a = Array::<i32, Ix1>::from_vec(Ix1::new([3]), vec![1, 2, 3]).unwrap();
1590 let b = Array::<i32, Ix1>::from_vec(Ix1::new([2]), vec![4, 5]).unwrap();
1591 let c = Array::<i32, Ix1>::from_vec(Ix1::new([1]), vec![6]).unwrap();
1592 let r = r_(&[a, b, c]).unwrap();
1593 assert_eq!(
1594 r.iter().copied().collect::<Vec<_>>(),
1595 vec![1, 2, 3, 4, 5, 6]
1596 );
1597 }
1598
1599 #[test]
1600 fn test_r_empty_input_errs() {
1601 let r = r_::<f64>(&[]);
1602 assert!(r.is_err());
1603 }
1604
1605 #[test]
1606 fn test_c_columns_to_2d() {
1607 use crate::Array;
1608 let a = Array::<i32, Ix1>::from_vec(Ix1::new([3]), vec![1, 2, 3]).unwrap();
1609 let b = Array::<i32, Ix1>::from_vec(Ix1::new([3]), vec![10, 20, 30]).unwrap();
1610 let r = c_(&[a, b]).unwrap();
1611 assert_eq!(r.shape(), &[3, 2]);
1612 assert_eq!(
1614 r.iter().copied().collect::<Vec<_>>(),
1615 vec![1, 10, 2, 20, 3, 30],
1616 );
1617 }
1618
1619 #[test]
1620 fn test_c_length_mismatch_errs() {
1621 use crate::Array;
1622 let a = Array::<i32, Ix1>::from_vec(Ix1::new([3]), vec![1, 2, 3]).unwrap();
1623 let b = Array::<i32, Ix1>::from_vec(Ix1::new([2]), vec![10, 20]).unwrap();
1624 assert!(c_(&[a, b]).is_err());
1625 }
1626}