1#ifndef PROBFD_DISTRIBUTION_H
2#define PROBFD_DISTRIBUTION_H
4#include "probfd/value_type.h"
6#include "downward/utils/rng.h"
19template <
typename T,
typename PrType = value_t>
27 std::tuple<Args...> args,
28 std::tuple<Args2...> args2,
29 std::index_sequence<Indices...>,
30 std::index_sequence<Indices2...>)
31 :
item(std::get<Indices>(args)...)
42 requires(std::is_default_constructible_v<T> &&
43 std::is_default_constructible_v<PrType>)
46 template <
typename A,
typename B>
47 requires(std::is_constructible_v<T, A> &&
48 std::is_constructible_v<PrType, B>)
49 explicit(!std::is_convertible_v<T, A> || !std::is_convertible_v<PrType, B>)
56 template <
typename A,
typename B>
57 requires(std::is_constructible_v<T, A> &&
58 std::is_constructible_v<PrType, B>)
59 explicit(!std::is_convertible_v<T, A> || !std::is_convertible_v<PrType, B>)
67 requires(std::is_constructible_v<T, A> &&
68 std::is_constructible_v<PrType, A>)
69 explicit(!std::is_convertible_v<T, A> || !std::is_convertible_v<PrType, A>)
77 template <
typename A,
typename B>
78 requires(std::is_constructible_v<T, A> &&
79 std::is_constructible_v<PrType, B>)
80 explicit(!std::is_convertible_v<T, A> || !std::is_convertible_v<PrType, B>)
89 template <
typename... Args,
typename... Args2>
91 std::piecewise_construct_t,
92 std::tuple<Args...> t1,
93 std::tuple<Args2...> t2)
97 std::index_sequence_for<Args...>{},
98 std::index_sequence_for<Args2...>{})
107 operator std::pair<T, PrType>()
const
112 template <std::
size_t Index>
115 if constexpr (Index == 0)
return item;
119 template <std::
size_t Index>
120 const auto& get() const&
122 if constexpr (Index == 0)
return item;
126 template <std::
size_t Index>
129 if constexpr (Index == 0)
return std::move(
item);
130 if constexpr (Index == 1)
return std::move(
probability);
133 template <std::
size_t Index>
134 const auto&& get() const&&
136 if constexpr (Index == 0)
return std::move(
item);
137 if constexpr (Index == 1)
return std::move(
probability);
156 std::vector<ItemProbabilityPair<T>> distribution_;
159 using iterator =
typename std::vector<ItemProbabilityPair<T>>::iterator;
160 using const_iterator =
161 typename std::vector<ItemProbabilityPair<T>>::const_iterator;
163 Distribution() =
default;
165 Distribution(std::initializer_list<ItemProbabilityPair<T>> list)
166 : distribution_(list)
172 std::initializer_list<ItemProbabilityPair<T>> list,
174 : distribution_(list)
178 template <std::ranges::input_range R>
179 requires(std::convertible_to<
180 std::ranges::range_reference_t<R>,
181 ItemProbabilityPair<T>>)
182 explicit Distribution(std::from_range_t, R&& pair_range)
183 : distribution_(
std::from_range,
std::forward<R>(pair_range))
188 template <std::ranges::input_range R>
189 requires(std::convertible_to<
190 std::ranges::range_reference_t<R>,
191 ItemProbabilityPair<T>>)
192 explicit Distribution(std::from_range_t, no_normalize_t, R&& pair_range)
193#ifdef __cpp_lib_containers_ranges
194 : distribution_(std::from_range, std::forward<R>(pair_range))
197 std::ranges::begin(pair_range),
198 std::ranges::end(pair_range))
207 void reserve(
size_t capacity) { distribution_.reserve(capacity); }
215 return distribution_.empty();
224 return distribution_.size();
227 void clear() { distribution_.clear(); }
229 void swap(Distribution<T>& other)
231 other.distribution_.swap(distribution_);
234 void add_probability(T t,
value_t prob)
238 auto it = this->find(t);
241 it->probability += prob;
245 distribution_.emplace(it, std::move(t), prob);
248 auto find(
this auto&& self,
const T& t)
250 auto it = std::ranges::lower_bound(
256 if (it == self.end() || it->item == t) {
269 return size() == 1 && distribution_.front().item == t;
285 template <
typename RandomVariable>
286 requires(std::invocable<RandomVariable, T>)
290 for (
const auto [succ, prob] : distribution_) {
291 ex += prob * rv(succ);
300 template <
typename RandomVariable>
301 requires requires(RandomVariable& rv,
const T& t) {
302 { rv[t] } -> std::convertible_to<value_t>;
307 for (
const auto [succ, prob] : distribution_) {
308 ex += prob * rv[succ];
318 for (
auto& pair : distribution_) {
319 pair.probability *= scale;
332 for (
auto& pair : distribution_) {
333 sum += pair.probability;
338 auto sample(utils::RandomNumberGenerator& rng)
345 const value_t r = rng.random();
347 auto it = distribution_.begin();
351 sum += (++it)->probability;
357 auto sample(utils::RandomNumberGenerator& rng)
const
359 return static_cast<const_iterator
>(
360 const_cast<Distribution<T>*
>(
this)->sample(rng));
369 iterator
erase(iterator it) {
return distribution_.erase(it); }
377 iterator
erase(iterator it, iterator last)
379 return distribution_.erase(it, last);
382 template <
typename UnaryPredicate>
383 size_t remove_if(UnaryPredicate pred)
385 return std::erase_if(distribution_, pred);
388 template <
typename UnaryPredicate>
389 value_t remove_if_normalize(UnaryPredicate pred)
391 value_t normalize_factor = 0_vt;
395 [&pred, &normalize_factor](
auto& target) {
397 normalize_factor += target.probability;
403 if (normalize_factor > 0) {
404 this->
normalize(1_vt / (1_vt - normalize_factor));
407 return normalize_factor;
410 value_t remove_if_normalize(
const T& t)
412 return remove_if_normalize(
413 [&](
const auto& elem) {
return elem.item == t; });
416 auto begin(
this auto&& self) {
return self.distribution_.begin(); }
417 auto end(
this auto&& self) {
return self.distribution_.end(); }
419 auto support(
this auto&& self)
421 return std::views::transform(
427 operator<=>(
const Distribution<T>& left,
const Distribution<T>& right) =
434struct is_item_prob_pair : std::false_type {};
437struct is_item_prob_pair<ItemProbabilityPair<T>> : std::true_type {};
440constexpr bool is_item_prob_pair_v = is_item_prob_pair<T>::value;
446struct item<ItemProbabilityPair<T>> {
451using item_t =
typename item<T>::type;
455template <std::ranges::input_range R>
456 requires(detail::is_item_prob_pair_v<std::ranges::range_value_t<R>>)
457Distribution(std::from_range_t, R&&)
458 -> Distribution<detail::item_t<std::ranges::range_value_t<R>>>;
462template <
typename T,
typename F>
463struct std::tuple_size<
probfd::ItemProbabilityPair<T, F>>
464 :
public integral_constant<std::size_t, 2> {};
466template <std::
size_t I,
typename T,
typename F>
467struct std::tuple_element<I,
probfd::ItemProbabilityPair<T, F>> {
468 static_assert(
false,
"Invalid index");
471template <
typename T,
typename F>
472struct std::tuple_element<0,
probfd::ItemProbabilityPair<T, F>> {
476template <
typename T,
typename F>
477struct std::tuple_element<1,
probfd::ItemProbabilityPair<T, F>> {
void reserve(size_t capacity)
Reserves space for capacity number of elements in the support of the distribution.
Definition distribution.h:207
value_t expectation(RandomVariable rv) const
Computes the expectation over a real random variable according to the distribution.
Definition distribution.h:287
size_t size() const
Returns the size of the support.
Definition distribution.h:222
iterator erase(iterator it)
Removes the element-probability pair pointed to by it.
Definition distribution.h:369
bool is_dirac() const
Checks if the distribution is a Dirac distribution.
Definition distribution.h:276
void normalize(value_t scale)
Scales all element probablities by a common factor.
Definition distribution.h:316
bool is_dirac(const T &t) const
Checks if the distribution is a Dirac distribution wrt an element.
Definition distribution.h:267
value_t expectation(RandomVariable rv) const
Computes the expectation over a real random variable according to the distribution.
Definition distribution.h:304
void normalize()
Normalizes the probabilities of the elements to sum up to one.
Definition distribution.h:326
iterator erase(iterator it, iterator last)
Removes a range of element-probability pairs.
Definition distribution.h:377
bool empty() const
Checks if the distribution is in an empty state.
Definition distribution.h:213
An item-probability pair.
Definition distribution.h:20
PrType probability
The probability of the item.
Definition distribution.h:38
ItemProbabilityPair()=default
Pairs a default-constructed item with an indeterminate probability.
T item
The item.
Definition distribution.h:37
ItemProbabilityPair(std::piecewise_construct_t, std::tuple< Args... > t1, std::tuple< Args2... > t2)
Pairs an item constructed from a tuple of constructor arguments with a given probability.
Definition distribution.h:90
friend auto operator<=>(const ItemProbabilityPair< T, PrType > &left, const ItemProbabilityPair< T, PrType > &right)=default
Lexicographical comparison.
The top-level namespace of probabilistic Fast Downward.
Definition command_line.h:8
constexpr no_normalize_t no_normalize
Disambiguator tag for Distribution constructor to indicate that the probabilities are already normali...
Definition distribution.h:146
double value_t
Typedef for the state value type.
Definition aliases.h:7
Disambiguator tag type.
Definition distribution.h:142