hexed 0.4.0
 
Loading...
Searching...
No Matches
hexed::Array< T > Class Template Reference

Represents a dynamic-sized multidimensional array. More...

#include <Array.hpp>

Public Types

typedef T * iterator
 Iterator type to allow Array to function like a standard container.
 
typedef const T * constiterator
 Iterator type to allow Array to function like a standard container.
 

Public Member Functions

 Array (std::vector< Int > shape_arg, T *data_arg=nullptr)
 Creates an array from scratch.
 
template<typename input_it >
 Array (std::vector< Int > shape_arg, input_it first, input_it last)
 Constructs an array and initializes it with the range [first, last).
 
 Array (std::vector< Int > shape_arg, std::function< T(Int)> func)
 Constructs an array and initializes it with func(i) for each index i in [0, size()).
 
template<int sz>
 Array (Eigen::Vector< T, sz > vec)
 Constructs an array from an Eigen::Vector.
 
 Array (Array &that)
 Copies that, maintaining the same ownership status.
 
 Array (Array< T > &&that)
 Steals whatever assets that had.
 
template<typename... U>
void initialize (Int index, U... args)
 Initializes an element of the array.
 
template<typename U >
Array< T > & operator= (const Array< U > &other)
 Assigns the values in other to this.
 
Array< T > & operator= (const Array< T > &other)
 This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
 
template<typename U >
Array< T > & operator= (const U &value)
 Sets all entries to the specified value.
 
template<typename U >
Array< T > & operator= (U *ptr)
 Sets the entries to the first size() objects pointed to by ptr.
 
Array< T > & operator= (std::initializer_list< T > list)
 Sets the entries to the entries of list, which must have the same size as this.
 
template<typename U = T>
Array< U > copy () const
 Creates a new array that owns its data, which is a copy of this's data (i.e. new data is allocated).
 
Int order () const
 Returns the number of dimensions of the Array.
 
std::vector< Intshape () const
 Fetches the shape (size of each dimension) of the Array.
 
Int size () const
 Returns the total size of the array.
 
bool same_shape (const Array< T > &other)
 true iff this and other have the same shape().
 
Int stride (Int i_dim) const
 The stride for indexing along demension i_dim.
 
bool owns () const
 
flat_interp (double index) const
 Linearly interpolates between entries of the array according to flat indexing.
 
T * data ()
 fetches pointer to data
 
T & operator[] (Int i)
 Accesses elements by flat indexing.
 
Array< T > operator() ()
 Creates an array as a reference to this's data.
 
Array< T > operator() (Int i)
 Creates an array which is a view of the ith "row" of this.
 
Array operator() (Int start, Int stop)
 Creates an array which is a view of rows [start, stop) of this.
 
Array column (Int i)
 
Array reshaped (std::vector< Int > new_shape)
 Returns an array referencing the same data as this but with a different shape.
 
iterator begin ()
 Iterator to beginning of (flat) data.
 
iterator end ()
 Iterator 1 word past the end of (flat) data.
 
Eigen::Map< Eigen::Matrix< T, dyn, 1 >, Eigen::Unaligned, Eigen::InnerStride<> > vector ()
 view of data as an Eigen vector object
 
Array interp (double index)
 
const T * data () const
 fetches pointer to data
 
const T & operator[] (Int i) const
 Accesses elements by flat indexing.
 
const Array< T > operator() () const
 Creates an array as a reference to this's data.
 
const Array< T > operator() (Int i) const
 Creates an array which is a view of the ith "row" of this.
 
const Array operator() (Int start, Int stop) const
 Creates an array which is a view of rows [start, stop) of this.
 
const Array column (Int i) const
 
const Array reshaped (std::vector< Int > new_shape) const
 Returns an array referencing the same data as this but with a different shape.
 
constiterator begin () const
 Iterator to beginning of (flat) data.
 
constiterator end () const
 Iterator 1 word past the end of (flat) data.
 
const Eigen::Map< Eigen::Matrix< T, dyn, 1 >, Eigen::Unaligned, Eigen::InnerStride<> > vector () const
 view of data as an Eigen vector object
 
const Array interp (double index) const
 
