10#ifndef XTENSOR_FUNCTION_HPP
11#define XTENSOR_FUNCTION_HPP
21#include <xtl/xsequence.hpp>
22#include <xtl/xtype_traits.hpp>
24#include "xaccessible.hpp"
25#include "xexpression_traits.hpp"
26#include "xiterable.hpp"
27#include "xiterator.hpp"
31#include "xstrides.hpp"
32#include "xtensor_simd.hpp"
47 template <
class S,
class is_shape_trivial>
48 struct xfunction_cache_impl
54 xfunction_cache_impl()
55 : shape(xtl::make_sequence<S>(0, std::size_t(0)))
57 , is_initialized(false)
62 template <std::size_t... N,
class is_shape_trivial>
63 struct xfunction_cache_impl<fixed_shape<N...>, is_shape_trivial>
65 XTENSOR_CONSTEXPR_ENHANCED_STATIC fixed_shape<N...> shape = fixed_shape<N...>();
66 XTENSOR_CONSTEXPR_ENHANCED_STATIC
bool is_trivial = is_shape_trivial::value;
67 XTENSOR_CONSTEXPR_ENHANCED_STATIC
bool is_initialized =
true;
70#ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED
72 template <std::size_t... N,
class is_shape_trivial>
73 constexpr fixed_shape<N...> xfunction_cache_impl<fixed_shape<N...>, is_shape_trivial>::shape;
75 template <std::size_t... N,
class is_shape_trivial>
76 constexpr bool xfunction_cache_impl<fixed_shape<N...>, is_shape_trivial>::is_trivial;
78 template <std::size_t... N,
class is_shape_trivial>
79 constexpr bool xfunction_cache_impl<fixed_shape<N...>, is_shape_trivial>::is_initialized;
82 template <
class... CT>
83 struct xfunction_bool_load_type
85 using type = xtl::promote_type_t<typename std::decay_t<CT>::bool_load_type...>;
89 struct xfunction_bool_load_type<CT>
91 using type =
typename std::decay_t<CT>::bool_load_type;
94 template <
class... CT>
95 using xfunction_bool_load_type_t =
typename xfunction_bool_load_type<CT...>::type;
105 template <
class Tag,
class F,
class... CT>
108 template <
class F,
class...
CT>
114 template <
class F,
class...
CT>
119 template <
class F,
class...
CT>
123 template <
class promote>
124 struct xfunction_cache : detail::xfunction_cache_impl<typename promote::type, promote>
128 template <
class F,
class...
CT>
131 template <
class F,
class...
CT>
134 template <
class F,
class...
CT>
137 template <
class F,
class...
CT>
145 template <
class F,
class...
CT>
150 decltype(std::declval<F>()(std::declval<xvalue_type_t<std::decay_t<CT>>>()...))>::type;
151 using value_type = std::decay_t<func_return_type>;
152 using reference = func_return_type;
153 using const_reference = reference;
157 template <
class T,
class F,
class...
CT>
160 has_simd_apply<F, xt_simd::simd_type<T>>,
161 has_simd_interface<std::decay_t<CT>, T>...>
172 std::
enable_if_t<!has_memory_address<E>::value && is_specialization_of<xfunction, E>::value>>
174 template <std::size_t I = 0,
class... T, std::enable_if_t<(I ==
sizeof...(T)),
int> = 0>
175 static bool check_tuple(
const std::tuple<T...>&,
const memory_range&)
180 template <std::size_t I = 0,
class... T, std::enable_if_t<(I <
sizeof...(T)),
int> = 0>
183 using ChildE = std::decay_t<decltype(std::get<I>(
t))>;
190 if (
expr.size() == 0)
216 template <
class F,
class...
CT>
220 public extension::xfunction_base_t<F, CT...>
226 using extension_base = extension::xfunction_base_t<
F,
CT...>;
227 using expression_tag =
typename extension_base::expression_tag;
229 using functor_type =
typename std::remove_reference<F>::type;
230 using tuple_type = std::tuple<
CT...>;
233 using value_type =
typename inner_types::value_type;
234 using reference =
typename inner_types::reference;
235 using const_reference =
typename inner_types::const_reference;
236 using pointer = value_type*;
237 using const_pointer =
const value_type*;
238 using size_type =
typename inner_types::size_type;
241 using simd_value_type = xt_simd::simd_type<value_type>;
244 using bool_load_type = detail::xfunction_bool_load_type_t<
CT...>;
246 template <
class requested_type>
247 using simd_return_type = xt_simd::simd_return_type<value_type, requested_type>;
250 using inner_shape_type =
typename iterable_base::inner_shape_type;
251 using shape_type = inner_shape_type;
253 using stepper =
typename iterable_base::stepper;
254 using const_stepper =
typename iterable_base::const_stepper;
259 template <layout_type L>
261 template <layout_type L>
263 template <layout_type L>
265 template <layout_type L>
268 template <
class S, layout_type L>
270 template <
class S, layout_type L>
272 template <
class S, layout_type L>
274 template <
class S, layout_type L>
279 using const_reverse_linear_iterator = std::reverse_iterator<const_linear_iterator>;
280 using reverse_linear_iterator = std::reverse_iterator<linear_iterator>;
287 template <
class Func,
class...
CTA,
class U = std::enable_if_t<!std::is_base_of<std::decay_t<Func>,
self_type>::value>>
290 template <
class FA,
class...
CTA>
303 const inner_shape_type&
shape()
const;
305 bool is_contiguous()
const noexcept;
308 template <
class...
Args>
309 const_reference operator()(
Args...
args)
const;
311 template <
class...
Args>
312 const_reference unchecked(
Args...
args)
const;
314 using accessible_base::at;
315 using accessible_base::operator[];
319 using accessible_base::periodic;
330 using iterable_base::begin;
331 using iterable_base::cbegin;
332 using iterable_base::cend;
333 using iterable_base::crbegin;
334 using iterable_base::crend;
335 using iterable_base::end;
336 using iterable_base::rbegin;
337 using iterable_base::rend;
344 const_reverse_linear_iterator linear_rbegin()
const noexcept;
345 const_reverse_linear_iterator linear_rend()
const noexcept;
346 const_reverse_linear_iterator linear_crbegin()
const noexcept;
347 const_reverse_linear_iterator linear_crend()
const noexcept;
350 const_stepper stepper_begin(
const S&
shape)
const noexcept;
354 const_reference data_element(size_type
i)
const;
356 const_reference
flat(size_type
i)
const;
359 operator value_type()
const;
364 const tuple_type& arguments()
const noexcept;
366 const functor_type& functor()
const noexcept;
370 template <std::size_t... I>
371 layout_type layout_impl(std::index_sequence<I...>)
const noexcept;
373 template <std::size_t... I,
class...
Args>
374 const_reference access_impl(std::index_sequence<I...>,
Args...
args)
const;
376 template <std::size_t... I,
class...
Args>
377 const_reference unchecked_impl(std::index_sequence<I...>,
Args...
args)
const;
379 template <std::size_t... I,
class It>
380 const_reference element_access_impl(std::index_sequence<I...>,
It first,
It last)
const;
382 template <std::size_t... I>
383 const_reference data_element_impl(std::index_sequence<I...>, size_type
i)
const;
386 auto load_simd_impl(std::index_sequence<I...>, size_type
i)
const;
388 template <
class Func, std::size_t... I>
389 const_stepper build_stepper(
Func&&
f, std::index_sequence<I...>)
const noexcept;
391 template <
class Func, std::size_t... I>
392 auto build_iterator(
Func&&
f, std::index_sequence<I...>)
const noexcept;
394 size_type compute_dimension()
const noexcept;
396 void compute_cached_shape()
const;
412 template <
class F,
class...
CT>
414 xfunction_iterator<F, CT...>,
415 typename xfunction<F, CT...>::value_type,
416 typename xfunction<F, CT...>::difference_type,
417 typename xfunction<F, CT...>::pointer,
418 typename xfunction<F, CT...>::reference>
423 using functor_type =
typename std::remove_reference<F>::type;
426 using value_type =
typename xfunction_type::value_type;
427 using reference =
typename xfunction_type::value_type;
428 using pointer =
typename xfunction_type::const_pointer;
429 using difference_type =
typename xfunction_type::difference_type;
430 using iterator_category = std::random_access_iterator_tag;
432 template <
class...
It>
443 reference operator*()
const;
450 using data_type = std::tuple<
decltype(xt::linear_begin(std::declval<
const std::decay_t<CT>>()))...>;
452 template <std::size_t... I>
453 reference deref_impl(std::index_sequence<I...>)
const;
455 template <std::size_t... I>
457 tuple_max_diff(std::index_sequence<I...>,
const data_type&
lhs,
const data_type&
rhs)
const;
463 template <
class F,
class...
CT>
466 template <
class F,
class...
CT>
473 template <
class F,
class...
CT>
479 using functor_type =
typename std::remove_reference<F>::type;
482 using value_type =
typename xfunction_type::value_type;
483 using reference =
typename xfunction_type::reference;
484 using pointer =
typename xfunction_type::const_pointer;
485 using size_type =
typename xfunction_type::size_type;
488 using shape_type =
typename xfunction_type::shape_type;
490 template <
class requested_type>
491 using simd_return_type = xt_simd::simd_return_type<value_type, requested_type>;
493 template <
class...
St>
496 void step(size_type
dim);
497 void step_back(size_type
dim);
498 void step(size_type
dim, size_type
n);
499 void step_back(size_type
dim, size_type
n);
500 void reset(size_type
dim);
501 void reset_back(size_type
dim);
506 reference operator*()
const;
515 template <std::size_t... I>
516 reference deref_impl(std::index_sequence<I...>)
const;
518 template <
class T, std::size_t... I>
522 std::tuple<typename std::decay_t<CT>::const_stepper...> m_st;
539 template <
class F,
class...
CT>
540 template <
class Func,
class...
CTA,
class U>
542 : m_e(std::forward<CTA>(
e)...)
543 , m_f(std::forward<Func>(
f))
552 template <
class F,
class...
CT>
553 template <
class FA,
class...
CTA>
555 : m_e(
xf.arguments())
569 template <
class F,
class...
CT>
572 size_type dimension = m_cache.is_initialized ? m_cache.shape.size() : compute_dimension();
576 template <
class F,
class...
CT>
579 static_assert(!detail::is_fixed<shape_type>::value,
"Calling compute_cached_shape on fixed!");
582 m_cache.is_trivial = broadcast_shape(m_cache.shape,
false);
583 m_cache.is_initialized =
true;
589 template <
class F,
class... CT>
592 xtl::mpl::static_if<!detail::is_fixed<inner_shape_type>::value>(
595 if (!m_cache.is_initialized)
597 self(
this)->compute_cached_shape();
602 return m_cache.shape;
608 template <
class F,
class...
CT>
611 return layout_impl(std::make_index_sequence<
sizeof...(
CT)>());
614 template <
class F,
class...
CT>
619 [](
bool r,
const auto& exp)
621 return r && exp.is_contiguous();
640 template <
class F,
class... CT>
641 template <
class... Args>
646 return access_impl(std::make_index_sequence<
sizeof...(
CT)>(),
static_cast<size_type
>(
args)...);
658 template <
class F,
class...
CT>
661 return data_element_impl(std::make_index_sequence<
sizeof...(
CT)>(), index);
683 template <
class F,
class...
CT>
684 template <
class...
Args>
689 return unchecked_impl(std::make_index_sequence<
sizeof...(
CT)>(),
static_cast<size_type
>(
args)...);
699 template <
class F,
class...
CT>
703 return element_access_impl(std::make_index_sequence<
sizeof...(
CT)>(),
first,
last);
718 template <
class F,
class...
CT>
724 std::copy(m_cache.shape.cbegin(), m_cache.shape.cend(), shape.begin());
725 return m_cache.is_trivial;
730 auto func = [&shape](
bool b,
auto&&
e)
732 return e.broadcast_shape(shape) &&
b;
743 template <
class F,
class...
CT>
749 return b &&
e.has_linear_assign(
strides);
756 template <
class F,
class...
CT>
759 return linear_cbegin();
762 template <
class F,
class... CT>
763 inline auto xfunction<F, CT...>::linear_end() const noexcept -> const_linear_iterator
765 return linear_cend();
768 template <
class F,
class... CT>
769 inline auto xfunction<F, CT...>::linear_cbegin() const noexcept -> const_linear_iterator
771 auto f = [](
const auto& e)
noexcept
773 return xt::linear_begin(e);
775 return build_iterator(f, std::make_index_sequence<
sizeof...(CT)>());
778 template <
class F,
class... CT>
779 inline auto xfunction<F, CT...>::linear_cend() const noexcept -> const_linear_iterator
781 auto f = [](
const auto& e)
noexcept
783 return xt::linear_end(e);
785 return build_iterator(f, std::make_index_sequence<
sizeof...(CT)>());
788 template <
class F,
class... CT>
789 inline auto xfunction<F, CT...>::linear_rbegin() const noexcept -> const_reverse_linear_iterator
791 return linear_crbegin();
794 template <
class F,
class... CT>
795 inline auto xfunction<F, CT...>::linear_rend() const noexcept -> const_reverse_linear_iterator
797 return linear_crend();
800 template <
class F,
class... CT>
801 inline auto xfunction<F, CT...>::linear_crbegin() const noexcept -> const_reverse_linear_iterator
803 return const_reverse_linear_iterator(linear_cend());
806 template <
class F,
class... CT>
807 inline auto xfunction<F, CT...>::linear_crend() const noexcept -> const_reverse_linear_iterator
809 return const_reverse_linear_iterator(linear_cbegin());
812 template <
class F,
class... CT>
814 inline auto xfunction<F, CT...>::stepper_begin(
const S& shape)
const noexcept -> const_stepper
816 auto f = [&shape](
const auto& e)
noexcept
818 return e.stepper_begin(shape);
820 return build_stepper(f, std::make_index_sequence<
sizeof...(CT)>());
823 template <
class F,
class... CT>
825 inline auto xfunction<F, CT...>::stepper_end(
const S& shape,
layout_type l)
const noexcept -> const_stepper
827 auto f = [&shape, l](
const auto& e)
noexcept
829 return e.stepper_end(shape, l);
831 return build_stepper(f, std::make_index_sequence<
sizeof...(CT)>());
834 template <
class F,
class... CT>
835 inline auto xfunction<F, CT...>::data_element(size_type i)
const -> const_reference
837 return data_element_impl(std::make_index_sequence<
sizeof...(CT)>(), i);
840 template <
class F,
class... CT>
841 template <
class UT,
class>
842 inline xfunction<F, CT...>::operator value_type()
const
847 template <
class F,
class... CT>
848 template <
class align,
class requested_type, std::
size_t N>
849 inline auto xfunction<F, CT...>::load_simd(size_type i)
const -> simd_return_type<requested_type>
851 return load_simd_impl<align, requested_type, N>(std::make_index_sequence<
sizeof...(CT)>(), i);
854 template <
class F,
class... CT>
855 inline auto xfunction<F, CT...>::arguments() const noexcept -> const tuple_type&
860 template <
class F,
class... CT>
861 inline auto xfunction<F, CT...>::functor() const noexcept -> const functor_type&
866 template <
class F,
class... CT>
867 template <std::size_t... I>
868 inline layout_type xfunction<F, CT...>::layout_impl(std::index_sequence<I...>)
const noexcept
873 template <
class F,
class... CT>
874 template <std::size_t... I,
class... Args>
875 inline auto xfunction<F, CT...>::access_impl(std::index_sequence<I...>, Args... args)
const
878 XTENSOR_TRY(check_index(shape(), args...));
879 XTENSOR_CHECK_DIMENSION(shape(), args...);
880 return m_f(std::get<I>(m_e)(args...)...);
883 template <
class F,
class... CT>
884 template <std::size_t... I,
class... Args>
885 inline auto xfunction<F, CT...>::unchecked_impl(std::index_sequence<I...>, Args... args)
const
888 return m_f(std::get<I>(m_e).unchecked(args...)...);
891 template <
class F,
class... CT>
892 template <std::size_t... I,
class It>
893 inline auto xfunction<F, CT...>::element_access_impl(std::index_sequence<I...>, It first, It last)
const
896 XTENSOR_TRY(check_element_index(shape(), first, last));
897 return m_f((std::get<I>(m_e).element(first, last))...);
900 template <
class F,
class... CT>
901 template <std::size_t... I>
902 inline auto xfunction<F, CT...>::data_element_impl(std::index_sequence<I...>, size_type i)
const
905 return m_f((std::get<I>(m_e).data_element(i))...);
908 template <
class F,
class... CT>
909 template <
class align,
class requested_type, std::size_t N, std::size_t... I>
910 inline auto xfunction<F, CT...>::load_simd_impl(std::index_sequence<I...>, size_type i)
const
912 return m_f.simd_apply((std::get<I>(m_e).
template load_simd<align, requested_type>(i))...);
915 template <
class F,
class... CT>
916 template <
class Func, std::size_t... I>
917 inline auto xfunction<F, CT...>::build_stepper(Func&& f, std::index_sequence<I...>)
const noexcept
920 return const_stepper(
this, f(std::get<I>(m_e))...);
923 template <
class F,
class... CT>
924 template <
class Func, std::size_t... I>
925 inline auto xfunction<F, CT...>::build_iterator(Func&& f, std::index_sequence<I...>)
const noexcept
927 return const_linear_iterator(
this, f(std::get<I>(m_e))...);
930 template <
class F,
class... CT>
931 inline auto xfunction<F, CT...>::compute_dimension() const noexcept -> size_type
933 auto func = [](size_type d,
auto&& e)
noexcept
935 return (std::max)(d, e.dimension());
944 template <
class F,
class... CT>
945 template <
class... It>
946 inline xfunction_iterator<F, CT...>::xfunction_iterator(
const xfunction_type* func, It&&... it) noexcept
948 , m_it(std::forward<It>(it)...)
952 template <
class F,
class... CT>
953 inline auto xfunction_iterator<F, CT...>::operator++() -> self_type&
955 auto f = [](
auto& it)
963 template <
class F,
class... CT>
964 inline auto xfunction_iterator<F, CT...>::operator--() -> self_type&
966 auto f = [](
auto& it)
974 template <
class F,
class... CT>
975 inline auto xfunction_iterator<F, CT...>::operator+=(difference_type n) -> self_type&
977 auto f = [n](
auto& it)
985 template <
class F,
class... CT>
986 inline auto xfunction_iterator<F, CT...>::operator-=(difference_type n) -> self_type&
988 auto f = [n](
auto& it)
996 template <
class F,
class... CT>
997 inline auto xfunction_iterator<F, CT...>::operator-(
const self_type& rhs)
const -> difference_type
999 return tuple_max_diff(std::make_index_sequence<
sizeof...(CT)>(), m_it, rhs.m_it);
1002 template <
class F,
class... CT>
1003 inline auto xfunction_iterator<F, CT...>::operator*() const -> reference
1005 return deref_impl(std::make_index_sequence<
sizeof...(CT)>());
1008 template <
class F,
class... CT>
1009 inline bool xfunction_iterator<F, CT...>::equal(
const self_type& rhs)
const
1013 constexpr std::size_t temp = xtl::mpl::find_if<is_not_xdummy_iterator, data_type>::value;
1014 constexpr std::size_t index = (temp == std::tuple_size<data_type>::value) ? 0 : temp;
1015 return std::get<index>(m_it) == std::get<index>(rhs.m_it);
1018 template <
class F,
class... CT>
1019 inline bool xfunction_iterator<F, CT...>::less_than(
const self_type& rhs)
const
1023 constexpr std::size_t temp = xtl::mpl::find_if<is_not_xdummy_iterator, data_type>::value;
1024 constexpr std::size_t index = (temp == std::tuple_size<data_type>::value) ? 0 : temp;
1025 return std::get<index>(m_it) < std::get<index>(rhs.m_it);
1028 template <
class F,
class... CT>
1029 template <std::size_t... I>
1030 inline auto xfunction_iterator<F, CT...>::deref_impl(std::index_sequence<I...>)
const -> reference
1032 return (p_f->m_f)(*std::get<I>(m_it)...);
1035 template <
class F,
class... CT>
1036 template <std::size_t... I>
1037 inline auto xfunction_iterator<F, CT...>::tuple_max_diff(
1038 std::index_sequence<I...>,
1039 const data_type& lhs,
1040 const data_type& rhs
1041 )
const -> difference_type
1043 auto diff = std::make_tuple((std::get<I>(lhs) - std::get<I>(rhs))...);
1044 auto func = [](difference_type n,
auto&& v)
1046 return (std::max)(n, v);
1051 template <
class F,
class... CT>
1052 inline bool operator==(
const xfunction_iterator<F, CT...>& it1,
const xfunction_iterator<F, CT...>& it2)
1054 return it1.equal(it2);
1057 template <
class F,
class... CT>
1058 inline bool operator<(
const xfunction_iterator<F, CT...>& it1,
const xfunction_iterator<F, CT...>& it2)
1060 return it1.less_than(it2);
1067 template <
class F,
class... CT>
1068 template <
class... St>
1069 inline xfunction_stepper<F, CT...>::xfunction_stepper(
const xfunction_type* func, St&&... st) noexcept
1071 , m_st(std::forward<St>(st)...)
1075 template <
class F,
class... CT>
1076 inline void xfunction_stepper<F, CT...>::step(size_type dim)
1078 auto f = [dim](
auto& st)
1085 template <
class F,
class... CT>
1086 inline void xfunction_stepper<F, CT...>::step_back(size_type dim)
1088 auto f = [dim](
auto& st)
1095 template <
class F,
class... CT>
1096 inline void xfunction_stepper<F, CT...>::step(size_type dim, size_type n)
1098 auto f = [dim, n](
auto& st)
1105 template <
class F,
class... CT>
1106 inline void xfunction_stepper<F, CT...>::step_back(size_type dim, size_type n)
1108 auto f = [dim, n](
auto& st)
1110 st.step_back(dim, n);
1115 template <
class F,
class... CT>
1116 inline void xfunction_stepper<F, CT...>::reset(size_type dim)
1118 auto f = [dim](
auto& st)
1125 template <
class F,
class... CT>
1126 inline void xfunction_stepper<F, CT...>::reset_back(size_type dim)
1128 auto f = [dim](
auto& st)
1135 template <
class F,
class... CT>
1136 inline void xfunction_stepper<F, CT...>::to_begin()
1138 auto f = [](
auto& st)
1145 template <
class F,
class... CT>
1146 inline void xfunction_stepper<F, CT...>::to_end(
layout_type l)
1148 auto f = [l](
auto& st)
1155 template <
class F,
class... CT>
1156 inline auto xfunction_stepper<F, CT...>::operator*() const -> reference
1158 return deref_impl(std::make_index_sequence<
sizeof...(CT)>());
1161 template <
class F,
class... CT>
1162 template <std::size_t... I>
1163 inline auto xfunction_stepper<F, CT...>::deref_impl(std::index_sequence<I...>)
const -> reference
1165 return (p_f->m_f)(*std::get<I>(m_st)...);
1168 template <
class F,
class... CT>
1169 template <
class T, std::size_t... I>
1170 inline auto xfunction_stepper<F, CT...>::step_simd_impl(std::index_sequence<I...>) -> simd_return_type<T>
1172 return (p_f->m_f.simd_apply)(std::get<I>(m_st).template step_simd<T>()...);
1175 template <
class F,
class... CT>
1177 inline auto xfunction_stepper<F, CT...>::step_simd() -> simd_return_type<T>
1179 return step_simd_impl<T>(std::make_index_sequence<
sizeof...(CT)>());
1182 template <
class F,
class... CT>
1183 inline void xfunction_stepper<F, CT...>::step_leading()
1185 auto step_leading_lambda = [](
auto&& st)
1189 for_each(step_leading_lambda, m_st);
Base class for implementation of common expression constant access methods.
const_reference front() const
Returns a constant reference to first the element of the expression.
size_type size() const noexcept
Returns the size of the expression.
bool in_bounds(Args... args) const
Returns true only if the the specified position is a valid entry in the expression.
const_reference back() const
Returns a constant reference to last the element of the expression.
size_type shape(size_type index) const
Returns the i-th dimension of the expression.
Base class for multidimensional iterable constant expressions.
Multidimensional function operating on xtensor expressions.
bool broadcast_shape(S &shape, bool reuse_cache=false) const
Broadcast the shape of the function to the specified parameter.
layout_type layout() const noexcept
Returns the layout_type of the xfunction.
const inner_shape_type & shape() const
Returns the shape of the xfunction.
size_type dimension() const noexcept
Returns the number of dimensions of the function.
xfunction(Func &&f, CTA &&... e) noexcept
Constructs an xfunction applying the specified function to the given arguments.
bool has_linear_assign(const S &strides) const noexcept
Checks whether the xfunction can be linearly assigned to an expression with the specified strides.
const_reference flat(size_type i) const
Returns a constant reference to the element at the specified position of the underlying contiguous st...
auto diff(const xexpression< T > &a, std::size_t n=1, std::ptrdiff_t axis=-1)
Calculate the n-th discrete difference along the given axis.
auto strides(const E &e, stride_type type=stride_type::normal) noexcept
Get strides of an object.
standard mathematical functions for xexpressions
constexpr layout_type compute_layout(Args... args) noexcept
Implementation of the following logical table:
bool operator==(const xaxis_iterator< CT > &lhs, const xaxis_iterator< CT > &rhs)
Checks equality of the iterators.
auto accumulate(F &&f, E &&e, EVS evaluation_strategy=EVS())
Accumulate and flatten array NOTE This function is not lazy!