xrepeat.hpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  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. #ifndef XTENSOR_XREPEAT
  10. #define XTENSOR_XREPEAT
  11. #include <utility>
  12. #include <vector>
  13. #include "xaccessible.hpp"
  14. #include "xexpression.hpp"
  15. #include "xiterable.hpp"
  16. namespace xt
  17. {
  18. template <class CT, class R>
  19. class xrepeat;
  20. template <class S, class R>
  21. class xrepeat_stepper;
  22. /*********************
  23. * xrepeat extension *
  24. *********************/
  25. namespace extension
  26. {
  27. template <class Tag, class CT, class X>
  28. struct xrepeat_base_impl;
  29. template <class CT, class X>
  30. struct xrepeat_base_impl<xtensor_expression_tag, CT, X>
  31. {
  32. using type = xtensor_empty_base;
  33. };
  34. template <class CT, class X>
  35. struct xrepeat_base : xrepeat_base_impl<xexpression_tag_t<CT>, CT, X>
  36. {
  37. };
  38. template <class CT, class X>
  39. using xrepeat_base_t = typename xrepeat_base<CT, X>::type;
  40. }
  41. /***********
  42. * xrepeat *
  43. ***********/
  44. template <class CT, class R>
  45. struct xcontainer_inner_types<xrepeat<CT, R>>
  46. {
  47. using xexpression_type = std::decay_t<CT>;
  48. using reference = typename xexpression_type::const_reference;
  49. using const_reference = typename xexpression_type::const_reference;
  50. using size_type = typename xexpression_type::size_type;
  51. using temporary_type = typename xexpression_type::temporary_type;
  52. static constexpr bool is_const = std::is_const<std::remove_reference_t<CT>>::value;
  53. using extract_storage_type = xtl::mpl::eval_if_t<
  54. has_data_interface<xexpression_type>,
  55. detail::expr_storage_type<xexpression_type>,
  56. make_invalid_type<>>;
  57. using storage_type = std::conditional_t<is_const, const extract_storage_type, extract_storage_type>;
  58. };
  59. template <class CT, class R>
  60. struct xiterable_inner_types<xrepeat<CT, R>>
  61. {
  62. using xexpression_type = std::decay_t<CT>;
  63. using repeats_type = std::decay_t<R>;
  64. using inner_shape_type = typename xexpression_type::inner_shape_type;
  65. using const_stepper = xrepeat_stepper<typename xexpression_type::const_stepper, repeats_type>;
  66. using stepper = const_stepper;
  67. };
  68. /**
  69. * @class xrepeat
  70. * @brief Expression with repeated values along an axis.
  71. *
  72. * The xrepeat class implements the repetition of the elements of
  73. * an \ref xexpression along a given axis. xrepeat is not meant
  74. * to be used directly, but only with the \ref repeat helper
  75. * functions.
  76. *
  77. * @sa repeat
  78. */
  79. template <class CT, class R>
  80. class xrepeat : public xconst_iterable<xrepeat<CT, R>>,
  81. public xconst_accessible<xrepeat<CT, R>>,
  82. public xsharable_expression<xrepeat<CT, R>>,
  83. public extension::xrepeat_base_t<CT, R>
  84. {
  85. public:
  86. using self_type = xrepeat<CT, R>;
  87. using xexpression_type = std::decay_t<CT>;
  88. using accessible_base = xconst_accessible<self_type>;
  89. using extension_base = extension::xrepeat_base_t<CT, R>;
  90. using expression_tag = typename extension_base::expression_tag;
  91. using value_type = typename xexpression_type::value_type;
  92. using shape_type = typename xexpression_type::shape_type;
  93. using repeats_type = xtl::const_closure_type_t<R>;
  94. using container_type = xcontainer_inner_types<xrepeat<CT, R>>;
  95. using reference = typename container_type::reference;
  96. using const_reference = typename container_type::const_reference;
  97. using size_type = typename container_type::size_type;
  98. using temporary_type = typename container_type::temporary_type;
  99. static constexpr layout_type static_layout = xexpression_type::static_layout;
  100. static constexpr bool contiguous_layout = false;
  101. using bool_load_type = typename xexpression_type::bool_load_type;
  102. using pointer = typename xexpression_type::pointer;
  103. using const_pointer = typename xexpression_type::const_pointer;
  104. using difference_type = typename xexpression_type::difference_type;
  105. using iterable_type = xiterable<xrepeat<CT, R>>;
  106. using stepper = typename iterable_type::stepper;
  107. using const_stepper = typename iterable_type::const_stepper;
  108. template <class CTA>
  109. explicit xrepeat(CTA&& e, R&& repeats, size_type axis);
  110. using accessible_base::size;
  111. const shape_type& shape() const noexcept;
  112. layout_type layout() const noexcept;
  113. bool is_contiguous() const noexcept;
  114. using accessible_base::shape;
  115. template <class... Args>
  116. const_reference operator()(Args... args) const;
  117. template <class... Args>
  118. const_reference unchecked(Args... args) const;
  119. template <class It>
  120. const_reference element(It first, It last) const;
  121. const xexpression_type& expression() const noexcept;
  122. template <class S>
  123. bool broadcast_shape(S& shape, bool reuse_cache = false) const;
  124. template <class S>
  125. bool has_linear_assign(const S& strides) const noexcept;
  126. const_stepper stepper_begin() const;
  127. const_stepper stepper_begin(const shape_type& s) const;
  128. const_stepper stepper_end(layout_type l) const;
  129. const_stepper stepper_end(const shape_type& s, layout_type l) const;
  130. private:
  131. CT m_e;
  132. size_type m_repeating_axis;
  133. repeats_type m_repeats;
  134. shape_type m_shape;
  135. const_reference access() const;
  136. template <class Arg, class... Args>
  137. const_reference access(Arg arg, Args... args) const;
  138. template <std::size_t I, class Arg, class... Args>
  139. const_reference access_impl(stepper&& s, Arg arg, Args... args) const;
  140. template <std::size_t I>
  141. const_reference access_impl(stepper&& s) const;
  142. };
  143. /*******************
  144. * xrepeat_stepper *
  145. *******************/
  146. template <class S, class R>
  147. class xrepeat_stepper
  148. {
  149. public:
  150. using repeats_type = R;
  151. using storage_type = typename S::storage_type;
  152. using subiterator_type = typename S::subiterator_type;
  153. using subiterator_traits = typename S::subiterator_traits;
  154. using value_type = typename subiterator_traits::value_type;
  155. using reference = typename subiterator_traits::reference;
  156. using pointer = typename subiterator_traits::pointer;
  157. using difference_type = typename subiterator_traits::difference_type;
  158. using size_type = typename storage_type::size_type;
  159. using shape_type = typename storage_type::shape_type;
  160. using simd_value_type = xt_simd::simd_type<value_type>;
  161. template <class requested_type>
  162. using simd_return_type = xt_simd::simd_return_type<value_type, requested_type>;
  163. xrepeat_stepper(S&& s, const shape_type& shape, const repeats_type& repeats, size_type axis);
  164. reference operator*() const;
  165. void step(size_type dim, size_type n = 1);
  166. void step_back(size_type dim, size_type n = 1);
  167. void reset(size_type dim);
  168. void reset_back(size_type dim);
  169. void to_begin();
  170. void to_end(layout_type l);
  171. template <class T>
  172. simd_return_type<T> step_simd();
  173. void step_leading();
  174. template <class V>
  175. void store_simd(const V& vec);
  176. private:
  177. S m_substepper;
  178. const shape_type& m_shape;
  179. std::ptrdiff_t m_repeating_steps;
  180. std::vector<size_type> m_positions;
  181. size_type m_subposition;
  182. size_type m_repeating_axis;
  183. const repeats_type& m_repeats;
  184. void make_step(size_type dim, size_type n);
  185. void make_step_back(size_type dim, size_type n);
  186. std::vector<size_type> get_next_positions(size_type dim, size_type steps_to_go) const;
  187. std::vector<size_type> get_next_positions_back(size_type dim, size_type steps_to_go) const;
  188. };
  189. /**************************
  190. * xrepeat implementation *
  191. **************************/
  192. /**
  193. * Constructs an xrepeat expression repeating the element of the specified
  194. * \ref xexpression.
  195. *
  196. * @param e the input expression
  197. * @param repeats The number of repetitions for each elements
  198. * @param axis The axis along which to repeat the value
  199. */
  200. template <class CT, class R>
  201. template <class CTA>
  202. xrepeat<CT, R>::xrepeat(CTA&& e, R&& repeats, size_type axis)
  203. : m_e(std::forward<CTA>(e))
  204. , m_repeating_axis(axis)
  205. , m_repeats(std::forward<R>(repeats))
  206. , m_shape(e.shape())
  207. {
  208. using shape_value_type = typename shape_type::value_type;
  209. m_shape[axis] = static_cast<shape_value_type>(
  210. std::accumulate(m_repeats.begin(), m_repeats.end(), shape_value_type(0))
  211. );
  212. }
  213. /**
  214. * @name Size and shape
  215. */
  216. //@{
  217. /**
  218. * Returns the shape of the expression.
  219. */
  220. template <class CT, class R>
  221. inline auto xrepeat<CT, R>::shape() const noexcept -> const shape_type&
  222. {
  223. return m_shape;
  224. }
  225. /**
  226. * Returns the layout_type of the expression.
  227. */
  228. template <class CT, class R>
  229. inline auto xrepeat<CT, R>::layout() const noexcept -> layout_type
  230. {
  231. return m_e.layout();
  232. }
  233. template <class CT, class R>
  234. inline bool xrepeat<CT, R>::is_contiguous() const noexcept
  235. {
  236. return false;
  237. }
  238. //@}
  239. /**
  240. * @name Data
  241. */
  242. //@{
  243. /**
  244. * Returns a constant reference to the element at the specified position in the expression.
  245. * @param args a list of indices specifying the position in the function. Indices
  246. * must be unsigned integers, the number of indices should be equal or greater than
  247. * the number of dimensions of the expression.
  248. */
  249. template <class CT, class R>
  250. template <class... Args>
  251. inline auto xrepeat<CT, R>::operator()(Args... args) const -> const_reference
  252. {
  253. return access(args...);
  254. }
  255. /**
  256. * Returns a constant reference to the element at the specified position in the expression.
  257. * @param args a list of indices specifying the position in the expression. Indices
  258. * must be unsigned integers, the number of indices must be equal to the number of
  259. * dimensions of the expression, else the behavior is undefined.
  260. *
  261. * @warning This method is meant for performance, for expressions with a dynamic
  262. * number of dimensions (i.e. not known at compile time). Since it may have
  263. * undefined behavior (see parameters), operator() should be preferred whenever
  264. * it is possible.
  265. * @warning This method is NOT compatible with broadcasting, meaning the following
  266. * code has undefined behavior:
  267. * @code{.cpp}
  268. * xt::xarray<double> a = {{0, 1}, {2, 3}};
  269. * xt::xarray<double> b = {0, 1};
  270. * auto fd = a + b;
  271. * double res = fd.uncheked(0, 1);
  272. * @endcode
  273. */
  274. template <class CT, class R>
  275. template <class... Args>
  276. inline auto xrepeat<CT, R>::unchecked(Args... args) const -> const_reference
  277. {
  278. return this->operator()(args...);
  279. }
  280. /**
  281. * Returns a constant reference to the element at the specified position in the view.
  282. * @param first iterator starting the sequence of indices
  283. * @param last iterator ending the sequence of indices
  284. * The number of indices in the sequence should be equal to or greater than the the number
  285. * of dimensions of the view..
  286. */
  287. template <class CT, class R>
  288. template <class It>
  289. inline auto xrepeat<CT, R>::element(It first, It last) const -> const_reference
  290. {
  291. auto s = stepper_begin(m_e.shape());
  292. std::size_t dimension = 0;
  293. auto iter = first;
  294. while (iter != last)
  295. {
  296. s.step(dimension, *iter);
  297. ++dimension;
  298. ++iter;
  299. }
  300. return access_impl<0>(std::forward<stepper>(s));
  301. }
  302. /**
  303. * Returns a constant reference to the underlying expression of the broadcast expression.
  304. */
  305. template <class CT, class R>
  306. inline auto xrepeat<CT, R>::expression() const noexcept -> const xexpression_type&
  307. {
  308. return m_e;
  309. }
  310. //@}
  311. /**
  312. * @name Broadcasting
  313. */
  314. //@{
  315. /**
  316. * Broadcast the shape of the function to the specified parameter.
  317. * @param shape the result shape
  318. * @param reuse_cache parameter for internal optimization
  319. * @return a boolean indicating whether the broadcasting is trivial
  320. */
  321. template <class CT, class R>
  322. template <class S>
  323. inline bool xrepeat<CT, R>::broadcast_shape(S& shape, bool) const
  324. {
  325. return xt::broadcast_shape(m_shape, shape);
  326. }
  327. /**
  328. * Checks whether the xbroadcast can be linearly assigned to an expression
  329. * with the specified strides.
  330. * @return a boolean indicating whether a linear assign is possible
  331. */
  332. template <class CT, class R>
  333. template <class S>
  334. inline bool xrepeat<CT, R>::has_linear_assign(const S&) const noexcept
  335. {
  336. return false;
  337. }
  338. //@}
  339. template <class CT, class R>
  340. inline auto xrepeat<CT, R>::access() const -> const_reference
  341. {
  342. return access_impl<0>(stepper_begin(m_e.shape()));
  343. }
  344. template <class CT, class R>
  345. template <class Arg, class... Args>
  346. inline auto xrepeat<CT, R>::access(Arg arg, Args... args) const -> const_reference
  347. {
  348. constexpr size_t number_of_arguments = 1 + sizeof...(Args);
  349. if (number_of_arguments > this->dimension())
  350. {
  351. return access(args...);
  352. }
  353. return access_impl<0>(stepper_begin(m_e.shape()), arg, args...);
  354. }
  355. template <class CT, class R>
  356. inline auto xrepeat<CT, R>::stepper_begin() const -> const_stepper
  357. {
  358. return stepper_begin(m_e.shape());
  359. }
  360. template <class CT, class R>
  361. inline auto xrepeat<CT, R>::stepper_begin(const shape_type& s) const -> const_stepper
  362. {
  363. return const_stepper(m_e.stepper_begin(s), m_shape, m_repeats, m_repeating_axis);
  364. }
  365. template <class CT, class R>
  366. inline auto xrepeat<CT, R>::stepper_end(layout_type l) const -> const_stepper
  367. {
  368. return stepper_end(m_e.shape(), l);
  369. }
  370. template <class CT, class R>
  371. inline auto xrepeat<CT, R>::stepper_end(const shape_type& s, layout_type l) const -> const_stepper
  372. {
  373. auto st = const_stepper(m_e.stepper_begin(s), m_shape, m_repeats, m_repeating_axis);
  374. st.to_end(l);
  375. return st;
  376. }
  377. template <class CT, class R>
  378. template <std::size_t I, class Arg, class... Args>
  379. inline auto xrepeat<CT, R>::access_impl(stepper&& s, Arg arg, Args... args) const -> const_reference
  380. {
  381. s.step(I, static_cast<size_type>(arg));
  382. return access_impl<I + 1>(std::forward<stepper>(s), args...);
  383. }
  384. template <class CT, class R>
  385. template <std::size_t I>
  386. inline auto xrepeat<CT, R>::access_impl(stepper&& s) const -> const_reference
  387. {
  388. return *s;
  389. }
  390. /**********************************
  391. * xrepeat_stepper implementation *
  392. **********************************/
  393. template <class S, class R>
  394. xrepeat_stepper<S, R>::xrepeat_stepper(S&& s, const shape_type& shape, const repeats_type& repeats, size_type axis)
  395. : m_substepper(std::forward<S>(s))
  396. , m_shape(shape)
  397. , m_repeating_steps(0)
  398. , m_positions(shape.size())
  399. , m_subposition(0)
  400. , m_repeating_axis(axis)
  401. , m_repeats(repeats)
  402. {
  403. }
  404. template <class S, class R>
  405. inline auto xrepeat_stepper<S, R>::operator*() const -> reference
  406. {
  407. return m_substepper.operator*();
  408. }
  409. template <class S, class R>
  410. inline void xrepeat_stepper<S, R>::step(size_type dim, size_type steps_to_go)
  411. {
  412. if (m_positions[dim] + steps_to_go >= m_shape[dim])
  413. {
  414. const auto next_positions = get_next_positions(dim, steps_to_go);
  415. if (next_positions[dim] > m_positions[dim])
  416. {
  417. make_step(dim, next_positions[dim] - m_positions[dim]);
  418. }
  419. else
  420. {
  421. make_step_back(dim, m_positions[dim] - next_positions[dim]);
  422. }
  423. for (size_type d = 0; d < dim; ++d)
  424. {
  425. make_step(d, next_positions[d] - m_positions[d]);
  426. }
  427. }
  428. else
  429. {
  430. make_step(dim, steps_to_go);
  431. }
  432. }
  433. template <class S, class R>
  434. inline void xrepeat_stepper<S, R>::step_back(size_type dim, size_type steps_to_go)
  435. {
  436. if (m_positions[dim] < steps_to_go)
  437. {
  438. const auto next_positions = get_next_positions_back(dim, steps_to_go);
  439. if (next_positions[dim] < m_positions[dim])
  440. {
  441. make_step_back(dim, m_positions[dim] - next_positions[dim]);
  442. }
  443. else
  444. {
  445. make_step(dim, next_positions[dim] - m_positions[dim]);
  446. }
  447. for (size_type d = 0; d < dim; ++d)
  448. {
  449. make_step_back(d, m_positions[d] - next_positions[d]);
  450. }
  451. }
  452. else
  453. {
  454. make_step_back(dim, steps_to_go);
  455. }
  456. }
  457. template <class S, class R>
  458. inline void xrepeat_stepper<S, R>::reset(size_type dim)
  459. {
  460. m_substepper.reset(dim);
  461. m_positions[dim] = 0;
  462. if (dim == m_repeating_axis)
  463. {
  464. m_subposition = 0;
  465. m_repeating_steps = 0;
  466. }
  467. }
  468. template <class S, class R>
  469. inline void xrepeat_stepper<S, R>::reset_back(size_type dim)
  470. {
  471. m_substepper.reset_back(dim);
  472. m_positions[dim] = m_shape[dim] - 1;
  473. if (dim == m_repeating_axis)
  474. {
  475. m_subposition = m_repeats.size() - 1;
  476. m_repeating_steps = static_cast<std::ptrdiff_t>(m_repeats.back()) - 1;
  477. }
  478. }
  479. template <class S, class R>
  480. inline void xrepeat_stepper<S, R>::to_begin()
  481. {
  482. m_substepper.to_begin();
  483. std::fill(m_positions.begin(), m_positions.end(), 0);
  484. m_subposition = 0;
  485. m_repeating_steps = 0;
  486. }
  487. template <class S, class R>
  488. inline void xrepeat_stepper<S, R>::to_end(layout_type l)
  489. {
  490. m_substepper.to_end(l);
  491. std::transform(
  492. m_shape.begin(),
  493. m_shape.end(),
  494. m_positions.begin(),
  495. [](auto value)
  496. {
  497. return value - 1;
  498. }
  499. );
  500. if (layout_type::row_major == l)
  501. {
  502. ++m_positions.front();
  503. }
  504. else
  505. {
  506. ++m_positions.back();
  507. }
  508. m_subposition = m_repeats.size();
  509. m_repeating_steps = 0;
  510. }
  511. template <class S, class R>
  512. inline void xrepeat_stepper<S, R>::step_leading()
  513. {
  514. step(m_shape.size() - 1, 1);
  515. }
  516. template <class S, class R>
  517. inline void xrepeat_stepper<S, R>::make_step(size_type dim, size_type steps_to_go)
  518. {
  519. if (steps_to_go > 0)
  520. {
  521. if (dim == m_repeating_axis)
  522. {
  523. size_type subposition = m_subposition;
  524. m_repeating_steps += static_cast<std::ptrdiff_t>(steps_to_go);
  525. while (m_repeating_steps >= static_cast<ptrdiff_t>(m_repeats[subposition]))
  526. {
  527. m_repeating_steps -= static_cast<ptrdiff_t>(m_repeats[subposition]);
  528. ++subposition;
  529. }
  530. m_substepper.step(dim, subposition - m_subposition);
  531. m_subposition = subposition;
  532. }
  533. else
  534. {
  535. m_substepper.step(dim, steps_to_go);
  536. }
  537. m_positions[dim] += steps_to_go;
  538. }
  539. }
  540. template <class S, class R>
  541. inline void xrepeat_stepper<S, R>::make_step_back(size_type dim, size_type steps_to_go)
  542. {
  543. if (steps_to_go > 0)
  544. {
  545. if (dim == m_repeating_axis)
  546. {
  547. size_type subposition = m_subposition;
  548. m_repeating_steps -= static_cast<std::ptrdiff_t>(steps_to_go);
  549. while (m_repeating_steps < 0)
  550. {
  551. --subposition;
  552. m_repeating_steps += static_cast<ptrdiff_t>(m_repeats[subposition]);
  553. }
  554. m_substepper.step_back(dim, m_subposition - subposition);
  555. m_subposition = subposition;
  556. }
  557. else
  558. {
  559. m_substepper.step_back(dim, steps_to_go);
  560. }
  561. m_positions[dim] -= steps_to_go;
  562. }
  563. }
  564. template <class S, class R>
  565. inline auto xrepeat_stepper<S, R>::get_next_positions(size_type dim, size_type steps_to_go) const
  566. -> std::vector<size_type>
  567. {
  568. size_type next_position_for_dim = m_positions[dim] + steps_to_go;
  569. if (dim > 0)
  570. {
  571. size_type steps_in_previous_dim = 0;
  572. while (next_position_for_dim >= m_shape[dim])
  573. {
  574. next_position_for_dim -= m_shape[dim];
  575. ++steps_in_previous_dim;
  576. }
  577. if (steps_in_previous_dim > 0)
  578. {
  579. auto next_positions = get_next_positions(dim - 1, steps_in_previous_dim);
  580. next_positions[dim] = next_position_for_dim;
  581. return next_positions;
  582. }
  583. }
  584. std::vector<size_type> next_positions = m_positions;
  585. next_positions[dim] = next_position_for_dim;
  586. return next_positions;
  587. }
  588. template <class S, class R>
  589. inline auto xrepeat_stepper<S, R>::get_next_positions_back(size_type dim, size_type steps_to_go) const
  590. -> std::vector<size_type>
  591. {
  592. auto next_position_for_dim = static_cast<std::ptrdiff_t>(m_positions[dim] - steps_to_go);
  593. if (dim > 0)
  594. {
  595. size_type steps_in_previous_dim = 0;
  596. while (next_position_for_dim < 0)
  597. {
  598. next_position_for_dim += static_cast<std::ptrdiff_t>(m_shape[dim]);
  599. ++steps_in_previous_dim;
  600. }
  601. if (steps_in_previous_dim > 0)
  602. {
  603. auto next_positions = get_next_positions_back(dim - 1, steps_in_previous_dim);
  604. next_positions[dim] = static_cast<size_type>(next_position_for_dim);
  605. return next_positions;
  606. }
  607. }
  608. std::vector<size_type> next_positions = m_positions;
  609. next_positions[dim] = static_cast<size_type>(next_position_for_dim);
  610. return next_positions;
  611. }
  612. }
  613. #endif