CDT++ 1.0.0
Causal Dynamical Triangulations in C++
Loading...
Searching...
No Matches
Random.hpp
Go to the documentation of this file.
1/*******************************************************************************
2 Causal Dynamical Triangulations in C++ using CGAL
3
4 Copyright © 2026 Adam Getchell
5 ******************************************************************************/
6
9
10#ifndef CDT_PLUSPLUS_RANDOM_HPP
11#define CDT_PLUSPLUS_RANDOM_HPP
12
13#include <concepts>
14#include <cstdint>
15#include <istream>
16#include <limits>
17#include <locale>
18#include <ostream>
19#include <random>
20#include <sstream>
21#include <stdexcept>
22#include <string>
23#include <string_view>
24
25#if !defined(__SIZEOF_INT128__) || (defined(PCG_FORCE_EMULATED_128BIT_MATH) && \
26 PCG_FORCE_EMULATED_128BIT_MATH)
27#include "pcg_uint128.hpp"
28
30namespace pcg_extras
31{
32 // PCG's specific_stream::set_stream uses an int literal with its emulated
33 // 128-bit value. Supply the heterogeneous overload that template deduction
34 // cannot obtain through uint_x4's converting constructor.
35 template <typename UInt, typename UIntX2>
36 [[nodiscard]] auto operator|(uint_x4<UInt, UIntX2> const& value,
37 int const bits) -> uint_x4<UInt, UIntX2>
38 { return value | uint_x4<UInt, UIntX2>{bits}; }
39} // namespace pcg_extras
41#endif
42
43#include "pcg_random.hpp"
44
45namespace cdt
46{
48 class RandomSeed final
49 {
50 std::uint64_t m_value{};
51
52 public:
53 constexpr RandomSeed() noexcept = default;
55 explicit constexpr RandomSeed(std::uint64_t const value) noexcept
56 : m_value{value}
57 {}
58
60 [[nodiscard]] constexpr auto value() const noexcept -> std::uint64_t
61 { return m_value; }
62
65 [[nodiscard]] auto operator==(RandomSeed const& other) const noexcept
66 -> bool = default;
67 };
68
70 class RandomStream final
71 {
72 std::uint64_t m_value{};
73
74 public:
75 constexpr RandomStream() noexcept = default;
77 explicit constexpr RandomStream(std::uint64_t const value) noexcept
78 : m_value{value}
79 {}
80
82 [[nodiscard]] constexpr auto value() const noexcept -> std::uint64_t
83 { return m_value; }
84
87 [[nodiscard]] auto operator==(RandomStream const& other) const noexcept
88 -> bool = default;
89 };
90
93 [[nodiscard]] constexpr auto format_as(RandomSeed const seed) noexcept
94 -> std::uint64_t
95 { return seed.value(); }
96
99 [[nodiscard]] constexpr auto format_as(RandomStream const stream) noexcept
100 -> std::uint64_t
101 { return stream.value(); }
102
106 inline auto operator<<(std::ostream& output, RandomSeed const seed)
107 -> std::ostream&
108 { return output << seed.value(); }
109
113 inline auto operator<<(std::ostream& output, RandomStream const stream)
114 -> std::ostream&
115 { return output << stream.value(); }
116
117 namespace random_streams
118 {
120 inline constexpr RandomStream initialization{0};
122 inline constexpr RandomStream transitions{1};
123 } // namespace random_streams
124
136 class Random final
137 {
138 public:
140 using result_type = pcg64::result_type;
141
142 private:
143 RandomSeed m_seed{};
144 RandomStream m_stream{};
145 pcg64 m_engine;
146
147 [[nodiscard]] static auto entropy_seed() -> RandomSeed
148 {
149 std::random_device entropy;
150 std::uniform_int_distribution<std::uint64_t> distribution{
151 std::numeric_limits<std::uint64_t>::min(),
152 std::numeric_limits<std::uint64_t>::max()};
153 return RandomSeed{distribution(entropy)};
154 }
155
156 public:
158 Random() : Random{entropy_seed()} {}
159
162 explicit Random(std::uint64_t const seed) : Random{RandomSeed{seed}} {}
163
168 explicit Random(RandomSeed const seed,
170 : m_seed{seed}, m_stream{stream}, m_engine{seed.value(), stream.value()}
171 {}
172
174 [[nodiscard]] static constexpr auto min() noexcept -> result_type
175 { return pcg64::min(); }
176
178 [[nodiscard]] static constexpr auto max() noexcept -> result_type
179 { return pcg64::max(); }
180
182 [[nodiscard]] auto operator()() -> result_type { return m_engine(); }
183
185 [[nodiscard]] auto seed() const noexcept -> RandomSeed { return m_seed; }
186
188 [[nodiscard]] auto stream() const noexcept -> RandomStream
189 { return m_stream; }
190
194 [[nodiscard]] auto split(RandomStream const stream) const -> Random
195 { return Random{m_seed, stream}; }
196
199 [[nodiscard]] auto serialized_state() const -> std::string
200 {
201 std::ostringstream output;
202 output.imbue(std::locale::classic());
203 output << m_engine;
204 if (!output)
205 {
206 throw std::runtime_error("Could not serialize PCG state.");
207 }
208 return output.str();
209 }
210
218 [[nodiscard]] static auto from_serialized_state(
219 RandomSeed const seed, RandomStream const stream,
220 std::string_view const state) -> Random
221 {
222 auto restored = Random{seed, stream};
223 auto const expected_stream = restored.m_engine.stream();
224 std::istringstream input{std::string{state}};
225 input.imbue(std::locale::classic());
226 input >> restored.m_engine;
227 if (!input || restored.m_engine.stream() != expected_stream)
228 {
229 throw std::invalid_argument("Malformed or mismatched PCG state.");
230 }
231 input >> std::ws;
232 if (!input.eof())
233 {
234 throw std::invalid_argument("PCG state contains trailing data.");
235 }
236 return restored;
237 }
238 };
239
240 static_assert(std::uniform_random_bit_generator<Random>);
241} // namespace cdt
242
243#endif // CDT_PLUSPLUS_RANDOM_HPP
constexpr RandomStream initialization
Stream reserved for initial triangulation generation.
Definition Random.hpp:120
constexpr RandomStream transitions
Stream reserved for stochastic state transitions.
Definition Random.hpp:122
auto split(RandomStream const stream) const -> Random
Create a fresh reproducible stream from the same root seed.
Definition Random.hpp:194
auto serialized_state() const -> std::string
Serialize the complete mutable PCG state for exact continuation.
Definition Random.hpp:199
Random()
Construct a root stream from operating-system entropy.
Definition Random.hpp:158
Random(std::uint64_t const seed)
Construct a root stream from a raw seed value.
Definition Random.hpp:162
static constexpr auto max() noexcept -> result_type
Definition Random.hpp:178
auto operator()() -> result_type
Definition Random.hpp:182
static auto from_serialized_state(RandomSeed const seed, RandomStream const stream, std::string_view const state) -> Random
Restore an exact PCG continuation point.
Definition Random.hpp:218
Random(RandomSeed const seed, RandomStream const stream=RandomStream{})
Construct a reproducible PCG stream without consulting entropy.
Definition Random.hpp:168
static constexpr auto min() noexcept -> result_type
Definition Random.hpp:174
pcg64::result_type result_type
Unsigned result type required by std::uniform_random_bit_generator.
Definition Random.hpp:140
auto seed() const noexcept -> RandomSeed
Definition Random.hpp:185
auto stream() const noexcept -> RandomStream
Definition Random.hpp:188
Root entropy value used to reproduce a random run.
Definition Random.hpp:49
constexpr auto value() const noexcept -> std::uint64_t
Definition Random.hpp:60
auto operator==(RandomSeed const &other) const noexcept -> bool=default
constexpr RandomSeed(std::uint64_t const value) noexcept
Definition Random.hpp:55
PCG sequence selector derived from a root random seed.
Definition Random.hpp:71
auto operator==(RandomStream const &other) const noexcept -> bool=default
constexpr auto value() const noexcept -> std::uint64_t
Definition Random.hpp:82
constexpr RandomStream(std::uint64_t const value) noexcept
Definition Random.hpp:77
clang-15 does not support std::format
constexpr auto format_as(RandomSeed const seed) noexcept -> std::uint64_t
Definition Random.hpp:93
auto operator<<(std::ostream &output, RandomSeed const seed) -> std::ostream &
Definition Random.hpp:106