void reshape (std::vector< Int > new_shape)
 
Array< T > & operator-= (const Array< T > &that)
 
template<typename Scalar >
Array< T > & operator-= (Scalar s)
 
Array< T > & operator+= (const Array< T > &that)
 
template<typename Scalar >
Array< T > & operator+= (Scalar s)
 
Array< T > & operator/= (const Array< T > &that)
 
template<typename Scalar >
Array< T > & operator/= (Scalar s)
 
Array< T > & operator*= (const Array< T > &that)
 
template<typename Scalar >
Array< T > & operator*= (Scalar s)
 
Array< T > & operator%= (const Array< T > &that)
 
template<typename Scalar >
Array< T > & operator%= (Scalar s)
 
Array extreme (bool minmax, Array that) const
 Entrywise extreme (min or max) of this and that.
 
extreme (bool minmax) const
 Extremal (minimum or maximum) entry of this array.
 
norm_squared () const
 Sum of the squares of all entries.
 
norm () const
 Square root of the sum of the squares of all entries.
 
Array entrywise (std::function< T(T)> f, bool inplace=false)
 Applies a function to each entry of the array.
 
Array abs (bool inplace=false)
 Applies entrywise.
 
Array sqrt (bool inplace=false)
 Applies entrywise.
 
Array exp (bool inplace=false)
 Applies entrywise.
 
Array log (bool inplace=false)
 Applies entrywise.
 
Array sin (bool inplace=false)
 Applies entrywise.
 
Array cos (bool inplace=false)
 Applies entrywise.
 
Array tan (bool inplace=false)
 Applies entrywise.
 
Array asin (bool inplace=false)
 Applies entrywise.
 
Array acos (bool inplace=false)
 Applies entrywise.
 
Array atan (bool inplace=false)
 Applies entrywise.
 
sum ()
 
prod ()
 
template<typename U >
bool equal (const Array< U > &that) const
 Returns true iff this and that have the same shape and equal entries.
 

Static Public Member Functions

template<typename... U>
static Array< T > make_uniform (std::vector< Int > size_arg, U... args)
 Constructs an array and initializes each element with args.
 
template<typename... U>
static Array< T > make (U... args)
 Constructs a 1D array whose elements are args.
 

Detailed Description

template<typename T>
class hexed::Array< T >

Represents a dynamic-sized multidimensional array.

This is an array-style container designed to meet the following objectives:

  • Data is contiguous in memory.
  • Supports an arbitrary number of dimensions.
  • Can own its own data or be a reference to separately-allocated data.
  • A subset of an Array can be accessed with another Array, so that a single function can accept a whole array or a slice without requiring overloads for different types.

Neither the standard library nor Eigen appear to supply a container that meets these criteria. This is a mid-performance class. For absolutely optimum performance, you can use data() and work with the raw pointer. Data is stored in row-major order. Also, here is an overview of how to manage ownership with this class, although this information is also scattered through the member documentation.

  • To create a new array that owns its data, use Array(std::vector<Int>).
  • To create a new array that references data in another array other, use Array(other()).
  • To create a new array that references existing data that is not in an array, use Array(std::vector<Int>, T*)
  • To create a new array that is a copy of an existing array (allocating new data), use Array(other.copy())
  • To copy data from an existing array to another existing array (of the same size) without allocating or creating references, use the = operator.

If you want to pass an Array as a function argument, you should be able to pass it by value without thinking about it. If you're passing a temporary object, it should be preserved as long as it needs to be with the move constructor. That said, for performance it's better to try to use the move constructor instead of the copy constructor whenever appropriate, because this will avoid unnecessary allocations for arrays that own their data.

Note
I want to emphasize that the copy and move constructors will copy/move the data if the array owns it and only keep a pointer to the data if the array does not own it, so the ownership status of the new array is the same as the old one. If you want to explicitly control whether the new array owns data or references existing data, use operator()() or copy().

By default, if DEBUG is defined, then dynamic bounds checking is performed and out-of-bounds access will result in an exception. Otherwise, no bounds checking is performed and out-of-bounds access is undefined behavior. This can be overridden by explicitly defining the HEXED_ARRAY_BOUNDS_CHECK macro to be true or false.

