Multivectors and multiexpressions

The vex::multivector<T,N> class allows to store several equally sized device vectors and perform computations on each component in sync. Each operation is delegated to the underlying vectors, but usually results in the launch of a single fused kernel. Expressions may include values of std::array<T,N> where N is equal to the number of multivector components, or appropriately sized tuples. Each component gets the corresponding element of either the array or the tuple when the expression is applied. Similarly, vex::multivector::operator[]() or reduction of a multivector returns an instance of std::array<T,N>. vex::multivector::operator()() allows to access individual components of a multivector.

Some examples:

VEX_FUNCTION(bool, between, (double, a)(double, b)(double, c),
    return a <= b && b <= c;
    );

vex::Reductor<double, vex::SUM> sum(ctx);
vex::SpMat<double> A(ctx, ... );
std::array<double, 2> v = {6.0, 7.0};

vex::multivector<double, 2> X(ctx, N), Y(ctx, N);

// ...

X = sin(v * Y + 1);             // X(k) = sin(v[k] * Y(k) + 1);
v = sum( between(0, X, Y) );    // v[k] = sum( between( 0, X(k), Y(k) ) );
X = A * Y;                      // X(k) = A * Y(k);

Some operations can not be expressed with simple multivector arithmetic. For example, an operation of two dimensional rotation mixes components in the right hand side expressions:

\[\begin{split}y_0 = x_0 \cos(\alpha) - x_1 \sin(\alpha),\\ y_1 = x_0 \sin(\alpha) + x_1 \cos(\alpha).\end{split}\]

This may in principle be implemented as:

double alpha;
vex::multivector<double, 2> X(ctx, N), Y(ctx, N);

Y(0) = X(0) * cos(alpha) - X(1) * sin(alpha);
Y(1) = X(0) * sin(alpha) + X(1) * cos(alpha);

But this would result in two kernel launches instead of single fused launch. VexCL allows one to assign a tuple of expressions to a multivector, which will lead to the launch of a single fused kernel:

Y = std::make_tuple(
    X(0) * cos(alpha) - X(1) * sin(alpha),
    X(0) * sin(alpha) + X(1) * cos(alpha) );

vex::tie() function even allows to get rid of multivectors completely and fuse several vector expressions into a single kernel. We can rewrite the above examples with just vex::vector<double> instances:

vex::vector<double> x0(ctx, N), x1(ctx,N), y0(ctx, N), y1(ctx, N);

vex::tie(y0, y1) = std::make_tuple(
    x0 * cos(alpha) - x1 * sin(alpha),
    x0 * sin(alpha) + x1 * cos(alpha) );
template<typename T, size_t N>
class vex::multivector : public vex::multivector_expression<Expr>

Container for several equally sized instances of vex::vector<T>.

Public Functions

inline multivector(const std::vector<backend::command_queue> &queue, const std::vector<T> &host, backend::mem_flags flags = backend::MEM_READ_WRITE)

Constructor.

The host vector data is divided equally between the created multivector components. Each component gets continuous chunk of the source vector.

inline multivector(const std::vector<backend::command_queue> &queue, size_t size, const T *host = 0, backend::mem_flags flags = backend::MEM_READ_WRITE)

Constructor.

If host pointer is not NULL, it is copied to the underlying vector components of the multivector. Each component gets continuous chunk of the source vector.

inline multivector(size_t size)

Constructor.

Uses the most recently created VexCL context.

inline multivector(const multivector &mv)

Copy constructor.

inline multivector(multivector &&mv) noexcept

Move constructor.

inline void resize(const std::vector<backend::command_queue> &queue, size_t size)

Resizes the multivector.

This is equivalent to reconstructing the vector with the given parameters. Any data contained in the resized vector will be lost as a result.

inline void resize(size_t size)

Resizes the multivector.

Uses the most recently created VexCL context. This is equivalent to reconstructing the vector with the given parameters. Any data contained in the resized vector will be lost as a result.

inline void clear()

Fills the multivector with zeros.

inline size_t size() const

Returns size of the multivector (equals size of individual components).

inline const vex::vector<T> &operator()(size_t i) const

Returns i-th multivector component.

inline vex::vector<T> &operator()(size_t i)

Returns i-th multivector component.

inline const_iterator begin() const

Returns const iterator to the first element of the multivector.

inline iterator begin()

Returns const iterator to the first element of the multivector.

