LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
numpy_random_state.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 */
5#ifndef LINE_OPT_DE_NUMPY_RANDOM_STATE_H
6#define LINE_OPT_DE_NUMPY_RANDOM_STATE_H
7
8/**
9 * @file
10 * @ingroup line_opt
11 * Bit-exact port of `matlab/src/opt/+opt/+de/NumpyRandomState.m`.
12 *
13 * Only the legacy NumPy RandomState operations consumed by line-opt are
14 * exposed: random_sample, uniform, default-dtype randint, shuffle and
15 * permutation. Their word consumption is part of the contract.
16 */
17
18#include <algorithm>
19#include <cstddef>
20#include <cstdint>
21#include <numeric>
22#include <vector>
23
24#include "line/opt/de/mt19937.h"
25#include "line/util/error.h"
26
27namespace line {
28namespace opt {
29namespace de {
30
32public:
33 explicit NumpyRandomState(std::uint64_t seed) : gen_(seed) {}
34
35 MT19937& generator() { return gen_; }
36 const MT19937& generator() const { return gen_; }
37
38 /** NumPy `random_sample()`: one 53-bit double from two generator words. */
39 double random_sample() {
40 const std::uint64_t a = static_cast<std::uint64_t>(gen_.next_uint32() >> 5);
41 const std::uint64_t b = static_cast<std::uint64_t>(gen_.next_uint32() >> 6);
42 return (static_cast<double>(a) * 67108864.0 + static_cast<double>(b)) /
43 9007199254740992.0;
44 }
45
46 std::vector<double> random_sample(std::size_t n) {
47 std::vector<double> out(n);
48 for (double& value : out) value = random_sample();
49 return out;
50 }
51
52 double uniform(double low = 0.0, double high = 1.0) {
53 return low + (high - low) * random_sample();
54 }
55
56 std::vector<double> uniform(double low, double high, std::size_t n) {
57 std::vector<double> out(n);
58 for (double& value : out) value = low + (high - low) * random_sample();
59 return out;
60 }
61
62 std::uint64_t randint(std::uint64_t low, std::uint64_t high) {
63 if (high <= low) throw InputError("NumpyRandomState::randint: high must exceed low");
64 const std::uint64_t range = high - 1 - low;
65 if (range > UINT64_C(0xffffffff))
66 throw InputError(
67 "NumpyRandomState::randint: the line-opt RandomState subset uses 32-bit ranges");
68 if (range == 0) return low;
69 const std::uint64_t mask = fill_mask(range);
70 for (;;) {
71 const std::uint64_t value = static_cast<std::uint64_t>(gen_.next_uint32()) & mask;
72 if (value <= range) return low + value;
73 }
74 }
75
76 std::uint64_t randint(std::uint64_t high) { return randint(0, high); }
77
78 std::uint64_t random_interval(std::uint64_t max_value) {
79 if (max_value > UINT64_C(0xffffffff))
80 throw InputError("NumpyRandomState::random_interval: max exceeds 32 bits");
81 if (max_value == 0) return 0;
82 const std::uint64_t mask = fill_mask(max_value);
83 for (;;) {
84 const std::uint64_t value = static_cast<std::uint64_t>(gen_.next_uint32()) & mask;
85 if (value <= max_value) return value;
86 }
87 }
88
89 template <class T>
90 void shuffle(std::vector<T>& values) {
91 for (std::size_t p = values.size(); p > 1; --p) {
92 const std::size_t j = static_cast<std::size_t>(random_interval(p - 1));
93 std::swap(values[p - 1], values[j]);
94 }
95 }
96
97 std::vector<std::size_t> permutation(std::size_t n) {
98 std::vector<std::size_t> out(n);
99 std::iota(out.begin(), out.end(), std::size_t(0));
100 shuffle(out);
101 return out;
102 }
103
104private:
105 static std::uint64_t fill_mask(std::uint64_t value) {
106 value |= value >> 1;
107 value |= value >> 2;
108 value |= value >> 4;
109 value |= value >> 8;
110 value |= value >> 16;
111 return value;
112 }
113
114 MT19937 gen_;
115};
116
117} // namespace de
118} // namespace opt
119} // namespace line
120
121#endif
InputError(const std::string &what)
Definition error.h:39
std::vector< std::size_t > permutation(std::size_t n)
void shuffle(std::vector< T > &values)
std::vector< double > uniform(double low, double high, std::size_t n)
double random_sample()
NumPy random_sample(): one 53-bit double from two generator words.
std::uint64_t random_interval(std::uint64_t max_value)
const MT19937 & generator() const
std::uint64_t randint(std::uint64_t high)
std::uint64_t randint(std::uint64_t low, std::uint64_t high)
std::vector< double > random_sample(std::size_t n)
double uniform(double low=0.0, double high=1.0)
The exception types the port throws.
Bit-exact port of matlab/src/opt/+opt/+de/MT19937.m.