Arrays support the unary arithmetic operators - and + as well as the binary operators -, +, /, *, %, &&, and ||. Binary operators can operate on two arrays or on an array and a scalar. All operators perform their operations elementwise. They always create a copy, so for truly optimal performance you might consider a loop instead. For binary operators, both operands (arrays or scalars) must have the same data type. To perform operations on arrays that have different, but compatible, types, you can cast them to the same type with Array::copy<U>().

Note
Implementing a feature-complete array container is a large task, and I have not yet implemented all of the features that I ultimately plan to. If there is a feature you want and feel that an array class ought to have, feel free to let me know and I may be able to move it up in the queue.

Member Typedef Documentation

◆ constiterator

template<typename T >
typedef const T* hexed::Array< T >::constiterator

Iterator type to allow Array to function like a standard container.

Iterators remain valid throughout the lifetime of the array, since there is no mechanism that changes the address of its underlying data.

Warning
Only valid for Arrays with inner stride 0.

◆ iterator

template<typename T >
typedef T* hexed::Array< T >::iterator

Iterator type to allow Array to function like a standard container.

Iterators remain valid throughout the lifetime of the array, since there is no mechanism that changes the address of its underlying data.

Warning
Only valid for Arrays with inner stride 0.

Constructor & Destructor Documentation

◆ Array() [1/4]

template<typename T >
hexed::Array< T >::Array ( std::vector< Int > shape_arg,
T * data_arg = nullptr )
inline

Creates an array from scratch.

Array will have dimensions specified by shape_arg. If data_arg is null, this Array will allocate new data, which it will now own. The data values will be uninitialized. Otherwise, this array will be a reference to the data starting at data_arg and will not own that data.

Warning
If data_arg is null and T is a class type, you must initialize() each element before you assign to them or destroy the array or else behavior is undefined. The elements are truly uninitialized, not default-constructed. That is, use array.initialize(i, value) not array[i] = value. If T is not a class type (e.g. if it is a double or an int), you can initialize the elements with the assignment operator or destroy the array without initializing its elements. Once you initialize the elements, you can then assign to them even if T is a class type.

◆ Array() [2/4]

template<typename T >
template<int sz>
hexed::Array< T >::Array ( Eigen::Vector< T, sz > vec)
inline

Constructs an array from an Eigen::Vector.

Elements are copied.

◆ Array() [3/4]

template<typename T >
hexed::Array< T >::Array ( Array< T > & that)
inline

Copies that, maintaining the same ownership status.

If that owns its data, this will allocate new data which is a copy of thats data. If it does not, this will be a reference to that's data. This behavior is good for avoiding accidental dangling pointers, but isn't necessarily the most efficient. Whenever possible, it is best to explitly use operator()(), copy(), or the move constructor to control who owns what.

◆ Array() [4/4]

template<typename T >
hexed::Array< T >::Array ( Array< T > && that)
inline

Steals whatever assets that had.

If that owned its data, this will steal that data. If that had a reference to existing data, this will also be a reference to that data. Leaves that in an unspecified but valid state.

Member Function Documentation

◆ copy()

template<typename T >
template<typename U = T>
Array< U > hexed::Array< T >::copy ( ) const
inline

Creates a new array that owns its data, which is a copy of this's data (i.e. new data is allocated).

If the template argument is specified to be something other than T, the array will be cast to a different type. The old type must by copy-assignable to the new type.

◆ data() [1/2]

template<typename T >
T * hexed::Array< T >::data ( )
inline

fetches pointer to data

nullptr if array is empty

◆ data() [2/2]

template<typename T >
const T * hexed::Array< T >::data ( ) const
inline

fetches pointer to data

nullptr if array is empty

◆ entrywise()

template<typename T >
Array hexed::Array< T >::entrywise ( std::function< T(T)> f,
bool inplace = false )
inline

Applies a function to each entry of the array.

If inplace is true, modifies the entries of this array and returns an array that references the data. If inplace is false, does not modify the original array and returns a new array with f applied to the entries.

◆ extreme() [1/2]