inline const_iterator end() const

Returns const iterator referring to the past-the-end element in the multivector.

inline iterator end()

Returns iterator referring to the past-the-end element in the multivector.

inline const_element operator[](size_t i) const

Returns i-th elements of all components packed in a std::array<T,N>.

inline element operator[](size_t i)

Assigns values from std::array<T,N> to i-th elements of all components.

inline const std::vector<backend::command_queue> &queue_list() const

Returns reference to the multivector’s queue list.

inline const multivector &operator=(const multivector &mv)

Assignment operator.

template<class Expr>
inline auto operator=(const Expr &expr) -> typename std::enable_if<boost::proto::matches<typename boost::proto::result_of::as_expr<Expr>::type, multivector_expr_grammar>::value || is_tuple<Expr>::value, const multivector&>::type

Assignment operator

template<class Expr>
inline auto operator+=(const Expr &expr) -> typename std::enable_if<boost::proto::matches<typename boost::proto::result_of::as_expr<Expr>::type, multivector_expr_grammar>::value || is_tuple<Expr>::value, const multivector&>::type

Assignment operator

template<class Expr>
inline auto operator-=(const Expr &expr) -> typename std::enable_if<boost::proto::matches<typename boost::proto::result_of::as_expr<Expr>::type, multivector_expr_grammar>::value || is_tuple<Expr>::value, const multivector&>::type

Assignment operator

template<class Expr>
inline auto operator*=(const Expr &expr) -> typename std::enable_if<boost::proto::matches<typename boost::proto::result_of::as_expr<Expr>::type, multivector_expr_grammar>::value || is_tuple<Expr>::value, const multivector&>::type

Assignment operator

template<class Expr>
inline auto operator/=(const Expr &expr) -> typename std::enable_if<boost::proto::matches<typename boost::proto::result_of::as_expr<Expr>::type, multivector_expr_grammar>::value || is_tuple<Expr>::value, const multivector&>::type

Assignment operator

template<class Expr>
inline auto operator%=(const Expr &expr) -> typename std::enable_if<boost::proto::matches<typename boost::proto::result_of::as_expr<Expr>::type, multivector_expr_grammar>::value || is_tuple<Expr>::value, const multivector&>::type

Assignment operator

template<class Expr>
inline auto operator&=(const Expr &expr) -> typename std::enable_if<boost::proto::matches<typename boost::proto::result_of::as_expr<Expr>::type, multivector_expr_grammar>::value || is_tuple<Expr>::value, const multivector&>::type

Assignment operator

template<class Expr>
inline auto operator|=(const Expr &expr) -> typename std::enable_if<boost::proto::matches<typename boost::proto::result_of::as_expr<Expr>::type, multivector_expr_grammar>::value || is_tuple<Expr>::value, const multivector&>::type

Assignment operator

template<class Expr>
inline auto operator^=(const Expr &expr) -> typename std::enable_if<boost::proto::matches<typename boost::proto::result_of::as_expr<Expr>::type, multivector_expr_grammar>::value || is_tuple<Expr>::value, const multivector&>::type

Assignment operator

template<class Expr>
inline auto operator<<=(const Expr &expr) -> typename std::enable_if<boost::proto::matches<typename boost::proto::result_of::as_expr<Expr>::type, multivector_expr_grammar>::value || is_tuple<Expr>::value, const multivector&>::type

Assignment operator

template<class Expr>
inline auto operator>>=(const Expr &expr) -> typename std::enable_if<boost::proto::matches<typename boost::proto::result_of::as_expr<Expr>::type, multivector_expr_grammar>::value || is_tuple<Expr>::value, const multivector&>::type

Assignment operator

class const_element
class element
template<class V, class E>
class iterator_type : public boost::iterator_facade<iterator_type<V, E>, sub_value_type, std::random_access_iterator_tag, E>
template<class ...Expr>
auto vex::tie(const Expr&... expr) -> expression_tuple<std::tuple<const Expr&...>>

Ties several vector expressions into a writeable tuple.

The following example results in a single kernel:

vex::vector<double> x(ctx, 1024);
vex::vector<double> y(ctx, 1024);

vex::tie(x,y) = std::make_tuple( x + y, y - x );

This is functionally equivalent to the following code, but does not use temporary vectors and is more efficient:

tmp_x = x + y;
tmp_y = y - x;
x = tmp_x;
y = tmp_y;