xtensor
Loading...
Searching...
No Matches
xoperation.hpp
1/***************************************************************************
2 * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
3 * Copyright (c) QuantStack *
4 * *
5 * Distributed under the terms of the BSD 3-Clause License. *
6 * *
7 * The full license is in the file LICENSE, distributed with this software. *
8 ****************************************************************************/
9
10#ifndef XTENSOR_OPERATION_HPP
11#define XTENSOR_OPERATION_HPP
12
13#include <algorithm>
14#include <functional>
15#include <type_traits>
16
17#include <xtl/xsequence.hpp>
18
19#include "xfunction.hpp"
20#include "xscalar.hpp"
21#include "xstrided_view.hpp"
22#include "xstrides.hpp"
23
24namespace xt
25{
26
27 /***********
28 * helpers *
29 ***********/
30
31#define UNARY_OPERATOR_FUNCTOR(NAME, OP) \
32 struct NAME \
33 { \
34 template <class A1> \
35 constexpr auto operator()(const A1& arg) const \
36 { \
37 return OP arg; \
38 } \
39 template <class B> \
40 constexpr auto simd_apply(const B& arg) const \
41 { \
42 return OP arg; \
43 } \
44 }
45
46#define DEFINE_COMPLEX_OVERLOAD(OP) \
47 template <class T1, class T2, XTL_REQUIRES(xtl::negation<std::is_same<T1, T2>>)> \
48 constexpr auto operator OP(const std::complex<T1>& arg1, const std::complex<T2>& arg2) \
49 { \
50 using result_type = typename xtl::promote_type_t<std::complex<T1>, std::complex<T2>>; \
51 return (result_type(arg1) OP result_type(arg2)); \
52 } \
53 \
54 template <class T1, class T2, XTL_REQUIRES(xtl::negation<std::is_same<T1, T2>>)> \
55 constexpr auto operator OP(const T1& arg1, const std::complex<T2>& arg2) \
56 { \
57 using result_type = typename xtl::promote_type_t<T1, std::complex<T2>>; \
58 return (result_type(arg1) OP result_type(arg2)); \
59 } \
60 \
61 template <class T1, class T2, XTL_REQUIRES(xtl::negation<std::is_same<T1, T2>>)> \
62 constexpr auto operator OP(const std::complex<T1>& arg1, const T2& arg2) \
63 { \
64 using result_type = typename xtl::promote_type_t<std::complex<T1>, T2>; \
65 return (result_type(arg1) OP result_type(arg2)); \
66 }
67
68#define BINARY_OPERATOR_FUNCTOR(NAME, OP) \
69 struct NAME \
70 { \
71 template <class T1, class T2> \
72 constexpr auto operator()(T1&& arg1, T2&& arg2) const \
73 { \
74 using xt::detail::operator OP; \
75 return (std::forward<T1>(arg1) OP std::forward<T2>(arg2)); \
76 } \
77 template <class B> \
78 constexpr auto simd_apply(const B& arg1, const B& arg2) const \
79 { \
80 return (arg1 OP arg2); \
81 } \
82 }
83
84 namespace detail
85 {
86 DEFINE_COMPLEX_OVERLOAD(+);
87 DEFINE_COMPLEX_OVERLOAD(-);
88 DEFINE_COMPLEX_OVERLOAD(*);
89 DEFINE_COMPLEX_OVERLOAD(/);
90 DEFINE_COMPLEX_OVERLOAD(%);
91 DEFINE_COMPLEX_OVERLOAD(||);
92 DEFINE_COMPLEX_OVERLOAD(&&);
93 DEFINE_COMPLEX_OVERLOAD(|);
94 DEFINE_COMPLEX_OVERLOAD(&);
95 DEFINE_COMPLEX_OVERLOAD(^);
96 DEFINE_COMPLEX_OVERLOAD(<<);
97 DEFINE_COMPLEX_OVERLOAD(>>);
98 DEFINE_COMPLEX_OVERLOAD(<);
99 DEFINE_COMPLEX_OVERLOAD(<=);
100 DEFINE_COMPLEX_OVERLOAD(>);
101 DEFINE_COMPLEX_OVERLOAD(>=);
102 DEFINE_COMPLEX_OVERLOAD(==);
103 DEFINE_COMPLEX_OVERLOAD(!=);
104
105 UNARY_OPERATOR_FUNCTOR(identity, +);
106 UNARY_OPERATOR_FUNCTOR(negate, -);
107 BINARY_OPERATOR_FUNCTOR(plus, +);
108 BINARY_OPERATOR_FUNCTOR(minus, -);
109 BINARY_OPERATOR_FUNCTOR(multiplies, *);
110 BINARY_OPERATOR_FUNCTOR(divides, /);
111 BINARY_OPERATOR_FUNCTOR(modulus, %);
112 BINARY_OPERATOR_FUNCTOR(logical_or, ||);
113 BINARY_OPERATOR_FUNCTOR(logical_and, &&);
114 UNARY_OPERATOR_FUNCTOR(logical_not, !);
115 BINARY_OPERATOR_FUNCTOR(bitwise_or, |);
116 BINARY_OPERATOR_FUNCTOR(bitwise_and, &);
117 BINARY_OPERATOR_FUNCTOR(bitwise_xor, ^);
118 UNARY_OPERATOR_FUNCTOR(bitwise_not, ~);
119 BINARY_OPERATOR_FUNCTOR(left_shift, <<);
120 BINARY_OPERATOR_FUNCTOR(right_shift, >>);
121 BINARY_OPERATOR_FUNCTOR(less, <);
122 BINARY_OPERATOR_FUNCTOR(less_equal, <=);
123 BINARY_OPERATOR_FUNCTOR(greater, >);
124 BINARY_OPERATOR_FUNCTOR(greater_equal, >=);
125 BINARY_OPERATOR_FUNCTOR(equal_to, ==);
126 BINARY_OPERATOR_FUNCTOR(not_equal_to, !=);
127
128 struct conditional_ternary
129 {
130 template <class B>
131 using get_batch_bool = typename xt_simd::simd_traits<typename xt_simd::revert_simd_traits<B>::type>::bool_type;
132
133 template <class B, class A1, class A2>
134 constexpr auto operator()(const B& cond, const A1& v1, const A2& v2) const noexcept
135 {
136 return xtl::select(cond, v1, v2);
137 }
138
139 template <class B>
140 constexpr B simd_apply(const get_batch_bool<B>& t1, const B& t2, const B& t3) const noexcept
141 {
142 return xt_simd::select(t1, t2, t3);
143 }
144 };
145
146 template <class R>
147 struct cast
148 {
149 struct functor
150 {
151 using result_type = R;
152
153 template <class A1>
154 constexpr result_type operator()(const A1& arg) const
155 {
156 return static_cast<R>(arg);
157 }
158
159 // SIMD conversion disabled for now since it does not make sense
160 // in most of the cases
161 /*constexpr simd_result_type simd_apply(const simd_value_type& arg) const
162 {
163 return static_cast<R>(arg);
164 }*/
165 };
166 };
167
168 template <class Tag, class F, class... E>
169 struct select_xfunction_expression;
170
171 template <class F, class... E>
172 struct select_xfunction_expression<xtensor_expression_tag, F, E...>
173 {
174 using type = xfunction<F, E...>;
175 };
176
177 template <class F, class... E>
178 struct select_xfunction_expression<xoptional_expression_tag, F, E...>
179 {
180 using type = xfunction<F, E...>;
181 };
182
183 template <class Tag, class F, class... E>
184 using select_xfunction_expression_t = typename select_xfunction_expression<Tag, F, E...>::type;
185
186 template <class F, class... E>
187 struct xfunction_type
188 {
189 using expression_tag = xexpression_tag_t<E...>;
190 using functor_type = F;
191 using type = select_xfunction_expression_t<expression_tag, functor_type, const_xclosure_t<E>...>;
192 };
193
194 template <class F, class... E>
195 inline auto make_xfunction(E&&... e) noexcept
196 {
197 using function_type = xfunction_type<F, E...>;
198 using functor_type = typename function_type::functor_type;
199 using type = typename function_type::type;
200 return type(functor_type(), std::forward<E>(e)...);
201 }
202
203 // On MSVC, the second argument of enable_if_t is always evaluated, even if the condition is false.
204 // Wrapping the xfunction type in the xfunction_type metafunction avoids this evaluation when
205 // the condition is false, since it leads to a tricky bug preventing from using operator+ and
206 // operator- on vector and arrays iterators.
207 template <class F, class... E>
208 using xfunction_type_t = typename std::
209 enable_if_t<has_xexpression<std::decay_t<E>...>::value, xfunction_type<F, E...>>::type;
210 }
211
212#undef UNARY_OPERATOR_FUNCTOR
213#undef BINARY_OPERATOR_FUNCTOR
214
215 /*************
216 * operators *
217 *************/
218
232 template <class E>
233 inline auto operator+(E&& e) noexcept -> detail::xfunction_type_t<detail::identity, E>
234 {
235 return detail::make_xfunction<detail::identity>(std::forward<E>(e));
236 }
237
247 template <class E>
248 inline auto operator-(E&& e) noexcept -> detail::xfunction_type_t<detail::negate, E>
249 {
250 return detail::make_xfunction<detail::negate>(std::forward<E>(e));
251 }
252
263 template <class E1, class E2>
264 inline auto operator+(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::plus, E1, E2>
265 {
266 return detail::make_xfunction<detail::plus>(std::forward<E1>(e1), std::forward<E2>(e2));
267 }
268
279 template <class E1, class E2>
280 inline auto operator-(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::minus, E1, E2>
281 {
282 return detail::make_xfunction<detail::minus>(std::forward<E1>(e1), std::forward<E2>(e2));
283 }
284
295 template <class E1, class E2>
296 inline auto operator*(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::multiplies, E1, E2>
297 {
298 return detail::make_xfunction<detail::multiplies>(std::forward<E1>(e1), std::forward<E2>(e2));
299 }
300
311 template <class E1, class E2>
312 inline auto operator/(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::divides, E1, E2>
313 {
314 return detail::make_xfunction<detail::divides>(std::forward<E1>(e1), std::forward<E2>(e2));
315 }
316
327 template <class E1, class E2>
328 inline auto operator%(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::modulus, E1, E2>
329 {
330 return detail::make_xfunction<detail::modulus>(std::forward<E1>(e1), std::forward<E2>(e2));
331 }
332
347 template <class E1, class E2>
348 inline auto operator||(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::logical_or, E1, E2>
349 {
350 return detail::make_xfunction<detail::logical_or>(std::forward<E1>(e1), std::forward<E2>(e2));
351 }
352
363 template <class E1, class E2>
364 inline auto operator&&(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::logical_and, E1, E2>
365 {
366 return detail::make_xfunction<detail::logical_and>(std::forward<E1>(e1), std::forward<E2>(e2));
367 }
368
378 template <class E>
379 inline auto operator!(E&& e) noexcept -> detail::xfunction_type_t<detail::logical_not, E>
380 {
381 return detail::make_xfunction<detail::logical_not>(std::forward<E>(e));
382 }
383
398 template <class E1, class E2>
399 inline auto operator&(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::bitwise_and, E1, E2>
400 {
401 return detail::make_xfunction<detail::bitwise_and>(std::forward<E1>(e1), std::forward<E2>(e2));
402 }
403
414 template <class E1, class E2>
415 inline auto operator|(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::bitwise_or, E1, E2>
416 {
417 return detail::make_xfunction<detail::bitwise_or>(std::forward<E1>(e1), std::forward<E2>(e2));
418 }
419
430 template <class E1, class E2>
431 inline auto operator^(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::bitwise_xor, E1, E2>
432 {
433 return detail::make_xfunction<detail::bitwise_xor>(std::forward<E1>(e1), std::forward<E2>(e2));
434 }
435
445 template <class E>
446 inline auto operator~(E&& e) noexcept -> detail::xfunction_type_t<detail::bitwise_not, E>
447 {
448 return detail::make_xfunction<detail::bitwise_not>(std::forward<E>(e));
449 }
450
461 template <class E1, class E2>
462 inline auto left_shift(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::left_shift, E1, E2>
463 {
464 return detail::make_xfunction<detail::left_shift>(std::forward<E1>(e1), std::forward<E2>(e2));
465 }
466
477 template <class E1, class E2>
478 inline auto right_shift(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::right_shift, E1, E2>
479 {
480 return detail::make_xfunction<detail::right_shift>(std::forward<E1>(e1), std::forward<E2>(e2));
481 }
482
483 namespace detail
484 {
485 // Shift operator is not available for all the types, so the xfunction type instantiation
486 // has to be delayed, enable_if_t is not sufficient
487 template <class F, class E1, class E2>
488 struct shift_function_getter
489 {
490 using type = xfunction_type_t<F, E1, E2>;
491 };
492
493 template <bool B, class T>
494 struct eval_enable_if
495 {
496 using type = typename T::type;
497 };
498
499 template <class T>
500 struct eval_enable_if<false, T>
501 {
502 };
503
504 template <bool B, class T>
505 using eval_enable_if_t = typename eval_enable_if<B, T>::type;
506
507 template <class F, class E1, class E2>
508 using shift_return_type_t = eval_enable_if_t<
509 is_xexpression<std::decay_t<E1>>::value,
510 shift_function_getter<F, E1, E2>>;
511 }
512
524 template <class E1, class E2>
525 inline auto operator<<(E1&& e1, E2&& e2) noexcept
527 {
528 return left_shift(std::forward<E1>(e1), std::forward<E2>(e2));
529 }
530
542 template <class E1, class E2>
544 {
545 return right_shift(std::forward<E1>(e1), std::forward<E2>(e2));
546 }
547
562 template <class E1, class E2>
563 inline auto operator<(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::less, E1, E2>
564 {
565 return detail::make_xfunction<detail::less>(std::forward<E1>(e1), std::forward<E2>(e2));
566 }
567
578 template <class E1, class E2>
579 inline auto operator<=(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::less_equal, E1, E2>
580 {
581 return detail::make_xfunction<detail::less_equal>(std::forward<E1>(e1), std::forward<E2>(e2));
582 }
583
594 template <class E1, class E2>
595 inline auto operator>(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::greater, E1, E2>
596 {
597 return detail::make_xfunction<detail::greater>(std::forward<E1>(e1), std::forward<E2>(e2));
598 }
599
610 template <class E1, class E2>
611 inline auto operator>=(E1&& e1, E2&& e2) noexcept
612 -> detail::xfunction_type_t<detail::greater_equal, E1, E2>
613 {
614 return detail::make_xfunction<detail::greater_equal>(std::forward<E1>(e1), std::forward<E2>(e2));
615 }
616
628 template <class E1, class E2>
629 inline std::enable_if_t<xoptional_comparable<E1, E2>::value, bool>
631 {
632 const E1& de1 = e1.derived_cast();
633 const E2& de2 = e2.derived_cast();
634 bool res = de1.dimension() == de2.dimension()
635 && std::equal(de1.shape().begin(), de1.shape().end(), de2.shape().begin());
636 auto iter1 = de1.begin();
637 auto iter2 = de2.begin();
638 auto iter_end = de1.end();
639 while (res && iter1 != iter_end)
640 {
641 res = (*iter1++ == *iter2++);
642 }
643 return res;
644 }
645
657 template <class E1, class E2>
658 inline bool operator!=(const xexpression<E1>& e1, const xexpression<E2>& e2)
659 {
660 return !(e1 == e2);
661 }
662
673 template <class E1, class E2>
674 inline auto equal(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::equal_to, E1, E2>
675 {
676 return detail::make_xfunction<detail::equal_to>(std::forward<E1>(e1), std::forward<E2>(e2));
677 }
678
689 template <class E1, class E2>
690 inline auto not_equal(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<detail::not_equal_to, E1, E2>
691 {
692 return detail::make_xfunction<detail::not_equal_to>(std::forward<E1>(e1), std::forward<E2>(e2));
693 }
694
706 template <class E1, class E2>
707 inline auto less(E1&& e1, E2&& e2) noexcept -> decltype(std::forward<E1>(e1) < std::forward<E2>(e2))
708 {
709 return std::forward<E1>(e1) < std::forward<E2>(e2);
710 }
711
723 template <class E1, class E2>
724 inline auto less_equal(E1&& e1, E2&& e2) noexcept -> decltype(std::forward<E1>(e1) <= std::forward<E2>(e2))
725 {
726 return std::forward<E1>(e1) <= std::forward<E2>(e2);
727 }
728
740 template <class E1, class E2>
741 inline auto greater(E1&& e1, E2&& e2) noexcept -> decltype(std::forward<E1>(e1) > std::forward<E2>(e2))
742 {
743 return std::forward<E1>(e1) > std::forward<E2>(e2);
744 }
745
757 template <class E1, class E2>
758 inline auto greater_equal(E1&& e1, E2&& e2) noexcept
759 -> decltype(std::forward<E1>(e1) >= std::forward<E2>(e2))
760 {
761 return std::forward<E1>(e1) >= std::forward<E2>(e2);
762 }
763
776 template <class E1, class E2, class E3>
777 inline auto where(E1&& e1, E2&& e2, E3&& e3) noexcept
778 -> detail::xfunction_type_t<detail::conditional_ternary, E1, E2, E3>
779 {
780 return detail::make_xfunction<detail::conditional_ternary>(
781 std::forward<E1>(e1),
782 std::forward<E2>(e2),
783 std::forward<E3>(e3)
784 );
785 }
786
787 namespace detail
788 {
789 template <layout_type L>
790 struct next_idx_impl;
791
792 template <>
793 struct next_idx_impl<layout_type::row_major>
794 {
795 template <class S, class I>
796 inline auto operator()(const S& shape, I& idx)
797 {
798 for (std::size_t j = shape.size(); j > 0; --j)
799 {
800 std::size_t i = j - 1;
801 if (idx[i] >= shape[i] - 1)
802 {
803 idx[i] = 0;
804 }
805 else
806 {
807 idx[i]++;
808 return idx;
809 }
810 }
811 // return empty index, happens at last iteration step, but remains unused
812 return I();
813 }
814 };
815
816 template <>
817 struct next_idx_impl<layout_type::column_major>
818 {
819 template <class S, class I>
820 inline auto operator()(const S& shape, I& idx)
821 {
822 for (std::size_t i = 0; i < shape.size(); ++i)
823 {
824 if (idx[i] >= shape[i] - 1)
825 {
826 idx[i] = 0;
827 }
828 else
829 {
830 idx[i]++;
831 return idx;
832 }
833 }
834 // return empty index, happens at last iteration step, but remains unused
835 return I();
836 }
837 };
838
839 template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S, class I>
840 inline auto next_idx(const S& shape, I& idx)
841 {
842 next_idx_impl<L> nii;
843 return nii(shape, idx);
844 }
845 }
846
855 template <class T>
856 inline auto nonzero(const T& arr)
857 {
858 auto shape = arr.shape();
859 using index_type = xindex_type_t<typename T::shape_type>;
860 using size_type = typename T::size_type;
861
862 auto idx = xtl::make_sequence<index_type>(arr.dimension(), 0);
863 std::vector<std::vector<size_type>> indices(arr.dimension());
864
865 size_type total_size = compute_size(shape);
866 for (size_type i = 0; i < total_size; i++, detail::next_idx(shape, idx))
867 {
868 if (arr.element(std::begin(idx), std::end(idx)))
869 {
870 for (std::size_t n = 0; n < indices.size(); ++n)
871 {
872 indices.at(n).push_back(idx[n]);
873 }
874 }
875 }
876
877 return indices;
878 }
879
888 template <class T>
889 inline auto where(const T& condition)
890 {
891 return nonzero(condition);
892 }
893
904 template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class T>
905 inline auto argwhere(const T& arr)
906 {
907 auto shape = arr.shape();
908 using index_type = xindex_type_t<typename T::shape_type>;
909 using size_type = typename T::size_type;
910
911 auto idx = xtl::make_sequence<index_type>(arr.dimension(), 0);
912 std::vector<index_type> indices;
913
914 size_type total_size = compute_size(shape);
915 for (size_type i = 0; i < total_size; i++, detail::next_idx<L>(shape, idx))
916 {
917 if (arr.element(std::begin(idx), std::end(idx)))
918 {
919 indices.push_back(idx);
920 }
921 }
922
923 return indices;
924 }
925
935 template <class E>
936 inline bool any(E&& e)
937 {
938 using xtype = std::decay_t<E>;
939 using value_type = typename xtype::value_type;
940 return std::any_of(
941 e.cbegin(),
942 e.cend(),
943 [](const value_type& el)
944 {
945 return el;
946 }
947 );
948 }
949
959 template <class E>
960 inline bool all(E&& e)
961 {
962 using xtype = std::decay_t<E>;
963 using value_type = typename xtype::value_type;
964 return std::all_of(
965 e.cbegin(),
966 e.cend(),
967 [](const value_type& el)
968 {
969 return el;
970 }
971 );
972 }
973
989 template <class R, class E>
990 inline auto cast(E&& e) noexcept -> detail::xfunction_type_t<typename detail::cast<R>::functor, E>
991 {
992 return detail::make_xfunction<typename detail::cast<R>::functor>(std::forward<E>(e));
993 }
994
995}
996
997#endif
auto operator+(E &&e) noexcept -> detail::xfunction_type_t< detail::identity, E >
Identity.
auto operator/(E1 &&e1, E2 &&e2) noexcept -> detail::xfunction_type_t< detail::divides, E1, E2 >
Division.
auto operator%(E1 &&e1, E2 &&e2) noexcept -> detail::xfunction_type_t< detail::modulus, E1, E2 >
Modulus.
auto operator-(E &&e) noexcept -> detail::xfunction_type_t< detail::negate, E >
Opposite.
auto operator*(E1 &&e1, E2 &&e2) noexcept -> detail::xfunction_type_t< detail::multiplies, E1, E2 >
Multiplication.
auto operator&(E1 &&e1, E2 &&e2) noexcept -> detail::xfunction_type_t< detail::bitwise_and, E1, E2 >
Bitwise and.
auto left_shift(E1 &&e1, E2 &&e2) noexcept -> detail::xfunction_type_t< detail::left_shift, E1, E2 >
Bitwise left shift.
auto right_shift(E1 &&e1, E2 &&e2) noexcept -> detail::xfunction_type_t< detail::right_shift, E1, E2 >
Bitwise left shift.
auto operator~(E &&e) noexcept -> detail::xfunction_type_t< detail::bitwise_not, E >
Bitwise not.
auto operator^(E1 &&e1, E2 &&e2) noexcept -> detail::xfunction_type_t< detail::bitwise_xor, E1, E2 >
Bitwise xor.
auto operator|(E1 &&e1, E2 &&e2) noexcept -> detail::xfunction_type_t< detail::bitwise_or, E1, E2 >
Bitwise or.
auto operator>>(E1 &&e1, E2 &&e2) -> detail::shift_return_type_t< detail::right_shift, E1, E2 >
Bitwise right shift.
auto cast(E &&e) noexcept -> detail::xfunction_type_t< typename detail::cast< R >::functor, E >
Element-wise static_cast.
auto not_equal(E1 &&e1, E2 &&e2) noexcept -> detail::xfunction_type_t< detail::not_equal_to, E1, E2 >
Element-wise inequality.
auto less(E1 &&e1, E2 &&e2) noexcept -> decltype(std::forward< E1 >(e1)< std::forward< E2 >(e2))
Lesser than.
auto equal(E1 &&e1, E2 &&e2) noexcept -> detail::xfunction_type_t< detail::equal_to, E1, E2 >
Element-wise equality.
auto greater_equal(E1 &&e1, E2 &&e2) noexcept -> decltype(std::forward< E1 >(e1) >=std::forward< E2 >(e2))
Greater or equal.
auto greater(E1 &&e1, E2 &&e2) noexcept -> decltype(std::forward< E1 >(e1) > std::forward< E2 >(e2))
Greater than.
auto less_equal(E1 &&e1, E2 &&e2) noexcept -> decltype(std::forward< E1 >(e1)<=std::forward< E2 >(e2))
Lesser or equal.
auto operator!(E &&e) noexcept -> detail::xfunction_type_t< detail::logical_not, E >
Not.
auto argwhere(const T &arr)
return vector of indices where arr is not zero
auto operator&&(E1 &&e1, E2 &&e2) noexcept -> detail::xfunction_type_t< detail::logical_and, E1, E2 >
And.
auto nonzero(const T &arr)
return vector of indices where T is not zero
auto operator||(E1 &&e1, E2 &&e2) noexcept -> detail::xfunction_type_t< detail::logical_or, E1, E2 >
Or.
auto where(E1 &&e1, E2 &&e2, E3 &&e3) noexcept -> detail::xfunction_type_t< detail::conditional_ternary, E1, E2, E3 >
Ternary selection.
auto arg(E &&e) noexcept
Calculates the phase angle (in radians) elementwise for the complex numbers in e.
Definition xcomplex.hpp:221
standard mathematical functions for xexpressions
auto all() noexcept
Returns a slice representing a full dimension, to be used as an argument of view function.
Definition xslice.hpp:234
bool operator==(const xaxis_iterator< CT > &lhs, const xaxis_iterator< CT > &rhs)
Checks equality of the iterators.
layout_type
Definition xlayout.hpp:24
bool operator!=(const xaxis_iterator< CT > &lhs, const xaxis_iterator< CT > &rhs)
Checks inequality of the iterators.