template<typename T >
T hexed::Array< T >::extreme ( bool minmax) const
inline

Extremal (minimum or maximum) entry of this array.

Computes maximum if minmax is true, otherwise minimum.

◆ extreme() [2/2]

template<typename T >
Array hexed::Array< T >::extreme ( bool minmax,
Array< T > that ) const
inline

Entrywise extreme (min or max) of this and that.

Computes maximum if minmax is true, otherwise minimum.

◆ flat_interp()

template<typename T >
T hexed::Array< T >::flat_interp ( double index) const
inline

Linearly interpolates between entries of the array according to flat indexing.

Like interp(double), but with [] indexing instead of () indexing.

◆ initialize()

template<typename T >
template<typename... U>
void hexed::Array< T >::initialize ( Int index,
U... args )
inline

Initializes an element of the array.

Element will be initialized with args. It is now safe to dereference or assign this element.

◆ make()

template<typename T >
template<typename... U>
static Array< T > hexed::Array< T >::make ( U... args)
inlinestatic

Constructs a 1D array whose elements are args.

Each element of the array will be initialized with one of args. To pass the same arguments to the constructor of every element, use make_uniform().

◆ make_uniform()

template<typename T >
template<typename... U>
static Array< T > hexed::Array< T >::make_uniform ( std::vector< Int > size_arg,
U... args )
inlinestatic

Constructs an array and initializes each element with args.

All of args are passed to every element, not one of args for each element. For that, use make()

◆ norm()

template<typename T >
T hexed::Array< T >::norm ( ) const
inline

Square root of the sum of the squares of all entries.

For vectors, this is the \( L^2 \) norm and for matrices this is the Frobenius norm.

◆ operator()() [1/6]

template<typename T >
Array< T > hexed::Array< T >::operator() ( )
inline

Creates an array as a reference to this's data.

Obviously, don't do this to a temporary array, or you will create a dangling reference.

◆ operator()() [2/6]

template<typename T >
const Array< T > hexed::Array< T >::operator() ( ) const
inline

Creates an array as a reference to this's data.

Obviously, don't do this to a temporary array, or you will create a dangling reference.

◆ operator()() [3/6]

template<typename T >
Array< T > hexed::Array< T >::operator() ( Int i)
inline

Creates an array which is a view of the ith "row" of this.

Resulting array will have 1 less order() and shape equal to the shape of this but with the first element removed. You can think of it as equivalent to the operator [] of multidimensional builtin arrays or NumPy arrays. For example, if you have an order 3 array a with shape {10, 4, 5}, you can access the element at (5, 2, 3) with either a[113] (5*4*5 + 2*5 + 3 = 113) or a(5)(2)[3].

◆ operator()() [4/6]

template<typename T >
const Array< T > hexed::Array< T >::operator() ( Int i) const
inline

Creates an array which is a view of the ith "row" of this.

Resulting array will have 1 less order() and shape equal to the shape of this but with the first element removed. You can think of it as equivalent to the operator [] of multidimensional builtin arrays or NumPy arrays. For example, if you have an order 3 array a with shape {10, 4, 5}, you can access the element at (5, 2, 3) with either a[113] (5*4*5 + 2*5 + 3 = 113) or a(5)(2)[3].

◆ operator()() [5/6]

template<typename T >
Array hexed::Array< T >::operator() ( Int start,
Int stop )
inline

Creates an array which is a view of rows [start, stop) of this.

As indicated by the interval notation, includes start but not stop. If stop is less than start or not less than size()[0], this results in an array with 0 as the first entry of its shape (and consequently size 0). This will not result in an exception nor undefined behavior, unless of course you attempt to access data from this empty array. Equivalent to array[start:stop] for NumPy arrays. The resulting array will have the same order as this. The first entry of shape() will be stop - start and the rest will be the same as this (granted the above caveat about empty results).

◆ operator()() [6/6]

template<typename T >
const Array hexed::Array< T >::operator() ( Int start,
Int stop ) const
inline

Creates an array which is a view of rows [start, stop) of this.

