1use std::mem::MaybeUninit;
7
8use crate::array::owned::Array;
9use crate::array::view::ArrayView;
10use crate::dimension::{Dimension, Ix1, Ix2, IxDyn};
11use crate::dtype::Element;
12use crate::error::{FerrayError, FerrayResult};
13
14pub fn array<T: Element, D: Dimension>(dim: D, data: Vec<T>) -> FerrayResult<Array<T, D>> {
27 Array::from_vec(dim, data)
28}
29
30pub fn asarray<T: Element, D: Dimension>(dim: D, data: Vec<T>) -> FerrayResult<Array<T, D>> {
38 Array::from_vec(dim, data)
39}
40
41pub fn frombuffer<T: Element, D: Dimension>(dim: D, buf: &[u8]) -> FerrayResult<Array<T, D>> {
49 let elem_size = std::mem::size_of::<T>();
50 if elem_size == 0 {
51 return Err(FerrayError::invalid_value("zero-sized type"));
52 }
53 if buf.len() % elem_size != 0 {
54 return Err(FerrayError::invalid_value(format!(
55 "buffer length {} is not a multiple of element size {}",
56 buf.len(),
57 elem_size,
58 )));
59 }
60 let n_elems = buf.len() / elem_size;
61 let expected = dim.size();
62 if n_elems != expected {
63 return Err(FerrayError::shape_mismatch(format!(
64 "buffer contains {} elements but shape {:?} requires {}",
65 n_elems,
66 dim.as_slice(),
67 expected,
68 )));
69 }
70 if std::any::TypeId::of::<T>() == std::any::TypeId::of::<bool>() {
73 for &byte in buf {
74 if byte > 1 {
75 return Err(FerrayError::invalid_value(format!(
76 "invalid byte {byte:#04x} for bool (must be 0x00 or 0x01)"
77 )));
78 }
79 }
80 }
81
82 let mut data = Vec::with_capacity(n_elems);
84 for i in 0..n_elems {
85 let start = i * elem_size;
86 let end = start + elem_size;
87 let slice = &buf[start..end];
88 let val = unsafe {
92 let mut val = MaybeUninit::<T>::uninit();
93 std::ptr::copy_nonoverlapping(slice.as_ptr(), val.as_mut_ptr().cast::<u8>(), elem_size);
94 val.assume_init()
95 };
96 data.push(val);
97 }
98 Array::from_vec(dim, data)
99}
100
101pub fn frombuffer_view<T: Element, D: Dimension>(
118 dim: D,
119 buf: &[u8],
120) -> FerrayResult<ArrayView<'_, T, D>> {
121 let elem_size = std::mem::size_of::<T>();
122 if elem_size == 0 {
123 return Err(FerrayError::invalid_value("zero-sized type"));
124 }
125 if buf.len() % elem_size != 0 {
126 return Err(FerrayError::invalid_value(format!(
127 "buffer length {} is not a multiple of element size {}",
128 buf.len(),
129 elem_size,
130 )));
131 }
132 let n_elems = buf.len() / elem_size;
133 let expected = dim.size();
134 if n_elems != expected {
135 return Err(FerrayError::shape_mismatch(format!(
136 "buffer contains {} elements but shape {:?} requires {}",
137 n_elems,
138 dim.as_slice(),
139 expected,
140 )));
141 }
142
143 let align = std::mem::align_of::<T>();
146 let addr = buf.as_ptr() as usize;
147 if addr % align != 0 {
148 return Err(FerrayError::invalid_value(format!(
149 "buffer address 0x{addr:x} is not aligned to {align} bytes required by the element type; \
150 use `frombuffer` for misaligned input"
151 )));
152 }
153
154 if std::any::TypeId::of::<T>() == std::any::TypeId::of::<bool>() {
157 for &byte in buf {
158 if byte > 1 {
159 return Err(FerrayError::invalid_value(format!(
160 "invalid byte {byte:#04x} for bool (must be 0x00 or 0x01)"
161 )));
162 }
163 }
164 }
165
166 let ptr = buf.as_ptr().cast::<T>();
177 let nd_dim = dim.to_ndarray_dim();
178 let nd_view = unsafe { ndarray::ArrayView::from_shape_ptr(nd_dim, ptr) };
179 Ok(ArrayView::from_ndarray(nd_view))
180}
181
182pub fn fromiter<T: Element>(iter: impl IntoIterator<Item = T>) -> FerrayResult<Array<T, Ix1>> {
189 Array::from_iter_1d(iter)
190}
191
192pub fn zeros<T: Element, D: Dimension>(dim: D) -> FerrayResult<Array<T, D>> {
196 Array::zeros(dim)
197}
198
199pub fn ones<T: Element, D: Dimension>(dim: D) -> FerrayResult<Array<T, D>> {
203 Array::ones(dim)
204}
205
206pub fn full<T: Element, D: Dimension>(dim: D, fill_value: T) -> FerrayResult<Array<T, D>> {
210 Array::from_elem(dim, fill_value)
211}
212
213pub fn zeros_like<T: Element, D: Dimension>(other: &Array<T, D>) -> FerrayResult<Array<T, D>> {
217 Array::zeros(other.dim().clone())
218}
219
220pub fn ones_like<T: Element, D: Dimension>(other: &Array<T, D>) -> FerrayResult<Array<T, D>> {
224 Array::ones(other.dim().clone())
225}
226
227pub fn full_like<T: Element, D: Dimension>(
231 other: &Array<T, D>,
232 fill_value: T,
233) -> FerrayResult<Array<T, D>> {
234 Array::from_elem(other.dim().clone(), fill_value)
235}
236
237pub struct UninitArray<T: Element, D: Dimension> {
246 data: Vec<MaybeUninit<T>>,
247 dim: D,
248}
249
250impl<T: Element, D: Dimension> UninitArray<T, D> {
251 #[inline]
253 pub fn shape(&self) -> &[usize] {
254 self.dim.as_slice()
255 }
256
257 #[inline]
259 pub fn size(&self) -> usize {
260 self.data.len()
261 }
262
263 #[inline]
265 pub fn ndim(&self) -> usize {
266 self.dim.ndim()
267 }
268
269 #[inline]
274 pub fn as_mut_ptr(&mut self) -> *mut MaybeUninit<T> {
275 self.data.as_mut_ptr()
276 }
277
278 pub fn write_at(&mut self, flat_index: usize, value: T) -> FerrayResult<()> {
283 let size = self.size();
284 if flat_index >= size {
285 return Err(FerrayError::IndexOutOfBounds {
286 index: flat_index as isize,
287 axis: 0,
288 size,
289 });
290 }
291 self.data[flat_index] = MaybeUninit::new(value);
292 Ok(())
293 }
294
295 pub unsafe fn assume_init(self) -> Array<T, D> {
302 let nd_dim = self.dim.to_ndarray_dim();
303 let len = self.data.len();
304
305 let mut raw_vec = std::mem::ManuallyDrop::new(self.data);
309 let data: Vec<T> = unsafe {
310 Vec::from_raw_parts(raw_vec.as_mut_ptr().cast::<T>(), len, raw_vec.capacity())
311 };
312
313 let inner = ndarray::Array::from_shape_vec(nd_dim, data)
314 .expect("UninitArray assume_init: shape/data mismatch (this is a bug)");
315 Array::from_ndarray(inner)
316 }
317}
318
319pub fn empty<T: Element, D: Dimension>(dim: D) -> UninitArray<T, D> {
327 let size = dim.size();
328 let mut data = Vec::with_capacity(size);
329 unsafe {
332 data.set_len(size);
333 }
334 UninitArray { data, dim }
335}
336
337pub fn empty_like<T: Element, D: Dimension>(other: &Array<T, D>) -> UninitArray<T, D> {
346 empty(other.dim().clone())
347}
348
349pub trait ArangeNum: Element + PartialOrd {
356 fn from_f64(v: f64) -> Self;
358 fn to_f64(self) -> f64;
360}
361
362macro_rules! impl_arange_int {
363 ($($ty:ty),*) => {
364 $(
365 impl ArangeNum for $ty {
366 #[inline]
367 fn from_f64(v: f64) -> Self { v as Self }
368 #[inline]
369 fn to_f64(self) -> f64 { self as f64 }
370 }
371 )*
372 };
373}
374
375macro_rules! impl_arange_float {
376 ($($ty:ty),*) => {
377 $(
378 impl ArangeNum for $ty {
379 #[inline]
380 fn from_f64(v: f64) -> Self { v as Self }
381 #[inline]
382 fn to_f64(self) -> f64 { self as f64 }
383 }
384 )*
385 };
386}
387
388impl_arange_int!(u8, u16, u32, u64, i8, i16, i32, i64);
389impl_arange_float!(f32, f64);
390
391pub fn arange<T: ArangeNum>(start: T, stop: T, step: T) -> FerrayResult<Array<T, Ix1>> {
398 let step_f = step.to_f64();
399 if step_f == 0.0 {
400 return Err(FerrayError::invalid_value("step cannot be zero"));
401 }
402 let start_f = start.to_f64();
403 let stop_f = stop.to_f64();
404 let n = ((stop_f - start_f) / step_f).ceil();
405 let n = if n < 0.0 { 0 } else { n as usize };
406
407 let mut data = Vec::with_capacity(n);
408 for i in 0..n {
409 data.push(T::from_f64((i as f64).mul_add(step_f, start_f)));
410 }
411 let dim = Ix1::new([data.len()]);
412 Array::from_vec(dim, data)
413}
414
415pub trait LinspaceNum: Element + PartialOrd {
417 fn from_f64(v: f64) -> Self;
419 fn to_f64(self) -> f64;
421}
422
423impl LinspaceNum for f32 {
424 #[inline]
425 fn from_f64(v: f64) -> Self {
426 v as Self
427 }
428 #[inline]
429 fn to_f64(self) -> f64 {
430 self as f64
431 }
432}
433
434impl LinspaceNum for f64 {
435 #[inline]
436 fn from_f64(v: f64) -> Self {
437 v
438 }
439 #[inline]
440 fn to_f64(self) -> f64 {
441 self
442 }
443}
444
445pub fn linspace<T: LinspaceNum>(
456 start: T,
457 stop: T,
458 num: usize,
459 endpoint: bool,
460) -> FerrayResult<Array<T, Ix1>> {
461 if num == 0 {
462 return Array::from_vec(Ix1::new([0]), vec![]);
463 }
464 if num == 1 {
465 return Array::from_vec(Ix1::new([1]), vec![start]);
466 }
467 let start_f = start.to_f64();
468 let stop_f = stop.to_f64();
469 let divisor = if endpoint {
470 (num - 1) as f64
471 } else {
472 num as f64
473 };
474 let step = (stop_f - start_f) / divisor;
475 let mut data = Vec::with_capacity(num);
476 for i in 0..num {
477 data.push(T::from_f64((i as f64).mul_add(step, start_f)));
478 }
479 Array::from_vec(Ix1::new([num]), data)
480}
481
482pub fn logspace<T: LinspaceNum>(
491 start: T,
492 stop: T,
493 num: usize,
494 endpoint: bool,
495 base: f64,
496) -> FerrayResult<Array<T, Ix1>> {
497 let lin = linspace(start, stop, num, endpoint)?;
498 let data: Vec<T> = lin
499 .iter()
500 .map(|v| T::from_f64(base.powf(v.clone().to_f64())))
501 .collect();
502 Array::from_vec(Ix1::new([num]), data)
503}
504
505pub fn geomspace<T: LinspaceNum>(
515 start: T,
516 stop: T,
517 num: usize,
518 endpoint: bool,
519) -> FerrayResult<Array<T, Ix1>> {
520 let start_f = start.clone().to_f64();
521 let stop_f = stop.to_f64();
522 if start_f == 0.0 || stop_f == 0.0 {
523 return Err(FerrayError::invalid_value(
524 "geomspace: start and stop must be non-zero",
525 ));
526 }
527 if (start_f < 0.0) != (stop_f < 0.0) {
528 return Err(FerrayError::invalid_value(
529 "geomspace: start and stop must have the same sign",
530 ));
531 }
532 if num == 0 {
533 return Array::from_vec(Ix1::new([0]), vec![]);
534 }
535 if num == 1 {
536 return Array::from_vec(Ix1::new([1]), vec![start]);
537 }
538 let log_start = start_f.abs().ln();
539 let log_stop = stop_f.abs().ln();
540 let sign = if start_f < 0.0 { -1.0 } else { 1.0 };
541 let divisor = if endpoint {
542 (num - 1) as f64
543 } else {
544 num as f64
545 };
546 let step = (log_stop - log_start) / divisor;
547 let mut data = Vec::with_capacity(num);
548 for i in 0..num {
549 let log_val = (i as f64).mul_add(step, log_start);
550 data.push(T::from_f64(sign * log_val.exp()));
551 }
552 Array::from_vec(Ix1::new([num]), data)
553}
554
555pub fn meshgrid(
569 arrays: &[Array<f64, Ix1>],
570 indexing: &str,
571) -> FerrayResult<Vec<Array<f64, IxDyn>>> {
572 if indexing != "xy" && indexing != "ij" {
573 return Err(FerrayError::invalid_value(
574 "meshgrid: indexing must be 'xy' or 'ij'",
575 ));
576 }
577 let ndim = arrays.len();
578 if ndim == 0 {
579 return Ok(vec![]);
580 }
581
582 let mut shapes: Vec<usize> = arrays.iter().map(|a| a.shape()[0]).collect();
583 if indexing == "xy" && ndim >= 2 {
584 shapes.swap(0, 1);
585 }
586
587 let total: usize = shapes.iter().product();
588 let mut results = Vec::with_capacity(ndim);
589
590 for (k, arr) in arrays.iter().enumerate() {
591 let src_data: Vec<f64> = arr.iter().copied().collect();
592 let mut data = Vec::with_capacity(total);
593 let effective_k = if indexing == "xy" && ndim >= 2 {
595 match k {
596 0 => 1,
597 1 => 0,
598 other => other,
599 }
600 } else {
601 k
602 };
603
604 for flat in 0..total {
606 let mut rem = flat;
608 let mut idx_k = 0;
609 for (d, &s) in shapes.iter().enumerate().rev() {
610 if d == effective_k {
611 idx_k = rem % s;
612 }
613 rem /= s;
614 }
615 data.push(src_data[idx_k]);
616 }
617
618 let dim = IxDyn::new(&shapes);
619 results.push(Array::from_vec(dim, data)?);
620 }
621 Ok(results)
622}
623
624pub fn mgrid(ranges: &[(f64, f64, f64)]) -> FerrayResult<Vec<Array<f64, IxDyn>>> {
634 let mut arrs: Vec<Array<f64, Ix1>> = Vec::with_capacity(ranges.len());
635 for &(start, stop, step) in ranges {
636 arrs.push(arange(start, stop, step)?);
637 }
638 meshgrid(&arrs, "ij")
639}
640
641pub fn ogrid(ranges: &[(f64, f64, f64)]) -> FerrayResult<Vec<Array<f64, IxDyn>>> {
651 let ndim = ranges.len();
652 let mut results = Vec::with_capacity(ndim);
653 for (i, &(start, stop, step)) in ranges.iter().enumerate() {
654 let arr1d = arange(start, stop, step)?;
655 let n = arr1d.shape()[0];
656 let data: Vec<f64> = arr1d.iter().copied().collect();
657 let mut shape = vec![1usize; ndim];
659 shape[i] = n;
660 let dim = IxDyn::new(&shape);
661 results.push(Array::from_vec(dim, data)?);
662 }
663 Ok(results)
664}
665
666pub fn identity<T: Element>(n: usize) -> FerrayResult<Array<T, Ix2>> {
674 eye(n, n, 0)
675}
676
677pub fn eye<T: Element>(n: usize, m: usize, k: isize) -> FerrayResult<Array<T, Ix2>> {
683 let mut data = vec![T::zero(); n * m];
684 for i in 0..n {
685 let j = i as isize + k;
686 if j >= 0 && (j as usize) < m {
687 data[i * m + j as usize] = T::one();
688 }
689 }
690 Array::from_vec(Ix2::new([n, m]), data)
691}
692
693pub fn diag<T: Element>(a: &Array<T, IxDyn>, k: isize) -> FerrayResult<Array<T, IxDyn>> {
703 let shape = a.shape();
704 match shape.len() {
705 1 => {
706 let n = shape[0];
708 let size = n + k.unsigned_abs();
709 let mut data = vec![T::zero(); size * size];
710 let src: Vec<T> = a.iter().cloned().collect();
711 for (i, val) in src.into_iter().enumerate() {
712 let row = if k >= 0 { i } else { i + k.unsigned_abs() };
713 let col = if k >= 0 { i + k as usize } else { i };
714 data[row * size + col] = val;
715 }
716 Array::from_vec(IxDyn::new(&[size, size]), data)
717 }
718 2 => {
719 let (n, m) = (shape[0], shape[1]);
721 let src: Vec<T> = a.iter().cloned().collect();
722 let mut diag_vals = Vec::new();
723 for i in 0..n {
724 let j = i as isize + k;
725 if j >= 0 && (j as usize) < m {
726 diag_vals.push(src[i * m + j as usize].clone());
727 }
728 }
729 let len = diag_vals.len();
730 Array::from_vec(IxDyn::new(&[len]), diag_vals)
731 }
732 _ => Err(FerrayError::invalid_value("diag: input must be 1-D or 2-D")),
733 }
734}
735
736pub fn diagflat<T: Element>(a: &Array<T, IxDyn>, k: isize) -> FerrayResult<Array<T, IxDyn>> {
743 let flat: Vec<T> = a.iter().cloned().collect();
745 let n = flat.len();
746 let arr1d = Array::from_vec(IxDyn::new(&[n]), flat)?;
747 diag(&arr1d, k)
748}
749
750pub fn tri<T: Element>(n: usize, m: usize, k: isize) -> FerrayResult<Array<T, Ix2>> {
756 let mut data = vec![T::zero(); n * m];
757 for i in 0..n {
758 for j in 0..m {
759 if (i as isize) >= (j as isize) - k {
760 data[i * m + j] = T::one();
761 }
762 }
763 }
764 Array::from_vec(Ix2::new([n, m]), data)
765}
766
767pub fn tril<T: Element>(a: &Array<T, IxDyn>, k: isize) -> FerrayResult<Array<T, IxDyn>> {
776 let shape = a.shape();
777 if shape.len() != 2 {
778 return Err(FerrayError::invalid_value("tril: input must be 2-D"));
779 }
780 let (n, m) = (shape[0], shape[1]);
781 let src: Vec<T> = a.iter().cloned().collect();
782 let mut data = vec![T::zero(); n * m];
783 for i in 0..n {
784 for j in 0..m {
785 if (i as isize) >= (j as isize) - k {
786 data[i * m + j] = src[i * m + j].clone();
787 }
788 }
789 }
790 Array::from_vec(IxDyn::new(&[n, m]), data)
791}
792
793pub fn triu<T: Element>(a: &Array<T, IxDyn>, k: isize) -> FerrayResult<Array<T, IxDyn>> {
802 let shape = a.shape();
803 if shape.len() != 2 {
804 return Err(FerrayError::invalid_value("triu: input must be 2-D"));
805 }
806 let (n, m) = (shape[0], shape[1]);
807 let src: Vec<T> = a.iter().cloned().collect();
808 let mut data = vec![T::zero(); n * m];
809 for i in 0..n {
810 for j in 0..m {
811 if (i as isize) <= (j as isize) - k {
812 data[i * m + j] = src[i * m + j].clone();
813 }
814 }
815 }
816 Array::from_vec(IxDyn::new(&[n, m]), data)
817}
818
819pub fn vander<T>(
835 x: &Array<T, Ix1>,
836 n: Option<usize>,
837 increasing: bool,
838) -> FerrayResult<Array<T, IxDyn>>
839where
840 T: Element + std::ops::Mul<Output = T> + Copy,
841{
842 let m = x.shape()[0];
843 if m == 0 {
844 return Err(FerrayError::invalid_value(
845 "vander: input array must not be empty",
846 ));
847 }
848 let cols = n.unwrap_or(m);
849 let xs: Vec<T> = x.iter().copied().collect();
850 let mut data = vec![<T as Element>::one(); m * cols];
851 for (i, &xi) in xs.iter().enumerate() {
852 let mut acc = <T as Element>::one();
854 let mut powers = Vec::with_capacity(cols);
855 for _ in 0..cols {
856 powers.push(acc);
857 acc = acc * xi;
858 }
859 if increasing {
860 for (j, p) in powers.iter().enumerate() {
861 data[i * cols + j] = *p;
862 }
863 } else {
864 for (j, p) in powers.iter().enumerate() {
865 data[i * cols + (cols - 1 - j)] = *p;
866 }
867 }
868 }
869 Array::from_vec(IxDyn::new(&[m, cols]), data)
870}
871
872pub fn copy<T: Element, D: Dimension>(a: &Array<T, D>) -> Array<T, D> {
881 a.clone()
882}
883
884pub fn ascontiguousarray<T: Element, D: Dimension>(a: &Array<T, D>) -> Array<T, D> {
890 a.clone()
891}
892
893pub fn asfortranarray<T: Element, D: Dimension>(a: &Array<T, D>) -> Array<T, D> {
909 let transposed = a.inner.view().reversed_axes();
910 let c_contig = transposed.as_standard_layout().into_owned();
911 let f_contig = c_contig.reversed_axes();
912 Array::<T, D>::from_ndarray(f_contig)
913}
914
915pub fn asanyarray<T: Element, D: Dimension>(a: &Array<T, D>) -> Array<T, D> {
924 a.clone()
925}
926
927pub fn asarray_chkfinite<T, D: Dimension>(a: &Array<T, D>) -> FerrayResult<Array<T, D>>
935where
936 T: Element + num_traits::Float,
937{
938 for v in a.iter() {
939 if !v.is_finite() {
940 return Err(FerrayError::invalid_value(
941 "asarray_chkfinite: array contains non-finite values (NaN or Inf)",
942 ));
943 }
944 }
945 Ok(a.clone())
946}
947
948pub fn require<T: Element, D: Dimension>(a: &Array<T, D>, _requirements: &str) -> Array<T, D> {
959 a.clone()
960}
961
962pub fn fromfunction<T, D, F>(shape: D, mut f: F) -> FerrayResult<Array<T, D>>
977where
978 T: Element,
979 D: Dimension,
980 F: FnMut(&[usize]) -> T,
981{
982 let dims: Vec<usize> = shape.as_slice().to_vec();
983 let total: usize = dims.iter().product();
984 let mut data = Vec::with_capacity(total);
985 let mut idx = vec![0usize; dims.len()];
986 for _ in 0..total {
987 data.push(f(&idx));
988 for axis in (0..dims.len()).rev() {
990 idx[axis] += 1;
991 if idx[axis] < dims[axis] {
992 break;
993 }
994 idx[axis] = 0;
995 }
996 }
997 Array::from_vec(shape, data)
998}
999
1000pub fn fromstring<T>(s: &str, sep: &str) -> FerrayResult<Array<T, Ix1>>
1012where
1013 T: Element + std::str::FromStr,
1014 <T as std::str::FromStr>::Err: std::fmt::Display,
1015{
1016 let parts: Vec<&str> = if sep.is_empty() {
1017 s.split_whitespace().collect()
1018 } else {
1019 s.split(sep)
1020 .map(str::trim)
1021 .filter(|t| !t.is_empty())
1022 .collect()
1023 };
1024 let mut data = Vec::with_capacity(parts.len());
1025 for tok in parts {
1026 let v = tok.parse::<T>().map_err(|e| {
1027 FerrayError::invalid_value(format!("fromstring: failed to parse {tok:?}: {e}"))
1028 })?;
1029 data.push(v);
1030 }
1031 let n = data.len();
1032 Array::from_vec(Ix1::new([n]), data)
1033}
1034
1035pub fn fromfile<T, P: AsRef<std::path::Path>>(path: P, sep: &str) -> FerrayResult<Array<T, Ix1>>
1046where
1047 T: Element + std::str::FromStr,
1048 <T as std::str::FromStr>::Err: std::fmt::Display,
1049{
1050 let s = std::fs::read_to_string(path)
1051 .map_err(|e| FerrayError::invalid_value(format!("fromfile: {e}")))?;
1052 fromstring(&s, sep)
1053}
1054
1055#[cfg(test)]
1060mod tests {
1061 use super::*;
1062 use crate::dimension::{Ix1, Ix2, IxDyn};
1063
1064 #[test]
1067 fn test_array_creation() {
1068 let a = array(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]).unwrap();
1069 assert_eq!(a.shape(), &[2, 3]);
1070 assert_eq!(a.size(), 6);
1071 }
1072
1073 #[test]
1074 fn test_asarray() {
1075 let a = asarray(Ix1::new([3]), vec![1, 2, 3]).unwrap();
1076 assert_eq!(a.as_slice().unwrap(), &[1, 2, 3]);
1077 }
1078
1079 #[test]
1080 fn test_frombuffer() {
1081 let bytes: Vec<u8> = vec![1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0];
1082 let a = frombuffer::<i32, Ix1>(Ix1::new([3]), &bytes).unwrap();
1083 assert_eq!(a.as_slice().unwrap(), &[1, 2, 3]);
1084 }
1085
1086 #[test]
1087 fn test_frombuffer_bad_length() {
1088 let bytes: Vec<u8> = vec![1, 0, 0];
1089 assert!(frombuffer::<i32, Ix1>(Ix1::new([1]), &bytes).is_err());
1090 }
1091
1092 #[test]
1093 fn test_frombuffer_bool() {
1094 let bytes: Vec<u8> = vec![0, 1, 0, 1, 1];
1099 let a = frombuffer::<bool, Ix1>(Ix1::new([5]), &bytes).unwrap();
1100 assert_eq!(a.as_slice().unwrap(), &[false, true, false, true, true]);
1101 }
1102
1103 #[test]
1104 fn test_frombuffer_bool_wrong_length() {
1105 let bytes: Vec<u8> = vec![0, 1];
1108 assert!(frombuffer::<bool, Ix1>(Ix1::new([3]), &bytes).is_err());
1109 }
1110
1111 fn aligned_bytes<T: Copy>(src: &[T]) -> Vec<u8> {
1116 let n = std::mem::size_of_val(src);
1117 let mut out = vec![0u8; n];
1118 unsafe {
1120 std::ptr::copy_nonoverlapping(src.as_ptr().cast::<u8>(), out.as_mut_ptr(), n);
1121 }
1122 out
1123 }
1124
1125 #[test]
1126 fn test_frombuffer_view_i32_is_zero_copy() {
1127 let source: Vec<i32> = vec![10, 20, 30];
1129 let bytes = aligned_bytes(&source);
1130 let view = frombuffer_view::<i32, Ix1>(Ix1::new([3]), &bytes).unwrap();
1131 assert_eq!(view.shape(), &[3]);
1132 let values: Vec<i32> = view.iter().copied().collect();
1133 assert_eq!(values, vec![10, 20, 30]);
1134 assert_eq!(view.as_ptr().cast::<u8>(), bytes.as_ptr());
1137 }
1138
1139 #[test]
1140 fn test_frombuffer_view_f64_2d() {
1141 let source: Vec<f64> = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
1142 let bytes = aligned_bytes(&source);
1143 let view = frombuffer_view::<f64, Ix2>(Ix2::new([2, 3]), &bytes).unwrap();
1144 assert_eq!(view.shape(), &[2, 3]);
1145 let values: Vec<f64> = view.iter().copied().collect();
1146 assert_eq!(values, source);
1147 }
1148
1149 #[test]
1150 fn test_frombuffer_view_bool_valid() {
1151 let bytes: Vec<u8> = vec![0, 1, 0, 1];
1152 let view = frombuffer_view::<bool, Ix1>(Ix1::new([4]), &bytes).unwrap();
1153 let values: Vec<bool> = view.iter().copied().collect();
1154 assert_eq!(values, vec![false, true, false, true]);
1155 }
1156
1157 #[test]
1158 fn test_frombuffer_view_bool_rejects_invalid_byte() {
1159 let bytes: Vec<u8> = vec![0, 1, 42]; assert!(frombuffer_view::<bool, Ix1>(Ix1::new([3]), &bytes).is_err());
1161 }
1162
1163 #[test]
1164 fn test_frombuffer_view_rejects_wrong_length() {
1165 let bytes = vec![0u8; 13];
1167 assert!(frombuffer_view::<i32, Ix1>(Ix1::new([3]), &bytes).is_err());
1168 let bytes = vec![0u8; 8];
1170 assert!(frombuffer_view::<i32, Ix1>(Ix1::new([3]), &bytes).is_err());
1171 }
1172
1173 #[test]
1174 fn test_frombuffer_view_rejects_misalignment() {
1175 let mut backing: Vec<u8> = vec![0u8; 1 + 4 * 3];
1177 for (i, chunk) in backing[1..].chunks_exact_mut(4).enumerate() {
1178 chunk.copy_from_slice(&(i as i32).to_ne_bytes());
1179 }
1180 let misaligned = &backing[1..];
1181 assert!((misaligned.as_ptr() as usize) % 4 != 0);
1184 assert!(frombuffer_view::<i32, Ix1>(Ix1::new([3]), misaligned).is_err());
1185 }
1186
1187 #[test]
1188 fn test_fromiter() {
1189 let a = fromiter((0..5).map(|x| x as f64)).unwrap();
1190 assert_eq!(a.shape(), &[5]);
1191 assert_eq!(a.as_slice().unwrap(), &[0.0, 1.0, 2.0, 3.0, 4.0]);
1192 }
1193
1194 #[test]
1195 fn test_zeros() {
1196 let a = zeros::<f64, Ix2>(Ix2::new([3, 4])).unwrap();
1197 assert_eq!(a.shape(), &[3, 4]);
1198 assert!(a.iter().all(|&v| v == 0.0));
1199 }
1200
1201 #[test]
1202 fn test_ones() {
1203 let a = ones::<f64, Ix1>(Ix1::new([5])).unwrap();
1204 assert!(a.iter().all(|&v| v == 1.0));
1205 }
1206
1207 #[test]
1208 fn test_full() {
1209 let a = full(Ix1::new([4]), 42i32).unwrap();
1210 assert!(a.iter().all(|&v| v == 42));
1211 }
1212
1213 #[test]
1214 fn test_zeros_like() {
1215 let a = ones::<f64, Ix2>(Ix2::new([2, 3])).unwrap();
1216 let b = zeros_like(&a).unwrap();
1217 assert_eq!(b.shape(), &[2, 3]);
1218 assert!(b.iter().all(|&v| v == 0.0));
1219 }
1220
1221 #[test]
1222 fn test_ones_like() {
1223 let a = zeros::<f64, Ix1>(Ix1::new([4])).unwrap();
1224 let b = ones_like(&a).unwrap();
1225 assert!(b.iter().all(|&v| v == 1.0));
1226 }
1227
1228 #[test]
1229 fn test_full_like() {
1230 let a = zeros::<i32, Ix1>(Ix1::new([3])).unwrap();
1231 let b = full_like(&a, 7).unwrap();
1232 assert!(b.iter().all(|&v| v == 7));
1233 }
1234
1235 #[test]
1238 fn test_empty_and_init() {
1239 let mut u = empty::<f64, Ix1>(Ix1::new([3]));
1240 assert_eq!(u.shape(), &[3]);
1241 u.write_at(0, 1.0).unwrap();
1242 u.write_at(1, 2.0).unwrap();
1243 u.write_at(2, 3.0).unwrap();
1244 let a = unsafe { u.assume_init() };
1246 assert_eq!(a.as_slice().unwrap(), &[1.0, 2.0, 3.0]);
1247 }
1248
1249 #[test]
1250 fn test_empty_write_oob() {
1251 let mut u = empty::<f64, Ix1>(Ix1::new([2]));
1252 assert!(u.write_at(5, 1.0).is_err());
1253 }
1254
1255 #[test]
1257 fn test_empty_like_matches_shape_2d() {
1258 use crate::dimension::Ix2;
1259 let src = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
1260 .unwrap();
1261 let mut u = empty_like(&src);
1262 assert_eq!(u.shape(), &[2, 3]);
1263 assert_eq!(u.size(), 6);
1264 assert_eq!(u.ndim(), 2);
1265
1266 for i in 0..6 {
1268 u.write_at(i, -(i as f64)).unwrap();
1269 }
1270 let out = unsafe { u.assume_init() };
1272 assert_eq!(out.shape(), &[2, 3]);
1273 assert_eq!(
1274 out.as_slice().unwrap(),
1275 &[0.0, -1.0, -2.0, -3.0, -4.0, -5.0]
1276 );
1277 assert_eq!(src.as_slice().unwrap(), &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1279 }
1280
1281 #[test]
1282 fn test_empty_like_zero_sized() {
1283 let src = Array::<f64, Ix1>::from_vec(Ix1::new([0]), vec![]).unwrap();
1284 let u = empty_like(&src);
1285 assert_eq!(u.shape(), &[0]);
1286 assert_eq!(u.size(), 0);
1287 let out = unsafe { u.assume_init() };
1289 assert_eq!(out.size(), 0);
1290 }
1291
1292 #[test]
1295 fn test_arange_int() {
1296 let a = arange(0i32, 5, 1).unwrap();
1297 assert_eq!(a.as_slice().unwrap(), &[0, 1, 2, 3, 4]);
1298 }
1299
1300 #[test]
1301 fn test_arange_float() {
1302 let a = arange(0.0_f64, 1.0, 0.25).unwrap();
1303 assert_eq!(a.shape(), &[4]);
1304 let data = a.as_slice().unwrap();
1305 assert!((data[0] - 0.0).abs() < 1e-10);
1306 assert!((data[1] - 0.25).abs() < 1e-10);
1307 assert!((data[2] - 0.5).abs() < 1e-10);
1308 assert!((data[3] - 0.75).abs() < 1e-10);
1309 }
1310
1311 #[test]
1312 fn test_arange_negative_step() {
1313 let a = arange(5.0_f64, 0.0, -1.0).unwrap();
1314 assert_eq!(a.shape(), &[5]);
1315 }
1316
1317 #[test]
1318 fn test_arange_zero_step() {
1319 assert!(arange(0.0_f64, 1.0, 0.0).is_err());
1320 }
1321
1322 #[test]
1323 fn test_arange_empty() {
1324 let a = arange(5i32, 0, 1).unwrap();
1325 assert_eq!(a.shape(), &[0]);
1326 }
1327
1328 #[test]
1329 fn test_linspace() {
1330 let a = linspace(0.0_f64, 1.0, 5, true).unwrap();
1331 assert_eq!(a.shape(), &[5]);
1332 let data = a.as_slice().unwrap();
1333 assert!((data[0] - 0.0).abs() < 1e-10);
1334 assert!((data[4] - 1.0).abs() < 1e-10);
1335 assert!((data[2] - 0.5).abs() < 1e-10);
1336 }
1337
1338 #[test]
1339 fn test_linspace_no_endpoint() {
1340 let a = linspace(0.0_f64, 1.0, 4, false).unwrap();
1341 assert_eq!(a.shape(), &[4]);
1342 let data = a.as_slice().unwrap();
1343 assert!((data[0] - 0.0).abs() < 1e-10);
1344 assert!((data[1] - 0.25).abs() < 1e-10);
1345 }
1346
1347 #[test]
1348 fn test_linspace_single() {
1349 let a = linspace(5.0_f64, 10.0, 1, true).unwrap();
1350 assert_eq!(a.as_slice().unwrap(), &[5.0]);
1351 }
1352
1353 #[test]
1354 fn test_linspace_empty() {
1355 let a = linspace(0.0_f64, 1.0, 0, true).unwrap();
1356 assert_eq!(a.shape(), &[0]);
1357 }
1358
1359 #[test]
1360 fn test_logspace() {
1361 let a = logspace(0.0_f64, 2.0, 3, true, 10.0).unwrap();
1362 let data = a.as_slice().unwrap();
1363 assert!((data[0] - 1.0).abs() < 1e-10); assert!((data[1] - 10.0).abs() < 1e-10); assert!((data[2] - 100.0).abs() < 1e-10); }
1367
1368 #[test]
1369 fn test_geomspace() {
1370 let a = geomspace(1.0_f64, 1000.0, 4, true).unwrap();
1371 let data = a.as_slice().unwrap();
1372 assert!((data[0] - 1.0).abs() < 1e-10);
1373 assert!((data[1] - 10.0).abs() < 1e-8);
1374 assert!((data[2] - 100.0).abs() < 1e-6);
1375 assert!((data[3] - 1000.0).abs() < 1e-4);
1376 }
1377
1378 #[test]
1379 fn test_geomspace_zero_start() {
1380 assert!(geomspace(0.0_f64, 1.0, 5, true).is_err());
1381 }
1382
1383 #[test]
1384 fn test_geomspace_different_signs() {
1385 assert!(geomspace(-1.0_f64, 1.0, 5, true).is_err());
1386 }
1387
1388 #[test]
1389 fn test_meshgrid_xy() {
1390 let x = Array::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
1391 let y = Array::from_vec(Ix1::new([2]), vec![4.0, 5.0]).unwrap();
1392 let grids = meshgrid(&[x, y], "xy").unwrap();
1393 assert_eq!(grids.len(), 2);
1394 assert_eq!(grids[0].shape(), &[2, 3]);
1395 assert_eq!(grids[1].shape(), &[2, 3]);
1396 let xdata: Vec<f64> = grids[0].iter().copied().collect();
1398 assert_eq!(xdata, vec![1.0, 2.0, 3.0, 1.0, 2.0, 3.0]);
1399 let ydata: Vec<f64> = grids[1].iter().copied().collect();
1401 assert_eq!(ydata, vec![4.0, 4.0, 4.0, 5.0, 5.0, 5.0]);
1402 }
1403
1404 #[test]
1405 fn test_meshgrid_ij() {
1406 let x = Array::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
1407 let y = Array::from_vec(Ix1::new([2]), vec![4.0, 5.0]).unwrap();
1408 let grids = meshgrid(&[x, y], "ij").unwrap();
1409 assert_eq!(grids.len(), 2);
1410 assert_eq!(grids[0].shape(), &[3, 2]);
1411 assert_eq!(grids[1].shape(), &[3, 2]);
1412 }
1413
1414 #[test]
1415 fn test_meshgrid_bad_indexing() {
1416 assert!(meshgrid(&[], "zz").is_err());
1417 }
1418
1419 #[test]
1420 fn test_mgrid() {
1421 let grids = mgrid(&[(0.0, 3.0, 1.0), (0.0, 2.0, 1.0)]).unwrap();
1422 assert_eq!(grids.len(), 2);
1423 assert_eq!(grids[0].shape(), &[3, 2]);
1424 }
1425
1426 #[test]
1427 fn test_ogrid() {
1428 let grids = ogrid(&[(0.0, 3.0, 1.0), (0.0, 2.0, 1.0)]).unwrap();
1429 assert_eq!(grids.len(), 2);
1430 assert_eq!(grids[0].shape(), &[3, 1]);
1431 assert_eq!(grids[1].shape(), &[1, 2]);
1432 }
1433
1434 #[test]
1437 fn test_identity() {
1438 let a = identity::<f64>(3).unwrap();
1439 assert_eq!(a.shape(), &[3, 3]);
1440 let data = a.as_slice().unwrap();
1441 assert_eq!(data, &[1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]);
1442 }
1443
1444 #[test]
1445 fn test_eye() {
1446 let a = eye::<f64>(3, 4, 0).unwrap();
1447 assert_eq!(a.shape(), &[3, 4]);
1448 let data = a.as_slice().unwrap();
1449 assert_eq!(
1450 data,
1451 &[1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0]
1452 );
1453 }
1454
1455 #[test]
1456 fn test_eye_positive_k() {
1457 let a = eye::<f64>(3, 3, 1).unwrap();
1458 let data = a.as_slice().unwrap();
1459 assert_eq!(data, &[0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0]);
1460 }
1461
1462 #[test]
1463 fn test_eye_negative_k() {
1464 let a = eye::<f64>(3, 3, -1).unwrap();
1465 let data = a.as_slice().unwrap();
1466 assert_eq!(data, &[0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0]);
1467 }
1468
1469 #[test]
1470 fn test_diag_from_1d() {
1471 let a = Array::from_vec(IxDyn::new(&[3]), vec![1.0, 2.0, 3.0]).unwrap();
1472 let d = diag(&a, 0).unwrap();
1473 assert_eq!(d.shape(), &[3, 3]);
1474 let data: Vec<f64> = d.iter().copied().collect();
1475 assert_eq!(data, vec![1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 3.0]);
1476 }
1477
1478 #[test]
1479 fn test_diag_from_2d() {
1480 let a = Array::from_vec(
1481 IxDyn::new(&[3, 3]),
1482 vec![1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 3.0],
1483 )
1484 .unwrap();
1485 let d = diag(&a, 0).unwrap();
1486 assert_eq!(d.shape(), &[3]);
1487 let data: Vec<f64> = d.iter().copied().collect();
1488 assert_eq!(data, vec![1.0, 2.0, 3.0]);
1489 }
1490
1491 #[test]
1492 fn test_diag_k_positive() {
1493 let a = Array::from_vec(IxDyn::new(&[2]), vec![1.0, 2.0]).unwrap();
1494 let d = diag(&a, 1).unwrap();
1495 assert_eq!(d.shape(), &[3, 3]);
1496 let data: Vec<f64> = d.iter().copied().collect();
1497 assert_eq!(data, vec![0.0, 1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0]);
1498 }
1499
1500 #[test]
1501 fn test_diagflat() {
1502 let a = Array::from_vec(IxDyn::new(&[2, 2]), vec![1.0, 2.0, 3.0, 4.0]).unwrap();
1503 let d = diagflat(&a, 0).unwrap();
1504 assert_eq!(d.shape(), &[4, 4]);
1505 let extracted = diag(&d, 0).unwrap();
1507 let data: Vec<f64> = extracted.iter().copied().collect();
1508 assert_eq!(data, vec![1.0, 2.0, 3.0, 4.0]);
1509 }
1510
1511 #[test]
1512 fn test_tri() {
1513 let a = tri::<f64>(3, 3, 0).unwrap();
1514 let data = a.as_slice().unwrap();
1515 assert_eq!(data, &[1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0]);
1516 }
1517
1518 #[test]
1519 fn test_tril() {
1520 let a = Array::from_vec(
1521 IxDyn::new(&[3, 3]),
1522 vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0],
1523 )
1524 .unwrap();
1525 let t = tril(&a, 0).unwrap();
1526 let data: Vec<f64> = t.iter().copied().collect();
1527 assert_eq!(data, vec![1.0, 0.0, 0.0, 4.0, 5.0, 0.0, 7.0, 8.0, 9.0]);
1528 }
1529
1530 #[test]
1531 fn test_triu() {
1532 let a = Array::from_vec(
1533 IxDyn::new(&[3, 3]),
1534 vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0],
1535 )
1536 .unwrap();
1537 let t = triu(&a, 0).unwrap();
1538 let data: Vec<f64> = t.iter().copied().collect();
1539 assert_eq!(data, vec![1.0, 2.0, 3.0, 0.0, 5.0, 6.0, 0.0, 0.0, 9.0]);
1540 }
1541
1542 #[test]
1543 fn test_tril_not_2d() {
1544 let a = Array::from_vec(IxDyn::new(&[3]), vec![1.0, 2.0, 3.0]).unwrap();
1545 assert!(tril(&a, 0).is_err());
1546 }
1547
1548 #[test]
1549 fn test_triu_not_2d() {
1550 let a = Array::from_vec(IxDyn::new(&[3]), vec![1.0, 2.0, 3.0]).unwrap();
1551 assert!(triu(&a, 0).is_err());
1552 }
1553
1554 #[test]
1557 fn test_vander_default_decreasing() {
1558 let x = Array::from_vec(Ix1::new([3]), vec![1.0_f64, 2.0, 3.0]).unwrap();
1559 let v = vander(&x, None, false).unwrap();
1560 assert_eq!(v.shape(), &[3, 3]);
1561 let data: Vec<f64> = v.iter().copied().collect();
1563 assert_eq!(data, vec![1.0, 1.0, 1.0, 4.0, 2.0, 1.0, 9.0, 3.0, 1.0]);
1564 }
1565
1566 #[test]
1567 fn test_vander_increasing() {
1568 let x = Array::from_vec(Ix1::new([3]), vec![1.0_f64, 2.0, 3.0]).unwrap();
1569 let v = vander(&x, None, true).unwrap();
1570 let data: Vec<f64> = v.iter().copied().collect();
1571 assert_eq!(data, vec![1.0, 1.0, 1.0, 1.0, 2.0, 4.0, 1.0, 3.0, 9.0]);
1573 }
1574
1575 #[test]
1576 fn test_vander_explicit_n() {
1577 let x = Array::from_vec(Ix1::new([2]), vec![2.0_f64, 3.0]).unwrap();
1578 let v = vander(&x, Some(4), false).unwrap();
1579 assert_eq!(v.shape(), &[2, 4]);
1580 let data: Vec<f64> = v.iter().copied().collect();
1583 assert_eq!(data, vec![8.0, 4.0, 2.0, 1.0, 27.0, 9.0, 3.0, 1.0]);
1584 }
1585
1586 #[test]
1587 fn test_vander_empty() {
1588 let x: Array<f64, Ix1> = Array::from_vec(Ix1::new([0]), vec![]).unwrap();
1589 assert!(vander(&x, None, false).is_err());
1590 }
1591
1592 #[test]
1595 fn test_copy() {
1596 let a = array(Ix1::new([3]), vec![1.0_f64, 2.0, 3.0]).unwrap();
1597 let b = copy(&a);
1598 assert_eq!(
1599 a.iter().copied().collect::<Vec<_>>(),
1600 b.iter().copied().collect::<Vec<_>>()
1601 );
1602 assert_ne!(
1604 a.as_slice().unwrap().as_ptr(),
1605 b.as_slice().unwrap().as_ptr()
1606 );
1607 }
1608
1609 #[test]
1610 fn test_ascontiguousarray() {
1611 let a = array(Ix1::new([3]), vec![1.0_f64, 2.0, 3.0]).unwrap();
1612 let b = ascontiguousarray(&a);
1613 assert_eq!(b.shape(), a.shape());
1614 }
1615
1616 #[test]
1617 fn test_asarray_chkfinite_ok() {
1618 let a = array(Ix1::new([3]), vec![1.0_f64, 2.0, 3.0]).unwrap();
1619 assert!(asarray_chkfinite(&a).is_ok());
1620 }
1621
1622 #[test]
1623 fn test_asarray_chkfinite_nan_fails() {
1624 let a = array(Ix1::new([3]), vec![1.0_f64, f64::NAN, 3.0]).unwrap();
1625 assert!(asarray_chkfinite(&a).is_err());
1626 }
1627
1628 #[test]
1629 fn test_asarray_chkfinite_inf_fails() {
1630 let a = array(Ix1::new([3]), vec![1.0_f64, f64::INFINITY, 3.0]).unwrap();
1631 assert!(asarray_chkfinite(&a).is_err());
1632 }
1633
1634 #[test]
1635 fn test_require() {
1636 let a = array(Ix1::new([3]), vec![1, 2, 3]).unwrap();
1637 let b = require(&a, "CW");
1638 assert_eq!(b.shape(), a.shape());
1639 }
1640
1641 #[test]
1644 fn test_fromfunction_2d() {
1645 let a = fromfunction(Ix2::new([3, 3]), |idx| (idx[0] + idx[1]) as i32).unwrap();
1646 let data: Vec<i32> = a.iter().copied().collect();
1647 assert_eq!(data, vec![0, 1, 2, 1, 2, 3, 2, 3, 4]);
1648 }
1649
1650 #[test]
1651 fn test_fromfunction_1d() {
1652 let a = fromfunction(Ix1::new([5]), |idx| idx[0] as f64 * 2.0).unwrap();
1653 let data: Vec<f64> = a.iter().copied().collect();
1654 assert_eq!(data, vec![0.0, 2.0, 4.0, 6.0, 8.0]);
1655 }
1656
1657 #[test]
1658 fn test_fromstring_whitespace() {
1659 let a: Array<f64, Ix1> = fromstring("1.5 2.5 3.5", " ").unwrap();
1660 let data: Vec<f64> = a.iter().copied().collect();
1661 assert_eq!(data, vec![1.5, 2.5, 3.5]);
1662 }
1663
1664 #[test]
1665 fn test_fromstring_comma() {
1666 let a: Array<i32, Ix1> = fromstring("1, 2, 3, 4", ",").unwrap();
1667 assert_eq!(a.shape(), &[4]);
1668 let data: Vec<i32> = a.iter().copied().collect();
1669 assert_eq!(data, vec![1, 2, 3, 4]);
1670 }
1671
1672 #[test]
1673 fn test_fromstring_empty_sep_uses_whitespace() {
1674 let a: Array<i32, Ix1> = fromstring("1 2\t3\n4", "").unwrap();
1675 let data: Vec<i32> = a.iter().copied().collect();
1676 assert_eq!(data, vec![1, 2, 3, 4]);
1677 }
1678
1679 #[test]
1680 fn test_fromstring_bad_token() {
1681 let r: FerrayResult<Array<f64, Ix1>> = fromstring("1.0 abc 3.0", " ");
1682 assert!(r.is_err());
1683 }
1684}