array
C++ library for multi-dimensional arrays
Macros | Functions
ein_reduce.h File Reference

Optional helper for computing Einstein reductions on arrays. More...

#include "array/array.h"

Go to the source code of this file.

Macros

#define NDARRAY_MAKE_EIN_BINARY_HELPERS(name, op)
 
#define NDARRAY_MAKE_EIN_BINARY_OP(name, op, is_assign_)
 
#define NDARRAY_MAKE_EIN_BINARY_FN(name, fn)
 

Functions

template<class Type , class Op >
auto cast (const internal::ein_op_base< Op > &op)
 
template<class OpA , class OpB >
auto min (const internal::ein_op_base< OpA > &a, const internal::ein_op_base< OpB > &b)
 
template<class OpA , class OpB >
auto max (const internal::ein_op_base< OpA > &a, const internal::ein_op_base< OpB > &b)
 
template<size_t... Is, class Op , class = internal::enable_if_callable<Op, decltype(Is)...>>
auto ein (Op op)
 
template<size_t... Is, class T , class Shape , class Alloc , class = std::enable_if_t<sizeof...(Is) == Shape::rank()>>
auto ein (array< T, Shape, Alloc > &op)
 
template<size_t... Is, class T , class Shape , class Alloc , class = std::enable_if_t<sizeof...(Is) == Shape::rank()>>
auto ein (const array< T, Shape, Alloc > &op)
 
template<class T >
auto ein (T &scalar)
 
template<size_t I0, class T >
auto ein (T *x, size_t N)
 
template<size_t I0, class T , size_t N>
auto ein (T(&x)[N])
 
template<class Expr , class = internal::enable_if_ein_assign<Expr>>
NDARRAY_INLINE auto ein_reduce (const Expr &expr)
 
template<size_t... ResultIs, class Expr , class = internal::enable_if_ein_op<Expr>>
NDARRAY_UNIQUE auto make_ein_reduce_shape (const Expr &expr)
 
template<class T , size_t... ResultIs, class Expr , class Alloc = std::allocator<T>, class = internal::enable_if_ein_op<Expr>>
NDARRAY_INLINE auto make_ein_sum (const Expr &expr, const T &init=T(), const Alloc &alloc=Alloc())
 

Detailed Description

Optional helper for computing Einstein reductions on arrays.

Macro Definition Documentation

#define NDARRAY_MAKE_EIN_BINARY_HELPERS (   name,
  op 
)
Value:
template <class OpA, class OpB> \
auto make_##name(const OpA& a, const OpB& b) { \
return name<OpA, OpB>(a, b); \
}
#define NDARRAY_MAKE_EIN_BINARY_OP (   name,
  op,
  is_assign_ 
)
Value:
template <class OpA, class OpB> \
struct name : public ein_binary_op<OpA, OpB, name<OpA, OpB>> { \
using base = ein_binary_op<OpA, OpB, name>; \
name(const OpA& a, const OpB& b) : base(a, b) {} \
using is_assign = is_assign_; \
template <class Idx> \
NDARRAY_INLINE auto operator()(const Idx& i) const { \
return base::op_a(i) op base::op_b(i); \
} \
}; \
NDARRAY_MAKE_EIN_BINARY_HELPERS(name, op)
#define NDARRAY_MAKE_EIN_BINARY_FN (   name,
  fn 
)
Value:
template <class OpA, class OpB> \
struct name : public ein_binary_op<OpA, OpB, name<OpA, OpB>> { \
using base = ein_binary_op<OpA, OpB, name>; \
name(const OpA& a, const OpB& b) : base(a, b) {} \
template <class Idx> \
NDARRAY_INLINE auto operator()(const Idx& i) const { \
using internal::min; \
using internal::max; \
return fn(base::op_a(i), base::op_b(i)); \
} \
}; \
NDARRAY_MAKE_EIN_BINARY_HELPERS(name, op)

Function Documentation

auto nda::cast ( const internal::ein_op_base< Op > &  op)

Cast an Einstein summation operand to a different type Type. The cast is performed using static_cast<Type>.

