1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
//! # Multidimensional array for Rust
//!
//! ## Overview
//!
//! The mdarray crate provides a multidimensional array for Rust. Its main target
//! is for numeric types, however generic types are supported as well. The purpose
//! is to provide a generic container type that is simple and flexible to use,
//! with interworking to other crates for e.g. BLAS/LAPACK functionality.
//!
//! Here are the main features of mdarray:
//!
//! - Dense array type, where the rank is known at compile time.
//! - Static or dynamic array dimensions, with optional inline storage.
//! - Standard Rust mechanisms are used for e.g. indexing and iteration.
//! - Generic expressions for multidimensional iteration.
//!
//! The design is inspired from other Rust crates (ndarray, nalgebra, bitvec
//! and dfdx), the proposed C++ mdarray and mdspan types, and multidimensional
//! arrays in other languages.
//!
//! ## Array types
//!
//! The basic array type is `Grid` for a dense array that owns the storage,
//! similar to the Rust `Vec` type. It is parameterized by the element type,
//! the shape (i.e. the size of each dimension) and optionally an allocator.
//!
//! `Array` is a dense array which stores elements inline, similar to the Rust
//! `array` type. The shape must consist of dimensions with constant size.
//!
//! `Expr` and `ExprMut` are array types that refer to a parent array. They are
//! used for example when creating array views without duplicating elements.
//!
//! `Span` is a generic array reference, similar to the Rust `slice` type.
//! It consists of a pointer to an internal structure that holds the storage
//! and the layout mapping. All arrays can be dereferenced to an array span.
//!
//! The following type aliases are provided:
//!
//! - `DGrid<T, const N: usize, ...>` for a dense array with a given rank.
//! - `DSpan<T, const N: usize, ...>` for an array span with a given rank.
//!
//! The layout mapping describes how elements are stored in memory. The mapping
//! is parameterized by the shape and the layout. It contains the dynamic size
//! and stride per dimension when needed.
//!
//! The layout is `Dense` if elements are stored contiguously without gaps.
//! The layout is `General` if each dimension can have arbitrary stride except
//! for the innermost one, which has unit stride. It is compatible with the
//! BLAS/LAPACK general matrix storage.
//!
//! The layout is `Flat` if the innermost dimension can have arbitrary stride
//! and the other dimensions must follow in order, allowing for linear indexing.
//! The layout is `Strided` if all dimensions can have arbitrary strides.
//!
//! The array elements are stored in column-major or Fortran order, where the
//! first dimension is the innermost one.
//!
//! ## Indexing and views
//!
//! Scalar indexing is done using the normal square-bracket index operator and
//! an array of `usize` per dimension as index.
//!
//! If the array layout supports linear indexing (i.e. the layout is `Dense` or
//! `Flat`), a scalar `usize` can also be used as index. If the layout is `Dense`,
//! a range can be used to select a slice.
//!
//! If linear or slice indexing is possible but the array layout is not known,
//! `remap`, `remap_mut` and `into_mapping` can be used to change layout.
//! Alternatively, `flatten`, `flatten_mut` and `into_flattened` can be used
//! to change to a one-dimensional array.
//!
//! An array view can be created with the `view` and `view_mut` methods, which
//! take indices per dimension as arguments. Each index can be either a range
//! or `usize`. The resulting array layout depends on both the layout inferred
//! from the indices and the input layout.
//!
//! For two-dimensional arrays, a view of one column or row can be created with
//! the `col`, `col_mut`, `row` and `row_mut` methods, and a view of the diagonal
//! with `diag` and `diag_mut`.
//!
//! ## Iteration
//!
//! An iterator can be created from an array with the `iter`, `iter_mut` and
//! `into_iter` methods like for `Vec` and `slice`.
//!
//! Expressions are similar to iterators, but support multidimensional iteration
//! and have consistency checking of shapes. An expression is created with the
//! `expr`, `expr_mut` and `into_expr` methods. Note that the array types `Expr`
//! and `ExprMut` are also expressions.
//!
//! There are methods for for evaluating expressions or converting into other
//! expressions, such as `eval`, `for_each` and `map`. Two expressions can be
//! merged to an expression of tuples with the `zip` method or free function.
//!
//! When merging expressions, if the rank differs the expression with the lower
//! rank is broadcast into the larger shape by adding outer dimensions. It is not
//! possible to broadcast mutable arrays or when moving elements out of an array.
//!
//! For multidimensional arrays, iteration over a single dimension can be done
//! with `outer_expr`, `outer_expr_mut`, `axis_expr` and `axis_expr_mut`.
//! The resulting expressions give array views of the remaining dimensions.
//!
//! It is also possible to iterate over all except one dimension with `cols`,
//! `cols_mut`, `lanes`, `lanes_mut`, `rows` and `rows_mut`.
//!
//! ## Operators
//!
//! Arithmetic, logical, negation, comparison and compound assignment operators
//! are supported for arrays and expressions.
//!
//! If at least one of the inputs is an array that is passed by value, the
//! operation is evaluated directly and the input array is reused for the result.
//! Otherwise, if all input parameters are array references or expressions, an
//! expression is returned. In the latter case, the result may have a different
//! element type.
//!
//! For comparison operators, the parameters must always be arrays that are passed
//! by reference. For compound assignment operators, the first parameter is always
//! a mutable reference to an array where the result is stored.
//!
//! Scalar parameters must passed using the `fill` function that wraps a value in
//! an `Expression<Fill<T>>` expression. If a type does not implement the `Copy`
//! trait, the parameter must be passed by reference.
//!
//! ## Example
//!
//! This example implements matrix multiplication and addition `C = A * B + C`.
//! The matrices use column-major ordering, and the inner loop runs over one column
//! in `A` and `C`. By using iterator-like expressions the array bounds checking
//! is avoided, and the compiler is able to vectorize the inner loop.
//!
//! ```
//! use mdarray::{expr, grid, DSpan, Expression};
//!
//! fn matmul(a: &DSpan<f64, 2>, b: &DSpan<f64, 2>, c: &mut DSpan<f64, 2>) {
//! for (mut cj, bj) in c.cols_mut().zip(b.cols()) {
//! for (ak, bkj) in a.cols().zip(bj) {
//! for (cij, aik) in cj.expr_mut().zip(ak) {
//! *cij = aik.mul_add(*bkj, *cij);
//! }
//! }
//! }
//! }
//!
//! let a = expr![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];
//! let b = expr![[0.0, 1.0], [1.0, 1.0]];
//!
//! let mut c = grid![[0.0; 3]; 2];
//!
//! matmul(&a, &b, &mut c);
//!
//! assert_eq!(c, expr![[4.0, 5.0, 6.0], [5.0, 7.0, 9.0]]);
//! ```
#![cfg_attr(feature = "nightly", feature(allocator_api))]
#![cfg_attr(feature = "nightly", feature(extern_types))]
#![cfg_attr(feature = "nightly", feature(hasher_prefixfree_extras))]
#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
#![cfg_attr(feature = "nightly", feature(slice_range))]
#![warn(missing_docs)]
#![warn(unreachable_pub)]
#![warn(unused_results)]
/// Array buffer module.
pub mod buffer;
/// Expression module, for multidimensional iteration.
pub mod expr;
/// Module for array span and view indexing, and for array axis subarray types.
pub mod index;
/// Array layout mapping module.
pub mod mapping;
mod array;
mod dim;
mod expression;
mod grid;
mod iter;
mod layout;
mod macros;
mod ops;
mod raw_grid;
mod raw_span;
mod shape;
mod span;
mod traits;
#[cfg(feature = "serde")]
mod serde;
#[cfg(not(feature = "nightly"))]
mod alloc {
pub trait Allocator {}
#[derive(Copy, Clone, Default, Debug)]
pub struct Global;
impl Allocator for Global {}
}
pub use array::Array;
pub use dim::{Const, Dim, Dims, Dyn, Strides};
pub use expression::Expression;
pub use grid::{DGrid, Grid};
pub use iter::Iter;
pub use layout::{Dense, Flat, General, Layout, Strided, Uniform, UnitStrided};
pub use ops::{step, StepRange};
pub use shape::{IntoShape, Rank, Shape};
pub use span::{DSpan, Span};
pub use traits::{Apply, IntoCloned, IntoExpression};