14 #include <hipipe/core/utility/random.hpp>
16 #include <range/v3/action/reverse.hpp>
17 #include <range/v3/algorithm/adjacent_find.hpp>
18 #include <range/v3/algorithm/all_of.hpp>
19 #include <range/v3/algorithm/fill.hpp>
20 #include <range/v3/algorithm/find.hpp>
21 #include <range/v3/algorithm/max.hpp>
22 #include <range/v3/numeric/accumulate.hpp>
23 #include <range/v3/numeric/partial_sum.hpp>
24 #include <range/v3/view/all.hpp>
25 #include <range/v3/view/chunk.hpp>
26 #include <range/v3/view/for_each.hpp>
33 #include <type_traits>
37 namespace hipipe::utility {
39 namespace rga = ranges::actions;
40 namespace rgv = ranges::views;
50 template<
typename Rng,
typename PrevRng =
void,
bool IsRange = ranges::range<Rng>>
54 template<
typename Rng,
typename PrevRng>
55 struct ndims<Rng, PrevRng, false> : std::integral_constant<long, 0L> {
58 template<
typename Rng,
typename PrevRng>
59 struct ndims<Rng, PrevRng, true>
60 : std::integral_constant<long, ndims<ranges::range_value_t<Rng>, Rng>{} + 1> {
65 template<
typename Rng>
66 struct ndims<Rng, Rng, true> : std::integral_constant<long, -1L> {
77 template<
typename,
template<
typename...>
typename>
80 template<
template<
typename...>
typename Template,
typename... Args>
98 template<
typename T,
long Dims,
template<
typename...>
typename Container = std::vector>
100 using type = Container<
typename ndim_container<T, Dims-1, Container>::type>;
101 static_assert(Dims >= 0,
"The number of dimensions has to be non-negative.");
104 template<
typename T,
template<
typename...>
typename Container>
109 template<
typename T,
long Dims,
template<
typename...>
typename Container = std::vector>
110 using ndim_container_t =
typename ndim_container<T, Dims, Container>::type;
124 template<
typename Rng,
long Dim = -1L>
127 : ndim_type<typename ranges::range_value_t<Rng>, Dim - 1L> {
128 static_assert(Dim > 0,
"Dimension has to be positive, zero or -1.");
133 struct ndim_type<T, 0L> {
137 template<
typename Rng>
138 struct ndim_type<Rng, -1L>
139 : ndim_type<Rng, ndims<Rng>{}> {
143 template<
typename T,
long Dim = -1L>
144 using ndim_type_t =
typename ndim_type<T, Dim>::type;
150 template<
typename Rng,
long Dim,
long NDims>
151 struct ndim_size_impl {
152 static void impl(
const Rng& rng, std::vector<std::vector<long>>& size_out)
154 size_out[Dim-1].push_back(ranges::size(rng));
155 for (
auto& subrng : rng) {
156 ndim_size_impl<ranges::range_value_t<Rng>, Dim+1, NDims>
157 ::impl(subrng, size_out);
162 template<
typename Rng,
long Dim>
163 struct ndim_size_impl<Rng, Dim, Dim> {
164 static void impl(
const Rng& rng, std::vector<std::vector<long>>& size_out)
166 size_out[Dim-1].push_back(ranges::size(rng));
191 template<
long NDims,
typename Rng>
192 std::vector<std::vector<long>>
ndim_size(
const Rng& rng)
194 static_assert(NDims > 0);
195 std::vector<std::vector<long>> size_out(NDims);
196 detail::ndim_size_impl<Rng, 1, NDims>::impl(rng, size_out);
204 template<
typename Rng>
205 std::vector<std::vector<long>>
ndim_size(
const Rng& rng)
207 return utility::ndim_size<ndims<Rng>{}>(rng);
214 template<
long Dim,
long NDims>
215 struct ndim_resize_impl {
216 template<
typename Rng,
typename ValT>
217 static void impl(Rng& vec,
218 const std::vector<std::vector<long>>& vec_size,
219 std::vector<long>& vec_size_idx,
222 vec.resize(vec_size[Dim-1][vec_size_idx[Dim-1]++]);
223 for (
auto& subvec : vec) {
224 ndim_resize_impl<Dim+1, NDims>::impl(subvec, vec_size, vec_size_idx, val);
230 struct ndim_resize_impl<Dim, Dim> {
231 template<
typename Rng,
typename ValT>
232 static void impl(Rng& vec,
233 const std::vector<std::vector<long>>& vec_size,
234 std::vector<long>& vec_size_idx,
237 vec.resize(vec_size[Dim-1][vec_size_idx[Dim-1]++], val);
262 template<
long NDims,
typename Rng,
typename ValT = ndim_type_t<Rng, NDims>>
264 const std::vector<std::vector<long>>& vec_size,
268 assert(vec_size.size() == NDims);
269 static_assert(NDims <= ndims<Rng>{} - ndims<ValT>{});
270 for (std::size_t i = 1; i < vec_size.size(); ++i) {
271 assert(vec_size[i].size() == ranges::accumulate(vec_size[i-1], 0UL));
274 std::vector<long> vec_size_idx(vec_size.size());
276 detail::ndim_resize_impl<1, NDims>::impl(vec, vec_size, vec_size_idx, val);
281 template<
typename Rng,
typename ValT = ndim_type_t<Rng>>
283 const std::vector<std::vector<long>>& vec_size,
286 return ndim_resize<ndims<Rng>{}-ndims<ValT>{}>(vec, vec_size, std::move(val));
309 template<
long NDims,
typename Rng,
typename ValT = ndim_type_t<Rng, NDims>>
310 Rng&
ndim_pad(Rng& vec, ValT val = ValT{})
312 static_assert(NDims <= ndims<Rng>{} - ndims<ValT>{});
313 std::vector<std::vector<long>> vec_size = ndim_size<NDims>(vec);
315 for (std::size_t i = 1; i < vec_size.size(); ++i) {
316 long max_size = ranges::max(vec_size[i]);
317 ranges::fill(vec_size[i], max_size);
319 return utility::ndim_resize<NDims>(vec, vec_size, std::move(val));
323 template<
typename Rng,
typename ValT = ndim_type_t<Rng>>
324 Rng&
ndim_pad(Rng& vec, ValT val = ValT{})
326 return utility::ndim_pad<ndims<Rng>{}-ndims<ValT>{}>(vec, std::move(val));
333 template<
typename Rng,
long Dim,
long NDims>
335 static void impl(
const Rng& rng, std::vector<long>&
shape)
337 shape[Dim-1] = ranges::size(rng);
338 if (ranges::size(rng)) {
339 shape_impl<typename ranges::range_value_t<Rng>, Dim+1, NDims>
340 ::impl(*ranges::begin(rng),
shape);
345 template<
typename Rng,
long Dim>
346 struct shape_impl<Rng, Dim, Dim> {
347 static void impl(
const Rng& rng, std::vector<long>&
shape)
349 shape[Dim-1] = ranges::size(rng);
354 template<
typename Rng,
long NDims>
355 struct check_rectangular_shape {
356 static bool all_same(std::vector<long>& vec)
358 return ranges::adjacent_find(vec, std::not_equal_to<long>{}) == ranges::end(vec);
361 static bool impl(
const Rng& rng)
363 std::vector<std::vector<long>> size = utility::ndim_size<NDims>(rng);
364 return ranges::all_of(size, all_same);
387 template<
long NDims,
typename Rng>
388 std::vector<long>
shape(
const Rng& rng)
390 static_assert(NDims > 0);
391 std::vector<long>
shape(NDims);
393 detail::shape_impl<Rng, 1, NDims>::impl(rng,
shape);
394 assert((detail::check_rectangular_shape<Rng, NDims>::impl(rng)));
402 template<
typename Rng>
403 std::vector<long>
shape(
const Rng& rng)
405 return utility::shape<ndims<Rng>{}>(rng);
414 struct flat_view_impl {
418 return flat_view_impl<Dim-1>::impl()(subrng);
425 struct flat_view_impl<1> {
450 template<
long NDims,
typename Rng>
453 static_assert(NDims > 0);
454 return detail::flat_view_impl<NDims>::impl()(rng);
458 template<
long NDims,
typename Rng>
461 static_assert(NDims > 0);
462 return detail::flat_view_impl<NDims>::impl()(rng);
466 template<
typename Rng>
469 return utility::flat_view<ndims<Rng>{}>(std::forward<Rng>(rng));
477 struct reshaped_view_impl_go {
478 static auto impl(
const std::shared_ptr<std::vector<long>>& shape_ptr)
480 return rgv::chunk((*shape_ptr)[N-2])
482 return reshaped_view_impl_go<N-1>::impl(shape_ptr)(std::move(subview));
488 struct reshaped_view_impl_go<1> {
489 static auto impl(
const std::shared_ptr<std::vector<long>>&)
495 template<
long N,
typename Rng>
496 auto reshaped_view_impl(Rng& vec, std::vector<long>
shape)
498 assert(
shape.size() == N);
502 auto deduced_pos = ranges::find(
shape, -1);
503 if (deduced_pos !=
shape.end()) {
504 auto flat_size = ranges::distance(flat);
505 auto shape_prod = -ranges::accumulate(
shape, 1, std::multiplies<>{});
506 assert(flat_size % shape_prod == 0);
507 *deduced_pos = flat_size / shape_prod;
511 assert(ranges::all_of(
shape, [](
long s) {
return s > 0; }));
513 assert(ranges::distance(flat) == ranges::accumulate(
shape, 1, std::multiplies<>{}));
515 shape |= rga::reverse;
516 ranges::partial_sum(
shape,
shape, std::multiplies<>{});
518 auto shape_ptr = std::make_shared<std::vector<long>>(std::move(
shape));
519 return detail::reshaped_view_impl_go<N>::impl(shape_ptr)(std::move(flat));
540 template<
long N,
typename Rng>
543 return detail::reshaped_view_impl<N, Rng>(rng, std::move(
shape));
547 template<
long N,
typename Rng>
550 return detail::reshaped_view_impl<N, const Rng>(rng, std::move(
shape));
557 template<
long Dim,
long NDims>
558 struct generate_impl {
559 template<
typename Rng,
typename Gen>
560 static void impl(Rng& rng, Gen& gen,
long gendims)
563 auto val = std::invoke(gen);
564 for (
auto& elem : flat_view<NDims-Dim+1>(rng)) elem = val;
566 for (
auto& subrng : rng) {
567 detail::generate_impl<Dim+1, NDims>::impl(subrng, gen, gendims);
574 struct generate_impl<Dim, Dim> {
575 template<
typename Rng,
typename Gen>
576 static void impl(Rng& rng, Gen& gen,
long gendims)
578 if (Dim > gendims) ranges::fill(rng, std::invoke(gen));
579 else for (
auto& val : rng) val = std::invoke(gen);
628 template<
long NDims,
typename Rng,
typename Gen>
631 long gendims = std::numeric_limits<long>::max())
633 static_assert(NDims > 0);
634 detail::generate_impl<1, NDims>::impl(rng, gen, gendims);
638 template<
typename Rng,
typename Gen>
641 long gendims = std::numeric_limits<long>::max())
643 using GenT = std::result_of_t<Gen()>;
644 detail::generate_impl<1, ndims<Rng>{}-ndims<GenT>{}>::impl(rng, gen, gendims);
681 typename Prng = std::mt19937&,
682 typename Dist = std::uniform_real_distribution<double>>
684 Dist&& dist = Dist{0, 1},
686 long gendims = std::numeric_limits<long>::max())
688 auto gen = [&dist, &prng]() {
return std::invoke(dist, prng); };
689 utility::generate<NDims>(std::forward<Rng>(rng), std::move(gen), gendims);
693 template<
typename Rng,
694 typename Prng = std::mt19937&,
695 typename Dist = std::uniform_real_distribution<double>>
697 Dist&& dist = Dist{0, 1},
699 long gendims = std::numeric_limits<long>::max())
701 auto gen = [&dist, &prng]() {
return std::invoke(dist, prng); };
707 struct same_size_impl {
708 template<
typename Rng,
typename... Rngs>
709 bool operator()(Rng&& rng, Rngs&&... rngs)
const
711 return (... && (ranges::size(rng) == ranges::size(rngs)));
714 bool operator()()
const
735 template<
typename Tuple>
738 return std::apply(detail::same_size_impl{}, rngs);