1#ifndef PROBFD_DYNAMIC_CARTESIAN_PRODUCT_H
2#define PROBFD_DYNAMIC_CARTESIAN_PRODUCT_H
10#include "probfd/views/fold.h"
12namespace probfd::views {
14template <
bool Const,
typename T>
15using maybe_const_t = std::conditional_t<Const, const T, T>;
17template <std::ranges::viewable_range Range>
18using all_t =
decltype(std::views::all(std::declval<Range>()));
20template <
typename Range>
22 std::ranges::view<Range> && std::ranges::range<const Range> &&
24 std::ranges::iterator_t<Range>,
25 std::ranges::iterator_t<const Range>> &&
27 std::ranges::sentinel_t<Range>,
28 std::ranges::sentinel_t<const Range>>;
32template <
bool Const,
typename R>
33concept dcartesian_product_is_random_access =
34 std::ranges::random_access_range<maybe_const_t<Const, R>> &&
35 std::ranges::sized_range<maybe_const_t<Const, R>>;
37template <
typename Range>
38concept dcartesian_product_common_arg =
39 std::ranges::common_range<Range> ||
40 (std::ranges::sized_range<Range> &&
41 std::ranges::random_access_range<Range>);
43template <
bool Const,
typename R>
44concept dcartesian_product_is_bidirectional =
45 std::ranges::bidirectional_range<maybe_const_t<Const, R>>;
47template <
bool Const,
template <
typename>
class RSent,
typename R>
48concept dcartesian_is_sized_sentinel = std::sized_sentinel_for<
49 RSent<maybe_const_t<Const, R>>,
50 std::ranges::iterator_t<maybe_const_t<Const, R>>>;
52template <dcartesian_product_common_arg Range>
53constexpr auto dcartesian_common_arg_end(Range&& r)
55 if constexpr (std::ranges::common_range<Range>)
56 return std::ranges::end(r);
58 return std::ranges::begin(r) + std::ranges::distance(r);
62template <
typename R,
typename T>
63concept container_compatible_range =
64 std::ranges::input_range<R> &&
65 std::convertible_to<std::ranges::range_reference_t<R>, T>;
68 requires std::is_object_v<T>
72bool operator==(
const array<T>& left,
const array<T>& right);
75bool operator<=>(
const array<T>& left,
const array<T>& right);
78 requires std::is_object_v<T>
86 using iterator = Iterator<false>;
87 using const_iterator = Iterator<true>;
89 template <container_compatible_range<T> R>
90 array(std::from_range_t, R&& rg)
91 : data(
std::from_range,
std::forward<R>(rg))
96 explicit(
false) array(
const array<U>& other)
98 std::convertible_to<std::ranges::range_reference_t<array<U>>, T>)
99 : data(
std::from_range, other)
103 array(
const array<T>& other) =
default;
104 array(array<T>&& other) =
default;
106 array<T>& operator=(
const array<T>& other) =
default;
107 array<T>& operator=(array<T>&& other) =
default;
109 auto begin() {
return Iterator<false>(data.begin()); }
110 auto begin()
const {
return Iterator<true>(data.begin()); }
112 auto end() {
return Iterator<false>(data.end()); }
113 auto end()
const {
return Iterator<true>(data.end()); }
115 auto size()
const {
return data.size(); }
117 decltype(
auto)
operator[](
typename decltype(data)::size_type i)
122 decltype(
auto)
operator[](
decltype(data)::size_type i)
const
127 friend bool operator== <>(
const array<T>& left,
const array<T>& right);
128 friend bool operator<=> <>(
const array<T>& left,
const array<T>& right);
132inline bool operator==(
const array<T>& left,
const array<T>& right)
134 return left.data == right.data;
138inline bool operator<=>(
const array<T>& left,
const array<T>& right)
140 return left.data <=> right.data;
144 requires std::is_object_v<T>
146class array<T>::Iterator {
147 friend class array<T>;
149 using IType = std::conditional_t<
151 typename std::vector<T>::const_iterator,
152 typename std::vector<T>::iterator>;
156 explicit Iterator(IType underlying)
157 : underlying(underlying)
162 using iterator_category =
163 typename std::iterator_traits<IType>::iterator_category;
165 using difference_type =
166 typename std::iterator_traits<IType>::difference_type;
168 using iterator_concept =
typename IType::iterator_concept;
170 using value_type = std::iter_value_t<IType>;
172 Iterator() =
default;
174 constexpr explicit(
false) Iterator(
const Iterator<Const>& i)
175 : underlying(i.underlying)
179 constexpr explicit(
false) Iterator(Iterator<!Const> i)
181 : underlying(i.underlying)
185 constexpr decltype(
auto)
operator*()
const {
return *underlying; }
187 constexpr decltype(
auto) operator->()
const
189 return underlying.operator->();
192 constexpr Iterator& operator++()
198 constexpr Iterator operator++(
int)
205 constexpr Iterator& operator--()
211 constexpr Iterator operator--(
int)
218 constexpr Iterator& operator+=(difference_type x)
224 constexpr Iterator& operator-=(difference_type x) {
return *
this += -x; }
226 constexpr decltype(
auto)
operator[](difference_type n)
const
228 return *((*this) + n);
231 friend constexpr bool operator==(
const Iterator& x,
const Iterator& y)
233 return x.underlying == y.underlying;
236 friend constexpr auto operator<=>(
const Iterator& x,
const Iterator& y)
238 return x.underlying <=> y.underlying;
241 friend constexpr Iterator
operator+(Iterator x, difference_type y)
246 friend constexpr Iterator
operator+(difference_type x, Iterator y)
251 friend constexpr Iterator operator-(Iterator x, difference_type y)
256 friend constexpr difference_type
257 operator-(
const Iterator& x,
const Iterator& y)
259 return x.underlying - y.underlying;
262 friend constexpr void iter_swap(
const Iterator& l,
const Iterator& r)
264 using std::iter_swap;
265 iter_swap(l.underlying, r.underlying);
268 friend constexpr decltype(
auto) iter_move(
const Iterator& l)
270 using std::ranges::iter_move;
271 return iter_move(l.underlying);
275template <std::ranges::input_range R>
276array(std::from_range_t, R&&) -> array<std::ranges::range_reference_t<R>>;
278template <std::ranges::b
idirectional_range OR>
279 requires std::ranges::view<OR> &&
280 std::ranges::input_range<std::ranges::range_reference_t<OR>> &&
281 std::ranges::borrowed_range<std::ranges::range_reference_t<OR>> &&
282 std::ranges::viewable_range<std::ranges::range_reference_t<OR>>
283class dynamic_cartesian_product_view
284 :
public std::ranges::view_interface<dynamic_cartesian_product_view<OR>> {
285 using IR = std::views::all_t<std::ranges::range_reference_t<OR>>;
286 using IRIT = std::ranges::iterator_t<IR>;
288 using CIR = std::views::all_t<std::ranges::range_reference_t<const OR>>;
289 using CIRIT = std::ranges::iterator_t<CIR>;
294 using S_difference_type =
295 std::common_type_t<ptrdiff_t, std::ranges::range_difference_t<IR>>;
297 using ST = std::make_unsigned_t<S_difference_type>;
300 std::vector<ST> M_multipliers;
304 dynamic_cartesian_product_view() =
default;
306 constexpr explicit dynamic_cartesian_product_view(OR r)
307 : M_bases(
std::move(r))
308 , M_multipliers(
std::ranges::size(r))
312 auto rit = M_bases.end();
313 auto rend = M_bases.begin();
314 auto it = M_multipliers.end();
316 while (rit != rend) {
321 static_cast<ST
>(std::ranges::size(std::views::all(*rit)));
327 constexpr Iterator<false> begin()
328 requires(!dsimple_view<OR>)
330 return Iterator<false>(
334 M_bases | std::views::transform(std::views::all) |
335 std::views::transform(std::ranges::begin)));
338 constexpr Iterator<true> begin()
const
340 return Iterator<true>(
344 M_bases | std::views::transform(std::views::all) |
345 std::views::transform(std::ranges::begin)));
348 constexpr Iterator<false> end()
349 requires(!dsimple_view<OR> && detail::dcartesian_product_common_arg<IR>)
351 std::vector<IRIT> ends(
353 M_bases | std::views::transform(std::views::all) |
354 std::views::transform(std::ranges::begin));
356 if (std::ranges::none_of(M_bases, std::ranges::empty)) {
357 ends.front() = detail::dcartesian_common_arg_end(
358 *std::ranges::begin(M_bases) | std::views::all);
361 return Iterator<false>(*
this, std::move(ends));
364 constexpr Iterator<true> end() const
365 requires detail::dcartesian_product_common_arg<const IR>
367 std::vector<CIRIT> ends(
369 M_bases | std::views::transform(std::views::all) |
370 std::views::transform(std::ranges::begin));
372 if (std::ranges::none_of(M_bases, std::ranges::empty)) {
373 ends.front() = detail::dcartesian_common_arg_end(
374 *std::ranges::begin(M_bases) | std::views::all);
377 return Iterator<true>(*
this, std::move(ends));
380 constexpr std::default_sentinel_t end() const noexcept
382 return std::default_sentinel;
385 constexpr auto size()
386 requires std::ranges::sized_range<IR>
391 constexpr auto size() const
392 requires
std::ranges::sized_range<const IR>
399dynamic_cartesian_product_view(R&&)
400 -> dynamic_cartesian_product_view<std::views::all_t<R>>;
402template <std::ranges::b
idirectional_range OR>
403 requires std::ranges::view<OR> &&
404 std::ranges::input_range<std::ranges::range_reference_t<OR>> &&
405 std::ranges::borrowed_range<std::ranges::range_reference_t<OR>> &&
406 std::ranges::viewable_range<std::ranges::range_reference_t<OR>>
408class dynamic_cartesian_product_view<OR>::Iterator {
409 using IR = std::views::all_t<
410 std::ranges::range_reference_t<maybe_const_t<Const, OR>>>;
411 using Parent = maybe_const_t<Const, dynamic_cartesian_product_view>;
413 Parent* M_parent =
nullptr;
415 std::vector<std::ranges::iterator_t<IR>> M_current;
417 constexpr Iterator(Parent& parent,
decltype(M_current) current)
418 : M_parent(
std::addressof(parent))
419 , M_current(
std::move(current))
423 static auto S_iter_concept()
425 if constexpr (detail::dcartesian_product_is_random_access<Const, IR>)
426 return std::random_access_iterator_tag{};
427 else if constexpr (detail::
428 dcartesian_product_is_bidirectional<Const, IR>)
429 return std::bidirectional_iterator_tag{};
430 else if constexpr (std::ranges::forward_range<maybe_const_t<Const, IR>>)
431 return std::forward_iterator_tag{};
433 return std::input_iterator_tag{};
436 friend dynamic_cartesian_product_view;
439 using iterator_category = std::input_iterator_tag;
440 using iterator_concept =
decltype(S_iter_concept());
441 using value_type = array<std::ranges::range_value_t<IR>>;
442 using difference_type = dynamic_cartesian_product_view::S_difference_type;
444 Iterator() =
default;
446 constexpr explicit(
false) Iterator(Iterator<!Const> i)
447 requires Const && std::convertible_to<
448 std::ranges::iterator_t<IR>,
449 std::ranges::iterator_t<const IR>>
450 : M_parent(i.M_parent)
451 , M_current(std::from_range, i.M_current)
457 auto f = [](std::ranges::iterator_t<IR> i) ->
auto {
458 if constexpr (std::is_lvalue_reference_v<
decltype(*i)>)
464 return M_current | std::views::transform(f) | std::ranges::to<array>();
467 constexpr Iterator& operator++()
469 auto base_it = std::prev(M_parent->M_bases.end());
470 auto it = std::prev(M_current.end());
472 for (; base_it != M_parent->M_bases.begin(); --base_it, --it) {
473 if (++*it != std::ranges::end(*base_it))
return *
this;
474 *it = std::ranges::begin(*base_it);
481 constexpr void operator++(
int) { ++*
this; }
483 constexpr Iterator operator++(
int)
484 requires std::ranges::forward_range<maybe_const_t<Const, IR>>
491 constexpr Iterator& operator--()
492 requires detail::dcartesian_product_is_bidirectional<Const, IR>
494 auto base_it = std::prev(M_parent->M_bases.end());
495 auto it = std::prev(M_current.end());
497 for (; base_it != M_parent->M_bases.begin(); --base_it, --it) {
498 if (*it != std::ranges::begin(*base_it)) {
502 *it = detail::dcartesian_common_arg_end(*base_it);
509 constexpr Iterator operator--(
int)
510 requires detail::dcartesian_product_is_bidirectional<Const, IR>
517 constexpr Iterator& operator+=(difference_type x)
518 requires detail::dcartesian_product_is_random_access<Const, IR>
520 auto base_it = std::prev(M_parent->M_bases.end());
521 auto it = std::prev(M_current.end());
523 for (; base_it != M_parent->M_bases.begin(); --base_it, --it) {
524 if (x == 0)
return *
this;
526 auto size = std::ranges::ssize(*base_it);
527 auto begin = std::ranges::begin(*base_it);
529 auto offset = *it - begin;
535 offset = size + offset;
539 *it = begin + offset;
547 constexpr Iterator& operator-=(difference_type x)
548 requires detail::dcartesian_product_is_random_access<Const, IR>
553 constexpr decltype(
auto)
operator[](difference_type n)
const
554 requires detail::dcartesian_product_is_random_access<Const, IR>
556 return *((*this) + n);
559 friend constexpr bool operator==(
const Iterator& x,
const Iterator& y)
560 requires std::equality_comparable<
561 std::ranges::iterator_t<maybe_const_t<Const, IR>>>
563 return x.M_current == y.M_current;
566 friend constexpr bool operator==(
const Iterator& x, std::default_sentinel_t)
568 return std::ranges::any_of(
569 std::views::zip(x.M_current, x.M_parent->M_bases),
570 std::equal_to<
decltype(x.M_current)>{});
573 friend constexpr auto operator<=>(
const Iterator& x,
const Iterator& y)
574 requires std::ranges::random_access_range<maybe_const_t<Const, IR>>
576 return x.M_current <=> y.M_current;
579 friend constexpr Iterator
operator+(Iterator x, difference_type y)
580 requires detail::dcartesian_product_is_random_access<Const, IR>
585 friend constexpr Iterator
operator+(difference_type x, Iterator y)
586 requires detail::dcartesian_product_is_random_access<Const, IR>
591 friend constexpr Iterator operator-(Iterator x, difference_type y)
592 requires detail::dcartesian_product_is_random_access<Const, IR>
597 friend constexpr difference_type
598 operator-(
const Iterator& x,
const Iterator& y)
600 dcartesian_is_sized_sentinel<Const, std::ranges::iterator_t, IR>
602 auto mit = x.get_multipliers().begin();
603 auto mend = std::prev(x.get_multipliers().end());
605 auto xit = x.M_current.begin();
606 auto yit = y.M_current.begin();
608 difference_type dist = 0;
610 for (; mit != mend; ++mit, ++xit, ++yit) {
611 dist += *mit *
static_cast<difference_type
>(*xit - *yit);
617 friend constexpr difference_type
618 operator-(
const Iterator& x, std::default_sentinel_t)
620 dcartesian_is_sized_sentinel<Const, std::ranges::sentinel_t, IR>
622 auto mit = x.get_multipliers().begin();
623 auto mend = std::prev(x.get_multipliers().end());
625 auto xit = x.M_current.begin();
626 auto rit = x.M_parent->M_bases.begin();
628 difference_type dist = 0;
630 for (; mit != mend; ++mit, ++xit, ++rit) {
632 static_cast<difference_type
>(*xit - std::ranges::end(*rit));
638 friend constexpr difference_type
639 operator-(std::default_sentinel_t,
const Iterator& i)
641 dcartesian_is_sized_sentinel<Const, std::ranges::sentinel_t, IR>
643 return -(i - std::default_sentinel);
646 friend constexpr void iter_swap(
const Iterator& l,
const Iterator& r)
647 requires(std::indirectly_swappable<
648 std::ranges::iterator_t<maybe_const_t<Const, IR>>>)
650 for (
auto& [lit, rit] : std::views::zip(l.M_current, r.M_current)) {
651 std::ranges::iter_swap(lit, rit);
656 const auto& get_multipliers()
const {
return M_parent->M_multipliers; }
662using all_t =
decltype(std::views::all(std::declval<T>()));
665concept can_dynamic_cartesian_product_view =
666 std::ranges::view<all_t<T>> &&
667 std::ranges::input_range<std::ranges::range_reference_t<all_t<T>>> &&
668 std::ranges::borrowed_range<std::ranges::range_reference_t<all_t<T>>> &&
669 std::ranges::viewable_range<std::ranges::range_reference_t<all_t<T>>>;
671struct DynamicCartesianProduct
672 :
public std::ranges::range_adaptor_closure<DynamicCartesianProduct> {
673 template <
typename T>
674 requires(detail::can_dynamic_cartesian_product_view<T>)
675 constexpr auto operator() [[nodiscard]] (T&& t)
const
677 return dynamic_cartesian_product_view<all_t<T>>(std::forward<T>(t));
687 requires std::is_reference_v<T>
689 using type = std::reference_wrapper<std::remove_reference_t<T>>;
693using wrap_ref_t =
typename wrap_ref<T>::type;
697inline constexpr detail::DynamicCartesianProduct dynamic_cartesian_product;
702constexpr bool std::ranges::enable_borrowed_range<probfd::views::array<T>> =
712struct std::basic_common_reference<
714 probfd::views::array<U>,
717 using type = probfd::views::array<probfd::views::detail::wrap_ref_t<
718 std::common_reference_t<TQual<T>, UQual<U>>>>;
The top-level namespace of probabilistic Fast Downward.
Definition command_line.h:8
Interval operator*(value_t scale_factor, Interval val)
Scales an interval.
Interval operator+(Interval lhs, Interval rhs)
Computes the component-wise addition of two intervals.