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