Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <boost/yap/expression.hpp>
- #include <algorithm>
- #include <cassert>
- #include <iostream>
- #include <vector>
- // TAKEN FROM BOOST.YAP EXAMPLES, BUT MODIFIED BY CODER3101
- /*
- * Every YAP expression be it any type must meet this concept.
- * - It must have a static const member named kind
- * - It must have a public member named elements
- */
- template <boost::yap::expr_kind Kind, typename Tuple>
- struct lazy_vector_expr;
- /*
- * This is a transform that extracts ith value from terminal node of YAP
- */
- struct take_nth
- {
- boost::yap::terminal<lazy_vector_expr, double>
- operator() (boost::yap::terminal<lazy_vector_expr, std::vector<double>> const & expr);
- std::size_t n;
- };
- /*
- * We finally create the lazy_vector_expr class following the
- * YAP concepts as mentioned above.
- *
- * Few Important things to mention :
- * - kind is a enum of boost::yap::expr_kind. This value denotes
- * the operand that has been applied. So if this is expr_kind::plus.
- * It means that this node in AST represents a plus operation.
- *
- * - Tuple is a boost::hana<..> type. YAP uses hana because it provides
- * compile time tuple, necessary to build expression templates. This tuple
- * holds the operands to which the expr_kind::kind operator will be applied.
- *
- * * If kind = expr_kind::terminal, this means that Tuple elements
- * only has one value that is terminal node of AST. Since boost.yap has some
- * limitations, if expr_kind::terminal it is required that elements must not have
- * a value that can be converted to any YAP expression concept. It is due to this reason
- * that we cannot follow CRTP pattern, we want terminal to have some value that cannot be
- * converted to YAP expression. In this case we use std::vector<>, which is enough to represent
- * the complete lazy_vector.
- */
- template <boost::yap::expr_kind Kind, typename Tuple>
- struct lazy_vector_expr
- {
- static const boost::yap::expr_kind kind = Kind;
- Tuple elements;
- // Note that this does not return an expression; it is greedily evaluated.
- auto operator[] (std::size_t n) const;
- };
- // Some Operator Overloads.
- BOOST_YAP_USER_BINARY_OPERATOR(plus, lazy_vector_expr, lazy_vector_expr)
- BOOST_YAP_USER_BINARY_OPERATOR(minus, lazy_vector_expr, lazy_vector_expr)
- /*
- * This runs the transform and evaluates the terminal expression returned from
- * the transform.
- */
- template <boost::yap::expr_kind Kind, typename Tuple>
- auto lazy_vector_expr<Kind, Tuple>::operator[] (std::size_t n) const
- { return boost::yap::evaluate(boost::yap::transform(*this, take_nth{n})); }
- /**
- * Defines the transform to extract the ith element from terminal node
- * This then wraps it into a terminal expression type for furthur lazy evaluation
- * if desired.
- */
- boost::yap::terminal<lazy_vector_expr, double>
- take_nth::operator() (boost::yap::terminal<lazy_vector_expr, std::vector<double>> const & expr)
- {
- double x = boost::yap::value(expr)[n];
- return boost::yap::make_terminal<lazy_vector_expr, double>(std::move(x));
- }
- /*
- * This is most Important section. Here we create the lazy_vector class.
- * Because we want that this template class to be trivially convertible to YAP expression terminal.
- * We inherit this class from a terminal type of lazy_vector_expr.
- *
- * Since, lazy_vector now is trivially convertible to an YAP expression, we need to put something else
- * into the terminal node of lazy_vector_expr. In this case we have choosen to put
- * std::vector<double> into the terminal.
- * The thing that we want to put in the terminal must meet following :
- * - It must have enough information so that expression values can be evaluated greedly.
- * - It must have enough information so that we can infer the dimension or shape of expression greedly.
- * In this case since it was a vector, std::vector<> values and .size() are enough to
- * satisfy the needs. In case of matrix or tensor, we may need to put more than one thing
- * say dimension/extent and data. While we can surely put multiple things into terminal,
- * it is usually good to wrap all those things into one single class like matrix/tensor_core.
- * We then put that core into the terminal. Now the Question how do we access the contents of
- * what we have placed in the terminal? See the in-class comments.
- */
- struct lazy_vector : public lazy_vector_expr<
- boost::yap::expr_kind::terminal,
- boost::hana::tuple<std::vector<double>>>
- {
- lazy_vector () {}
- explicit lazy_vector (std::vector<double> && vec)
- {
- /*
- * Since this elements is a hana::tuple of std::vector<double>,
- * we can assign it a new value at construction. We cannot do it at
- * initializer list however because elements does not belong to this class.
- */
- elements = boost::hana::tuple<std::vector<double>>(std::move(vec));
- }
- auto get_data() const {
- /*
- * To access the elements, we use hana literals and at 0th index of elements
- * lies the std::vector we have stored.
- */
- using namespace boost::hana::literals;
- return this->elements[0_c].data();
- }
- auto get_dimension() const {
- using namespace boost::hana::literals;
- return this->elements[0_c].size();
- }
- };
- /**
- * However there is a Issue with the this design.
- * elements is a public member and we inherit it publicly. So anyone can access the std::vector
- * We cannot make elements private because it will violate the YAP concepts.
- *
- * A possible solution as implemented in the tensor is that, we can make all those tensor_core datamembers
- * private and declare tensor and tensor_expression a friend. So, its private memebers are only available in
- * those classes.
- */
- /** This is the exact short implementation of tensor_expression of new ublas::tensor.*/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement