ndarray/doc/ndarray_for_numpy_users/mod.rs
1//! `ndarray` for NumPy users.
2//!
3//! This is an introductory guide to `ndarray` for people with experience using
4//! NumPy, although it may also be useful to others. For a more general
5//! introduction to `ndarray`'s array type `ArrayBase`, see the [`ArrayBase`
6//! docs][ArrayBase].
7//!
8//! # Contents
9//!
10//! * [Similarities](#similarities)
11//! * [Some key differences](#some-key-differences)
12//! * [The ndarray ecosystem](#the-ndarray-ecosystem)
13//! * [Other Rust array/matrix crates](#other-rust-arraymatrix-crates)
14//! * [Rough `ndarray`–NumPy equivalents](#rough-ndarraynumpy-equivalents)
15//!
16//! * [Array creation](#array-creation)
17//! * [Indexing and slicing](#indexing-and-slicing)
18//! * [Shape and strides](#shape-and-strides)
19//! * [Mathematics](#mathematics)
20//! * [Array manipulation](#array-manipulation)
21//! * [Iteration](#iteration)
22//! * [Type conversions](#type-conversions)
23//! * [Convenience methods for 2-D arrays](#convenience-methods-for-2-d-arrays)
24//!
25//! # Similarities
26//!
27//! `ndarray`'s array type ([`ArrayBase`]), is very similar to
28//! NumPy's array type (`numpy.ndarray`):
29//!
30//! * Arrays have a single element type.
31//! * Arrays can have arbitrarily many dimensions.
32//! * Arrays can have arbitrary strides.
33//! * Indexing starts at zero, not one.
34//! * The default memory layout is row-major, and the default iterators follow
35//! row-major order (also called "logical order" in the documentation).
36//! * Arithmetic operators work elementwise. (For example, `a * b` performs
37//! elementwise multiplication, not matrix multiplication.)
38//! * Owned arrays are contiguous in memory.
39//! * Many operations, such as slicing, are very cheap because they can return
40//! a view of an array instead of copying the data.
41//!
42//! NumPy has many features that `ndarray` doesn't have yet, such as:
43//!
44//! * [index arrays](https://docs.scipy.org/doc/numpy/user/basics.indexing.html#index-arrays)
45//! * [mask index arrays](https://docs.scipy.org/doc/numpy/user/basics.indexing.html#boolean-or-mask-index-arrays)
46//! * co-broadcasting (`ndarray` only supports broadcasting the right-hand array in a binary operation.)
47//!
48//! # Some key differences
49//!
50//! <table>
51//! <tr>
52//! <th>
53//!
54//! NumPy
55//!
56//! </th>
57//! <th>
58//!
59//! `ndarray`
60//!
61//! </th>
62//! </tr>
63//!
64//! <tr>
65//! <td>
66//!
67//! In NumPy, there is no distinction between owned arrays, views, and mutable
68//! views. There can be multiple arrays (instances of `numpy.ndarray`) that
69//! mutably reference the same data.
70//!
71//! </td>
72//! <td>
73//!
74//! In `ndarray`, all arrays are instances of [`ArrayBase`], but
75//! `ArrayBase` is generic over the ownership of the data. [`Array`]
76//! owns its data; [`ArrayView`] is a view;
77//! [`ArrayViewMut`] is a mutable view; [`CowArray`]
78//! either owns its data or is a view (with copy-on-write mutation of the view
79//! variant); and [`ArcArray`] has a reference-counted pointer to its
80//! data (with copy-on-write mutation). Arrays and views follow Rust's aliasing
81//! rules.
82//!
83//! </td>
84//! </tr>
85//!
86//! <tr>
87//! <td>
88//!
89//! In NumPy, all arrays are dynamic-dimensional.
90//!
91//! </td>
92//! <td>
93//!
94//! In `ndarray`, you can create fixed-dimension arrays, such as
95//! [`Array2`]. This takes advantage of the type system to help you
96//! write correct code and also avoids small heap allocations for the shape and
97//! strides.
98//!
99//! </td>
100//! </tr>
101//!
102//! <tr>
103//! <td>
104//!
105//! When slicing in NumPy, the indices are `start`, `start + step`, `start +
106//! 2*step`, … until reaching `end` (exclusive).
107//!
108//! </td>
109//! <td>
110//!
111//! When slicing in `ndarray`, the axis is first sliced with `start..end`. Then if
112//! `step` is positive, the first index is the front of the slice; if `step` is
113//! negative, the first index is the back of the slice. This means that the
114//! behavior is different from NumPy when `step < 0`. See the docs for the
115//! [`s![]` macro][s!] for more details.
116//!
117//! </td>
118//! </tr>
119//! </table>
120//!
121//! # The ndarray ecosystem
122//!
123//! `ndarray` does not provide advanced linear algebra routines out of the box (e.g. SVD decomposition).
124//! Most of the routines that you can find in `scipy.linalg`/`numpy.linalg` are provided by another crate,
125//! [`ndarray-linalg`](https://crates.io/crates/ndarray-linalg).
126//!
127//! The same holds for statistics: `ndarray` provides some basic functionalities (e.g. `mean`)
128//! but more advanced routines can be found in [`ndarray-stats`](https://crates.io/crates/ndarray-stats).
129//!
130//! If you are looking to generate random arrays instead, check out [`ndarray-rand`](https://crates.io/crates/ndarray-rand).
131//!
132//! It is also possible to serialize `NumPy` arrays in `.npy`/`.npz` format and deserialize them as `ndarray` arrays (and vice versa)
133//! using [`ndarray-npy`](https://crates.io/crates/ndarray-npy).
134//!
135//! # Other Rust array/matrix crates
136//!
137//! Of the array/matrix types in Rust crates, the `ndarray` array type is probably
138//! the most similar to NumPy's arrays and is the most flexible. However, if your
139//! use-case is constrained to linear algebra on 1-D and 2-D vectors and matrices,
140//! it might be worth considering other crates:
141//!
142//! * [`nalgebra`](https://crates.io/crates/nalgebra) provides 1-D and 2-D
143//! column-major vector and matrix types for linear algebra. Vectors and matrices
144//! can have constant or dynamic shapes, and `nalgebra` uses the type system to
145//! provide compile-time checking of shapes, not just the number of dimensions.
146//! `nalgebra` provides convenient functionality for geometry (e.g. coordinate
147//! transformations) and linear algebra.
148//! * [`cgmath`](https://crates.io/crates/cgmath) provides 1-D and 2-D column-major
149//! types of shape 4×4 or smaller. It's primarily designed for computer graphics
150//! and provides convenient functionality for geometry (e.g. coordinate
151//! transformations). Similar to `nalgebra`, `cgmath` uses the type system to
152//! provide compile-time checking of shapes.
153//! * [`rulinalg`](https://crates.io/crates/rulinalg) provides 1-D and 2-D
154//! row-major vector and matrix types with dynamic shapes. Similar to `ndarray`,
155//! `rulinalg` provides compile-time checking of the number of dimensions, but
156//! not shapes. `rulinalg` provides pure-Rust implementations of linear algebra
157//! operations.
158//! * If there's another crate that should be listed here, please let us know.
159//!
160//! In contrast to these crates, `ndarray` provides an *n*-dimensional array type,
161//! so it's not restricted to 1-D and 2-D vectors and matrices. Also, operators
162//! operate elementwise by default, so the multiplication operator `*` performs
163//! elementwise multiplication instead of matrix multiplication. (You have to
164//! specifically call `.dot()` if you want matrix multiplication.)
165//!
166//! # Rough `ndarray`–NumPy equivalents
167//!
168//! These tables provide some rough equivalents of NumPy operations in `ndarray`.
169//! There are a variety of other methods that aren't included in these tables,
170//! including shape-manipulation, array creation, and iteration routines.
171//!
172//! It's assumed that you've imported NumPy like this:
173//!
174//! ```python
175//! import numpy as np
176//! ```
177//!
178//! and `ndarray` like this:
179//!
180//! ```
181//! use ndarray::prelude::*;
182//! #
183//! # fn main() { let _ = arr0(1); }
184//! ```
185//!
186//! ## Array creation
187//!
188//! This table contains ways to create arrays from scratch. For creating arrays by
189//! operations on other arrays (e.g. arithmetic), see the other tables. Also see
190//! the [`::from_vec()`][::from_vec()], [`::from_iter()`][::from_iter()],
191//! [`::default()`][::default()], [`::from_shape_fn()`][::from_shape_fn()], and
192//! [`::from_shape_vec_unchecked()`][::from_shape_vec_unchecked()] methods.
193//!
194//! NumPy | `ndarray` | Notes
195//! ------|-----------|------
196//! `np.array([[1.,2.,3.], [4.,5.,6.]])` | [`array![[1.,2.,3.], [4.,5.,6.]]`][array!] or [`arr2(&[[1.,2.,3.], [4.,5.,6.]])`][arr2()] | 2×3 floating-point array literal
197//! `np.arange(0., 10., 0.5)` or `np.r_[:10.:0.5]` | [`Array::range(0., 10., 0.5)`][::range()] | create a 1-D array with values `0.`, `0.5`, …, `9.5`
198//! `np.linspace(0., 10., 11)` or `np.r_[:10.:11j]` | [`Array::linspace(0., 10., 11)`][::linspace()] | create a 1-D array with 11 elements with values `0.`, …, `10.`
199//! `np.logspace(2.0, 3.0, num=4, base=10.0)` | [`Array::logspace(10.0, 2.0, 3.0, 4)`][::logspace()] | create a 1-D array with 4 elements with values `100.`, `215.4`, `464.1`, `1000.`
200//! `np.geomspace(1., 1000., num=4)` | [`Array::geomspace(1e0, 1e3, 4)`][::geomspace()] | create a 1-D array with 4 elements with values `1.`, `10.`, `100.`, `1000.`
201//! `np.ones((3, 4, 5))` | [`Array::ones((3, 4, 5))`][::ones()] | create a 3×4×5 array filled with ones (inferring the element type)
202//! `np.zeros((3, 4, 5))` | [`Array::zeros((3, 4, 5))`][::zeros()] | create a 3×4×5 array filled with zeros (inferring the element type)
203//! `np.zeros((3, 4, 5), order='F')` | [`Array::zeros((3, 4, 5).f())`][::zeros()] | create a 3×4×5 array with Fortran (column-major) memory layout filled with zeros (inferring the element type)
204//! `np.zeros_like(a, order='C')` | [`Array::zeros(a.raw_dim())`][::zeros()] | create an array of zeros of the shape shape as `a`, with row-major memory layout (unlike NumPy, this infers the element type from context instead of duplicating `a`'s element type)
205//! `np.full((3, 4), 7.)` | [`Array::from_elem((3, 4), 7.)`][::from_elem()] | create a 3×4 array filled with the value `7.`
206//! `np.eye(3)` | [`Array::eye(3)`][::eye()] | create a 3×3 identity matrix (inferring the element type)
207//! `np.diag(np.array([1, 2, 3]))` | [`Array2::from_diag(&arr1(&[1, 2, 3]))`][::from_diag()] | create a 3×3 matrix with `[1, 2, 3]` as diagonal and zeros elsewhere (inferring the element type)
208//! `np.array([1, 2, 3, 4]).reshape((2, 2))` | [`Array::from_shape_vec((2, 2), vec![1, 2, 3, 4])?`][::from_shape_vec()] | create a 2×2 array from the elements in the list/`Vec`
209//! `np.array([1, 2, 3, 4]).reshape((2, 2), order='F')` | [`Array::from_shape_vec((2, 2).f(), vec![1, 2, 3, 4])?`][::from_shape_vec()] | create a 2×2 array from the elements in the list/`Vec` using Fortran (column-major) order
210//! `np.random` | See the [`ndarray-rand`](https://crates.io/crates/ndarray-rand) crate. | create arrays of random numbers
211//!
212//! Note that the examples in the table rely on the compiler inferring the
213//! element type and dimensionality from context, which is usually sufficient.
214//! However, if the compiler cannot infer the types, you can specify them
215//! manually. These are examples of creating a 3-D Fortran-layout array of
216//! `f64`s:
217//!
218//! ```
219//! # use ndarray::prelude::*;
220//! #
221//! // This is an example where the compiler can infer the element type
222//! // because `f64::sin` can only be called on `f64` elements:
223//! let arr1 = Array::zeros((3, 2, 4).f());
224//! arr1.mapv(f64::sin);
225//!
226//! // Specify just the element type and infer the dimensionality:
227//! let arr2 = Array::<f64, _>::zeros((3, 2, 4).f());
228//! let arr3: Array<f64, _> = Array::zeros((3, 2, 4).f());
229//!
230//! // Specify both the element type and dimensionality:
231//! let arr4 = Array3::<f64>::zeros((3, 2, 4).f());
232//! let arr5: Array3<f64> = Array::zeros((3, 2, 4).f());
233//! let arr6 = Array::<f64, Ix3>::zeros((3, 2, 4).f());
234//! let arr7: Array<f64, Ix3> = Array::zeros((3, 2, 4).f());
235//! ```
236//!
237//! ## Indexing and slicing
238//!
239//! A few notes:
240//!
241//! * Indices start at 0. For example, "row 1" is the second row in the array.
242//!
243//! * Some methods have multiple variants in terms of ownership and mutability.
244//! Only the non-mutable methods that take the array by reference are listed in
245//! this table. For example, [`.slice()`][.slice()] also has corresponding
246//! methods [`.slice_mut()`][.slice_mut()], [`.slice_move()`][.slice_move()], and
247//! [`.slice_collapse()`][.slice_collapse()].
248//!
249//! * The behavior of slicing is different from NumPy for slices with
250//! `step < 0`. See the docs for the [`s![]` macro][s!] for more details.
251//!
252//! NumPy | `ndarray` | Notes
253//! ------|-----------|------
254//! `a[-1]` | [`a[a.len() - 1]`][.index()] | access the last element in 1-D array `a`
255//! `a[1, 4]` | [`a[[1, 4]]`][.index()] | access the element in row 1, column 4
256//! `a[1]` or `a[1, :, :]` | [`a.slice(s![1, .., ..])`][.slice()] or [`a.index_axis(Axis(0), 1)`][.index_axis()] | get a 2-D subview of a 3-D array at index 1 of axis 0
257//! `a[0:5]` or `a[:5]` or `a[0:5, :]` | [`a.slice(s![0..5, ..])`][.slice()] or [`a.slice(s![..5, ..])`][.slice()] or [`a.slice_axis(Axis(0), Slice::from(0..5))`][.slice_axis()] | get the first 5 rows of a 2-D array
258//! `a[-5:]` or `a[-5:, :]` | [`a.slice(s![-5.., ..])`][.slice()] or [`a.slice_axis(Axis(0), Slice::from(-5..))`][.slice_axis()] | get the last 5 rows of a 2-D array
259//! `a[:3, 4:9]` | [`a.slice(s![..3, 4..9])`][.slice()] | columns 4, 5, 6, 7, and 8 of the first 3 rows
260//! `a[1:4:2, ::-1]` | [`a.slice(s![1..4;2, ..;-1])`][.slice()] | rows 1 and 3 with the columns in reverse order
261//! `a.take([4, 2])` | `a.select(Axis(0), &[4, 2])` | rows 4 and 2 of the array
262//!
263//! ## Shape and strides
264//!
265//! Note that [`a.shape()`][.shape()], [`a.dim()`][.dim()], and
266//! [`a.raw_dim()`][.raw_dim()] all return the shape of the array, but as
267//! different types. `a.shape()` returns the shape as `&[Ix]`, (where
268//! [`Ix`] is `usize`) which is useful for general operations on the shape.
269//! `a.dim()` returns the shape as `D::Pattern`, which is useful for
270//! pattern-matching shapes. `a.raw_dim()` returns the shape as `D`, which is
271//! useful for creating other arrays of the same shape.
272//!
273//! NumPy | `ndarray` | Notes
274//! ------|-----------|------
275//! `np.ndim(a)` or `a.ndim` | [`a.ndim()`][.ndim()] | get the number of dimensions of array `a`
276//! `np.size(a)` or `a.size` | [`a.len()`][.len()] | get the number of elements in array `a`
277//! `np.shape(a)` or `a.shape` | [`a.shape()`][.shape()] or [`a.dim()`][.dim()] | get the shape of array `a`
278//! `a.shape[axis]` | [`a.len_of(Axis(axis))`][.len_of()] | get the length of an axis
279//! `a.strides` | [`a.strides()`][.strides()] | get the strides of array `a`
280//! `np.size(a) == 0` or `a.size == 0` | [`a.is_empty()`][.is_empty()] | check if the array has zero elements
281//!
282//! ## Mathematics
283//!
284//! Note that [`.mapv()`][.mapv()] has corresponding methods [`.map()`][.map()],
285//! [`.mapv_into()`][.mapv_into()], [`.map_inplace()`][.map_inplace()], and
286//! [`.mapv_inplace()`][.mapv_inplace()]. Also look at [`.fold()`][.fold()],
287//! [`.for_each()`][.for_each()], [`.fold_axis()`][.fold_axis()], and
288//! [`.map_axis()`][.map_axis()].
289//!
290//! <table>
291//! <tr><th>
292//!
293//! NumPy
294//!
295//! </th><th>
296//!
297//! `ndarray`
298//!
299//! </th><th>
300//!
301//! Notes
302//!
303//! </th></tr>
304//!
305//! <tr><td>
306//!
307//! `a.transpose()` or `a.T`
308//!
309//! </td><td>
310//!
311//! [`a.t()`][.t()] or [`a.reversed_axes()`][.reversed_axes()]
312//!
313//! </td><td>
314//!
315//! transpose of array `a` (view for `.t()` or by-move for `.reversed_axes()`)
316//!
317//! </td></tr>
318//!
319//! <tr><td>
320//!
321//! `mat1.dot(mat2)`
322//!
323//! </td><td>
324//!
325//! [`mat1.dot(&mat2)`][dot-2-2]
326//!
327//! </td><td>
328//!
329//! 2-D matrix multiply
330//!
331//! </td></tr>
332//!
333//! <tr><td>
334//!
335//! `mat.dot(vec)`
336//!
337//! </td><td>
338//!
339//! [`mat.dot(&vec)`][dot-2-1]
340//!
341//! </td><td>
342//!
343//! 2-D matrix dot 1-D column vector
344//!
345//! </td></tr>
346//!
347//! <tr><td>
348//!
349//! `vec.dot(mat)`
350//!
351//! </td><td>
352//!
353//! [`vec.dot(&mat)`][dot-1-2]
354//!
355//! </td><td>
356//!
357//! 1-D row vector dot 2-D matrix
358//!
359//! </td></tr>
360//!
361//! <tr><td>
362//!
363//! `vec1.dot(vec2)`
364//!
365//! </td><td>
366//!
367//! [`vec1.dot(&vec2)`][dot-1-1]
368//!
369//! </td><td>
370//!
371//! vector dot product
372//!
373//! </td></tr>
374//!
375//! <tr><td>
376//!
377//! `a * b`, `a + b`, etc.
378//!
379//! </td><td>
380//!
381//! [`a * b`, `a + b`, etc.](ArrayBase#arithmetic-operations)
382//!
383//! </td><td>
384//!
385//! element-wise arithmetic operations
386//!
387//! </td></tr>
388//!
389//! <tr><td>
390//!
391//! `a**3`
392//!
393//! </td><td>
394//!
395//! [`a.mapv(|a| a.powi(3))`][.mapv()]
396//!
397//! </td><td>
398//!
399//! element-wise power of 3
400//!
401//! </td></tr>
402//!
403//! <tr><td>
404//!
405//! `np.sqrt(a)`
406//!
407//! </td><td>
408//!
409//! [`a.mapv(f64::sqrt)`][.mapv()]
410//!
411//! </td><td>
412//!
413//! element-wise square root for `f64` array
414//!
415//! </td></tr>
416//!
417//! <tr><td>
418//!
419//! `(a>0.5)`
420//!
421//! </td><td>
422//!
423//! [`a.mapv(|a| a > 0.5)`][.mapv()]
424//!
425//! </td><td>
426//!
427//! array of `bool`s of same shape as `a` with `true` where `a > 0.5` and `false` elsewhere
428//!
429//! </td></tr>
430//!
431//! <tr><td>
432//!
433//! `np.sum(a)` or `a.sum()`
434//!
435//! </td><td>
436//!
437//! [`a.sum()`][.sum()]
438//!
439//! </td><td>
440//!
441//! sum the elements in `a`
442//!
443//! </td></tr>
444//!
445//! <tr><td>
446//!
447//! `np.sum(a, axis=2)` or `a.sum(axis=2)`
448//!
449//! </td><td>
450//!
451//! [`a.sum_axis(Axis(2))`][.sum_axis()]
452//!
453//! </td><td>
454//!
455//! sum the elements in `a` along axis 2
456//!
457//! </td></tr>
458//!
459//! <tr><td>
460//!
461//! `np.mean(a)` or `a.mean()`
462//!
463//! </td><td>
464//!
465//! [`a.mean().unwrap()`][.mean()]
466//! </td><td>
467//!
468//! calculate the mean of the elements in `f64` array `a`
469//!
470//! </td></tr>
471//!
472//! <tr><td>
473//!
474//! `np.mean(a, axis=2)` or `a.mean(axis=2)`
475//!
476//! </td><td>
477//!
478//! [`a.mean_axis(Axis(2))`][.mean_axis()]
479//!
480//! </td><td>
481//!
482//! calculate the mean of the elements in `a` along axis 2
483//!
484//! </td></tr>
485//!
486//! <tr><td>
487//!
488//! `np.allclose(a, b, atol=1e-8)`
489//!
490//! </td><td>
491//!
492//! [`a.abs_diff_eq(&b, 1e-8)`][.abs_diff_eq()]
493//!
494//! </td><td>
495//!
496//! check if the arrays' elementwise differences are within an absolute tolerance (it requires the `approx` feature-flag)
497//!
498//! </td></tr>
499//!
500//! <tr><td>
501//!
502//! `np.diag(a)`
503//!
504//! </td><td>
505//!
506//! [`a.diag()`][.diag()]
507//!
508//! </td><td>
509//!
510//! view the diagonal of `a`
511//!
512//! </td></tr>
513//!
514//! <tr><td>
515//!
516//! `np.linalg`
517//!
518//! </td><td>
519//!
520//! See [`ndarray-linalg`](https://crates.io/crates/ndarray-linalg)
521//!
522//! </td><td>
523//!
524//! linear algebra (matrix inverse, solving, decompositions, etc.)
525//!
526//! </td></tr>
527//! </table>
528//!
529//! ## Array manipulation
530//!
531//! NumPy | `ndarray` | Notes
532//! ------|-----------|------
533//! `a[:] = 3.` | [`a.fill(3.)`][.fill()] | set all array elements to the same scalar value
534//! `a[:] = b` | [`a.assign(&b)`][.assign()] | copy the data from array `b` into array `a`
535//! `a[:5, 2] = 3.` | [`a.slice_mut(s![..5, 2]).fill(3.)`][.fill()] | set a portion of the array to the same scalar value
536//! `a[:5, 2] = b` | [`a.slice_mut(s![..5, 2]).assign(&b)`][.assign()] | copy the data from array `b` into part of array `a`
537//! `np.concatenate((a,b), axis=1)` | [`concatenate![Axis(1), a, b]`][concatenate!] or [`concatenate(Axis(1), &[a.view(), b.view()])`][concatenate()] | concatenate arrays `a` and `b` along axis 1
538//! `np.stack((a,b), axis=1)` | [`stack![Axis(1), a, b]`][stack!] or [`stack(Axis(1), vec![a.view(), b.view()])`][stack()] | stack arrays `a` and `b` along axis 1
539//! `a[:,np.newaxis]` or `np.expand_dims(a, axis=1)` | [`a.slice(s![.., NewAxis])`][.slice()] or [`a.insert_axis(Axis(1))`][.insert_axis()] | create an view of 1-D array `a`, inserting a new axis 1
540//! `a.transpose()` or `a.T` | [`a.t()`][.t()] or [`a.reversed_axes()`][.reversed_axes()] | transpose of array `a` (view for `.t()` or by-move for `.reversed_axes()`)
541//! `np.diag(a)` | [`a.diag()`][.diag()] | view the diagonal of `a`
542//! `a.flatten()` | [`use std::iter::FromIterator; Array::from_iter(a.iter().cloned())`][::from_iter()] | create a 1-D array by flattening `a`
543//!
544//! ## Iteration
545//!
546//! `ndarray` has lots of interesting iterators/producers that implement the
547//! [`NdProducer`](crate::NdProducer) trait, which is a generalization of `Iterator`
548//! to multiple dimensions. This makes it possible to correctly and efficiently
549//! zip together slices/subviews of arrays in multiple dimensions with
550//! [`Zip`] or [`azip!()`]. The purpose of this is similar to
551//! [`np.nditer`](https://docs.scipy.org/doc/numpy/reference/generated/numpy.nditer.html),
552//! but [`Zip`] is implemented and used somewhat differently.
553//!
554//! This table lists some of the iterators/producers which have a direct
555//! equivalent in NumPy. For a more complete introduction to producers and
556//! iterators, see [*Loops, Producers, and
557//! Iterators*](ArrayBase#loops-producers-and-iterators).
558//! Note that there are also variants of these iterators (with a `_mut` suffix)
559//! that yield `ArrayViewMut` instead of `ArrayView`.
560//!
561//! NumPy | `ndarray` | Notes
562//! ------|-----------|------
563//! `a.flat` | [`a.iter()`][.iter()] | iterator over the array elements in logical order
564//! `np.ndenumerate(a)` | [`a.indexed_iter()`][.indexed_iter()] | flat iterator yielding the index along with each element reference
565//! `iter(a)` | [`a.outer_iter()`][.outer_iter()] or [`a.axis_iter(Axis(0))`][.axis_iter()] | iterator over the first (outermost) axis, yielding each subview
566//!
567//! ## Type conversions
568//!
569//! In `ndarray`, conversions between datatypes are done with `mapv()` by
570//! passing a closure to convert every element independently.
571//! For the conversion itself, we have several options:
572//! - `std::convert::From` ensures lossless, safe conversions at compile-time
573//! and is generally recommended.
574//! - `std::convert::TryFrom` can be used for potentially unsafe conversions. It
575//! will return a `Result` which can be handled or `unwrap()`ed to panic if
576//! any value at runtime cannot be converted losslessly.
577//! - The `as` keyword compiles to lossless/lossy conversions depending on the
578//! source and target datatypes. It can be useful when `TryFrom` is a
579//! performance issue or does not apply. A notable difference to NumPy is that
580//! `as` performs a [*saturating* cast][sat_conv] when casting
581//! from floats to integers. Further information can be found in the
582//! [reference on type cast expressions][as_typecast].
583//!
584//! For details, be sure to check out the type conversion examples.
585//!
586
587//! <table>
588//! <tr><th>
589//!
590//! NumPy
591//!
592//! </th><th>
593//!
594//! `ndarray`
595//!
596//! </th><th>
597//!
598//! Notes
599//!
600//! </th></tr>
601//!
602//! <tr><td>
603//!
604//! `a.astype(np.float32)`
605//!
606//! </td><td>
607//!
608//! `a.mapv(f32::from)`
609//!
610//! </td><td>
611//!
612//! convert `u8` array infallibly to `f32` array with `std::convert::From`, generally recommended
613//!
614//! </td></tr>
615//!
616//! <tr><td>
617//!
618//! `a.astype(np.int32)`
619//!
620//! </td><td>
621//!
622//! `a.mapv(i32::from)`
623//!
624//! </td><td>
625//!
626//! upcast `u8` array to `i32` array with `std::convert::From`, preferable over `as` because it ensures at compile-time that the conversion is lossless
627//!
628//! </td></tr>
629//!
630//! <tr><td>
631//!
632//! `a.astype(np.uint8)`
633//!
634//! </td><td>
635//!
636//! `a.mapv(|x| u8::try_from(x).unwrap())`
637//!
638//! </td><td>
639//!
640//! try to convert `i8` array to `u8` array, panic if any value cannot be converted lossless at runtime (e.g. negative value)
641//!
642//! </td></tr>
643//!
644//! <tr><td>
645//!
646//! `a.astype(np.int32)`
647//!
648//! </td><td>
649//!
650//! `a.mapv(|x| x as i32)`
651//!
652//! </td><td>
653//!
654//! convert `f32` array to `i32` array with ["saturating" conversion][sat_conv]; care needed because it can be a lossy conversion or result in non-finite values! See [the reference for information][as_typecast].
655//!
656//! </td></tr>
657//! </table>
658//!
659//! [as_conv]: https://doc.rust-lang.org/rust-by-example/types/cast.html
660//! [sat_conv]: https://blog.rust-lang.org/2020/07/16/Rust-1.45.0.html#fixing-unsoundness-in-casts
661//! [as_typecast]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions
662//!
663//! ## Convenience methods for 2-D arrays
664//!
665//! NumPy | `ndarray` | Notes
666//! ------|-----------|------
667//! `len(a)` or `a.shape[0]` | [`a.nrows()`][.nrows()] | get the number of rows in a 2-D array
668//! `a.shape[1]` | [`a.ncols()`][.ncols()] | get the number of columns in a 2-D array
669//! `a[1]` or `a[1,:]` | [`a.row(1)`][.row()] or [`a.row_mut(1)`][.row_mut()] | view (or mutable view) of row 1 in a 2-D array
670//! `a[:,4]` | [`a.column(4)`][.column()] or [`a.column_mut(4)`][.column_mut()] | view (or mutable view) of column 4 in a 2-D array
671//! `a.shape[0] == a.shape[1]` | [`a.is_square()`][.is_square()] | check if the array is square
672//!
673//! [.abs_diff_eq()]: ArrayRef#impl-AbsDiffEq%3CArrayRef%3CB,+D%3E%3E
674//! [.assign()]: ArrayRef::assign
675//! [.axis_iter()]: ArrayRef::axis_iter
676//! [.ncols()]: LayoutRef::ncols
677//! [.column()]: ArrayRef::column
678//! [.column_mut()]: ArrayRef::column_mut
679//! [concatenate()]: crate::concatenate()
680//! [concatenate!]: crate::concatenate!
681//! [stack!]: crate::stack!
682//! [::default()]: ArrayBase::default
683//! [.diag()]: ArrayRef::diag
684//! [.dim()]: LayoutRef::dim
685//! [::eye()]: ArrayBase::eye
686//! [.fill()]: ArrayRef::fill
687//! [.fold()]: ArrayRef::fold
688//! [.fold_axis()]: ArrayRef::fold_axis
689//! [::from_elem()]: ArrayBase::from_elem
690//! [::from_iter()]: ArrayBase::from_iter
691//! [::from_diag()]: ArrayBase::from_diag
692//! [::from_shape_fn()]: ArrayBase::from_shape_fn
693//! [::from_shape_vec()]: ArrayBase::from_shape_vec
694//! [::from_shape_vec_unchecked()]: ArrayBase::from_shape_vec_unchecked
695//! [::from_vec()]: ArrayBase::from_vec
696//! [.index()]: ArrayBase#impl-Index<I>
697//! [.indexed_iter()]: ArrayRef::indexed_iter
698//! [.insert_axis()]: ArrayBase::insert_axis
699//! [.is_empty()]: LayoutRef::is_empty
700//! [.is_square()]: LayoutRef::is_square
701//! [.iter()]: ArrayRef::iter
702//! [.len()]: LayoutRef::len
703//! [.len_of()]: LayoutRef::len_of
704//! [::linspace()]: ArrayBase::linspace
705//! [::logspace()]: ArrayBase::logspace
706//! [::geomspace()]: ArrayBase::geomspace
707//! [.map()]: ArrayRef::map
708//! [.map_axis()]: ArrayRef::map_axis
709//! [.map_inplace()]: ArrayRef::map_inplace
710//! [.mapv()]: ArrayRef::mapv
711//! [.mapv_inplace()]: ArrayRef::mapv_inplace
712//! [.mapv_into()]: ArrayBase::mapv_into
713//! [dot-2-2]: ArrayRef#impl-Dot<ArrayRef<A,+Dim<[usize;+2]>>>-for-ArrayRef<A,+Dim<[usize;+2]>>
714//! [dot-1-1]: ArrayRef#impl-Dot<ArrayRef<A,+Dim<[usize;+1]>>>-for-ArrayRef<A,+Dim<[usize;+1]>>
715//! [dot-1-2]: ArrayRef#impl-Dot<ArrayRef<A,+Dim<[usize;+2]>>>-for-ArrayRef<A,+Dim<[usize;+1]>>
716//! [dot-2-1]: ArrayRef#impl-Dot<ArrayRef<A,+Dim<[usize;+1]>>>-for-ArrayRef<A,+Dim<[usize;+2]>>
717//! [.mean()]: ArrayRef::mean
718//! [.mean_axis()]: ArrayRef::mean_axis
719//! [.ndim()]: LayoutRef::ndim
720//! [::ones()]: ArrayBase::ones
721//! [.outer_iter()]: ArrayRef::outer_iter
722//! [::range()]: ArrayBase::range
723//! [.raw_dim()]: LayoutRef::raw_dim
724//! [.reversed_axes()]: ArrayBase::reversed_axes
725//! [.row()]: ArrayRef::row
726//! [.row_mut()]: ArrayRef::row_mut
727//! [.nrows()]: LayoutRef::nrows
728//! [.sum()]: ArrayRef::sum
729//! [.slice()]: ArrayRef::slice
730//! [.slice_axis()]: ArrayRef::slice_axis
731//! [.slice_collapse()]: LayoutRef::slice_collapse
732//! [.slice_move()]: ArrayBase::slice_move
733//! [.slice_mut()]: ArrayRef::slice_mut
734//! [.shape()]: LayoutRef::shape
735//! [stack()]: crate::stack()
736//! [.strides()]: LayoutRef::strides
737//! [.index_axis()]: ArrayRef::index_axis
738//! [.sum_axis()]: ArrayRef::sum_axis
739//! [.t()]: ArrayRef::t
740//! [vec-* dot]: ArrayRef::dot
741//! [.for_each()]: ArrayRef::for_each
742//! [::zeros()]: ArrayBase::zeros
743//! [`Zip`]: crate::Zip
744
745pub mod coord_transform;
746pub mod rk_step;
747pub mod simple_math;
748
749// This is to avoid putting `crate::` everywhere
750#[allow(unused_imports)]
751use crate::imp_prelude::*;