auto nda::min ( const internal::ein_op_base< OpA > &  a,
const internal::ein_op_base< OpB > &  b 
)

The min or max of two Einstein summation operands.

auto nda::ein ( Op  op)

Operand for an Einstein summation, which is an array or other callable object, along with a set of dimension indices. ein<i, j, ...>(a) means the dimensions i, j, ... of the summation index are used to address a during Einstein summation. The number of dimensions must match the number of arguments of a. See ein_reduce() for more details.

auto nda::ein ( T &  scalar)

Define an Einstein summation operand for a scalar. The scalar is broadcasted as needed during the summation. Because this operand does not provide a shape, the dimensions of the sum must be inferred from other operands. See ein_reduce() for more details.

auto nda::ein ( T *  x,
size_t  N 
)

Define an Einstein summation operand for a pointer and size.

auto nda::ein ( T(&)  x[N])

Define an Einstein summation operand for a C array.

NDARRAY_INLINE auto nda::ein_reduce ( const Expr &  expr)

Compute an Einstein reduction. This function allows one to specify many kinds of array transformations and reductions using Einstein notation.

This function accepts an expression expr constructed using operators on ein<i, j, ...>(op) operands. These operands describe which dimensions of the reduction index should be used to address that operand. The rank of the reduction operation is inferred from the number of dimensions used in the expression. The reduction operation is executed in the order of the indices, with the lowest numbered dimension executed as the innermost loop.

If expr is a reduction operator, the result must be initialized to some useful value, typically the identity value for the reduction operator, e.g. 0 for +=. Not initializing the result allows successive ein_reduce operations to be applied to the same result.

This function does not optimize the associative order in which the operations are performed. It evaluates the expression for each element of the final result reduction. This can be efficient for expansion operations, but it may be inefficient for contractions. Contractions may need to be reassociated manually for efficient computation.

This function does not optimize the loop ordering within each operation. The goal of this function is to provide a low-overhead and expressive reduction that can be composed with other explicit loop transformations to achieve good performance. Various optimization strategies can be implemented by splitting loops appropriately and by controlling the order of the loops with the reduction indices.

Examples:

  • ein_reduce(ein<>(tr_A) += ein<i, i>(A)), the trace of A.
  • ein_reduce(ein<>(dot) += (ein<i>(x) + ein<i>(y)) * ein<i>(z)), the dot product (x + y)*z.
  • ein_reduce(ein<i, j>(AB) += ein<i, k>(A) * ein<k, j>(B)), the matrix product A*B
  • ein_reduce(ein<i>(Ax) += ein<i, j>(A) * ein<j>(x)), the matrix-vector product A*x
  • ein_reduce(ein<i>(diag_A) = ein<i, i>(A)), the diagonal of A.

where:

  • A, B, AB are matrices (rank 2 arrays)
  • x, y, z, Ax are vectors (rank 1 arrays)
  • tr_A, dot are scalar (rank 0 arrays)
  • i, j, k are unique constexpr integers.
NDARRAY_UNIQUE auto nda::make_ein_reduce_shape ( const Expr &  expr)

Infer the shape of the result of make_ein_reduce.

NDARRAY_INLINE auto nda::make_ein_sum ( const Expr &  expr,
const T &  init = T(),
const Alloc &  alloc = Alloc() 
)

Compute an Einstein summation using ein_reduce and return the result. The value_type of the result will be T, and the result shape will be inferred from the shape of the operands. The result is initialized to init prior to computing the summation. The Einstein summation indices for the result operand are ResultIs....

Examples:

  • trace_A = make_ein_sum<T>(ein<i, i>(A))
  • dot = make_ein_sum<T>((ein<i>(x) + ein<i>(y)) * ein<i>(z))
  • AB = make_ein_sum<T, i, j>(ein<i, k>(A) * ein<k, j>(B))
  • Ax = make_ein_sum<T, i>(ein<i, j>(A) * ein<1>(x))

where:

  • A, B are matrices (rank 2 arrays)
  • x, y, z are vectors (rank 1 arrays)
  • i, j, k are unique constexpr integers.

See ein_reduce() for more details.