Ultra 0.9.4
Loading...
Searching...
No Matches
random.h
Go to the documentation of this file.
1
12
13#if !defined(ULTRA_RANDOM_H)
14#define ULTRA_RANDOM_H
15
16#include "kernel/interval.h"
17
18#include "utility/assert.h"
19#include "utility/misc.h"
20#include "utility/xoshiro256ss.h"
21
22#include <random>
23#include <type_traits>
24
25namespace ultra::random
26{
27
28enum class distribution {uniform, normal};
29
36using engine_t = vigna::xoshiro256ss;
37
38[[nodiscard]] engine_t &engine();
39[[nodiscard]] std::size_t ring(std::size_t, std::size_t, std::size_t);
40void randomize();
41
56template<std::floating_point T>
57[[nodiscard]] T between(T min, T sup)
58{
59 Expects(min < sup);
60
61 std::uniform_real_distribution<T> d(min, sup);
62 return d(engine());
63}
64
78template<std::integral T>
79[[nodiscard]] T between(T min, T sup)
80{
81 Expects(min < sup);
82
83 std::uniform_int_distribution<T> d(min, sup - 1);
84 return d(engine());
85}
86
87template<class T>
88requires std::is_enum_v<T>
89[[nodiscard]] T between(T min, T sup)
90{
91 Expects(min < sup);
92
93 return static_cast<T>(between<std::underlying_type_t<T>>(min, sup));
94}
95
102template<class T>
103requires std::is_arithmetic_v<T> || std::is_enum_v<T>
104[[nodiscard]] T sup(T sup)
105{
106 return between(static_cast<T>(0), sup);
107}
108
113template<std::ranges::sized_range C>
114[[nodiscard]] std::ranges::range_reference_t<const C> element(const C &c)
115{
116 Expects(c.size());
117
118 return *std::next(
119 c.begin(),
120 static_cast<typename C::difference_type>(sup(c.size())));
121}
122
127template<ArithmeticScalar A>
128[[nodiscard]] A element(const interval<A> &i)
129{
130 return between(i.min, i.sup);
131}
132
137template<std::ranges::sized_range C>
138[[nodiscard]] typename C::value_type &element(C &c)
139{
140 Expects(c.size());
141
142 return *std::next(
143 c.begin(),
144 static_cast<typename C::difference_type>(sup(c.size())));
145}
146
154[[nodiscard]] inline bool boolean(double p)
155{
156 Expects(in_0_1(p));
157
158 std::bernoulli_distribution d(p);
159 return d(engine());
160}
161
170[[nodiscard]] inline bool boolean()
171{
172 // Fast path for fair coin flips: cache one PRNG result and consume it one
173 // bit at a time, amortising one engine call across all bits in
174 // `engine_t::result_type`.
175 class thread_local_coin_flip
176 {
177 public:
178 [[nodiscard]] bool operator()()
179 {
180 if (!bits_left_) [[unlikely]]
181 {
182 cache_ = random::engine()();
183 bits_left_ = std::numeric_limits<word_t>::digits;
184 }
185
186 const bool result((cache_ >> (bits_left_ - 1)) & 1u);
187 --bits_left_;
188 return result;
189 }
190
191 private:
192 using word_t = random::engine_t::result_type;
193
194 word_t cache_ {random::engine()()};
195 unsigned bits_left_ {std::numeric_limits<word_t>::digits};
196 };
197
198 thread_local thread_local_coin_flip coin_flip;
199 return coin_flip();
200}
201
217template<class T>
218requires std::is_arithmetic_v<T>
219[[nodiscard]] T ephemeral(distribution d, T p1, T p2)
220{
221 Expects(p1 < p2);
222
223 switch (d)
224 {
225 case distribution::normal:
226 return std::normal_distribution<T>(std::midpoint(p1, p2),
227 p2 - p1)(engine());
228 default:
229 return between(p1, p2);
230 }
231}
232
233} // namespace ultra::random
234
235#endif // include guard
void randomize()
Definition random.cc:115
std::size_t ring(std::size_t base, std::size_t radius, std::size_t n)
Definition random.cc:64
engine_t & engine()
Definition random.cc:83
T ephemeral(distribution d, T p1, T p2)
Definition random.h:219
std::ranges::range_reference_t< const C > element(const C &c)
Definition random.h:114
T sup(T sup)
Definition random.h:104
bool boolean(double p)
Definition random.h:154
vigna::xoshiro256ss engine_t
Definition random.h:36
T between(T min, T sup)
Definition random.h:57
Definition interval.h:37