xtensor
Loading...
Searching...
No Matches
xrepeat.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_XREPEAT
11#define XTENSOR_XREPEAT
12
13#include <utility>
14#include <vector>
15
16#include "xaccessible.hpp"
17#include "xexpression.hpp"
18#include "xiterable.hpp"
19
20namespace xt
21{
22 template <class CT, class R>
23 class xrepeat;
24
25 template <class S, class R>
26 class xrepeat_stepper;
27
28 /*********************
29 * xrepeat extension *
30 *********************/
31
32 namespace extension
33 {
34 template <class Tag, class CT, class X>
36
37 template <class CT, class X>
42
43 template <class CT, class X>
44 struct xrepeat_base : xrepeat_base_impl<xexpression_tag_t<CT>, CT, X>
45 {
46 };
47
48 template <class CT, class X>
49 using xrepeat_base_t = typename xrepeat_base<CT, X>::type;
50 }
51
52 /***********
53 * xrepeat *
54 ***********/
55
56 template <class CT, class R>
58 {
59 using xexpression_type = std::decay_t<CT>;
60 using reference = typename xexpression_type::const_reference;
61 using const_reference = typename xexpression_type::const_reference;
62 using size_type = typename xexpression_type::size_type;
63 using temporary_type = typename xexpression_type::temporary_type;
64
65 static constexpr bool is_const = std::is_const<std::remove_reference_t<CT>>::value;
66
67 using extract_storage_type = xtl::mpl::eval_if_t<
69 detail::expr_storage_type<xexpression_type>,
71 using storage_type = std::conditional_t<is_const, const extract_storage_type, extract_storage_type>;
72 };
73
74 template <class CT, class R>
76 {
77 using xexpression_type = std::decay_t<CT>;
78 using repeats_type = std::decay_t<R>;
79 using inner_shape_type = typename xexpression_type::inner_shape_type;
81 using stepper = const_stepper;
82 };
83
95 template <class CT, class R>
96 class xrepeat : public xconst_iterable<xrepeat<CT, R>>,
97 public xconst_accessible<xrepeat<CT, R>>,
98 public xsharable_expression<xrepeat<CT, R>>,
99 public extension::xrepeat_base_t<CT, R>
100 {
101 public:
102
104 using xexpression_type = std::decay_t<CT>;
106 using extension_base = extension::xrepeat_base_t<CT, R>;
107 using expression_tag = typename extension_base::expression_tag;
108
109 using value_type = typename xexpression_type::value_type;
110 using shape_type = typename xexpression_type::shape_type;
111 using repeats_type = xtl::const_closure_type_t<R>;
112
114 using reference = typename container_type::reference;
115 using const_reference = typename container_type::const_reference;
116 using size_type = typename container_type::size_type;
117 using temporary_type = typename container_type::temporary_type;
118
119 static constexpr layout_type static_layout = xexpression_type::static_layout;
120 static constexpr bool contiguous_layout = false;
121
122 using bool_load_type = typename xexpression_type::bool_load_type;
123 using pointer = typename xexpression_type::pointer;
124 using const_pointer = typename xexpression_type::const_pointer;
125 using difference_type = typename xexpression_type::difference_type;
126
128 using stepper = typename iterable_type::stepper;
129 using const_stepper = typename iterable_type::const_stepper;
130
131 template <class CTA>
132 explicit xrepeat(CTA&& e, R&& repeats, size_type axis);
133
135 const shape_type& shape() const noexcept;
136 layout_type layout() const noexcept;
137 bool is_contiguous() const noexcept;
139
140 template <class... Args>
141 const_reference operator()(Args... args) const;
142
143 template <class... Args>
144 const_reference unchecked(Args... args) const;
145
146 template <class It>
147 const_reference element(It first, It last) const;
148
149 const xexpression_type& expression() const noexcept;
150
151 template <class S>
152 bool broadcast_shape(S& shape, bool reuse_cache = false) const;
153
154 template <class S>
155 bool has_linear_assign(const S& strides) const noexcept;
156
157 const_stepper stepper_begin() const;
158 const_stepper stepper_begin(const shape_type& s) const;
159
160 const_stepper stepper_end(layout_type l) const;
161 const_stepper stepper_end(const shape_type& s, layout_type l) const;
162
163 private:
164
165 CT m_e;
166 size_type m_repeating_axis;
167 repeats_type m_repeats;
168 shape_type m_shape;
169
170 const_reference access() const;
171
172 template <class Arg, class... Args>
173 const_reference access(Arg arg, Args... args) const;
174
175 template <std::size_t I, class Arg, class... Args>
176 const_reference access_impl(stepper&& s, Arg arg, Args... args) const;
177
178 template <std::size_t I>
179 const_reference access_impl(stepper&& s) const;
180 };
181
182 /*******************
183 * xrepeat_stepper *
184 *******************/
185
186 template <class S, class R>
188 {
189 public:
190
191 using repeats_type = R;
192 using storage_type = typename S::storage_type;
193 using subiterator_type = typename S::subiterator_type;
194 using subiterator_traits = typename S::subiterator_traits;
195 using value_type = typename subiterator_traits::value_type;
196 using reference = typename subiterator_traits::reference;
197 using pointer = typename subiterator_traits::pointer;
198 using difference_type = typename subiterator_traits::difference_type;
199 using size_type = typename storage_type::size_type;
200 using shape_type = typename storage_type::shape_type;
201 using simd_value_type = xt_simd::simd_type<value_type>;
202
203 template <class requested_type>
204 using simd_return_type = xt_simd::simd_return_type<value_type, requested_type>;
205
206 xrepeat_stepper(S&& s, const shape_type& shape, const repeats_type& repeats, size_type axis);
207
208 reference operator*() const;
209
210 void step(size_type dim, size_type n = 1);
211 void step_back(size_type dim, size_type n = 1);
212 void reset(size_type dim);
213 void reset_back(size_type dim);
214
215 void to_begin();
216 void to_end(layout_type l);
217
218 template <class T>
219 simd_return_type<T> step_simd();
220
221 void step_leading();
222
223 template <class V>
224 void store_simd(const V& vec);
225
226 private:
227
228 S m_substepper;
229 const shape_type& m_shape;
230
231 std::ptrdiff_t m_repeating_steps;
232 std::vector<size_type> m_positions;
233 size_type m_subposition;
234
235 size_type m_repeating_axis;
236 const repeats_type& m_repeats;
237
238 void make_step(size_type dim, size_type n);
239 void make_step_back(size_type dim, size_type n);
240
241 std::vector<size_type> get_next_positions(size_type dim, size_type steps_to_go) const;
242 std::vector<size_type> get_next_positions_back(size_type dim, size_type steps_to_go) const;
243 };
244
245 /**************************
246 * xrepeat implementation *
247 **************************/
248
257 template <class CT, class R>
258 template <class CTA>
259 xrepeat<CT, R>::xrepeat(CTA&& e, R&& repeats, size_type axis)
260 : m_e(std::forward<CTA>(e))
261 , m_repeating_axis(axis)
262 , m_repeats(std::forward<R>(repeats))
263 , m_shape(e.shape())
264 {
265 using shape_value_type = typename shape_type::value_type;
266 m_shape[axis] = static_cast<shape_value_type>(
267 std::accumulate(m_repeats.begin(), m_repeats.end(), shape_value_type(0))
268 );
269 }
270
278 template <class CT, class R>
279 inline auto xrepeat<CT, R>::shape() const noexcept -> const shape_type&
280 {
281 return m_shape;
282 }
283
287 template <class CT, class R>
289 {
290 return m_e.layout();
291 }
292
293 template <class CT, class R>
295 {
296 return false;
297 }
298
300
311 template <class CT, class R>
312 template <class... Args>
313 inline auto xrepeat<CT, R>::operator()(Args... args) const -> const_reference
314 {
315 return access(args...);
316 }
317
337 template <class CT, class R>
338 template <class... Args>
339 inline auto xrepeat<CT, R>::unchecked(Args... args) const -> const_reference
340 {
341 return this->operator()(args...);
342 }
343
351 template <class CT, class R>
352 template <class It>
353 inline auto xrepeat<CT, R>::element(It first, It last) const -> const_reference
354 {
355 auto s = stepper_begin(m_e.shape());
356 std::size_t dimension = 0;
357 auto iter = first;
358 while (iter != last)
359 {
360 s.step(dimension, *iter);
361 ++dimension;
362 ++iter;
363 }
364 return access_impl<0>(std::forward<stepper>(s));
365 }
366
370 template <class CT, class R>
371 inline auto xrepeat<CT, R>::expression() const noexcept -> const xexpression_type&
372 {
373 return m_e;
374 }
375
377
388 template <class CT, class R>
389 template <class S>
390 inline bool xrepeat<CT, R>::broadcast_shape(S& shape, bool) const
391 {
392 return xt::broadcast_shape(m_shape, shape);
393 }
394
400 template <class CT, class R>
401 template <class S>
402 inline bool xrepeat<CT, R>::has_linear_assign(const S&) const noexcept
403 {
404 return false;
405 }
406
408
409 template <class CT, class R>
410 inline auto xrepeat<CT, R>::access() const -> const_reference
411 {
412 return access_impl<0>(stepper_begin(m_e.shape()));
413 }
414
415 template <class CT, class R>
416 template <class Arg, class... Args>
417 inline auto xrepeat<CT, R>::access(Arg arg, Args... args) const -> const_reference
418 {
419 constexpr size_t number_of_arguments = 1 + sizeof...(Args);
420 if (number_of_arguments > this->dimension())
421 {
422 return access(args...);
423 }
424 return access_impl<0>(stepper_begin(m_e.shape()), arg, args...);
425 }
426
427 template <class CT, class R>
428 inline auto xrepeat<CT, R>::stepper_begin() const -> const_stepper
429 {
430 return stepper_begin(m_e.shape());
431 }
432
433 template <class CT, class R>
434 inline auto xrepeat<CT, R>::stepper_begin(const shape_type& s) const -> const_stepper
435 {
436 return const_stepper(m_e.stepper_begin(s), m_shape, m_repeats, m_repeating_axis);
437 }
438
439 template <class CT, class R>
440 inline auto xrepeat<CT, R>::stepper_end(layout_type l) const -> const_stepper
441 {
442 return stepper_end(m_e.shape(), l);
443 }
444
445 template <class CT, class R>
446 inline auto xrepeat<CT, R>::stepper_end(const shape_type& s, layout_type l) const -> const_stepper
447 {
448 auto st = const_stepper(m_e.stepper_begin(s), m_shape, m_repeats, m_repeating_axis);
449 st.to_end(l);
450 return st;
451 }
452
453 template <class CT, class R>
454 template <std::size_t I, class Arg, class... Args>
455 inline auto xrepeat<CT, R>::access_impl(stepper&& s, Arg arg, Args... args) const -> const_reference
456 {
457 s.step(I, static_cast<size_type>(arg));
458 return access_impl<I + 1>(std::forward<stepper>(s), args...);
459 }
460
461 template <class CT, class R>
462 template <std::size_t I>
463 inline auto xrepeat<CT, R>::access_impl(stepper&& s) const -> const_reference
464 {
465 return *s;
466 }
467
468 /**********************************
469 * xrepeat_stepper implementation *
470 **********************************/
471
472 template <class S, class R>
473 xrepeat_stepper<S, R>::xrepeat_stepper(S&& s, const shape_type& shape, const repeats_type& repeats, size_type axis)
474 : m_substepper(std::forward<S>(s))
475 , m_shape(shape)
476 , m_repeating_steps(0)
477 , m_positions(shape.size())
478 , m_subposition(0)
479 , m_repeating_axis(axis)
480 , m_repeats(repeats)
481 {
482 }
483
484 template <class S, class R>
485 inline auto xrepeat_stepper<S, R>::operator*() const -> reference
486 {
487 return m_substepper.operator*();
488 }
489
490 template <class S, class R>
491 inline void xrepeat_stepper<S, R>::step(size_type dim, size_type steps_to_go)
492 {
493 if (m_positions[dim] + steps_to_go >= m_shape[dim])
494 {
495 const auto next_positions = get_next_positions(dim, steps_to_go);
496 if (next_positions[dim] > m_positions[dim])
497 {
498 make_step(dim, next_positions[dim] - m_positions[dim]);
499 }
500 else
501 {
502 make_step_back(dim, m_positions[dim] - next_positions[dim]);
503 }
504 for (size_type d = 0; d < dim; ++d)
505 {
506 make_step(d, next_positions[d] - m_positions[d]);
507 }
508 }
509 else
510 {
511 make_step(dim, steps_to_go);
512 }
513 }
514
515 template <class S, class R>
516 inline void xrepeat_stepper<S, R>::step_back(size_type dim, size_type steps_to_go)
517 {
518 if (m_positions[dim] < steps_to_go)
519 {
520 const auto next_positions = get_next_positions_back(dim, steps_to_go);
521 if (next_positions[dim] < m_positions[dim])
522 {
523 make_step_back(dim, m_positions[dim] - next_positions[dim]);
524 }
525 else
526 {
527 make_step(dim, next_positions[dim] - m_positions[dim]);
528 }
529 for (size_type d = 0; d < dim; ++d)
530 {
531 make_step_back(d, m_positions[d] - next_positions[d]);
532 }
533 }
534 else
535 {
536 make_step_back(dim, steps_to_go);
537 }
538 }
539
540 template <class S, class R>
541 inline void xrepeat_stepper<S, R>::reset(size_type dim)
542 {
543 m_substepper.reset(dim);
544 m_positions[dim] = 0;
545 if (dim == m_repeating_axis)
546 {
547 m_subposition = 0;
548 m_repeating_steps = 0;
549 }
550 }
551
552 template <class S, class R>
553 inline void xrepeat_stepper<S, R>::reset_back(size_type dim)
554 {
555 m_substepper.reset_back(dim);
556 m_positions[dim] = m_shape[dim] - 1;
557 if (dim == m_repeating_axis)
558 {
559 m_subposition = m_repeats.size() - 1;
560 m_repeating_steps = static_cast<std::ptrdiff_t>(m_repeats.back()) - 1;
561 }
562 }
563
564 template <class S, class R>
565 inline void xrepeat_stepper<S, R>::to_begin()
566 {
567 m_substepper.to_begin();
568 std::fill(m_positions.begin(), m_positions.end(), 0);
569 m_subposition = 0;
570 m_repeating_steps = 0;
571 }
572
573 template <class S, class R>
574 inline void xrepeat_stepper<S, R>::to_end(layout_type l)
575 {
576 m_substepper.to_end(l);
577 std::transform(
578 m_shape.begin(),
579 m_shape.end(),
580 m_positions.begin(),
581 [](auto value)
582 {
583 return value - 1;
584 }
585 );
586 if (layout_type::row_major == l)
587 {
588 ++m_positions.front();
589 }
590 else
591 {
592 ++m_positions.back();
593 }
594 m_subposition = m_repeats.size();
595 m_repeating_steps = 0;
596 }
597
598 template <class S, class R>
599 inline void xrepeat_stepper<S, R>::step_leading()
600 {
601 step(m_shape.size() - 1, 1);
602 }
603
604 template <class S, class R>
605 inline void xrepeat_stepper<S, R>::make_step(size_type dim, size_type steps_to_go)
606 {
607 if (steps_to_go > 0)
608 {
609 if (dim == m_repeating_axis)
610 {
611 size_type subposition = m_subposition;
612 m_repeating_steps += static_cast<std::ptrdiff_t>(steps_to_go);
613 while (m_repeating_steps >= static_cast<ptrdiff_t>(m_repeats[subposition]))
614 {
615 m_repeating_steps -= static_cast<ptrdiff_t>(m_repeats[subposition]);
616 ++subposition;
617 }
618 m_substepper.step(dim, subposition - m_subposition);
619 m_subposition = subposition;
620 }
621 else
622 {
623 m_substepper.step(dim, steps_to_go);
624 }
625 m_positions[dim] += steps_to_go;
626 }
627 }
628
629 template <class S, class R>
630 inline void xrepeat_stepper<S, R>::make_step_back(size_type dim, size_type steps_to_go)
631 {
632 if (steps_to_go > 0)
633 {
634 if (dim == m_repeating_axis)
635 {
636 size_type subposition = m_subposition;
637 m_repeating_steps -= static_cast<std::ptrdiff_t>(steps_to_go);
638 while (m_repeating_steps < 0)
639 {
640 --subposition;
641 m_repeating_steps += static_cast<ptrdiff_t>(m_repeats[subposition]);
642 }
643 m_substepper.step_back(dim, m_subposition - subposition);
644 m_subposition = subposition;
645 }
646 else
647 {
648 m_substepper.step_back(dim, steps_to_go);
649 }
650 m_positions[dim] -= steps_to_go;
651 }
652 }
653
654 template <class S, class R>
655 inline auto xrepeat_stepper<S, R>::get_next_positions(size_type dim, size_type steps_to_go) const
656 -> std::vector<size_type>
657 {
658 size_type next_position_for_dim = m_positions[dim] + steps_to_go;
659 if (dim > 0)
660 {
661 size_type steps_in_previous_dim = 0;
662 while (next_position_for_dim >= m_shape[dim])
663 {
664 next_position_for_dim -= m_shape[dim];
665 ++steps_in_previous_dim;
666 }
667 if (steps_in_previous_dim > 0)
668 {
669 auto next_positions = get_next_positions(dim - 1, steps_in_previous_dim);
670 next_positions[dim] = next_position_for_dim;
671 return next_positions;
672 }
673 }
674 std::vector<size_type> next_positions = m_positions;
675 next_positions[dim] = next_position_for_dim;
676 return next_positions;
677 }
678
679 template <class S, class R>
680 inline auto xrepeat_stepper<S, R>::get_next_positions_back(size_type dim, size_type steps_to_go) const
681 -> std::vector<size_type>
682 {
683 auto next_position_for_dim = static_cast<std::ptrdiff_t>(m_positions[dim] - steps_to_go);
684 if (dim > 0)
685 {
686 size_type steps_in_previous_dim = 0;
687 while (next_position_for_dim < 0)
688 {
689 next_position_for_dim += static_cast<std::ptrdiff_t>(m_shape[dim]);
690 ++steps_in_previous_dim;
691 }
692 if (steps_in_previous_dim > 0)
693 {
694 auto next_positions = get_next_positions_back(dim - 1, steps_in_previous_dim);
695 next_positions[dim] = static_cast<size_type>(next_position_for_dim);
696 return next_positions;
697 }
698 }
699 std::vector<size_type> next_positions = m_positions;
700 next_positions[dim] = static_cast<size_type>(next_position_for_dim);
701 return next_positions;
702 }
703}
704
705#endif
Base class for implementation of common expression constant access methods.
size_type size() const noexcept
Returns the size 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.
Definition xiterable.hpp:37
Base class for multidimensional iterable expressions.
Expression with repeated values along an axis.
Definition xrepeat.hpp:100
bool has_linear_assign(const S &strides) const noexcept
Checks whether the xbroadcast can be linearly assigned to an expression with the specified strides.
Definition xrepeat.hpp:402
bool broadcast_shape(S &shape, bool reuse_cache=false) const
Broadcast the shape of the function to the specified parameter.
Definition xrepeat.hpp:390
layout_type layout() const noexcept
Returns the layout_type of the expression.
Definition xrepeat.hpp:288
const xexpression_type & expression() const noexcept
Returns a constant reference to the underlying expression of the broadcast expression.
Definition xrepeat.hpp:371
xrepeat(CTA &&e, R &&repeats, size_type axis)
Constructs an xrepeat expression repeating the element of the specified xexpression.
Definition xrepeat.hpp:259
const shape_type & shape() const noexcept
Returns the shape of the expression.
Definition xrepeat.hpp:279
auto strides(const E &e, stride_type type=stride_type::normal) noexcept
Get strides of an object.
Definition xstrides.hpp:248
standard mathematical functions for xexpressions
layout_type
Definition xlayout.hpp:24