-
Notifications
You must be signed in to change notification settings - Fork 5
YAP Expression Examples
The new expression templates works just like the old uBLAS expression templates. However the new expression templates are much easier and gives a lot of freedom to end-user (you) and to us (developers). It is therefor important to point out all the capabilities and new interfaces that the new expression templates have to offer. It is highly recommended to read What's new in new expression templates before reading this wiki. This wiki will focus more on how to exploit the new features rather than talking about the new features.
tensor_expression
is the structure in namespace boost::numeric::ublas::detail
that is returned from all the operations that are performed on the tensor types or any operation that involves any tensor-type.
You can capture your expression like this:
auto expr = 3*tensor1 + 5*tensor2;
In the following sections, we discuss some Freedoms of the new Expression template.
All the tensor expressions follow Boost.YAP Expression concept. Unlike previous expression template, the new expression templates can be copied or moved. Allowing you to treat an expression as a regular object.
auto expr1 = tensor1 + tensor2;
auto expr2 = expr1;
tensor<int> val(expr1);
tensor<int> val2(expr2);
The tensor variables are captured by references and hence a new reference is made not and not the internal variable are copied. However if the an operand is an r-value reference the the copy of that operand is made into the new expression.
Because rvalue operands of an expression are copied. You should not create copies of expression involving rvalue operands where copying can be performance overhead.
When it comes to scalars, you can perform all four fundamental operations with tensors. However we have absolutely no limit or what so ever on the scalar type that you can use with tensors as long as there is an operator overload for the operation.
struct Zero_Like{};
auto operator*(int, Zero_Like&);
auto t = tensor<int>{shape{5,5}, 0};
auto expr = t * Zero_Like{};
decltype(t) t2 = expr;
In other words you can take anything as scalar as long as you provide an operator overload for the operation. Like you can even take an lambda or equivalent as an scalar type.
Following the trend of Freedom for Scalar, We provide freedom for internal data-types of tensor
or matrix
or vectors
. The last expression template did not allowed user to mix-match the data-types. This is no longer true with the new expression templates: You can mix an match things as long as the operations are well defined. So,
auto td = tensor<int>{shape{5,5},0};
auto tf = tensor<float>{shape{5,5}, 1.2f};
auto expr = td + tf;
tensor<int> a = expr; // Fills a with 1
tensor<float> b = expr; // Fills b with 1.2
All such expressions follow the exact same standard C++ behaviour for type promotion and implicit casting. We also provide 3 casting operator for tensors. They are eager casting operators and eagerly cast tensor elements and return a new tensor. They are :
boost::numeric::ublas::static_tensor_cast<>
boost::numeric::ublas::dynamic_tensor_cast<>
boost::numeric::ublas::reinterpret_tensor_cast<>
auto td = tensor<int>{shape{5,5}, 5};
auto tf = static_tensor_cast<float>(td);
static_assert(std::is_same_v<typename tf::value_type, float>);
try{
auto res = dynamic_tensor_cast<float>(td);
}catch(std::bad_cast& e){
// Indeed a bad cast
}
auto tptrs = reinterpret_tensor_cast<char*>(td); // danger here :)
They behave same as standard C++ casting operators as it is just a wrapper for tensor type casting.
The tensor resulted from the cast will have
tensor::array_type
asstd::vector
always.
Do not pass an expression to for casting. It is an compile time error. A tensor expression casting operator is in the way.
A Complete set of operator overloads are as follow:
template <class T, class F, class A>
decltype(auto) operator-(tensor<T,F,A>); // unary minus
template <class T, class F, class A>
decltype(auto) operator+(tensor<T,F,A>); // unary plus
// Tensor to anything else overload
template <class T, class F, class A, typename other>
decltype(auto) operator+(tensor<T,F,A>, other); // binary plus
template <class T, class F, class A, typename other>
decltype(auto) operator+(other, tensor<T,F,A>); // binary plus
template <class T, class F, class A, typename other>
decltype(auto) operator-(tensor<T,F,A>, other); // binary minus
template <class T, class F, class A, typename other>
decltype(auto) operator-(other, tensor<T,F,A>); // binary minus
template <class T, class F, class A, typename other>
decltype(auto) operator*(tensor<T,F,A>, other); // binary multiplies
template <class T, class F, class A, typename other>
decltype(auto) operator*(other, tensor<T,F,A>); // binary multiplies
template <class T, class F, class A, typename other>
decltype(auto) operator/(tensor<T,F,A>, other); // binary divides
template <class T, class F, class A, typename other>
decltype(auto) operator/(other, tensor<T,F,A>); // binary divides
template <class T, class F, class A, typename other>
decltype(auto) operator>(tensor<T,F,A>, other); // binary greater
template <class T, class F, class A, typename other>
decltype(auto) operator>(other, tensor<T,F,A>); // binary greater
template <class T, class F, class A, typename other>
decltype(auto) operator<(tensor<T,F,A>, other); // binary less
template <class T, class F, class A, typename other>
decltype(auto) operator<(other, tensor<T,F,A>); // binary less
template <class T, class F, class A, typename other>
decltype(auto) operator==(tensor<T,F,A>, other); // binary equal
template <class T, class F, class A, typename other>
decltype(auto) operator==(other, tensor<T,F,A>); // binary equal
template <class T, class F, class A, typename other>
decltype(auto) operator!=(tensor<T,F,A>, other); // binary not equal
template <class T, class F, class A, typename other>
decltype(auto) operator!=(other, tensor<T,F,A>); // binary not equal
template <class T, class F, class A, typename other>
decltype(auto) operator>=(tensor<T,F,A>, other); // binary greater equal
template <class T, class F, class A, typename other>
decltype(auto) operator>=(other, tensor<T,F,A>); // binary greater equal
template <class T, class F, class A, typename other>
decltype(auto) operator<=(tensor<T,F,A>, other); // binary less equal
template <class T, class F, class A, typename other>
decltype(auto) operator<=(other, tensor<T,F,A>); // binary less equal
// Tensor Expression to anything else overload
template <boost::yap::expr_kind K, typename Tuple>
decltype(auto) operator-(tensor_expression<K,Tuple>); // unary negate expr
template <boost::yap::expr_kind K, typename Tuple>
decltype(auto) operator+(tensor_expression<K,Tuple>); // unary plus expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator+(tensor_expression<K,Tuple>, other); // binary plus expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator+(other, tensor_expression<K,Tuple>); // binary plus expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator-(tensor_expression<K,Tuple>, other); // binary minus expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator-(other, tensor_expression<K,Tuple>); // binary minus expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator*(tensor_expression<K,Tuple>, other); // binary multiplies expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator*(other, tensor_expression<K,Tuple>); // binary multiplies expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator/(tensor_expression<K,Tuple>, other); // binary divides expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator/(other, tensor_expression<K,Tuple>); // binary divides expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator<(tensor_expression<K,Tuple>, other); // binary less expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator<(other, tensor_expression<K,Tuple>); // binary less expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator>(tensor_expression<K,Tuple>, other); // binary greater expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator>(other, tensor_expression<K,Tuple>); // binary greater expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator>=(tensor_expression<K,Tuple>, other); // binary greater equal expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator>=(other, tensor_expression<K,Tuple>); // binary greater equal expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator<=(tensor_expression<K,Tuple>, other); // binary less equal expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator<=(other, tensor_expression<K,Tuple>); // binary less equal expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator==(tensor_expression<K,Tuple>, other); // binary equal expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator==(other, tensor_expression<K,Tuple>); // binary equal expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator!=(tensor_expression<K,Tuple>, other); // binary not equal expr
template <boost::yap::expr_kind K, typename Tuple, typename other>
decltype(auto) operator!=(other, tensor_expression<K,Tuple>); // binary not equal expr
// Tensor Assigmenent Overload
template <class T, class F, class A, typename Expr>
decltype(auto) operator+=(tensor<T,F,A>, Expr); // add assign
template <class T, class F, class A, typename Expr>
decltype(auto) operator-=(tensor<T,F,A>, Expr); // subtract assign
template <class T, class F, class A, typename Expr>
decltype(auto) operator*=(tensor<T,F,A>, Expr); // multiply assign
template <class T, class F, class A, typename Expr>
decltype(auto) operator/=(tensor<T,F,A>, Expr); // divide assign
The return type of all of the above overload is a tensor expression
Assignment of an expression to any tensor type or conversion of an expression to boolean (in case it involves logical operators) causes the lazy evaluation of the expression.
To be continued...
We both would like to thank our mentor Cem for his constant support and help in achieving our goals. We always find him helpful and he was always easy to reach for help or discussion regarding the work. We would also like to thank Google for the Google Summer of Code Programme, without which all these wouldn't be possible. Lastly, we express our gratitude to our parents for helping and providing us with all the indirect or direct needs for carrying out our work nicely in our homes.
- Home
- Project Proposal
- Milestones and Tasks
- Implementation
- Documentation
- Discussions
- Examples
- Experimental features
- Project Proposal
- Milestones and Tasks
- Implementation
- Documentation
- Discussions
- Example Code