1use std::mem::MaybeUninit;
23
24use crate::array::owned::Array;
25use crate::array::view::ArrayView;
26use crate::dimension::{Dimension, Ix1, Ix2, IxDyn};
27use crate::dtype::Element;
28use crate::error::{FerrayError, FerrayResult};
29
30pub fn array<T: Element, D: Dimension>(dim: D, data: Vec<T>) -> FerrayResult<Array<T, D>> {
43 Array::from_vec(dim, data)
44}
45
46pub fn asarray<T: Element, D: Dimension>(dim: D, data: Vec<T>) -> FerrayResult<Array<T, D>> {
54 Array::from_vec(dim, data)
55}
56
57pub fn frombuffer<T: Element, D: Dimension>(dim: D, buf: &[u8]) -> FerrayResult<Array<T, D>> {
65 let elem_size = std::mem::size_of::<T>();
66 if elem_size == 0 {
67 return Err(FerrayError::invalid_value("zero-sized type"));
68 }
69 if buf.len() % elem_size != 0 {
70 return Err(FerrayError::invalid_value(format!(
71 "buffer length {} is not a multiple of element size {}",
72 buf.len(),
73 elem_size,
74 )));
75 }
76 let n_elems = buf.len() / elem_size;
77 let expected = dim.size();
78 if n_elems != expected {
79 return Err(FerrayError::shape_mismatch(format!(
80 "buffer contains {} elements but shape {:?} requires {}",
81 n_elems,
82 dim.as_slice(),
83 expected,
84 )));
85 }
86 if std::any::TypeId::of::<T>() == std::any::TypeId::of::<bool>() {
89 for &byte in buf {
90 if byte > 1 {
91 return Err(FerrayError::invalid_value(format!(
92 "invalid byte {byte:#04x} for bool (must be 0x00 or 0x01)"
93 )));
94 }
95 }
96 }
97
98 let mut data = Vec::with_capacity(n_elems);
100 for i in 0..n_elems {
101 let start = i * elem_size;
102 let end = start + elem_size;
103 let slice = &buf[start..end];
104 let val = unsafe {
108 let mut val = MaybeUninit::<T>::uninit();
109 std::ptr::copy_nonoverlapping(slice.as_ptr(), val.as_mut_ptr().cast::<u8>(), elem_size);
110 val.assume_init()
111 };
112 data.push(val);
113 }
114 Array::from_vec(dim, data)
115}
116
117pub fn frombuffer_view<T: Element, D: Dimension>(
134 dim: D,
135 buf: &[u8],
136) -> FerrayResult<ArrayView<'_, T, D>> {
137 let elem_size = std::mem::size_of::<T>();
138 if elem_size == 0 {
139 return Err(FerrayError::invalid_value("zero-sized type"));
140 }
141 if buf.len() % elem_size != 0 {
142 return Err(FerrayError::invalid_value(format!(
143 "buffer length {} is not a multiple of element size {}",
144 buf.len(),
145 elem_size,
146 )));
147 }
148 let n_elems = buf.len() / elem_size;
149 let expected = dim.size();
150 if n_elems != expected {
151 return Err(FerrayError::shape_mismatch(format!(
152 "buffer contains {} elements but shape {:?} requires {}",
153 n_elems,
154 dim.as_slice(),
155 expected,
156 )));
157 }
158
159 let align = std::mem::align_of::<T>();
162 let addr = buf.as_ptr() as usize;
163 if addr % align != 0 {
164 return Err(FerrayError::invalid_value(format!(
165 "buffer address 0x{addr:x} is not aligned to {align} bytes required by the element type; \
166 use `frombuffer` for misaligned input"
167 )));
168 }
169
170 if std::any::TypeId::of::<T>() == std::any::TypeId::of::<bool>() {
173 for &byte in buf {
174 if byte > 1 {
175 return Err(FerrayError::invalid_value(format!(
176 "invalid byte {byte:#04x} for bool (must be 0x00 or 0x01)"
177 )));
178 }
179 }
180 }
181
182 let ptr = buf.as_ptr().cast::<T>();
193 let nd_dim = dim.to_ndarray_dim();
194 let nd_view = unsafe { ndarray::ArrayView::from_shape_ptr(nd_dim, ptr) };
195 Ok(ArrayView::from_ndarray(nd_view))
196}
197
198pub fn fromiter<T: Element>(iter: impl IntoIterator<Item = T>) -> FerrayResult<Array<T, Ix1>> {
205 Array::from_iter_1d(iter)
206}
207
208pub fn zeros<T: Element, D: Dimension>(dim: D) -> FerrayResult<Array<T, D>> {
212 Array::zeros(dim)
213}
214
215pub fn ones<T: Element, D: Dimension>(dim: D) -> FerrayResult<Array<T, D>> {
219 Array::ones(dim)
220}
221
222pub fn full<T: Element, D: Dimension>(dim: D, fill_value: T) -> FerrayResult<Array<T, D>> {
226 Array::from_elem(dim, fill_value)
227}
228
229pub fn zeros_like<T: Element, D: Dimension>(other: &Array<T, D>) -> FerrayResult<Array<T, D>> {
233 Array::zeros(other.dim().clone())
234}
235
236pub fn ones_like<T: Element, D: Dimension>(other: &Array<T, D>) -> FerrayResult<Array<T, D>> {
240 Array::ones(other.dim().clone())
241}
242
243pub fn full_like<T: Element, D: Dimension>(
247 other: &Array<T, D>,
248 fill_value: T,
249) -> FerrayResult<Array<T, D>> {
250 Array::from_elem(other.dim().clone(), fill_value)
251}
252
253pub struct UninitArray<T: Element, D: Dimension> {
262 data: Vec<MaybeUninit<T>>,
263 dim: D,
264}
265
266impl<T: Element, D: Dimension> UninitArray<T, D> {
267 #[inline]
269 pub fn shape(&self) -> &[usize] {
270 self.dim.as_slice()
271 }
272
273 #[inline]
275 pub fn size(&self) -> usize {
276 self.data.len()
277 }
278
279 #[inline]
281 pub fn ndim(&self) -> usize {
282 self.dim.ndim()
283 }
284
285 #[inline]
290 pub fn as_mut_ptr(&mut self) -> *mut MaybeUninit<T> {
291 self.data.as_mut_ptr()
292 }
293
294 pub fn write_at(&mut self, flat_index: usize, value: T) -> FerrayResult<()> {
299 let size = self.size();
300 if flat_index >= size {
301 return Err(FerrayError::IndexOutOfBounds {
302 index: flat_index as isize,
303 axis: 0,
304 size,
305 });
306 }
307 self.data[flat_index] = MaybeUninit::new(value);
308 Ok(())
309 }
310
311 pub unsafe fn assume_init(self) -> Array<T, D> {
318 let nd_dim = self.dim.to_ndarray_dim();
319 let len = self.data.len();
320
321 let mut raw_vec = std::mem::ManuallyDrop::new(self.data);
325 let data: Vec<T> = unsafe {
326 Vec::from_raw_parts(raw_vec.as_mut_ptr().cast::<T>(), len, raw_vec.capacity())
327 };
328
329 let inner = ndarray::Array::from_shape_vec(nd_dim, data)
330 .expect("UninitArray assume_init: shape/data mismatch (this is a bug)");
331 Array::from_ndarray(inner)
332 }
333}
334
335pub fn empty<T: Element, D: Dimension>(dim: D) -> UninitArray<T, D> {
343 let size = dim.size();
344 let mut data = Vec::with_capacity(size);
345 unsafe {
348 data.set_len(size);
349 }
350 UninitArray { data, dim }
351}
352
353pub fn empty_like<T: Element, D: Dimension>(other: &Array<T, D>) -> UninitArray<T, D> {
362 empty(other.dim().clone())
363}
364
365pub trait ArangeNum: Element + PartialOrd {
372 fn from_f64(v: f64) -> Self;
374 fn to_f64(self) -> f64;
376}
377
378macro_rules! impl_arange_int {
379 ($($ty:ty),*) => {
380 $(
381 impl ArangeNum for $ty {
382 #[inline]
383 fn from_f64(v: f64) -> Self { v as Self }
384 #[inline]
385 fn to_f64(self) -> f64 { self as f64 }
386 }
387 )*
388 };
389}
390
391macro_rules! impl_arange_float {
392 ($($ty:ty),*) => {
393 $(
394 impl ArangeNum for $ty {
395 #[inline]
396 fn from_f64(v: f64) -> Self { v as Self }
397 #[inline]
398 fn to_f64(self) -> f64 { self as f64 }
399 }
400 )*
401 };
402}
403
404impl_arange_int!(u8, u16, u32, u64, i8, i16, i32, i64);
405impl_arange_float!(f32, f64);
406
407pub fn arange<T: ArangeNum>(start: T, stop: T, step: T) -> FerrayResult<Array<T, Ix1>> {
414 let step_f = step.to_f64();
415 if step_f == 0.0 {
416 return Err(FerrayError::invalid_value("step cannot be zero"));
417 }
418 let start_f = start.to_f64();
419 let stop_f = stop.to_f64();
420 let n = ((stop_f - start_f) / step_f).ceil();
421 let n = if n < 0.0 { 0 } else { n as usize };
422
423 let delta = (start_f + step_f) - start_f;
436 let mut data = Vec::with_capacity(n);
437 for i in 0..n {
438 data.push(T::from_f64(i as f64 * delta + start_f));
439 }
440 let dim = Ix1::new([data.len()]);
441 Array::from_vec(dim, data)
442}
443
444pub trait LinspaceNum: Element + PartialOrd {
446 fn from_f64(v: f64) -> Self;
448 fn to_f64(self) -> f64;
450}
451
452impl LinspaceNum for f32 {
453 #[inline]
454 fn from_f64(v: f64) -> Self {
455 v as Self
456 }
457 #[inline]
458 fn to_f64(self) -> f64 {
459 self as f64
460 }
461}
462
463impl LinspaceNum for f64 {
464 #[inline]
465 fn from_f64(v: f64) -> Self {
466 v
467 }
468 #[inline]
469 fn to_f64(self) -> f64 {
470 self
471 }
472}
473
474pub fn linspace<T: LinspaceNum>(
485 start: T,
486 stop: T,
487 num: usize,
488 endpoint: bool,
489) -> FerrayResult<Array<T, Ix1>> {
490 if num == 0 {
491 return Array::from_vec(Ix1::new([0]), vec![]);
492 }
493 if num == 1 {
494 return Array::from_vec(Ix1::new([1]), vec![start]);
495 }
496 let start_f = start.to_f64();
497 let stop_f = stop.to_f64();
498 let divisor = if endpoint {
499 (num - 1) as f64
500 } else {
501 num as f64
502 };
503 let step = (stop_f - start_f) / divisor;
504 let mut data = Vec::with_capacity(num);
505 for i in 0..num {
506 data.push(T::from_f64(i as f64 * step + start_f));
511 }
512 if endpoint && num > 1 {
516 data[num - 1] = T::from_f64(stop_f);
519 }
520 Array::from_vec(Ix1::new([num]), data)
521}
522
523pub fn logspace<T: LinspaceNum>(
532 start: T,
533 stop: T,
534 num: usize,
535 endpoint: bool,
536 base: f64,
537) -> FerrayResult<Array<T, Ix1>> {
538 let lin = linspace(start, stop, num, endpoint)?;
539 let data: Vec<T> = lin
540 .iter()
541 .map(|v| T::from_f64(base.powf(v.clone().to_f64())))
542 .collect();
543 Array::from_vec(Ix1::new([num]), data)
544}
545
546pub fn geomspace<T: LinspaceNum>(
556 start: T,
557 stop: T,
558 num: usize,
559 endpoint: bool,
560) -> FerrayResult<Array<T, Ix1>> {
561 let start_f = start.clone().to_f64();
562 let stop_f = stop.to_f64();
563 if start_f == 0.0 || stop_f == 0.0 {
564 return Err(FerrayError::invalid_value(
565 "geomspace: start and stop must be non-zero",
566 ));
567 }
568 if (start_f < 0.0) != (stop_f < 0.0) {
569 return Err(FerrayError::invalid_value(
570 "geomspace: start and stop must have the same sign",
571 ));
572 }
573 if num == 0 {
574 return Array::from_vec(Ix1::new([0]), vec![]);
575 }
576 if num == 1 {
577 return Array::from_vec(Ix1::new([1]), vec![start]);
578 }
579 let out_sign = if start_f < 0.0 { -1.0 } else { 1.0 };
590 let rot_start = start_f / out_sign;
591 let rot_stop = stop_f / out_sign;
592 let log_start = rot_start.log10();
593 let log_stop = rot_stop.log10();
594 let divisor = if endpoint {
595 (num - 1) as f64
596 } else {
597 num as f64
598 };
599 let step = (log_stop - log_start) / divisor;
600 let mut data = Vec::with_capacity(num);
601 for i in 0..num {
602 let log_val = i as f64 * step + log_start;
603 data.push(10.0_f64.powf(log_val));
604 }
605 data[0] = rot_start;
607 if num > 1 && endpoint {
608 data[num - 1] = rot_stop;
609 }
610 let out: Vec<T> = data
612 .into_iter()
613 .map(|v| T::from_f64(v * out_sign))
614 .collect();
615 Array::from_vec(Ix1::new([num]), out)
616}
617
618pub fn meshgrid(
632 arrays: &[Array<f64, Ix1>],
633 indexing: &str,
634) -> FerrayResult<Vec<Array<f64, IxDyn>>> {
635 if indexing != "xy" && indexing != "ij" {
636 return Err(FerrayError::invalid_value(
637 "meshgrid: indexing must be 'xy' or 'ij'",
638 ));
639 }
640 let ndim = arrays.len();
641 if ndim == 0 {
642 return Ok(vec![]);
643 }
644
645 let mut shapes: Vec<usize> = arrays.iter().map(|a| a.shape()[0]).collect();
646 if indexing == "xy" && ndim >= 2 {
647 shapes.swap(0, 1);
648 }
649
650 let total: usize = shapes.iter().product();
651 let mut results = Vec::with_capacity(ndim);
652
653 for (k, arr) in arrays.iter().enumerate() {
654 let src_data: Vec<f64> = arr.iter().copied().collect();
655 let mut data = Vec::with_capacity(total);
656 let effective_k = if indexing == "xy" && ndim >= 2 {
658 match k {
659 0 => 1,
660 1 => 0,
661 other => other,
662 }
663 } else {
664 k
665 };
666
667 for flat in 0..total {
669 let mut rem = flat;
671 let mut idx_k = 0;
672 for (d, &s) in shapes.iter().enumerate().rev() {
673 if d == effective_k {
674 idx_k = rem % s;
675 }
676 rem /= s;
677 }
678 data.push(src_data[idx_k]);
679 }
680
681 let dim = IxDyn::new(&shapes);
682 results.push(Array::from_vec(dim, data)?);
683 }
684 Ok(results)
685}
686
687pub fn mgrid(ranges: &[(f64, f64, f64)]) -> FerrayResult<Vec<Array<f64, IxDyn>>> {
697 let mut arrs: Vec<Array<f64, Ix1>> = Vec::with_capacity(ranges.len());
698 for &(start, stop, step) in ranges {
699 arrs.push(arange(start, stop, step)?);
700 }
701 meshgrid(&arrs, "ij")
702}
703
704pub fn ogrid(ranges: &[(f64, f64, f64)]) -> FerrayResult<Vec<Array<f64, IxDyn>>> {
714 let ndim = ranges.len();
715 let mut results = Vec::with_capacity(ndim);
716 for (i, &(start, stop, step)) in ranges.iter().enumerate() {
717 let arr1d = arange(start, stop, step)?;
718 let n = arr1d.shape()[0];
719 let data: Vec<f64> = arr1d.iter().copied().collect();
720 let mut shape = vec![1usize; ndim];
722 shape[i] = n;
723 let dim = IxDyn::new(&shape);
724 results.push(Array::from_vec(dim, data)?);
725 }
726 Ok(results)
727}
728
729pub fn identity<T: Element>(n: usize) -> FerrayResult<Array<T, Ix2>> {
737 eye(n, n, 0)
738}
739
740pub fn eye<T: Element>(n: usize, m: usize, k: isize) -> FerrayResult<Array<T, Ix2>> {
746 let mut data = vec![T::zero(); n * m];
747 for i in 0..n {
748 let j = i as isize + k;
749 if j >= 0 && (j as usize) < m {
750 data[i * m + j as usize] = T::one();
751 }
752 }
753 Array::from_vec(Ix2::new([n, m]), data)
754}
755
756pub fn diag<T: Element>(a: &Array<T, IxDyn>, k: isize) -> FerrayResult<Array<T, IxDyn>> {
766 let shape = a.shape();
767 match shape.len() {
768 1 => {
769 let n = shape[0];
771 let size = n + k.unsigned_abs();
772 let mut data = vec![T::zero(); size * size];
773 let src: Vec<T> = a.iter().cloned().collect();
774 for (i, val) in src.into_iter().enumerate() {
775 let row = if k >= 0 { i } else { i + k.unsigned_abs() };
776 let col = if k >= 0 { i + k as usize } else { i };
777 data[row * size + col] = val;
778 }
779 Array::from_vec(IxDyn::new(&[size, size]), data)
780 }
781 2 => {
782 let (n, m) = (shape[0], shape[1]);
784 let src: Vec<T> = a.iter().cloned().collect();
785 let mut diag_vals = Vec::new();
786 for i in 0..n {
787 let j = i as isize + k;
788 if j >= 0 && (j as usize) < m {
789 diag_vals.push(src[i * m + j as usize].clone());
790 }
791 }
792 let len = diag_vals.len();
793 Array::from_vec(IxDyn::new(&[len]), diag_vals)
794 }
795 _ => Err(FerrayError::invalid_value("diag: input must be 1-D or 2-D")),
796 }
797}
798
799pub fn diagflat<T: Element>(a: &Array<T, IxDyn>, k: isize) -> FerrayResult<Array<T, IxDyn>> {
806 let flat: Vec<T> = a.iter().cloned().collect();
808 let n = flat.len();
809 let arr1d = Array::from_vec(IxDyn::new(&[n]), flat)?;
810 diag(&arr1d, k)
811}
812
813pub fn tri<T: Element>(n: usize, m: usize, k: isize) -> FerrayResult<Array<T, Ix2>> {
819 let mut data = vec![T::zero(); n * m];
820 for i in 0..n {
821 for j in 0..m {
822 if (i as isize) >= (j as isize) - k {
823 data[i * m + j] = T::one();
824 }
825 }
826 }
827 Array::from_vec(Ix2::new([n, m]), data)
828}
829
830pub fn tril<T: Element>(a: &Array<T, IxDyn>, k: isize) -> FerrayResult<Array<T, IxDyn>> {
839 let shape = a.shape();
840 if shape.len() != 2 {
841 return Err(FerrayError::invalid_value("tril: input must be 2-D"));
842 }
843 let (n, m) = (shape[0], shape[1]);
844 let src: Vec<T> = a.iter().cloned().collect();
845 let mut data = vec![T::zero(); n * m];
846 for i in 0..n {
847 for j in 0..m {
848 if (i as isize) >= (j as isize) - k {
849 data[i * m + j] = src[i * m + j].clone();
850 }
851 }
852 }
853 Array::from_vec(IxDyn::new(&[n, m]), data)
854}
855
856pub fn triu<T: Element>(a: &Array<T, IxDyn>, k: isize) -> FerrayResult<Array<T, IxDyn>> {
865 let shape = a.shape();
866 if shape.len() != 2 {
867 return Err(FerrayError::invalid_value("triu: input must be 2-D"));
868 }
869 let (n, m) = (shape[0], shape[1]);
870 let src: Vec<T> = a.iter().cloned().collect();
871 let mut data = vec![T::zero(); n * m];
872 for i in 0..n {
873 for j in 0..m {
874 if (i as isize) <= (j as isize) - k {
875 data[i * m + j] = src[i * m + j].clone();
876 }
877 }
878 }
879 Array::from_vec(IxDyn::new(&[n, m]), data)
880}
881
882pub fn vander<T>(
898 x: &Array<T, Ix1>,
899 n: Option<usize>,
900 increasing: bool,
901) -> FerrayResult<Array<T, IxDyn>>
902where
903 T: Element + std::ops::Mul<Output = T> + Copy,
904{
905 let m = x.shape()[0];
906 if m == 0 {
907 return Err(FerrayError::invalid_value(
908 "vander: input array must not be empty",
909 ));
910 }
911 let cols = n.unwrap_or(m);
912 let xs: Vec<T> = x.iter().copied().collect();
913 let mut data = vec![<T as Element>::one(); m * cols];
914 for (i, &xi) in xs.iter().enumerate() {
915 let mut acc = <T as Element>::one();
917 let mut powers = Vec::with_capacity(cols);
918 for _ in 0..cols {
919 powers.push(acc);
920 acc = acc * xi;
921 }
922 if increasing {
923 for (j, p) in powers.iter().enumerate() {
924 data[i * cols + j] = *p;
925 }
926 } else {
927 for (j, p) in powers.iter().enumerate() {
928 data[i * cols + (cols - 1 - j)] = *p;
929 }
930 }
931 }
932 Array::from_vec(IxDyn::new(&[m, cols]), data)
933}
934
935pub fn copy<T: Element, D: Dimension>(a: &Array<T, D>) -> Array<T, D> {
944 a.clone()
945}
946
947pub fn ascontiguousarray<T: Element, D: Dimension>(a: &Array<T, D>) -> Array<T, D> {
953 a.clone()
954}
955
956pub fn asfortranarray<T: Element, D: Dimension>(a: &Array<T, D>) -> Array<T, D> {
972 let transposed = a.inner.view().reversed_axes();
973 let c_contig = transposed.as_standard_layout().into_owned();
974 let f_contig = c_contig.reversed_axes();
975 Array::<T, D>::from_ndarray(f_contig)
976}
977
978pub fn asanyarray<T: Element, D: Dimension>(a: &Array<T, D>) -> Array<T, D> {
987 a.clone()
988}
989
990pub fn asarray_chkfinite<T, D: Dimension>(a: &Array<T, D>) -> FerrayResult<Array<T, D>>
998where
999 T: Element + num_traits::Float,
1000{
1001 for v in a.iter() {
1002 if !v.is_finite() {
1003 return Err(FerrayError::invalid_value(
1004 "asarray_chkfinite: array contains non-finite values (NaN or Inf)",
1005 ));
1006 }
1007 }
1008 Ok(a.clone())
1009}
1010
1011pub fn require<T: Element, D: Dimension>(a: &Array<T, D>, _requirements: &str) -> Array<T, D> {
1022 a.clone()
1023}
1024
1025pub fn fromfunction<T, D, F>(shape: D, mut f: F) -> FerrayResult<Array<T, D>>
1040where
1041 T: Element,
1042 D: Dimension,
1043 F: FnMut(&[usize]) -> T,
1044{
1045 let dims: Vec<usize> = shape.as_slice().to_vec();
1046 let total: usize = dims.iter().product();
1047 let mut data = Vec::with_capacity(total);
1048 let mut idx = vec![0usize; dims.len()];
1049 for _ in 0..total {
1050 data.push(f(&idx));
1051 for axis in (0..dims.len()).rev() {
1053 idx[axis] += 1;
1054 if idx[axis] < dims[axis] {
1055 break;
1056 }
1057 idx[axis] = 0;
1058 }
1059 }
1060 Array::from_vec(shape, data)
1061}
1062
1063pub fn fromstring<T>(s: &str, sep: &str) -> FerrayResult<Array<T, Ix1>>
1075where
1076 T: Element + std::str::FromStr,
1077 <T as std::str::FromStr>::Err: std::fmt::Display,
1078{
1079 let parts: Vec<&str> = if sep.is_empty() {
1080 s.split_whitespace().collect()
1081 } else {
1082 s.split(sep)
1083 .map(str::trim)
1084 .filter(|t| !t.is_empty())
1085 .collect()
1086 };
1087 let mut data = Vec::with_capacity(parts.len());
1088 for tok in parts {
1089 let v = tok.parse::<T>().map_err(|e| {
1090 FerrayError::invalid_value(format!("fromstring: failed to parse {tok:?}: {e}"))
1091 })?;
1092 data.push(v);
1093 }
1094 let n = data.len();
1095 Array::from_vec(Ix1::new([n]), data)
1096}
1097
1098pub fn fromfile<T, P: AsRef<std::path::Path>>(path: P, sep: &str) -> FerrayResult<Array<T, Ix1>>
1109where
1110 T: Element + std::str::FromStr,
1111 <T as std::str::FromStr>::Err: std::fmt::Display,
1112{
1113 let s = std::fs::read_to_string(path)
1114 .map_err(|e| FerrayError::invalid_value(format!("fromfile: {e}")))?;
1115 fromstring(&s, sep)
1116}
1117
1118#[cfg(test)]
1123mod tests {
1124 use super::*;
1125 use crate::dimension::{Ix1, Ix2, IxDyn};
1126
1127 #[test]
1130 fn test_array_creation() {
1131 let a = array(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]).unwrap();
1132 assert_eq!(a.shape(), &[2, 3]);
1133 assert_eq!(a.size(), 6);
1134 }
1135
1136 #[test]
1137 fn test_asarray() {
1138 let a = asarray(Ix1::new([3]), vec![1, 2, 3]).unwrap();
1139 assert_eq!(a.as_slice().unwrap(), &[1, 2, 3]);
1140 }
1141
1142 #[test]
1143 fn test_frombuffer() {
1144 let bytes: Vec<u8> = vec![1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0];
1145 let a = frombuffer::<i32, Ix1>(Ix1::new([3]), &bytes).unwrap();
1146 assert_eq!(a.as_slice().unwrap(), &[1, 2, 3]);
1147 }
1148
1149 #[test]
1150 fn test_frombuffer_bad_length() {
1151 let bytes: Vec<u8> = vec![1, 0, 0];
1152 assert!(frombuffer::<i32, Ix1>(Ix1::new([1]), &bytes).is_err());
1153 }
1154
1155 #[test]
1156 fn test_frombuffer_bool() {
1157 let bytes: Vec<u8> = vec![0, 1, 0, 1, 1];
1162 let a = frombuffer::<bool, Ix1>(Ix1::new([5]), &bytes).unwrap();
1163 assert_eq!(a.as_slice().unwrap(), &[false, true, false, true, true]);
1164 }
1165
1166 #[test]
1167 fn test_frombuffer_bool_wrong_length() {
1168 let bytes: Vec<u8> = vec![0, 1];
1171 assert!(frombuffer::<bool, Ix1>(Ix1::new([3]), &bytes).is_err());
1172 }
1173
1174 fn aligned_bytes<T: Copy>(src: &[T]) -> Vec<u8> {
1179 let n = std::mem::size_of_val(src);
1180 let mut out = vec![0u8; n];
1181 unsafe {
1183 std::ptr::copy_nonoverlapping(src.as_ptr().cast::<u8>(), out.as_mut_ptr(), n);
1184 }
1185 out
1186 }
1187
1188 #[test]
1189 fn test_frombuffer_view_i32_is_zero_copy() {
1190 let source: Vec<i32> = vec![10, 20, 30];
1192 let bytes = aligned_bytes(&source);
1193 let view = frombuffer_view::<i32, Ix1>(Ix1::new([3]), &bytes).unwrap();
1194 assert_eq!(view.shape(), &[3]);
1195 let values: Vec<i32> = view.iter().copied().collect();
1196 assert_eq!(values, vec![10, 20, 30]);
1197 assert_eq!(view.as_ptr().cast::<u8>(), bytes.as_ptr());
1200 }
1201
1202 #[test]
1203 fn test_frombuffer_view_f64_2d() {
1204 let source: Vec<f64> = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
1205 let bytes = aligned_bytes(&source);
1206 let view = frombuffer_view::<f64, Ix2>(Ix2::new([2, 3]), &bytes).unwrap();
1207 assert_eq!(view.shape(), &[2, 3]);
1208 let values: Vec<f64> = view.iter().copied().collect();
1209 assert_eq!(values, source);
1210 }
1211
1212 #[test]
1213 fn test_frombuffer_view_bool_valid() {
1214 let bytes: Vec<u8> = vec![0, 1, 0, 1];
1215 let view = frombuffer_view::<bool, Ix1>(Ix1::new([4]), &bytes).unwrap();
1216 let values: Vec<bool> = view.iter().copied().collect();
1217 assert_eq!(values, vec![false, true, false, true]);
1218 }
1219
1220 #[test]
1221 fn test_frombuffer_view_bool_rejects_invalid_byte() {
1222 let bytes: Vec<u8> = vec![0, 1, 42]; assert!(frombuffer_view::<bool, Ix1>(Ix1::new([3]), &bytes).is_err());
1224 }
1225
1226 #[test]
1227 fn test_frombuffer_view_rejects_wrong_length() {
1228 let bytes = vec![0u8; 13];
1230 assert!(frombuffer_view::<i32, Ix1>(Ix1::new([3]), &bytes).is_err());
1231 let bytes = vec![0u8; 8];
1233 assert!(frombuffer_view::<i32, Ix1>(Ix1::new([3]), &bytes).is_err());
1234 }
1235
1236 #[test]
1237 fn test_frombuffer_view_rejects_misalignment() {
1238 let mut backing: Vec<u8> = vec![0u8; 1 + 4 * 3];
1240 for (i, chunk) in backing[1..].chunks_exact_mut(4).enumerate() {
1241 chunk.copy_from_slice(&(i as i32).to_ne_bytes());
1242 }
1243 let misaligned = &backing[1..];
1244 assert!((misaligned.as_ptr() as usize) % 4 != 0);
1247 assert!(frombuffer_view::<i32, Ix1>(Ix1::new([3]), misaligned).is_err());
1248 }
1249
1250 #[test]
1251 fn test_fromiter() {
1252 let a = fromiter((0..5).map(|x| x as f64)).unwrap();
1253 assert_eq!(a.shape(), &[5]);
1254 assert_eq!(a.as_slice().unwrap(), &[0.0, 1.0, 2.0, 3.0, 4.0]);
1255 }
1256
1257 #[test]
1258 fn test_zeros() {
1259 let a = zeros::<f64, Ix2>(Ix2::new([3, 4])).unwrap();
1260 assert_eq!(a.shape(), &[3, 4]);
1261 assert!(a.iter().all(|&v| v == 0.0));
1262 }
1263
1264 #[test]
1265 fn test_ones() {
1266 let a = ones::<f64, Ix1>(Ix1::new([5])).unwrap();
1267 assert!(a.iter().all(|&v| v == 1.0));
1268 }
1269
1270 #[test]
1271 fn test_full() {
1272 let a = full(Ix1::new([4]), 42i32).unwrap();
1273 assert!(a.iter().all(|&v| v == 42));
1274 }
1275
1276 #[test]
1277 fn test_zeros_like() {
1278 let a = ones::<f64, Ix2>(Ix2::new([2, 3])).unwrap();
1279 let b = zeros_like(&a).unwrap();
1280 assert_eq!(b.shape(), &[2, 3]);
1281 assert!(b.iter().all(|&v| v == 0.0));
1282 }
1283
1284 #[test]
1285 fn test_ones_like() {
1286 let a = zeros::<f64, Ix1>(Ix1::new([4])).unwrap();
1287 let b = ones_like(&a).unwrap();
1288 assert!(b.iter().all(|&v| v == 1.0));
1289 }
1290
1291 #[test]
1292 fn test_full_like() {
1293 let a = zeros::<i32, Ix1>(Ix1::new([3])).unwrap();
1294 let b = full_like(&a, 7).unwrap();
1295 assert!(b.iter().all(|&v| v == 7));
1296 }
1297
1298 #[test]
1301 fn test_empty_and_init() {
1302 let mut u = empty::<f64, Ix1>(Ix1::new([3]));
1303 assert_eq!(u.shape(), &[3]);
1304 u.write_at(0, 1.0).unwrap();
1305 u.write_at(1, 2.0).unwrap();
1306 u.write_at(2, 3.0).unwrap();
1307 let a = unsafe { u.assume_init() };
1309 assert_eq!(a.as_slice().unwrap(), &[1.0, 2.0, 3.0]);
1310 }
1311
1312 #[test]
1313 fn test_empty_write_oob() {
1314 let mut u = empty::<f64, Ix1>(Ix1::new([2]));
1315 assert!(u.write_at(5, 1.0).is_err());
1316 }
1317
1318 #[test]
1320 fn test_empty_like_matches_shape_2d() {
1321 use crate::dimension::Ix2;
1322 let src = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
1323 .unwrap();
1324 let mut u = empty_like(&src);
1325 assert_eq!(u.shape(), &[2, 3]);
1326 assert_eq!(u.size(), 6);
1327 assert_eq!(u.ndim(), 2);
1328
1329 for i in 0..6 {
1331 u.write_at(i, -(i as f64)).unwrap();
1332 }
1333 let out = unsafe { u.assume_init() };
1335 assert_eq!(out.shape(), &[2, 3]);
1336 assert_eq!(
1337 out.as_slice().unwrap(),
1338 &[0.0, -1.0, -2.0, -3.0, -4.0, -5.0]
1339 );
1340 assert_eq!(src.as_slice().unwrap(), &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1342 }
1343
1344 #[test]
1345 fn test_empty_like_zero_sized() {
1346 let src = Array::<f64, Ix1>::from_vec(Ix1::new([0]), vec![]).unwrap();
1347 let u = empty_like(&src);
1348 assert_eq!(u.shape(), &[0]);
1349 assert_eq!(u.size(), 0);
1350 let out = unsafe { u.assume_init() };
1352 assert_eq!(out.size(), 0);
1353 }
1354
1355 #[test]
1358 fn test_arange_int() {
1359 let a = arange(0i32, 5, 1).unwrap();
1360 assert_eq!(a.as_slice().unwrap(), &[0, 1, 2, 3, 4]);
1361 }
1362
1363 #[test]
1364 fn test_arange_float() {
1365 let a = arange(0.0_f64, 1.0, 0.25).unwrap();
1366 assert_eq!(a.shape(), &[4]);
1367 let data = a.as_slice().unwrap();
1368 assert!((data[0] - 0.0).abs() < 1e-10);
1369 assert!((data[1] - 0.25).abs() < 1e-10);
1370 assert!((data[2] - 0.5).abs() < 1e-10);
1371 assert!((data[3] - 0.75).abs() < 1e-10);
1372 }
1373
1374 #[test]
1375 fn test_arange_negative_step() {
1376 let a = arange(5.0_f64, 0.0, -1.0).unwrap();
1377 assert_eq!(a.shape(), &[5]);
1378 }
1379
1380 #[test]
1381 fn test_arange_zero_step() {
1382 assert!(arange(0.0_f64, 1.0, 0.0).is_err());
1383 }
1384
1385 #[test]
1386 fn test_arange_empty() {
1387 let a = arange(5i32, 0, 1).unwrap();
1388 assert_eq!(a.shape(), &[0]);
1389 }
1390
1391 #[test]
1392 fn test_linspace() {
1393 let a = linspace(0.0_f64, 1.0, 5, true).unwrap();
1394 assert_eq!(a.shape(), &[5]);
1395 let data = a.as_slice().unwrap();
1396 assert!((data[0] - 0.0).abs() < 1e-10);
1397 assert!((data[4] - 1.0).abs() < 1e-10);
1398 assert!((data[2] - 0.5).abs() < 1e-10);
1399 }
1400
1401 #[test]
1402 fn test_linspace_no_endpoint() {
1403 let a = linspace(0.0_f64, 1.0, 4, false).unwrap();
1404 assert_eq!(a.shape(), &[4]);
1405 let data = a.as_slice().unwrap();
1406 assert!((data[0] - 0.0).abs() < 1e-10);
1407 assert!((data[1] - 0.25).abs() < 1e-10);
1408 }
1409
1410 #[test]
1411 fn test_linspace_single() {
1412 let a = linspace(5.0_f64, 10.0, 1, true).unwrap();
1413 assert_eq!(a.as_slice().unwrap(), &[5.0]);
1414 }
1415
1416 #[test]
1417 fn test_linspace_empty() {
1418 let a = linspace(0.0_f64, 1.0, 0, true).unwrap();
1419 assert_eq!(a.shape(), &[0]);
1420 }
1421
1422 #[test]
1423 fn test_logspace() {
1424 let a = logspace(0.0_f64, 2.0, 3, true, 10.0).unwrap();
1425 let data = a.as_slice().unwrap();
1426 assert!((data[0] - 1.0).abs() < 1e-10); assert!((data[1] - 10.0).abs() < 1e-10); assert!((data[2] - 100.0).abs() < 1e-10); }
1430
1431 #[test]
1432 fn test_geomspace() {
1433 let a = geomspace(1.0_f64, 1000.0, 4, true).unwrap();
1434 let data = a.as_slice().unwrap();
1435 assert!((data[0] - 1.0).abs() < 1e-10);
1436 assert!((data[1] - 10.0).abs() < 1e-8);
1437 assert!((data[2] - 100.0).abs() < 1e-6);
1438 assert!((data[3] - 1000.0).abs() < 1e-4);
1439 }
1440
1441 #[test]
1442 fn test_geomspace_zero_start() {
1443 assert!(geomspace(0.0_f64, 1.0, 5, true).is_err());
1444 }
1445
1446 #[test]
1447 fn test_geomspace_different_signs() {
1448 assert!(geomspace(-1.0_f64, 1.0, 5, true).is_err());
1449 }
1450
1451 #[test]
1452 fn test_meshgrid_xy() {
1453 let x = Array::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
1454 let y = Array::from_vec(Ix1::new([2]), vec![4.0, 5.0]).unwrap();
1455 let grids = meshgrid(&[x, y], "xy").unwrap();
1456 assert_eq!(grids.len(), 2);
1457 assert_eq!(grids[0].shape(), &[2, 3]);
1458 assert_eq!(grids[1].shape(), &[2, 3]);
1459 let xdata: Vec<f64> = grids[0].iter().copied().collect();
1461 assert_eq!(xdata, vec![1.0, 2.0, 3.0, 1.0, 2.0, 3.0]);
1462 let ydata: Vec<f64> = grids[1].iter().copied().collect();
1464 assert_eq!(ydata, vec![4.0, 4.0, 4.0, 5.0, 5.0, 5.0]);
1465 }
1466
1467 #[test]
1468 fn test_meshgrid_ij() {
1469 let x = Array::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
1470 let y = Array::from_vec(Ix1::new([2]), vec![4.0, 5.0]).unwrap();
1471 let grids = meshgrid(&[x, y], "ij").unwrap();
1472 assert_eq!(grids.len(), 2);
1473 assert_eq!(grids[0].shape(), &[3, 2]);
1474 assert_eq!(grids[1].shape(), &[3, 2]);
1475 }
1476
1477 #[test]
1478 fn test_meshgrid_bad_indexing() {
1479 assert!(meshgrid(&[], "zz").is_err());
1480 }
1481
1482 #[test]
1483 fn test_mgrid() {
1484 let grids = mgrid(&[(0.0, 3.0, 1.0), (0.0, 2.0, 1.0)]).unwrap();
1485 assert_eq!(grids.len(), 2);
1486 assert_eq!(grids[0].shape(), &[3, 2]);
1487 }
1488
1489 #[test]
1490 fn test_ogrid() {
1491 let grids = ogrid(&[(0.0, 3.0, 1.0), (0.0, 2.0, 1.0)]).unwrap();
1492 assert_eq!(grids.len(), 2);
1493 assert_eq!(grids[0].shape(), &[3, 1]);
1494 assert_eq!(grids[1].shape(), &[1, 2]);
1495 }
1496
1497 #[test]
1500 fn test_identity() {
1501 let a = identity::<f64>(3).unwrap();
1502 assert_eq!(a.shape(), &[3, 3]);
1503 let data = a.as_slice().unwrap();
1504 assert_eq!(data, &[1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]);
1505 }
1506
1507 #[test]
1508 fn test_eye() {
1509 let a = eye::<f64>(3, 4, 0).unwrap();
1510 assert_eq!(a.shape(), &[3, 4]);
1511 let data = a.as_slice().unwrap();
1512 assert_eq!(
1513 data,
1514 &[1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0]
1515 );
1516 }
1517
1518 #[test]
1519 fn test_eye_positive_k() {
1520 let a = eye::<f64>(3, 3, 1).unwrap();
1521 let data = a.as_slice().unwrap();
1522 assert_eq!(data, &[0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0]);
1523 }
1524
1525 #[test]
1526 fn test_eye_negative_k() {
1527 let a = eye::<f64>(3, 3, -1).unwrap();
1528 let data = a.as_slice().unwrap();
1529 assert_eq!(data, &[0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0]);
1530 }
1531
1532 #[test]
1533 fn test_diag_from_1d() {
1534 let a = Array::from_vec(IxDyn::new(&[3]), vec![1.0, 2.0, 3.0]).unwrap();
1535 let d = diag(&a, 0).unwrap();
1536 assert_eq!(d.shape(), &[3, 3]);
1537 let data: Vec<f64> = d.iter().copied().collect();
1538 assert_eq!(data, vec![1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 3.0]);
1539 }
1540
1541 #[test]
1542 fn test_diag_from_2d() {
1543 let a = Array::from_vec(
1544 IxDyn::new(&[3, 3]),
1545 vec![1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 3.0],
1546 )
1547 .unwrap();
1548 let d = diag(&a, 0).unwrap();
1549 assert_eq!(d.shape(), &[3]);
1550 let data: Vec<f64> = d.iter().copied().collect();
1551 assert_eq!(data, vec![1.0, 2.0, 3.0]);
1552 }
1553
1554 #[test]
1555 fn test_diag_k_positive() {
1556 let a = Array::from_vec(IxDyn::new(&[2]), vec![1.0, 2.0]).unwrap();
1557 let d = diag(&a, 1).unwrap();
1558 assert_eq!(d.shape(), &[3, 3]);
1559 let data: Vec<f64> = d.iter().copied().collect();
1560 assert_eq!(data, vec![0.0, 1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0]);
1561 }
1562
1563 #[test]
1564 fn test_diagflat() {
1565 let a = Array::from_vec(IxDyn::new(&[2, 2]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
1566 let d = diagflat(&a, 0).unwrap();
1567 assert_eq!(d.shape(), &[4, 4]);
1568 let extracted = diag(&d, 0).unwrap();
1570 let data: Vec<f64> = extracted.iter().copied().collect();
1571 assert_eq!(data, vec![1.0, 2.0, 3.0, 4.0]);
1572 }
1573
1574 #[test]
1575 fn test_tri() {
1576 let a = tri::<f64>(3, 3, 0).unwrap();
1577 let data = a.as_slice().unwrap();
1578 assert_eq!(data, &[1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0]);
1579 }
1580
1581 #[test]
1582 fn test_tril() {
1583 let a = Array::from_vec(
1584 IxDyn::new(&[3, 3]),
1585 vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0],
1586 )
1587 .unwrap();
1588 let t = tril(&a, 0).unwrap();
1589 let data: Vec<f64> = t.iter().copied().collect();
1590 assert_eq!(data, vec![1.0, 0.0, 0.0, 4.0, 5.0, 0.0, 7.0, 8.0, 9.0]);
1591 }
1592
1593 #[test]
1594 fn test_triu() {
1595 let a = Array::from_vec(
1596 IxDyn::new(&[3, 3]),
1597 vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0],
1598 )
1599 .unwrap();
1600 let t = triu(&a, 0).unwrap();
1601 let data: Vec<f64> = t.iter().copied().collect();
1602 assert_eq!(data, vec![1.0, 2.0, 3.0, 0.0, 5.0, 6.0, 0.0, 0.0, 9.0]);
1603 }
1604
1605 #[test]
1606 fn test_tril_not_2d() {
1607 let a = Array::from_vec(IxDyn::new(&[3]), vec![1.0, 2.0, 3.0]).unwrap();
1608 assert!(tril(&a, 0).is_err());
1609 }
1610
1611 #[test]
1612 fn test_triu_not_2d() {
1613 let a = Array::from_vec(IxDyn::new(&[3]), vec![1.0, 2.0, 3.0]).unwrap();
1614 assert!(triu(&a, 0).is_err());
1615 }
1616
1617 #[test]
1620 fn test_vander_default_decreasing() {
1621 let x = Array::from_vec(Ix1::new([3]), vec![1.0_f64, 2.0, 3.0]).unwrap();
1622 let v = vander(&x, None, false).unwrap();
1623 assert_eq!(v.shape(), &[3, 3]);
1624 let data: Vec<f64> = v.iter().copied().collect();
1626 assert_eq!(data, vec![1.0, 1.0, 1.0, 4.0, 2.0, 1.0, 9.0, 3.0, 1.0]);
1627 }
1628
1629 #[test]
1630 fn test_vander_increasing() {
1631 let x = Array::from_vec(Ix1::new([3]), vec![1.0_f64, 2.0, 3.0]).unwrap();
1632 let v = vander(&x, None, true).unwrap();
1633 let data: Vec<f64> = v.iter().copied().collect();
1634 assert_eq!(data, vec![1.0, 1.0, 1.0, 1.0, 2.0, 4.0, 1.0, 3.0, 9.0]);
1636 }
1637
1638 #[test]
1639 fn test_vander_explicit_n() {
1640 let x = Array::from_vec(Ix1::new([2]), vec![2.0_f64, 3.0]).unwrap();
1641 let v = vander(&x, Some(4), false).unwrap();
1642 assert_eq!(v.shape(), &[2, 4]);
1643 let data: Vec<f64> = v.iter().copied().collect();
1646 assert_eq!(data, vec![8.0, 4.0, 2.0, 1.0, 27.0, 9.0, 3.0, 1.0]);
1647 }
1648
1649 #[test]
1650 fn test_vander_empty() {
1651 let x: Array<f64, Ix1> = Array::from_vec(Ix1::new([0]), vec![]).unwrap();
1652 assert!(vander(&x, None, false).is_err());
1653 }
1654
1655 #[test]
1658 fn test_copy() {
1659 let a = array(Ix1::new([3]), vec![1.0_f64, 2.0, 3.0]).unwrap();
1660 let b = copy(&a);
1661 assert_eq!(
1662 a.iter().copied().collect::<Vec<_>>(),
1663 b.iter().copied().collect::<Vec<_>>()
1664 );
1665 assert_ne!(
1667 a.as_slice().unwrap().as_ptr(),
1668 b.as_slice().unwrap().as_ptr()
1669 );
1670 }
1671
1672 #[test]
1673 fn test_ascontiguousarray() {
1674 let a = array(Ix1::new([3]), vec![1.0_f64, 2.0, 3.0]).unwrap();
1675 let b = ascontiguousarray(&a);
1676 assert_eq!(b.shape(), a.shape());
1677 }
1678
1679 #[test]
1680 fn test_asarray_chkfinite_ok() {
1681 let a = array(Ix1::new([3]), vec![1.0_f64, 2.0, 3.0]).unwrap();
1682 assert!(asarray_chkfinite(&a).is_ok());
1683 }
1684
1685 #[test]
1686 fn test_asarray_chkfinite_nan_fails() {
1687 let a = array(Ix1::new([3]), vec![1.0_f64, f64::NAN, 3.0]).unwrap();
1688 assert!(asarray_chkfinite(&a).is_err());
1689 }
1690
1691 #[test]
1692 fn test_asarray_chkfinite_inf_fails() {
1693 let a = array(Ix1::new([3]), vec![1.0_f64, f64::INFINITY, 3.0]).unwrap();
1694 assert!(asarray_chkfinite(&a).is_err());
1695 }
1696
1697 #[test]
1698 fn test_require() {
1699 let a = array(Ix1::new([3]), vec![1, 2, 3]).unwrap();
1700 let b = require(&a, "CW");
1701 assert_eq!(b.shape(), a.shape());
1702 }
1703
1704 #[test]
1707 fn test_fromfunction_2d() {
1708 let a = fromfunction(Ix2::new([3, 3]), |idx| (idx[0] + idx[1]) as i32).unwrap();
1709 let data: Vec<i32> = a.iter().copied().collect();
1710 assert_eq!(data, vec![0, 1, 2, 1, 2, 3, 2, 3, 4]);
1711 }
1712
1713 #[test]
1714 fn test_fromfunction_1d() {
1715 let a = fromfunction(Ix1::new([5]), |idx| idx[0] as f64 * 2.0).unwrap();
1716 let data: Vec<f64> = a.iter().copied().collect();
1717 assert_eq!(data, vec![0.0, 2.0, 4.0, 6.0, 8.0]);
1718 }
1719
1720 #[test]
1721 fn test_fromstring_whitespace() {
1722 let a: Array<f64, Ix1> = fromstring("1.5 2.5 3.5", " ").unwrap();
1723 let data: Vec<f64> = a.iter().copied().collect();
1724 assert_eq!(data, vec![1.5, 2.5, 3.5]);
1725 }
1726
1727 #[test]
1728 fn test_fromstring_comma() {
1729 let a: Array<i32, Ix1> = fromstring("1, 2, 3, 4", ",").unwrap();
1730 assert_eq!(a.shape(), &[4]);
1731 let data: Vec<i32> = a.iter().copied().collect();
1732 assert_eq!(data, vec![1, 2, 3, 4]);
1733 }
1734
1735 #[test]
1736 fn test_fromstring_empty_sep_uses_whitespace() {
1737 let a: Array<i32, Ix1> = fromstring("1 2\t3\n4", "").unwrap();
1738 let data: Vec<i32> = a.iter().copied().collect();
1739 assert_eq!(data, vec![1, 2, 3, 4]);
1740 }
1741
1742 #[test]
1743 fn test_fromstring_bad_token() {
1744 let r: FerrayResult<Array<f64, Ix1>> = fromstring("1.0 abc 3.0", " ");
1745 assert!(r.is_err());
1746 }
1747}