10#ifndef XTENSOR_ACCUMULATOR_HPP
11#define XTENSOR_ACCUMULATOR_HPP
18#include "xexpression.hpp"
19#include "xstrides.hpp"
20#include "xtensor_config.hpp"
21#include "xtensor_forward.hpp"
26#define DEFAULT_STRATEGY_ACCUMULATORS evaluation_strategy::immediate_type
30 template <
class V =
void>
31 struct accumulator_identity : xtl::identity
41 template <
class ACCUMULATE_FUNC,
class INIT_FUNC = detail::accumulator_
identity<
void>>
45 using base_type = std::tuple<ACCUMULATE_FUNC, INIT_FUNC>;
46 using accumulate_functor_type = ACCUMULATE_FUNC;
47 using init_functor_type = INIT_FUNC;
48 using init_value_type =
typename init_functor_type::value_type;
57 : base_type(std::forward<RF>(accumulate_func), INIT_FUNC())
61 template <
class RF,
class IF>
63 : base_type(std::forward<RF>(accumulate_func), std::forward<IF>(init_func))
69 auto make_xaccumulator_functor(RF&& accumulate_func)
72 return accumulator_type(std::forward<RF>(accumulate_func));
75 template <
class RF,
class IF>
76 auto make_xaccumulator_functor(RF&& accumulate_func, IF&& init_func)
78 using accumulator_type = xaccumulator_functor<std::remove_reference_t<RF>, std::remove_reference_t<IF>>;
79 return accumulator_type(std::forward<RF>(accumulate_func), std::forward<IF>(init_func));
84 template <
class F,
class E,
class EVS>
85 xarray<typename std::decay_t<E>::value_type> accumulator_impl(F&&, E&&, std::size_t, EVS)
88 !std::is_same<evaluation_strategy::lazy_type, EVS>::value,
89 "Lazy accumulators not yet implemented."
93 template <
class F,
class E,
class EVS>
94 xarray<typename std::decay_t<E>::value_type> accumulator_impl(F&&, E&&, EVS)
97 !std::is_same<evaluation_strategy::lazy_type, EVS>::value,
98 "Lazy accumulators not yet implemented."
102 template <
class T,
class R>
103 struct xaccumulator_return_type
105 using type = xarray<R>;
108 template <
class T, layout_type L,
class R>
109 struct xaccumulator_return_type<
xarray<T, L>, R>
111 using type = xarray<R, L>;
114 template <
class T, std::
size_t N, layout_type L,
class R>
115 struct xaccumulator_return_type<
xtensor<T, N, L>, R>
117 using type = xtensor<R, N, L>;
120 template <
class T, std::size_t... I,
layout_type L,
class R>
126 template <
class T,
class R>
127 using xaccumulator_return_type_t =
typename xaccumulator_return_type<T, R>::type;
130 struct fixed_compute_size;
132 template <
class T,
class R>
133 struct xaccumulator_linear_return_type
135 using type = xtensor<R, 1>;
138 template <
class T, layout_type L,
class R>
139 struct xaccumulator_linear_return_type<
xarray<T, L>, R>
141 using type = xtensor<R, 1, L>;
144 template <
class T, std::
size_t N, layout_type L,
class R>
145 struct xaccumulator_linear_return_type<
xtensor<T, N, L>, R>
147 using type = xtensor<R, 1, L>;
150 template <
class T, std::size_t... I,
layout_type L,
class R>
156 template <
class T,
class R>
157 using xaccumulator_linear_return_type_t =
typename xaccumulator_linear_return_type<T, R>::type;
159 template <
class F,
class E>
160 inline auto accumulator_init_with_f(F&& f, E& e, std::size_t axis)
166 std::size_t outer_loop_size, inner_loop_size, pos = 0;
167 std::size_t outer_stride, inner_stride;
169 auto set_loop_sizes = [&outer_loop_size, &inner_loop_size](
auto first,
auto last, std::ptrdiff_t ax)
171 outer_loop_size = std::accumulate(
175 std::multiplies<std::size_t>()
177 inner_loop_size = std::accumulate(
181 std::multiplies<std::size_t>()
186 auto set_loop_strides = [&outer_stride, &inner_stride](
auto first,
auto last, std::ptrdiff_t ax)
188 outer_stride =
static_cast<std::size_t
>(ax == 0 ? 1 : *std::min_element(first, first + ax));
189 inner_stride =
static_cast<std::size_t
>(
190 (ax == std::distance(first, last) - 1) ? 1 : *std::min_element(first + ax + 1, last)
194 set_loop_sizes(e.shape().begin(), e.shape().end(),
static_cast<std::ptrdiff_t
>(axis));
195 set_loop_strides(e.strides().begin(), e.strides().end(),
static_cast<std::ptrdiff_t
>(axis));
200 std::swap(outer_loop_size, inner_loop_size);
201 std::swap(outer_stride, inner_stride);
204 for (std::size_t i = 0; i < outer_loop_size; ++i)
206 pos = i * outer_stride;
207 for (std::size_t j = 0; j < inner_loop_size; ++j)
209 e.storage()[pos] = f(e.storage()[pos]);
215 template <
class F,
class E>
216 inline auto accumulator_impl(F&& f, E&& e, std::size_t axis, evaluation_strategy::immediate_type)
218 using init_type =
typename F::init_value_type;
219 using accumulate_functor_type =
typename F::accumulate_functor_type;
220 using expr_value_type =
typename std::decay_t<E>::value_type;
224 using return_type = std::decay_t<decltype(std::declval<accumulate_functor_type>()(
225 std::declval<init_type>(),
226 std::declval<expr_value_type>()
229 using result_type = xaccumulator_return_type_t<std::decay_t<E>, return_type>;
231 if (axis >= e.dimension())
233 XTENSOR_THROW(std::runtime_error,
"Axis larger than expression dimension in accumulator.");
238 if (res.shape(axis) != std::size_t(0))
240 std::size_t inner_stride =
static_cast<std::size_t
>(res.strides()[axis]);
241 std::size_t outer_stride = 1;
242 std::size_t outer_loop_size = 0;
243 std::size_t inner_loop_size = 0;
244 std::size_t init_size = e.shape()[axis] != std::size_t(1) ? std::size_t(1) : std::size_t(0);
246 auto set_loop_sizes =
247 [&outer_loop_size, &inner_loop_size, init_size](
auto first,
auto last, std::ptrdiff_t ax)
249 outer_loop_size = std::accumulate(first, first + ax, init_size, std::multiplies<std::size_t>());
251 inner_loop_size = std::accumulate(
255 std::multiplies<std::size_t>()
261 set_loop_sizes(res.shape().cbegin(), res.shape().cend(),
static_cast<std::ptrdiff_t
>(axis));
265 set_loop_sizes(res.shape().cbegin(), res.shape().cend(),
static_cast<std::ptrdiff_t
>(axis + 1));
266 std::swap(inner_loop_size, outer_loop_size);
271 inner_loop_size = inner_loop_size - inner_stride;
275 std::decay_t<typename F::init_functor_type>,
276 typename detail::accumulator_identity<init_type>>::value)
278 accumulator_init_with_f(
xt::get<1>(f), res, axis);
282 for (std::size_t i = 0; i < outer_loop_size; ++i)
284 for (std::size_t j = 0; j < inner_loop_size; ++j)
286 res.storage()[pos + inner_stride] =
xt::get<0>(f)(
288 res.storage()[pos + inner_stride]
299 template <
class F,
class E>
300 inline auto accumulator_impl(F&& f, E&& e, evaluation_strategy::immediate_type)
302 using init_type =
typename F::init_value_type;
303 using expr_value_type =
typename std::decay_t<E>::value_type;
304 using accumulate_functor_type =
typename F::accumulate_functor_type;
305 using return_type = std::decay_t<decltype(std::declval<accumulate_functor_type>()(
306 std::declval<init_type>(),
307 std::declval<expr_value_type>()
312 using result_type = xaccumulator_return_type_t<std::decay_t<E>, return_type>;
314 std::size_t sz = e.size();
315 auto result = result_type::from_shape({sz});
317 if (sz != std::size_t(0))
319 auto it = e.template begin<XTENSOR_DEFAULT_TRAVERSAL>();
323 for (std::size_t idx = 0; it != e.template end<XTENSOR_DEFAULT_TRAVERSAL>(); ++it)
325 result.storage()[idx + 1] =
xt::get<0>(f)(result.storage()[idx], *it);
343 template <
class F,
class E,
class EVS = DEFAULT_STRATEGY_ACCUMULATORS, XTL_REQUIRES(is_evaluation_strategy<EVS>)>
348 return detail::accumulator_impl(std::forward<F>(
f), std::forward<E>(
e), evaluation_strategy);
362 template <
class F,
class E,
class EVS = DEFAULT_STRATEGY_ACCUMULATORS>
365 std::size_t
ax = normalize_axis(
e.dimension(), axis);
366 return detail::accumulator_impl(std::forward<F>(
f), std::forward<E>(
e),
ax, evaluation_strategy);
standard mathematical functions for xexpressions
xtensor_container< uvector< T, A >, N, L > xtensor
Alias template on xtensor_container with default parameters for data container type.
xarray_container< uvector< T, A >, L, xt::svector< typename uvector< T, A >::size_type, 4, SA, true > > xarray
Alias template on xarray_container with default parameters for data container type and shape / stride...
auto accumulate(F &&f, E &&e, EVS evaluation_strategy=EVS())
Accumulate and flatten array NOTE This function is not lazy!
fixed_shape< N... > xshape
Alias template for fixed_shape allows for a shorter template shape definition in xtensor_fixed.
xfixed_container< T, FSH, L, Sharable > xtensor_fixed
Alias template on xfixed_container with default parameters for layout type.