Expression Templates Library (ETL)
globals.hpp
Go to the documentation of this file.
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 
13 #pragma once
14 
15 #include "etl/temporary.hpp"
16 
18 #include "etl/impl/det.hpp"
19 
21 
22 namespace etl {
23 
29 template <etl_expr E>
30 bool is_square(E&& expr) {
31  return is_2d<E> && etl::dim<0>(expr) == etl::dim<1>(expr);
32 }
33 
39 template <etl_expr E>
40 bool is_real_matrix([[maybe_unused]] E&& expr) {
41  return !is_complex<E>;
42 }
43 
49 template <etl_expr E>
50 bool is_complex_matrix([[maybe_unused]] E&& expr) {
51  return is_complex<E>;
52 }
53 
59 template <etl_expr E>
60 bool is_rectangular(E&& expr) {
61  return is_2d<E> && etl::dim<0>(expr) != etl::dim<1>(expr);
62 }
63 
69 template <etl_expr E>
70 bool is_sub_square(E&& expr) {
71  return is_3d<E> && etl::dim<1>(expr) == etl::dim<2>(expr);
72 }
73 
79 template <etl_expr E>
80 bool is_sub_rectangular(E&& expr) {
81  return is_3d<E> && etl::dim<1>(expr) != etl::dim<2>(expr);
82 }
83 
89 template <typename E>
90 bool is_uniform(E&& expr) {
91  if (!etl::size(expr)) {
92  return false;
93  }
94 
95  auto first = *expr.begin();
96 
97  for (auto v : expr) {
98  if (v != first) {
99  return false;
100  }
101  }
102 
103  return true;
104 }
105 
111 template <typename E>
112 bool is_permutation_matrix(E&& expr) {
113  if (!is_square(expr)) {
114  return false;
115  }
116 
117  //Conditions:
118  //a) Must be a square matrix
119  //b) Every row must have one 1
120  //c) Every column must have one 1
121 
122  for (size_t i = 0; i < etl::dim<0>(expr); ++i) {
123  auto sum = value_t<E>(0);
124  for (size_t j = 0; j < etl::dim<0>(expr); ++j) {
125  if (expr(i, j) != value_t<E>(0) && expr(i, j) != value_t<E>(1)) {
126  return false;
127  }
128 
129  sum += expr(i, j);
130  }
131 
132  if (sum != value_t<E>(1)) {
133  return false;
134  }
135  }
136 
137  for (size_t j = 0; j < etl::dim<0>(expr); ++j) {
138  auto sum = value_t<E>(0);
139  for (size_t i = 0; i < etl::dim<0>(expr); ++i) {
140  sum += expr(i, j);
141  }
142 
143  if (sum != value_t<E>(1)) {
144  return false;
145  }
146  }
147 
148  return true;
149 }
150 
156 template <etl_expr L, etl_expr R>
157 bool operator==(L&& lhs, R&& rhs) {
158  // Both expressions must have the same number of dimensions
159  if (etl::dimensions(lhs) != etl::dimensions(rhs)) {
160  return false;
161  }
162 
163  // The dimensions must be the same
164  for (size_t i = 0; i < etl::dimensions(rhs); ++i) {
165  if (etl::dim(lhs, i) != etl::dim(rhs, i)) {
166  return false;
167  }
168  }
169 
170  // At this point, the values are necessary for the comparison
171  force(lhs);
172  force(rhs);
173 
174  // Note: Ideally, we should use std::equal, but this is significantly
175  // faster to compile
176 
177  for (size_t i = 0; i < etl::size(lhs); ++i) {
178  if (lhs[i] != rhs[i]) {
179  return false;
180  }
181  }
182 
183  return true;
184 }
185 
191 template <etl_expr L, etl_expr R>
192 bool operator!=(L&& lhs, R&& rhs) {
193  return !(lhs == rhs);
194 }
195 
205 template <std::floating_point T, std::floating_point TE = T>
206 inline bool approx_equals_float(T a, T b, TE epsilon) {
207  using std::fabs;
208 
209  const auto abs_a = fabs(a);
210  const auto abs_b = fabs(b);
211  const auto abs_diff = fabs(a - b);
212 
213  // Note: min for floating points is the min normalized value
214  static constexpr T min_normal = std::numeric_limits<T>::min();
215  static constexpr T max = std::numeric_limits<T>::max();
216 
217  if (a == b) {
218  // This should handle infinities properly
219  return true;
220  } else if (a == 0 || b == 0 || abs_diff < min_normal) {
221  // a or b is zero or both are extremely close to it
222  // relative error is less meaningful here
223  return abs_diff < epsilon;
224  } else { // use relative error
225  return (abs_diff / std::min(abs_a + abs_b, max)) < epsilon;
226  }
227 }
228 
236 template <etl_expr L, etl_expr E>
237 bool approx_equals(L&& lhs, E&& rhs, value_t<L> eps) {
238  // Both expressions must have the same number of dimensions
239  if constexpr (etl::dimensions<L>() != etl::dimensions<E>()) {
240  return false;
241  } else {
242  // The dimensions must be the same
243  for (size_t i = 0; i < etl::dimensions(rhs); ++i) {
244  if (etl::dim(lhs, i) != etl::dim(rhs, i)) {
245  return false;
246  }
247  }
248 
249  // At this point, the values are necessary for the comparison
250  force(lhs);
251  force(rhs);
252 
253  for (size_t i = 0; i < etl::size(lhs); ++i) {
254  if (!approx_equals_float(lhs[i], rhs[i], eps)) {
255  return false;
256  }
257  }
258 
259  return true;
260  }
261 }
262 
271 template <etl_expr E>
272 value_t<E> trace(E&& expr) {
273  assert_square(expr);
274 
275  auto value = value_t<E>();
276 
277  for (size_t i = 0; i < etl::dim<0>(expr); ++i) {
278  value += expr(i, i);
279  }
280 
281  return value;
282 }
283 
292 template <etl_expr E>
294  assert_square(expr);
295 
296  return detail::det_impl::apply(expr);
297 }
298 
307 template <etl_expr AT, etl_expr LT, etl_expr UT, etl_expr PT>
308 bool lu(const AT& A, LT& L, UT& U, PT& P) {
309  // All matrices must be square
310  if (!is_square(A) || !is_square(L) || !is_square(U) || !is_square(P)) {
311  return false;
312  }
313 
314  // All matrices must be of the same dimension
315  if (etl::dim(A, 0) != etl::dim(L, 0) || etl::dim(A, 0) != etl::dim(U, 0) || etl::dim(A, 0) != etl::dim(P, 0)) {
316  return true;
317  }
318 
319  detail::lu_impl::apply(A, L, U, P);
320 
321  return true;
322 }
323 
331 template <etl_expr AT, etl_expr QT, etl_expr RT>
332 bool qr(AT& A, QT& Q, RT& R) {
333  // A and R have the same dimensions
334  if (etl::dim(A, 0) != etl::dim(R, 0) || etl::dim(A, 1) != etl::dim(R, 1)) {
335  return false;
336  }
337 
338  // A and Q have corresponding first dimensions and Q is square
339  if (etl::dim(A, 0) != etl::dim(Q, 0) || etl::dim(A, 0) != etl::dim(Q, 1)) {
340  return false;
341  }
342 
343  detail::qr_impl::apply(A, Q, R);
344 
345  return true;
346 }
347 
358 template <etl_expr T, typename G>
359 void shuffle_flat(T& vector, G&& g) {
360  const auto n = etl::size(vector);
361 
362  if (n < 2) {
363  return;
364  }
365 
366  if constexpr (impl::egblas::has_shuffle_seed) {
367  std::uniform_int_distribution<size_t> seed_dist;
368 
369  vector.ensure_gpu_up_to_date();
370 
371  impl::egblas::shuffle_seed(n, vector.gpu_memory(), sizeof(etl::value_t<T>), seed_dist(g));
372 
373  vector.invalidate_cpu();
374  } else {
375  using distribution_t = typename std::uniform_int_distribution<size_t>;
376  using param_t = typename distribution_t::param_type;
377 
378  distribution_t dist;
379 
380  for (auto i = n - 1; i > 0; --i) {
381  auto new_i = dist(g, param_t(0, i));
382 
383  using std::swap;
384  swap(vector[i], vector[new_i]);
385  }
386  }
387 }
388 
398 template <etl_expr T>
399 void shuffle_flat(T& vector) {
400  static std::random_device rd;
401  static etl::random_engine g(rd());
402 
403  shuffle_flat(vector, g);
404 }
405 
418 template <etl_expr T, typename G>
419 void shuffle_first(T& matrix, G&& g) {
420  const auto n = etl::dim<0>(matrix);
421 
422  if (n < 2) {
423  return;
424  }
425 
426  if constexpr (impl::egblas::has_shuffle_seed) {
427  std::uniform_int_distribution<size_t> seed_dist;
428 
429  matrix.ensure_gpu_up_to_date();
430 
431  impl::egblas::shuffle_seed(n, matrix.gpu_memory(), sizeof(etl::value_t<T>) * (etl::size(matrix) / n), seed_dist(g));
432 
433  matrix.invalidate_cpu();
434  } else {
435  using distribution_t = typename std::uniform_int_distribution<size_t>;
436  using param_t = typename distribution_t::param_type;
437 
438  distribution_t dist;
439 
440  auto temp = etl::force_temporary(matrix(0));
441 
442  for (auto i = n - 1; i > 0; --i) {
443  auto new_i = dist(g, param_t(0, i));
444 
445  temp = matrix(i);
446  matrix(i) = matrix(new_i);
447  matrix(new_i) = temp;
448  }
449  }
450 }
451 
463 template <etl_expr T>
464 void shuffle_first(T& matrix) {
465  static std::random_device rd;
466  static etl::random_engine g(rd());
467 
468  shuffle_first(matrix, g);
469 }
470 
479 template <etl_expr T>
480 void shuffle(T& vector) {
481  if constexpr (is_1d<T>) {
482  shuffle_flat(vector);
483  } else {
484  shuffle_first(vector);
485  }
486 }
487 
497 template <etl_expr T, typename G>
498 void shuffle(T& vector, G&& g) {
499  if constexpr (is_1d<T>) {
500  shuffle_flat(vector, g);
501  } else {
502  shuffle_first(vector, g);
503  }
504 }
505 
515 template <etl_expr T1, same_dimensions<T1> T2, typename G>
516 void parallel_shuffle_flat(T1& v1, T2& v2, G&& g) {
517  cpp_assert(etl::size(v1) == etl::size(v2), "Impossible to shuffle vector of different dimensions");
518 
519  const auto n = etl::size(v1);
520 
521  if (n < 2) {
522  return;
523  }
524 
525  if constexpr (impl::egblas::has_par_shuffle_seed) {
526  std::uniform_int_distribution<size_t> seed_dist;
527 
528  v1.ensure_gpu_up_to_date();
529  v2.ensure_gpu_up_to_date();
530 
531  impl::egblas::par_shuffle_seed(n, v1.gpu_memory(), sizeof(etl::value_t<T1>), v2.gpu_memory(), sizeof(etl::value_t<T2>), seed_dist(g));
532 
533  v1.invalidate_cpu();
534  v2.invalidate_cpu();
535  } else {
536  using distribution_t = typename std::uniform_int_distribution<size_t>;
537  using param_t = typename distribution_t::param_type;
538 
539  distribution_t dist;
540 
541  for (auto i = n - 1; i > 0; --i) {
542  auto new_i = dist(g, param_t(0, i));
543 
544  using std::swap;
545  swap(v1[i], v1[new_i]);
546  swap(v2[i], v2[new_i]);
547  }
548  }
549 }
550 
560 template <etl_expr T1, etl_expr T2>
561 void parallel_shuffle_flat(T1& v1, T2& v2) {
562  static std::random_device rd;
563  static etl::random_engine g(rd());
564 
565  parallel_shuffle_flat(v1, v2, g);
566 }
567 
580 template <etl_expr T1, etl_expr T2, typename G>
581 void parallel_shuffle_first(T1& m1, T2& m2, G&& g) {
582  cpp_assert(etl::dim<0>(m1) == etl::dim<0>(m2), "Impossible to shuffle together matrices of different first dimension");
583 
584  const auto n = etl::dim<0>(m1);
585 
586  if (n < 2) {
587  return;
588  }
589 
590  if constexpr (impl::egblas::has_par_shuffle_seed) {
591  std::uniform_int_distribution<size_t> seed_dist;
592 
593  m1.ensure_gpu_up_to_date();
594  m2.ensure_gpu_up_to_date();
595 
596  impl::egblas::par_shuffle_seed(n, m1.gpu_memory(), sizeof(etl::value_t<T1>) * (etl::size(m1) / n), m2.gpu_memory(),
597  sizeof(etl::value_t<T2>) * (etl::size(m2) / n), seed_dist(g));
598 
599  m1.invalidate_cpu();
600  m2.invalidate_cpu();
601  } else {
602  using distribution_t = typename std::uniform_int_distribution<size_t>;
603  using param_t = typename distribution_t::param_type;
604 
605  distribution_t dist;
606 
607  auto t1 = etl::force_temporary(m1(0));
608  auto t2 = etl::force_temporary(m2(0));
609 
610  for (auto i = n - 1; i > 0; --i) {
611  auto new_i = dist(g, param_t(0, i));
612 
613  t1 = m1(i);
614  m1(i) = m1(new_i);
615  m1(new_i) = t1;
616 
617  t2 = m2(i);
618  m2(i) = m2(new_i);
619  m2(new_i) = t2;
620  }
621  }
622 }
623 
636 template <etl_expr T1, etl_expr T2>
637 void parallel_shuffle_first(T1& m1, T2& m2) {
638  static std::random_device rd;
639  static etl::random_engine g(rd());
640 
641  parallel_shuffle_first(m1, m2, g);
642 }
643 
653 template <etl_expr T1, etl_expr T2>
654 void parallel_shuffle(T1& v1, T2& v2) {
655  static std::random_device rd;
656  static etl::random_engine g(rd());
657 
658  parallel_shuffle(v1, v2, g);
659 }
660 
661 template <etl_expr T>
662 void shuffle_swap(T& v1, size_t i, size_t new_i) {
663  if constexpr (is_1d<T>) {
664  auto t = v1(i);
665  v1(i) = v1(new_i);
666  v1(new_i) = t;
667  } else {
668  auto s1 = v1(i);
669  auto s2 = v1(new_i);
670 
671  for (size_t index = 0 ; index < etl::subsize(v1); ++index) {
672  auto t = s1[index];
673  s1[index] = s2[index];
674  s2[index] = t;
675  }
676  }
677 }
678 
688 template <etl_expr T1, etl_expr T2, typename G>
689 void parallel_shuffle(T1& v1, T2& v2, G&& g) {
690  cpp_assert(etl::dim<0>(v1) == etl::dim<0>(v2), "Impossible to shuffle together matrices of different first dimension");
691 
692  const auto n = etl::dim<0>(v1);
693 
694  if (n < 2) {
695  return;
696  }
697 
698  if constexpr (impl::egblas::has_par_shuffle_seed) {
699  std::uniform_int_distribution<size_t> seed_dist;
700 
701  v1.ensure_gpu_up_to_date();
702  v2.ensure_gpu_up_to_date();
703 
704  impl::egblas::par_shuffle_seed(n, v1.gpu_memory(), sizeof(etl::value_t<T1>) * (etl::size(v1) / n), v2.gpu_memory(),
705  sizeof(etl::value_t<T2>) * (etl::size(v2) / n), seed_dist(g));
706 
707  v1.invalidate_cpu();
708  v2.invalidate_cpu();
709  } else {
710  using distribution_t = typename std::uniform_int_distribution<size_t>;
711  using param_t = typename distribution_t::param_type;
712 
713  distribution_t dist;
714 
715  // Note: We must handle non-homogeneous matrices here
716  // For instance, a matrix and a vector hence, the code in shuffle_swap
717 
718  for (auto i = n - 1; i > 0; --i) {
719  auto new_i = dist(g, param_t(0, i));
720 
721  shuffle_swap(v1, i, new_i);
722  shuffle_swap(v2, i, new_i);
723  }
724  }
725 }
726 
736 template <etl_expr M, etl_expr N>
737 M& merge(M& merged, const N& sub, size_t index) {
738  const size_t s = etl::size(sub);
739  const size_t n = index * s;
740 
741  memory_slice(merged, n, n + s) = sub;
742 
743  return merged;
744 }
745 
755 template <etl_expr M, etl_expr N>
756 M& batch_merge(M& merged, const N& sub, size_t index) {
757  const size_t s = etl::size(sub(0));
758  const size_t n = index * s;
759 
760  for (size_t b = 0; b < etl::dim<0>(merged); ++b) {
761  memory_slice(merged(b), n, n + s) = sub(b);
762  }
763 
764  return merged;
765 }
766 
776 template <etl_expr M, etl_expr N>
777 M& dispatch(M& dispatched, const N& merged, size_t index) {
778  const size_t s = etl::size(dispatched);
779  const size_t n = index * s;
780 
781  dispatched = memory_slice(merged, n, n + s);
782 
783  return dispatched;
784 }
785 
795 template <etl_expr M, etl_expr N>
796 M& batch_dispatch(M& dispatched, const N& merged, size_t index) {
797  const size_t s = etl::size(dispatched(0));
798  const size_t n = index * s;
799 
800  for (size_t b = 0; b < etl::dim<0>(merged); ++b) {
801  dispatched(b) = memory_slice(merged(b), n, n + s);
802  }
803 
804  return dispatched;
805 }
806 
812 template <etl_expr M, typename T>
813 void binarize(M& matrix, T b) {
814  using VT = value_t<M>;
815 
816  for (auto& value : matrix) {
817  value = value > b ? VT(1) : VT(0);
818  }
819 }
820 
825 template <etl_expr M>
826 void normalize_flat(M& matrix) {
827  using VT = value_t<M>;
828 
829  auto m = mean(matrix);
830 
831  matrix = matrix - m;
832 
833  auto s = stddev(matrix, 0.0);
834 
835  if (s != VT(0)) {
836  matrix = matrix / s;
837  }
838 }
839 
846 template <etl_expr M>
847 void normalize_sub(M& matrix) {
848  using VT = value_t<M>;
849 
850 #ifdef ETL_CUDA
851  // The case of CUDA must be handled differently to avoid going
852  // back and forth between both memories
853  // While this could simply use egblas_normalize_sub, this would
854  // be much slower
855 
856  auto mm = matrix.memory_start();
857  const auto n = etl::dim<0>(matrix);
858  const auto sub_n = etl::size(matrix) / n;
859 
860  for (size_t i = 0; i < n; ++i) {
861  VT m(0);
862 
863  for (size_t j = 0; j < sub_n; ++j) {
864  m += mm[i * sub_n + j];
865  }
866 
867  m /= VT(sub_n);
868 
869  VT s(0);
870 
871  for (size_t j = 0; j < sub_n; ++j) {
872  s += (mm[i * sub_n + j] - m) * (mm[i * sub_n + j] - m);
873  }
874 
875  s = std::sqrt(s / VT(sub_n));
876 
877  for (size_t j = 0; j < sub_n; ++j) {
878  mm[i * sub_n + j] = (mm[i * sub_n + j] - m) / s;
879  }
880  }
881 #else
882  for (size_t i = 0; i < etl::dim<0>(matrix); ++i) {
883  auto m = mean(matrix(i));
884 
885  matrix(i) = matrix(i) - m;
886 
887  auto s = stddev(matrix(i), 0.0);
888 
889  if (s != VT(0)) {
890  matrix(i) = matrix(i) / s;
891  }
892  }
893 #endif
894 }
895 
896 } //end of namespace etl
void parallel_shuffle(T1 &v1, T2 &v2)
Shuffle all the elements of two vectors or matrices, using the same permutation.
Definition: globals.hpp:654
value_t< E > mean(E &&values)
Returns the mean of all the values contained in the given expression.
Definition: expression_builder.hpp:650
M & batch_dispatch(M &dispatched, const N &merged, size_t index)
Dispatch a part of merged to dispatched from the given position, for each batch.
Definition: globals.hpp:796
Selector for the decompositions implementation.
bool is_sub_square(E &&expr)
Indicates if the given expression contains sub matrices that are square.
Definition: globals.hpp:70
EGBLAS wrappers for the shuffle operations.
auto s(T &&value)
Force the evaluation of the given expression.
Definition: stop.hpp:18
bool approx_equals(L &&lhs, E &&rhs, value_t< L > eps)
Test if two ETL expression are approximately equals.
Definition: globals.hpp:237
bool qr(AT &A, QT &Q, RT &R)
Decomposition the matrix so that A = Q * R.
Definition: globals.hpp:332
void shuffle(T &vector)
Shuffle all the elements of an ETL vector.
Definition: globals.hpp:480
auto max(L &&lhs, R &&rhs)
Create an expression with the max value of lhs or rhs.
Definition: expression_builder.hpp:65
bool is_uniform(E &&expr)
Indicates if the given expression is uniform (all elements of the same value)
Definition: globals.hpp:90
M & batch_merge(M &merged, const N &sub, size_t index)
Merge sub inside merged at the given position, for each batch.
Definition: globals.hpp:756
bool is_permutation_matrix(E &&expr)
Indicates if the given expression represents a permutation matrix.
Definition: globals.hpp:112
void parallel_shuffle_flat(T1 &v1, T2 &v2, G &&g)
Shuffle all the elements of two vectors, using the same permutation.
Definition: globals.hpp:516
auto sqrt(E &&value) -> detail::unary_helper< E, sqrt_unary_op >
Apply square root on each value of the given expression.
Definition: function_expression_builder.hpp:24
void normalize_flat(M &matrix)
Normalize the given ETL contrainer to zero-mean and unit-variance.
Definition: globals.hpp:826
bool is_real_matrix([[maybe_unused]] E &&expr)
Indicates if the given expression is a real matrix or not.
Definition: globals.hpp:40
static void apply(AT &A, QT &Q, RT &R)
Apply the functor to A,Q,R.
Definition: decomposition.hpp:48
bool operator!=(const complex< T > &lhs, const complex< T > &rhs)
Test two complex numbers for inequality.
Definition: complex.hpp:179
value_t< E > trace(E &&expr)
Returns the trace of the given square matrix.
Definition: globals.hpp:272
M & merge(M &merged, const N &sub, size_t index)
Merge sub inside merged at the given position.
Definition: globals.hpp:737
void shuffle_flat(T &vector, G &&g)
Shuffle all the elements of an ETL vector or matrix (considered as array).
Definition: globals.hpp:359
void force(Expr &&expr)
Force the internal evaluation of an expression.
Definition: evaluator.hpp:1292
constexpr size_t dimensions() noexcept
Return the number of dimensions of the given ETL type.
Definition: helpers.hpp:28
void binarize(M &matrix, T b)
Binarize the given ETL contrainer.
Definition: globals.hpp:813
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 value_t< AT > apply(const AT &A)
Apply the functor to A.
Definition: det.hpp:30
value_t< E > determinant(E &&expr)
Returns the determinant of the given square matrix.
Definition: globals.hpp:293
value_t< E > stddev(E &&values)
Returns the standard deviation of all the values contained in the given expression.
Definition: expression_builder.hpp:670
bool is_square(E &&expr)
Indicates if the given expression is a square matrix or not.
Definition: globals.hpp:30
void parallel_shuffle_first(T1 &m1, T2 &m2, G &&g)
Shuffle all the elements of two matrices, using the same permutation.
Definition: globals.hpp:581
bool is_sub_rectangular(E &&expr)
Indicates if the given expression contains sub matrices that are rectangular.
Definition: globals.hpp:80
M & dispatch(M &dispatched, const N &merged, size_t index)
Dispatch a part of merged to dispatched from the given position.
Definition: globals.hpp:777
bool lu(const AT &A, LT &L, UT &U, PT &P)
Decomposition the matrix so that P * A = L * U.
Definition: globals.hpp:308
static void apply(const AT &A, LT &L, UT &U, PT &P)
Apply the functor to A, L, U, P.
Definition: decomposition.hpp:32
bool is_complex_matrix([[maybe_unused]] E &&expr)
Indicates if the given expression is a complex matrix or not.
Definition: globals.hpp:50
void swap(custom_dyn_matrix_impl< T, SO, D > &lhs, custom_dyn_matrix_impl< T, SO, D > &rhs)
Swap two dyn matrix.
Definition: custom_dyn.hpp:403
auto min(L &&lhs, R &&rhs)
Create an expression with the min value of lhs or rhs.
Definition: expression_builder.hpp:77
value_t< E > sum(E &&values)
Returns the sum of all the values contained in the given expression.
Definition: expression_builder.hpp:624
Selector for the determinant implementation.
bool is_rectangular(E &&expr)
Indicates if the given expression is a rectangular matrix or not.
Definition: globals.hpp:60
constexpr size_t size(const E &expr) noexcept
Returns the size of the given ETL expression.
Definition: helpers.hpp:108
void normalize_sub(M &matrix)
Normalize each sub container of the given ETL contrainer to zero-mean and unit-variance.
Definition: globals.hpp:847
auto memory_slice(E &&value, size_t first, size_t last) -> detail::identity_helper< E, memory_slice_view< detail::build_identity_type< E >, Aligned >>
Returns view representing a memory slice view of the given expression.
Definition: memory_slice_view.hpp:351
bool approx_equals_float(T a, T b, TE epsilon)
Test if two floating point numbers are approximately equals.
Definition: globals.hpp:206
decltype(auto) force_temporary(E &&expr)
Force a temporary out of the expression.
Definition: temporary.hpp:91
bool operator==(const complex< T > &lhs, const complex< T > &rhs)
Test two complex numbers for equality.
Definition: complex.hpp:168
std::mt19937_64 random_engine
The random engine used by the library.
Definition: random.hpp:22
typename decay_traits< E >::value_type value_t
Traits to extract the value type out of an ETL type.
Definition: tmp.hpp:81
void shuffle_first(T &matrix, G &&g)
Shuffle all the elements of a matrix.
Definition: globals.hpp:419
size_t subsize(const E &expr)
Returns the sub-size of the given ETL expression, i.e. the size not considering the first dimension...
Definition: helpers.hpp:118
void assert_square([[maybe_unused]] E &&expr)
Make sure that the expression is square.
Definition: checks.hpp:73