Expression Templates Library (ETL)
binary_expr.hpp
1 //=======================================================================
2 // Copyright (c) 2014-2023 Baptiste Wicht
3 // Distributed under the terms of the MIT License.
4 // (See accompanying file LICENSE or copy at
5 // http://opensource.org/licenses/MIT)
6 //=======================================================================
7 
8 #pragma once
9 
10 namespace etl {
11 
17 template <typename T, expr_or_scalar<T> LeftExpr, typename BinaryOp, expr_or_scalar<T> RightExpr>
18 struct binary_expr final : dim_testable<binary_expr<T, LeftExpr, BinaryOp, RightExpr>>,
19  value_testable<binary_expr<T, LeftExpr, BinaryOp, RightExpr>>,
20  iterable<binary_expr<T, LeftExpr, BinaryOp, RightExpr>> {
21 private:
23 
24  LeftExpr lhs;
25  RightExpr rhs;
26 
27  friend struct etl_traits<binary_expr>;
28  friend struct optimizer<binary_expr>;
29  friend struct optimizable<binary_expr>;
30  friend struct transformer<binary_expr>;
31 
32 public:
33  using value_type = T;
34  using memory_type = void;
35  using const_memory_type = void;
38  using operator_type = BinaryOp;
39 
40  using left_type = std::decay_t<LeftExpr>;
41  using right_type = std::decay_t<RightExpr>;
42 
46  template <typename V = default_vec>
47  using vec_type = typename V::template vec_type<T>;
48 
49  //Cannot be constructed with no args
50  binary_expr() = delete;
51 
57  binary_expr(LeftExpr l, RightExpr r) : lhs(std::forward<LeftExpr>(l)), rhs(std::forward<RightExpr>(r)) {
58  //Nothing else to init
59  }
60 
65  binary_expr(const binary_expr& e) = default;
66 
71  binary_expr(binary_expr&& e) noexcept = default;
72 
73  //Expressions are invariant
74  binary_expr& operator=(const binary_expr& e) = delete;
75  binary_expr& operator=(binary_expr&& e) = delete;
76 
82  template <typename E>
83  bool alias(const E& other) const noexcept {
84  return lhs.alias(other) || rhs.alias(other);
85  }
86 
87  //Apply the expression
88 
94  value_type operator[](size_t i) const {
95  return BinaryOp::apply(lhs[i], rhs[i]);
96  }
97 
104  value_type read_flat(size_t i) const {
105  return BinaryOp::apply(lhs.read_flat(i), rhs.read_flat(i));
106  }
107 
114  template <typename V = default_vec>
115  ETL_STRONG_INLINE(vec_type<V>)
116  load(size_t i) const {
117  return BinaryOp::template load<V>(lhs.template load<V>(i), rhs.template load<V>(i));
118  }
119 
126  template <typename V = default_vec>
127  ETL_STRONG_INLINE(vec_type<V>)
128  loadu(size_t i) const {
129  return BinaryOp::template load<V>(lhs.template loadu<V>(i), rhs.template loadu<V>(i));
130  }
131 
137  template <size_c... S>
138  value_type operator()(S... args) const requires(sizeof...(S) == safe_dimensions<this_type>) {
139  return BinaryOp::apply(lhs(args...), rhs(args...));
140  }
141 
147  auto operator()(size_t i) requires sub_capable<this_type> {
148  return sub(*this, i);
149  }
150 
156  auto operator()(size_t i) const requires sub_capable<this_type> {
157  return sub(*this, i);
158  }
159 
166  auto slice(size_t first, size_t last) noexcept {
167  return etl::slice(*this, first, last);
168  }
169 
176  auto slice(size_t first, size_t last) const noexcept {
177  return etl::slice(*this, first, last);
178  }
179 
184  template <typename Y>
185  decltype(auto) gpu_compute_hint(Y& y) const {
186  return BinaryOp::gpu_compute_hint(lhs, rhs, y);
187  }
188 
193  template <typename Y>
194  decltype(auto) gpu_compute(Y& y) const {
195  return BinaryOp::gpu_compute(lhs, rhs, y);
196  }
197 
198  // Assignment functions
199 
204  template <typename L>
205  void assign_to(L&& result) const {
206  std_assign_evaluate(*this, std::forward<L>(result));
207  }
208 
213  template <typename L>
214  void assign_add_to(L&& result) const {
215  std_add_evaluate(*this, std::forward<L>(result));
216  }
217 
222  template <typename L>
223  void assign_sub_to(L&& result) const {
224  std_sub_evaluate(*this, std::forward<L>(result));
225  }
226 
231  template <typename L>
232  void assign_mul_to(L&& result) const {
233  std_mul_evaluate(*this, std::forward<L>(result));
234  }
235 
240  template <typename L>
241  void assign_div_to(L&& result) const {
242  std_div_evaluate(*this, std::forward<L>(result));
243  }
244 
249  template <typename L>
250  void assign_mod_to(L&& result) const {
251  std_mod_evaluate(*this, std::forward<L>(result));
252  }
253 
254  // Internals
255 
260  void visit(detail::evaluator_visitor& visitor) const {
261  lhs.visit(visitor);
262  rhs.visit(visitor);
263  }
264 
269  void ensure_cpu_up_to_date() const {
270  // Need to ensure both LHS and RHS
271  lhs.ensure_cpu_up_to_date();
272  rhs.ensure_cpu_up_to_date();
273  }
274 
279  void ensure_gpu_up_to_date() const {
280  // Need to ensure both LHS and RHS
281  lhs.ensure_gpu_up_to_date();
282  rhs.ensure_gpu_up_to_date();
283  }
284 
289  const LeftExpr& get_lhs() const {
290  return lhs;
291  }
292 
297  const RightExpr& get_rhs() const {
298  return rhs;
299  }
300 
307  friend std::ostream& operator<<(std::ostream& os, const binary_expr& expr) {
308  if constexpr (BinaryOp::desc_func) {
309  return os << BinaryOp::desc() << "(" << expr.lhs << ", " << expr.rhs << ")";
310  } else {
311  return os << "(" << expr.lhs << ' ' << BinaryOp::desc() << ' ' << expr.rhs << ")";
312  }
313  }
314 };
315 
319 template <typename T, typename LE, typename BinaryOp, typename RE>
320 struct etl_traits<etl::binary_expr<T, LE, BinaryOp, RE>> {
322  using left_expr_t = std::decay_t<LE>;
323  using right_expr_t = std::decay_t<RE>;
324  using value_type = T;
325 
326  static constexpr bool left_directed =
328 
329  using sub_expr_t = std::conditional_t<left_directed, left_expr_t, right_expr_t>;
330 
334 
335  static constexpr bool is_etl = true;
336  static constexpr bool is_transformer = false;
337  static constexpr bool is_view = false;
338  static constexpr bool is_magic_view = false;
339  static constexpr bool is_fast = sub_traits::is_fast;
340  static constexpr bool is_linear = left_traits::is_linear && right_traits::is_linear && BinaryOp::linear;
341  static constexpr bool is_thread_safe =
342  left_traits::is_thread_safe && right_traits::is_thread_safe && BinaryOp::thread_safe;
343  static constexpr bool is_value = false;
344  static constexpr bool is_direct = false;
345  static constexpr bool is_generator = left_traits::is_generator && right_traits::is_generator;
346  static constexpr bool is_temporary = left_traits::is_temporary || right_traits::is_temporary;
347  static constexpr bool is_padded = is_linear && left_traits::is_padded && right_traits::is_padded;
348  static constexpr bool is_aligned = is_linear && left_traits::is_aligned && right_traits::is_aligned;
349  static constexpr order storage_order =
350  left_traits::is_generator ? right_traits::storage_order : left_traits::storage_order;
351 
355  static constexpr bool gpu_computable = all_gpu_computable<LE, RE> && BinaryOp::template gpu_computable<LE, RE> && all_homogeneous<LE, RE>;
356 
357  template <vector_mode_t V>
358  static constexpr bool vectorizable =
359  all_homogeneous<LE, RE>&& left_traits::template vectorizable<V>&& right_traits::template vectorizable<V>&& BinaryOp::template vectorizable<V>;
360 
366  static constexpr auto& get(const expr_t& v) {
367  if constexpr (left_directed) {
368  return v.lhs;
369  } else {
370  return v.rhs;
371  }
372  }
373 
379  static size_t size(const expr_t& v) {
380  return sub_traits::size(get(v));
381  }
382 
389  static size_t dim(const expr_t& v, size_t d) {
390  return sub_traits::dim(get(v), d);
391  }
392 
397  static constexpr size_t size() {
398  return sub_traits::size();
399  }
400 
406  template <size_t D>
407  static constexpr size_t dim() {
408  return sub_traits::template dim<D>();
409  }
410 
415  static constexpr size_t dimensions() {
416  return sub_traits::dimensions();
417  }
418 
423  static constexpr int complexity() noexcept {
424  return BinaryOp::complexity() + left_traits::complexity() + right_traits::complexity();
425  }
426 };
427 
428 } //end of namespace etl
CRTP class to inject iterators functions.
Definition: iterable.hpp:23
void assign_add_to(L &&lhs) const
Add to the given left-hand-side expression.
Definition: dyn_matrix_view.hpp:217
load(size_t i) const
Perform several operations at once.
Definition: binary_expr.hpp:116
static constexpr int complexity() noexcept
Estimate the complexity of computation.
Definition: binary_expr.hpp:423
std::decay_t< RightExpr > right_type
The RHS side type.
Definition: binary_expr.hpp:41
Transformer functor for optimizable expression.
Definition: expr_fwd.hpp:19
binary_expr(LeftExpr l, RightExpr r)
Construct a new binary expression.
Definition: binary_expr.hpp:57
static size_t size(const expr_t &v)
Returns the size of the given expression.
Definition: binary_expr.hpp:379
auto slice(E &&value, size_t first, size_t last) -> slice_view< detail::build_identity_type< E >>
Returns view representing a slice view of the given expression.
Definition: view_expression_builder.hpp:112
void std_assign_evaluate(Expr &&expr, Result &&result)
Evaluation of the expr into result.
Definition: evaluator.hpp:1176
void assign_div_to(L &&lhs) const
Divide the given left-hand-side expression.
Definition: dyn_matrix_view.hpp:244
void assign_mul_to(L &&lhs) const
Multiply the given left-hand-side expression.
Definition: dyn_matrix_view.hpp:235
constexpr bool is_magic_view
Traits indicating if the given ETL type is a magic view expression.
Definition: traits.hpp:311
std::decay_t< LE > left_expr_t
The type of the left expression.
Definition: binary_expr.hpp:322
T value_type
The Value type.
Definition: binary_expr.hpp:33
value_type operator[](size_t i) const
Returns the element at the given index.
Definition: binary_expr.hpp:94
void memory_type
The memory type.
Definition: binary_expr.hpp:34
void assign_to(L &&lhs) const
Assign to the given left-hand-side expression.
Definition: dyn_matrix_view.hpp:208
void const_memory_type
The const memory type.
Definition: binary_expr.hpp:35
order
Storage order of a matrix.
Definition: order.hpp:15
CRTP class to inject functions testing values of the expressions.
Definition: value_testable.hpp:26
constexpr bool is_fast
Traits to test if the given ETL expresion type is fast (sizes known at compile-time) ...
Definition: traits.hpp:588
An optimizer for the given expression type.
Definition: expr_fwd.hpp:16
A binary expression.
Definition: binary_expr.hpp:18
Traits to get information about ETL types.
Definition: tmp.hpp:68
Root namespace for the ETL library.
Definition: adapter.hpp:15
auto dim(E &&value, size_t i) -> detail::identity_helper< E, dim_view< detail::build_identity_type< E >, D >>
Return a view representing the ith Dth dimension.
Definition: view_expression_builder.hpp:25
static constexpr size_t dim()
Returns the Dth dimension of an expression of this type.
Definition: binary_expr.hpp:407
typename V::template vec_type< T > vec_type
The vectorization type for V.
Definition: binary_expr.hpp:47
std::ostream & operator<<(std::ostream &os, const etl::complex< T > &c)
Outputs a textual representation of the complex number in the given stream.
Definition: complex.hpp:576
void ensure_cpu_up_to_date() const
Ensures that the GPU memory is allocated and that the GPU memory is up to date (to undefined value)...
Definition: dyn_matrix_view.hpp:271
std::decay_t< LeftExpr > left_type
The LHS side type.
Definition: binary_expr.hpp:40
static constexpr size_t size()
Returns the size of an expression of this fast type.
Definition: binary_expr.hpp:397
std::conditional_t< left_directed, left_expr_t, right_expr_t > sub_expr_t
The type of sub expression.
Definition: binary_expr.hpp:329
static size_t dim(const expr_t &v, size_t d)
Returns the dth dimension of the given expression.
Definition: binary_expr.hpp:389
Visitor to perform local evaluation when necessary.
Definition: eval_visitors.hpp:23
value_type read_flat(size_t i) const
Returns the value at the given index This function never alters the state of the container.
Definition: binary_expr.hpp:104
Configurable iterator for ETL expressions.
Definition: iterator.hpp:24
void std_mod_evaluate(Expr &&expr, Result &&result)
Compound modulo evaluation of the expr into result.
Definition: evaluator.hpp:1271
const_return_type operator()(size_t j) const
Access to the element at the given position.
Definition: dyn_matrix_view.hpp:89
void std_mul_evaluate(Expr &&expr, Result &&result)
Compound multiply evaluation of the expr into result.
Definition: evaluator.hpp:1233
constexpr bool is_transformer
Traits indicating if the given ETL type is a transformer expression.
Definition: traits.hpp:297
void visit(detail::evaluator_visitor &visitor) const
Apply the given visitor to this expression and its descendants.
Definition: dyn_matrix_view.hpp:263
bool alias(const E &other) const noexcept
Test if this expression aliases with the given expression.
Definition: binary_expr.hpp:83
requires(D > 0) struct dyn_base
Matrix with run-time fixed dimensions.
Definition: dyn_base.hpp:113
T value_type
The value type.
Definition: binary_expr.hpp:324
constexpr bool is_view
Traits indicating if the given ETL type is a view expression.
Definition: traits.hpp:304
void ensure_gpu_up_to_date() const
Copy back from the GPU to the expression memory if necessary.
Definition: dyn_matrix_view.hpp:280
Simple traits to test if an expression is optimizable.
Definition: expr_fwd.hpp:13
static constexpr size_t dimensions()
Returns the number of expressions for this type.
Definition: binary_expr.hpp:415
std::decay_t< RE > right_expr_t
The type of the right expression.
Definition: binary_expr.hpp:323
void std_sub_evaluate(Expr &&expr, Result &&result)
Compound subtract evaluation of the expr into result.
Definition: evaluator.hpp:1214
void assign_mod_to(L &&lhs) const
Modulo the given left-hand-side expression.
Definition: dyn_matrix_view.hpp:253
constexpr bool is_thread_safe
Traits to test if the given ETL expresion type is thread safe.
Definition: traits.hpp:687
const auto & gpu_compute_hint([[maybe_unused]] Y &y) const
Return a GPU computed version of this expression.
Definition: sub_view.hpp:653
void std_div_evaluate(Expr &&expr, Result &&result)
Compound divide evaluation of the expr into result.
Definition: evaluator.hpp:1252
BinaryOp operator_type
The binary operator type.
Definition: binary_expr.hpp:38
void std_add_evaluate(Expr &&expr, Result &&result)
Compound add evaluation of the expr into result.
Definition: evaluator.hpp:1195
CRTP class to inject functions testing the dimensions.
Definition: dim_testable.hpp:45
loadu(size_t i) const
Perform several operations at once.
Definition: binary_expr.hpp:128
void assign_sub_to(L &&lhs) const
Sub from the given left-hand-side expression.
Definition: dyn_matrix_view.hpp:226