As indicated by the interval notation, includes start but not stop. If stop is less than start or not less than size()[0], this results in an array with 0 as the first entry of its shape (and consequently size 0). This will not result in an exception nor undefined behavior, unless of course you attempt to access data from this empty array. Equivalent to array[start:stop] for NumPy arrays. The resulting array will have the same order as this. The first entry of shape() will be stop - start and the rest will be the same as this (granted the above caveat about empty results).

◆ operator=()

template<typename T >
template<typename U >
Array< T > & hexed::Array< T >::operator= ( const Array< U > & other)
inline

Assigns the values in other to this.

other and this must have the same shape. Not allocations are performed and no new references are created. You are simply assigning values to existing data.

◆ operator[]() [1/2]

template<typename T >
T & hexed::Array< T >::operator[] ( Int i)
inline

Accesses elements by flat indexing.

Equivalent to data()[i], give or take bounds checking

◆ operator[]() [2/2]

template<typename T >
const T & hexed::Array< T >::operator[] ( Int i) const
inline

Accesses elements by flat indexing.

Equivalent to data()[i], give or take bounds checking

◆ order()

template<typename T >
Int hexed::Array< T >::order ( ) const
inline

Returns the number of dimensions of the Array.

If you think of the array as a tensor, then this is the order of the tensor.

◆ reshaped() [1/2]

template<typename T >
Array hexed::Array< T >::reshaped ( std::vector< Int > new_shape)
inline

Returns an array referencing the same data as this but with a different shape.

The new size must be less than or equal to the old size, or else behavior is undefined. If any entries of new_shape are hexed::same, then they will be converted to the entry of the current shape at the same index. E.g., if shape() is {2, 3, 4} and you call reshape({1, same, 4}), the resulting shape will be {1, 3, 4}. Of course, the index of any same arguments must be less than order(). If exactly one of the entries of new_shape is hexed::whatever, it will be converted to whatever value is necessary to keep the size the same. Making more than 1 entry hexed::whatever is not allowed. Note that reshaping maintains the underlying (row-major) storage order of the values (unlike Eigen's [conservativeResize] (https://eigen.tuxfamily.org/dox/classEigen_1_1PlainObjectBase.html#a712c25be1652e5a64a00f28c8ed11462)), so it can't generally be used to select a block of an Array. It is more useful for adding or removing dimensions. E.g., array.reshaped({hexed::whatever}) flattens array.

◆ reshaped() [2/2]

template<typename T >
const Array hexed::Array< T >::reshaped ( std::vector< Int > new_shape) const
inline

Returns an array referencing the same data as this but with a different shape.

The new size must be less than or equal to the old size, or else behavior is undefined. If any entries of new_shape are hexed::same, then they will be converted to the entry of the current shape at the same index. E.g., if shape() is {2, 3, 4} and you call reshape({1, same, 4}), the resulting shape will be {1, 3, 4}. Of course, the index of any same arguments must be less than order(). If exactly one of the entries of new_shape is hexed::whatever, it will be converted to whatever value is necessary to keep the size the same. Making more than 1 entry hexed::whatever is not allowed. Note that reshaping maintains the underlying (row-major) storage order of the values (unlike Eigen's [conservativeResize] (https://eigen.tuxfamily.org/dox/classEigen_1_1PlainObjectBase.html#a712c25be1652e5a64a00f28c8ed11462)), so it can't generally be used to select a block of an Array. It is more useful for adding or removing dimensions. E.g., array.reshaped({hexed::whatever}) flattens array.

◆ same_shape()

template<typename T >
bool hexed::Array< T >::same_shape ( const Array< T > & other)
inline

true iff this and other have the same shape().

It's okay to call this on arrays of different order(); naturally it will return false.

◆ size()

template<typename T >
Int hexed::Array< T >::size ( ) const
inline

Returns the total size of the array.

This is the number of values you can access with the [] operator, or equivalently the product of the entries of shape().

◆ stride()

template<typename T >
Int hexed::Array< T >::stride ( Int i_dim) const
inline

The stride for indexing along demension i_dim.

E.g.,

  • arr(1).data() == arr.data() + arr.stride(0)
  • arr(0)(1).data() == arr.data() + arr.stride(1)

The documentation for this class was generated from the following file: