ndarray/free_functions.rs
1// Copyright 2014-2016 bluss and ndarray developers.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use alloc::vec;
10#[cfg(not(feature = "std"))]
11use alloc::vec::Vec;
12#[allow(unused_imports)]
13use std::compile_error;
14use std::mem::{forget, size_of};
15use std::ptr::NonNull;
16
17use crate::imp_prelude::*;
18use crate::{dimension, ArcArray1, ArcArray2};
19
20/// Create an **[`Array`]** with one, two, three, four, five, or six dimensions.
21///
22/// ```
23/// use ndarray::array;
24/// let a1 = array![1, 2, 3, 4];
25///
26/// let a2 = array![[1, 2],
27/// [3, 4]];
28///
29/// let a3 = array![[[1, 2], [3, 4]],
30/// [[5, 6], [7, 8]]];
31///
32/// let a4 = array![[[[1, 2, 3, 4]]]];
33///
34/// let a5 = array![[[[[1, 2, 3, 4, 5]]]]];
35///
36/// let a6 = array![[[[[[1, 2, 3, 4, 5, 6]]]]]];
37///
38/// assert_eq!(a1.shape(), &[4]);
39/// assert_eq!(a2.shape(), &[2, 2]);
40/// assert_eq!(a3.shape(), &[2, 2, 2]);
41/// assert_eq!(a4.shape(), &[1, 1, 1, 4]);
42/// assert_eq!(a5.shape(), &[1, 1, 1, 1, 5]);
43/// assert_eq!(a6.shape(), &[1, 1, 1, 1, 1, 6]);
44/// ```
45///
46/// This macro uses `vec![]`, and has the same ownership semantics;
47/// elements are moved into the resulting `Array`.
48///
49/// Use `array![...].into_shared()` to create an `ArcArray`.
50///
51/// Attempts to crate 7D+ arrays with this macro will lead to
52/// a compiler error, since the difference between a 7D array
53/// of i32 and a 6D array of `[i32; 3]` is ambiguous. Higher-dim
54/// arrays can be created with [`ArrayD`].
55///
56/// ```compile_fail
57/// use ndarray::array;
58/// let a7 = array![[[[[[[1, 2, 3]]]]]]];
59/// // error: Arrays of 7 dimensions or more (or ndarrays of Rust arrays) cannot be constructed with the array! macro.
60/// ```
61#[macro_export]
62macro_rules! array {
63 ($([$([$([$([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*) => {{
64 compile_error!("Arrays of 7 dimensions or more (or ndarrays of Rust arrays) cannot be constructed with the array! macro.");
65 }};
66 ($([$([$([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*) => {{
67 $crate::Array6::from(vec![$([$([$([$([$([$($x,)*],)*],)*],)*],)*],)*])
68 }};
69 ($([$([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*) => {{
70 $crate::Array5::from(vec![$([$([$([$([$($x,)*],)*],)*],)*],)*])
71 }};
72 ($([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*) => {{
73 $crate::Array4::from(vec![$([$([$([$($x,)*],)*],)*],)*])
74 }};
75 ($([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*) => {{
76 $crate::Array3::from(vec![$([$([$($x,)*],)*],)*])
77 }};
78 ($([$($x:expr),* $(,)*]),+ $(,)*) => {{
79 $crate::Array2::from(vec![$([$($x,)*],)*])
80 }};
81 ($($x:expr),* $(,)*) => {{
82 $crate::Array::from(vec![$($x,)*])
83 }};
84}
85
86/// Create a zero-dimensional array with the element `x`.
87pub fn arr0<A>(x: A) -> Array0<A>
88{
89 unsafe { ArrayBase::from_shape_vec_unchecked((), vec![x]) }
90}
91
92/// Create a one-dimensional array with elements from `xs`.
93pub fn arr1<A: Clone>(xs: &[A]) -> Array1<A>
94{
95 ArrayBase::from(xs.to_vec())
96}
97
98/// Create a one-dimensional array with elements from `xs`.
99pub fn rcarr1<A: Clone>(xs: &[A]) -> ArcArray1<A>
100{
101 arr1(xs).into_shared()
102}
103
104/// Create a zero-dimensional array view borrowing `x`.
105pub const fn aview0<A>(x: &A) -> ArrayView0<'_, A>
106{
107 ArrayBase {
108 data: ViewRepr::new(),
109 // Safe because references are always non-null.
110 ptr: unsafe { NonNull::new_unchecked(x as *const A as *mut A) },
111 dim: Ix0(),
112 strides: Ix0(),
113 }
114}
115
116/// Create a one-dimensional array view with elements borrowing `xs`.
117///
118/// **Panics** if the length of the slice overflows `isize`. (This can only
119/// occur if `A` is zero-sized, because slices cannot contain more than
120/// `isize::MAX` number of bytes.)
121///
122/// ```
123/// use ndarray::{aview1, ArrayView1};
124///
125/// let data = [1.0; 1024];
126///
127/// // Create a 2D array view from borrowed data
128/// let a2d = aview1(&data).into_shape_with_order((32, 32)).unwrap();
129///
130/// assert_eq!(a2d.sum(), 1024.0);
131///
132/// // Create a const 1D array view
133/// const C: ArrayView1<'static, f64> = aview1(&[1., 2., 3.]);
134///
135/// assert_eq!(C.sum(), 6.);
136/// ```
137pub const fn aview1<A>(xs: &[A]) -> ArrayView1<'_, A>
138{
139 if size_of::<A>() == 0 {
140 assert!(
141 xs.len() <= isize::MAX as usize,
142 "Slice length must fit in `isize`.",
143 );
144 }
145 ArrayBase {
146 data: ViewRepr::new(),
147 // Safe because references are always non-null.
148 ptr: unsafe { NonNull::new_unchecked(xs.as_ptr() as *mut A) },
149 dim: Ix1(xs.len()),
150 strides: Ix1(1),
151 }
152}
153
154/// Create a two-dimensional array view with elements borrowing `xs`.
155///
156/// **Panics** if the product of non-zero axis lengths overflows `isize` (This
157/// can only occur if A is zero-sized or if `N` is zero, because slices cannot
158/// contain more than `isize::MAX` number of bytes).
159///
160/// ```
161/// use ndarray::{aview2, ArrayView2};
162///
163/// let data = vec![[1., 2., 3.], [4., 5., 6.]];
164///
165/// let view = aview2(&data);
166/// assert_eq!(view.sum(), 21.);
167///
168/// // Create a const 2D array view
169/// const C: ArrayView2<'static, f64> = aview2(&[[1., 2., 3.], [4., 5., 6.]]);
170/// assert_eq!(C.sum(), 21.);
171/// ```
172pub const fn aview2<A, const N: usize>(xs: &[[A; N]]) -> ArrayView2<'_, A>
173{
174 let cols = N;
175 let rows = xs.len();
176 if size_of::<A>() == 0 {
177 if let Some(n_elems) = rows.checked_mul(cols) {
178 assert!(
179 rows <= isize::MAX as usize
180 && cols <= isize::MAX as usize
181 && n_elems <= isize::MAX as usize,
182 "Product of non-zero axis lengths must not overflow isize.",
183 );
184 } else {
185 panic!("Overflow in number of elements.");
186 }
187 } else if N == 0 {
188 assert!(
189 rows <= isize::MAX as usize,
190 "Product of non-zero axis lengths must not overflow isize.",
191 );
192 }
193 // Safe because references are always non-null.
194 let ptr = unsafe { NonNull::new_unchecked(xs.as_ptr() as *mut A) };
195 let dim = Ix2(rows, cols);
196 let strides = if rows == 0 || cols == 0 {
197 Ix2(0, 0)
198 } else {
199 Ix2(cols, 1)
200 };
201 ArrayBase {
202 data: ViewRepr::new(),
203 ptr,
204 dim,
205 strides,
206 }
207}
208
209/// Create a one-dimensional read-write array view with elements borrowing `xs`.
210///
211/// ```
212/// use ndarray::{aview_mut1, s};
213/// // Create an array view over some data, then slice it and modify it.
214/// let mut data = [0; 1024];
215/// {
216/// let mut a = aview_mut1(&mut data).into_shape_with_order((32, 32)).unwrap();
217/// a.slice_mut(s![.., ..;3]).fill(5);
218/// }
219/// assert_eq!(&data[..10], [5, 0, 0, 5, 0, 0, 5, 0, 0, 5]);
220/// ```
221pub fn aview_mut1<A>(xs: &mut [A]) -> ArrayViewMut1<'_, A>
222{
223 ArrayViewMut::from(xs)
224}
225
226/// Create a two-dimensional read-write array view with elements borrowing `xs`.
227///
228/// **Panics** if the product of non-zero axis lengths overflows `isize` (This can only occur if A
229/// is zero-sized because slices cannot contain more than `isize::MAX` number of bytes).
230///
231/// # Example
232///
233/// ```
234/// use ndarray::aview_mut2;
235///
236/// // The inner (nested) and outer arrays can be of any length.
237/// let mut data = [[0.; 2]; 128];
238/// {
239/// // Make a 128 x 2 mut array view then turn it into 2 x 128
240/// let mut a = aview_mut2(&mut data).reversed_axes();
241/// // Make the first row ones and second row minus ones.
242/// a.row_mut(0).fill(1.);
243/// a.row_mut(1).fill(-1.);
244/// }
245/// // look at the start of the result
246/// assert_eq!(&data[..3], [[1., -1.], [1., -1.], [1., -1.]]);
247/// ```
248pub fn aview_mut2<A, const N: usize>(xs: &mut [[A; N]]) -> ArrayViewMut2<'_, A>
249{
250 ArrayViewMut2::from(xs)
251}
252
253/// Create a two-dimensional array with elements from `xs`.
254///
255/// ```
256/// use ndarray::arr2;
257///
258/// let a = arr2(&[[1, 2, 3],
259/// [4, 5, 6]]);
260/// assert!(
261/// a.shape() == [2, 3]
262/// );
263/// ```
264pub fn arr2<A: Clone, const N: usize>(xs: &[[A; N]]) -> Array2<A>
265{
266 Array2::from(xs.to_vec())
267}
268
269macro_rules! impl_from_nested_vec {
270 ($arr_type:ty, $ix_type:tt, $($n:ident),+) => {
271 impl<A, $(const $n: usize),+> From<Vec<$arr_type>> for Array<A, $ix_type>
272 {
273 fn from(mut xs: Vec<$arr_type>) -> Self
274 {
275 let dim = $ix_type(xs.len(), $($n),+);
276 let ptr = xs.as_mut_ptr();
277 let cap = xs.capacity();
278 let expand_len = dimension::size_of_shape_checked(&dim)
279 .expect("Product of non-zero axis lengths must not overflow isize.");
280 forget(xs);
281 unsafe {
282 let v = if size_of::<A>() == 0 {
283 Vec::from_raw_parts(ptr as *mut A, expand_len, expand_len)
284 } else if $($n == 0 ||)+ false {
285 Vec::new()
286 } else {
287 let expand_cap = cap $(* $n)+;
288 Vec::from_raw_parts(ptr as *mut A, expand_len, expand_cap)
289 };
290 ArrayBase::from_shape_vec_unchecked(dim, v)
291 }
292 }
293 }
294 };
295}
296
297impl_from_nested_vec!([A; N], Ix2, N);
298impl_from_nested_vec!([[A; M]; N], Ix3, N, M);
299impl_from_nested_vec!([[[A; L]; M]; N], Ix4, N, M, L);
300impl_from_nested_vec!([[[[A; K]; L]; M]; N], Ix5, N, M, L, K);
301impl_from_nested_vec!([[[[[A; J]; K]; L]; M]; N], Ix6, N, M, L, K, J);
302
303/// Create a two-dimensional array with elements from `xs`.
304///
305pub fn rcarr2<A: Clone, const N: usize>(xs: &[[A; N]]) -> ArcArray2<A>
306{
307 arr2(xs).into_shared()
308}
309
310/// Create a three-dimensional array with elements from `xs`.
311///
312/// **Panics** if the slices are not all of the same length.
313///
314/// ```
315/// use ndarray::arr3;
316///
317/// let a = arr3(&[[[1, 2],
318/// [3, 4]],
319/// [[5, 6],
320/// [7, 8]],
321/// [[9, 0],
322/// [1, 2]]]);
323/// assert!(
324/// a.shape() == [3, 2, 2]
325/// );
326/// ```
327pub fn arr3<A: Clone, const N: usize, const M: usize>(xs: &[[[A; M]; N]]) -> Array3<A>
328{
329 Array3::from(xs.to_vec())
330}
331
332/// Create a three-dimensional array with elements from `xs`.
333pub fn rcarr3<A: Clone, const N: usize, const M: usize>(xs: &[[[A; M]; N]]) -> ArcArray<A, Ix3>
334{
335 arr3(xs).into_shared()
336}