ndarray
NumPy-friendly multidimensional arrays in C++
Loading...
Searching...
No Matches
ndarray; Multidimensional Arrays in C++

ndarray is a template library that provides multidimensional array objects in C++, with an interface and features designed to mimic the Python 'numpy' package as much as possible.

A tutorial can be found here.

Other Multidimensional Array Libraries

A number of other public C++ multidimensional array libraries already exist, such as boost.MultiArray, Blitz++, and xtensor. Much of the architecture and some of the interface of the ndarray templates is built on ideas from both of these, particularly boost.MultiArray. ndarray supports shared ownership of data, lazy evaluation of mathematical operations using expression templates, and the ability to use externally allocated memory. It also supports optimized, natural, nested iteration and preserve const-correctness (albeit with different semantics).

While ndarray can perform numerical operations with broadcasting, it makes no attempt to perform explicit vectorization, and libraries that focus more on computational performance will be better at it in almost every context. ndarray's goal is to provide lightweight, flexible data structures with a more Python-friendly ownership model, while maintaining enough static typing to allow optimized libraries (such as Eigen) to work effectively on ndarray-managed arrays.

Copy and Constness Semantics

The memory used by ndarray objects is reference counted, and can be allocated using any STL-compatible allocator. Arrays can also be constructed from external memory buffers, with full reference counting for any external memory owned by an object that participates in any reference-counting scheme (most notably memory belonging to Python Numpy arrays in C++ Python extensions). Reference counting can also be disabled for individual arrays that reference external memory that is not reference-counted.

Array objects in ndarray preserve constness in the same way as most C++ smart pointers: there is a distinction between an array with const elements (Array<T const,N>) and a const array value or reference (Array<T,N> const). An array with const elements does not support operations that change element values ("deep" operations), while a const array object or reference does not allow the array's data pointer, shape, or strides to be changed ("shallow" operations). As a result, functions should generally use const references for both input and output array arguments (with const and non-const elements, respectively). Arrays with non-const elements are implicitly (and efficiently) convertible to arrays with const elements, while an array with const elements can be cast to one with non-const elements using the const_array_cast function.

The Row-Major Contiguous Template Parameter

In addition to being templated on its element type and total number of dimensions, Array is parameterized by the number of guaranteed row-major contiguous (RMC) dimensions, starting from the end. This parameter defaults to zero. For example:

  • Array<T,2,2> is a fully row-major contiguous matrix. Each row of the matrix is a vector with contiguous elements, and there is no space between rows.
  • Array<T,2,1> is a row-major matrix in which each row is a vector with contiguous elements, but there may be space between the rows (or there may not be; the template parameter indicates only the guaranteed number of RMC dimensions).
  • Array<T,2,0> is a matrix that can have any strides, including column-major.

An Array with M RMC dimensions can be implicitly converted to an Array with N<=M RMC dimensions. The static_dimension_cast and dynamic_dimension_cast functions can be used to create arrays with M<N RMC dimensions (dynamic_dimension_cast returns an empty Array if the strides are not appropriately RMC, while static_dimension_cast does no checking).

Indexing and Views

An Array with dimension N>1 behaves like largely like an STL container of Array of dimension N-1. An Array with dimension 1 behaves like a simple container of elements. Iterators over an Array with N>1 thus dereference to Arrays with dimension N-1, and standard [] indexing also yields the expected lower-dimensional array.

Arbitrary views can be retrieved by passing a view definition to an Array's bracket indexing operators. These view definitions are temporaries created by the view() function:

// let 'a' be a 3 dimensional array with dimensions (3,5,4)
// equivalent to a[1:3,:,2] in numpy:
Array<double,2,1> subset1 = a[view(1,3)()(2)];
// equivalent to a[:,:,0:4:2] in numpy in numpy:
Array<double,3> subset2 = a[view()()(0,4,2)];
View< boost::fusion::vector1< index::Full > > view()
Start a view definition that includes the entire first dimension.
Definition views.h:121

Supplying a single integer indexes a dimension by a scalar (which reduces the dimension of output), supplying a pair of integers indicates a contiguous range, and supplying three integers indicates a slice. Specifying no arguments for a dimension includes the entire dimension. Not indexing all dimensions is equivalent to including empty parentheses for the remaining dimensions.

Downloads

https://github.com/ndarray/ndarray/releases

License

ndarray is distributed under a simple BSD-like license: https://github.com/ndarray/ndarray/blob/master/LICENSE