10#ifndef CDT_PLUSPLUS_RANDOM_HPP
11#define CDT_PLUSPLUS_RANDOM_HPP
25#if !defined(__SIZEOF_INT128__) || (defined(PCG_FORCE_EMULATED_128BIT_MATH) && \
26 PCG_FORCE_EMULATED_128BIT_MATH)
27#include "pcg_uint128.hpp"
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}; }
43#include "pcg_random.hpp"
48 class RandomSeed final
50 std::uint64_t m_value{};
53 constexpr RandomSeed()
noexcept =
default;
60 [[nodiscard]]
constexpr auto value() const noexcept -> std::uint64_t
65 [[nodiscard]]
auto operator==(RandomSeed
const& other)
const noexcept
70 class RandomStream final
72 std::uint64_t m_value{};
75 constexpr RandomStream()
noexcept =
default;
82 [[nodiscard]]
constexpr auto value() const noexcept -> std::uint64_t
87 [[nodiscard]]
auto operator==(RandomStream
const& other)
const noexcept
95 {
return seed.value(); }
101 {
return stream.value(); }
108 {
return output << seed.value(); }
115 {
return output << stream.value(); }
117 namespace random_streams
147 [[nodiscard]]
static auto entropy_seed() -> RandomSeed
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)};
175 {
return pcg64::min(); }
179 {
return pcg64::max(); }
201 std::ostringstream output;
202 output.imbue(std::locale::classic());
206 throw std::runtime_error(
"Could not serialize PCG state.");
220 std::string_view
const state) ->
Random
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)
229 throw std::invalid_argument(
"Malformed or mismatched PCG state.");
234 throw std::invalid_argument(
"PCG state contains trailing data.");
240 static_assert(std::uniform_random_bit_generator<Random>);
constexpr RandomStream initialization
Stream reserved for initial triangulation generation.
constexpr RandomStream transitions
Stream reserved for stochastic state transitions.
auto split(RandomStream const stream) const -> Random
Create a fresh reproducible stream from the same root seed.
auto serialized_state() const -> std::string
Serialize the complete mutable PCG state for exact continuation.
Random()
Construct a root stream from operating-system entropy.
Random(std::uint64_t const seed)
Construct a root stream from a raw seed value.
static constexpr auto max() noexcept -> result_type
auto operator()() -> result_type
static auto from_serialized_state(RandomSeed const seed, RandomStream const stream, std::string_view const state) -> Random
Restore an exact PCG continuation point.
Random(RandomSeed const seed, RandomStream const stream=RandomStream{})
Construct a reproducible PCG stream without consulting entropy.
static constexpr auto min() noexcept -> result_type
pcg64::result_type result_type
Unsigned result type required by std::uniform_random_bit_generator.
auto seed() const noexcept -> RandomSeed
auto stream() const noexcept -> RandomStream
Root entropy value used to reproduce a random run.
constexpr auto value() const noexcept -> std::uint64_t
auto operator==(RandomSeed const &other) const noexcept -> bool=default
constexpr RandomSeed(std::uint64_t const value) noexcept
PCG sequence selector derived from a root random seed.
auto operator==(RandomStream const &other) const noexcept -> bool=default
constexpr auto value() const noexcept -> std::uint64_t
constexpr RandomStream(std::uint64_t const value) noexcept
clang-15 does not support std::format
constexpr auto format_as(RandomSeed const seed) noexcept -> std::uint64_t
auto operator<<(std::ostream &output, RandomSeed const seed) -> std::ostream &