Advertisement
Guest User

Untitled

a guest
Jun 17th, 2019
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.67 KB | None | 0 0
  1. #include <boost/yap/expression.hpp>
  2.  
  3. #include <algorithm>
  4. #include <cassert>
  5. #include <iostream>
  6. #include <vector>
  7.  
  8. // TAKEN FROM BOOST.YAP EXAMPLES, BUT MODIFIED BY CODER3101
  9.  
  10. /*
  11. * Every YAP expression be it any type must meet this concept.
  12. * - It must have a static const member named kind
  13. * - It must have a public member named elements
  14. */
  15. template <boost::yap::expr_kind Kind, typename Tuple>
  16. struct lazy_vector_expr;
  17.  
  18.  
  19. /*
  20. * This is a transform that extracts ith value from terminal node of YAP
  21. */
  22. struct take_nth
  23. {
  24. boost::yap::terminal<lazy_vector_expr, double>
  25. operator() (boost::yap::terminal<lazy_vector_expr, std::vector<double>> const & expr);
  26.  
  27. std::size_t n;
  28. };
  29.  
  30. /*
  31. * We finally create the lazy_vector_expr class following the
  32. * YAP concepts as mentioned above.
  33. *
  34. * Few Important things to mention :
  35. * - kind is a enum of boost::yap::expr_kind. This value denotes
  36. * the operand that has been applied. So if this is expr_kind::plus.
  37. * It means that this node in AST represents a plus operation.
  38. *
  39. * - Tuple is a boost::hana<..> type. YAP uses hana because it provides
  40. * compile time tuple, necessary to build expression templates. This tuple
  41. * holds the operands to which the expr_kind::kind operator will be applied.
  42. *
  43. * * If kind = expr_kind::terminal, this means that Tuple elements
  44. * only has one value that is terminal node of AST. Since boost.yap has some
  45. * limitations, if expr_kind::terminal it is required that elements must not have
  46. * a value that can be converted to any YAP expression concept. It is due to this reason
  47. * that we cannot follow CRTP pattern, we want terminal to have some value that cannot be
  48. * converted to YAP expression. In this case we use std::vector<>, which is enough to represent
  49. * the complete lazy_vector.
  50. */
  51.  
  52. template <boost::yap::expr_kind Kind, typename Tuple>
  53. struct lazy_vector_expr
  54. {
  55. static const boost::yap::expr_kind kind = Kind;
  56.  
  57. Tuple elements;
  58.  
  59. // Note that this does not return an expression; it is greedily evaluated.
  60. auto operator[] (std::size_t n) const;
  61. };
  62.  
  63. // Some Operator Overloads.
  64. BOOST_YAP_USER_BINARY_OPERATOR(plus, lazy_vector_expr, lazy_vector_expr)
  65. BOOST_YAP_USER_BINARY_OPERATOR(minus, lazy_vector_expr, lazy_vector_expr)
  66.  
  67. /*
  68. * This runs the transform and evaluates the terminal expression returned from
  69. * the transform.
  70. */
  71. template <boost::yap::expr_kind Kind, typename Tuple>
  72. auto lazy_vector_expr<Kind, Tuple>::operator[] (std::size_t n) const
  73. { return boost::yap::evaluate(boost::yap::transform(*this, take_nth{n})); }
  74.  
  75. /**
  76. * Defines the transform to extract the ith element from terminal node
  77. * This then wraps it into a terminal expression type for furthur lazy evaluation
  78. * if desired.
  79. */
  80. boost::yap::terminal<lazy_vector_expr, double>
  81. take_nth::operator() (boost::yap::terminal<lazy_vector_expr, std::vector<double>> const & expr)
  82. {
  83. double x = boost::yap::value(expr)[n];
  84. return boost::yap::make_terminal<lazy_vector_expr, double>(std::move(x));
  85. }
  86.  
  87. /*
  88. * This is most Important section. Here we create the lazy_vector class.
  89. * Because we want that this template class to be trivially convertible to YAP expression terminal.
  90. * We inherit this class from a terminal type of lazy_vector_expr.
  91. *
  92. * Since, lazy_vector now is trivially convertible to an YAP expression, we need to put something else
  93. * into the terminal node of lazy_vector_expr. In this case we have choosen to put
  94. * std::vector<double> into the terminal.
  95. * The thing that we want to put in the terminal must meet following :
  96. * - It must have enough information so that expression values can be evaluated greedly.
  97. * - It must have enough information so that we can infer the dimension or shape of expression greedly.
  98. * In this case since it was a vector, std::vector<> values and .size() are enough to
  99. * satisfy the needs. In case of matrix or tensor, we may need to put more than one thing
  100. * say dimension/extent and data. While we can surely put multiple things into terminal,
  101. * it is usually good to wrap all those things into one single class like matrix/tensor_core.
  102. * We then put that core into the terminal. Now the Question how do we access the contents of
  103. * what we have placed in the terminal? See the in-class comments.
  104. */
  105. struct lazy_vector : public lazy_vector_expr<
  106. boost::yap::expr_kind::terminal,
  107. boost::hana::tuple<std::vector<double>>>
  108. {
  109. lazy_vector () {}
  110.  
  111. explicit lazy_vector (std::vector<double> && vec)
  112. {
  113. /*
  114. * Since this elements is a hana::tuple of std::vector<double>,
  115. * we can assign it a new value at construction. We cannot do it at
  116. * initializer list however because elements does not belong to this class.
  117. */
  118. elements = boost::hana::tuple<std::vector<double>>(std::move(vec));
  119. }
  120.  
  121. auto get_data() const {
  122. /*
  123. * To access the elements, we use hana literals and at 0th index of elements
  124. * lies the std::vector we have stored.
  125. */
  126. using namespace boost::hana::literals;
  127. return this->elements[0_c].data();
  128. }
  129. auto get_dimension() const {
  130. using namespace boost::hana::literals;
  131. return this->elements[0_c].size();
  132. }
  133. };
  134. /**
  135. * However there is a Issue with the this design.
  136. * elements is a public member and we inherit it publicly. So anyone can access the std::vector
  137. * We cannot make elements private because it will violate the YAP concepts.
  138. *
  139. * A possible solution as implemented in the tensor is that, we can make all those tensor_core datamembers
  140. * private and declare tensor and tensor_expression a friend. So, its private memebers are only available in
  141. * those classes.
  142. */
  143.  
  144. /** This is the exact short implementation of tensor_expression of new ublas::tensor.*/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement