LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
mt19937.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_MT19937_H
6#define LINE_OPT_DE_MT19937_H
7
8/**
9 * @file
10 * @ingroup line_opt
11 * Bit-exact port of `matlab/src/opt/+opt/+de/MT19937.m`.
12 *
13 * This is NumPy's legacy MT19937 core, including its scalar seeding rule. It
14 * intentionally does not use `std::mt19937`: the standard fixes the generator
15 * recurrence but not NumPy RandomState's seed expansion and draw adapters, and
16 * line-opt requires the same word stream in every language so Differential
17 * Evolution follows the same trajectory for a fixed seed.
18 */
19
20#include <array>
21#include <cstddef>
22#include <cstdint>
23#include <vector>
24
25#include "line/util/error.h"
26
27namespace line {
28namespace opt {
29namespace de {
30
31class MT19937 {
32public:
33 static constexpr std::size_t state_size = 624;
34
35 explicit MT19937(std::uint64_t seed_value) { seed(seed_value); }
36
37 /** NumPy legacy scalar seeding (`init_genrand`, or little-endian words). */
38 void seed(std::uint64_t value) {
39 if (value <= UINT64_C(0xffffffff)) {
40 init_genrand(static_cast<std::uint32_t>(value));
41 return;
42 }
43 std::vector<std::uint32_t> key;
44 while (value != 0) {
45 key.push_back(static_cast<std::uint32_t>(value & UINT64_C(0xffffffff)));
46 value >>= 32;
47 }
48 init_by_array(key);
49 }
50
51 void init_genrand(std::uint32_t value) {
52 mt_[0] = value;
53 for (std::size_t i = 1; i < state_size; ++i) {
54 const std::uint32_t prev = mt_[i - 1];
55 mt_[i] = UINT32_C(1812433253) * (prev ^ (prev >> 30)) +
56 static_cast<std::uint32_t>(i);
57 }
58 pos_ = state_size;
59 }
60
61 void init_by_array(const std::vector<std::uint32_t>& key) {
62 if (key.empty()) throw InputError("MT19937::init_by_array: the seed key is empty");
63 init_genrand(UINT32_C(19650218));
64 std::size_t i = 1, j = 0;
65 std::size_t k = state_size > key.size() ? state_size : key.size();
66 for (; k != 0; --k) {
67 const std::uint32_t prev = mt_[i - 1];
68 mt_[i] = (mt_[i] ^ ((prev ^ (prev >> 30)) * UINT32_C(1664525))) + key[j] +
69 static_cast<std::uint32_t>(j);
70 ++i;
71 ++j;
72 if (i >= state_size) {
73 mt_[0] = mt_[state_size - 1];
74 i = 1;
75 }
76 if (j >= key.size()) j = 0;
77 }
78 for (k = state_size - 1; k != 0; --k) {
79 const std::uint32_t prev = mt_[i - 1];
80 mt_[i] = (mt_[i] ^ ((prev ^ (prev >> 30)) * UINT32_C(1566083941))) -
81 static_cast<std::uint32_t>(i);
82 ++i;
83 if (i >= state_size) {
84 mt_[0] = mt_[state_size - 1];
85 i = 1;
86 }
87 }
88 mt_[0] = UINT32_C(0x80000000);
89 pos_ = state_size;
90 }
91
92 /** Next tempered word, exactly `MT19937.nextUint32` in the MATLAB port. */
93 std::uint32_t next_uint32() {
94 constexpr std::size_t M = 397;
95 constexpr std::uint32_t matrix_a = UINT32_C(0x9908b0df);
96 constexpr std::uint32_t upper = UINT32_C(0x80000000);
97 constexpr std::uint32_t lower = UINT32_C(0x7fffffff);
98 if (pos_ >= state_size) {
99 std::size_t k = 0;
100 for (; k < state_size - M; ++k) {
101 const std::uint32_t y = (mt_[k] & upper) | (mt_[k + 1] & lower);
102 mt_[k] = mt_[k + M] ^ (y >> 1) ^ ((y & 1U) ? matrix_a : 0U);
103 }
104 for (; k < state_size - 1; ++k) {
105 const std::uint32_t y = (mt_[k] & upper) | (mt_[k + 1] & lower);
106 mt_[k] = mt_[k + (M - state_size)] ^ (y >> 1) ^
107 ((y & 1U) ? matrix_a : 0U);
108 }
109 const std::uint32_t y = (mt_[state_size - 1] & upper) | (mt_[0] & lower);
110 mt_[state_size - 1] = mt_[M - 1] ^ (y >> 1) ^ ((y & 1U) ? matrix_a : 0U);
111 pos_ = 0;
112 }
113
114 std::uint32_t y = mt_[pos_++];
115 y ^= y >> 11;
116 y ^= (y << 7) & UINT32_C(0x9d2c5680);
117 y ^= (y << 15) & UINT32_C(0xefc60000);
118 y ^= y >> 18;
119 return y;
120 }
121
122 const std::array<std::uint32_t, state_size>& state_key() const { return mt_; }
123 std::size_t position() const { return pos_; }
124
125private:
126 std::array<std::uint32_t, state_size> mt_{};
127 std::size_t pos_ = state_size;
128};
129
130} // namespace de
131} // namespace opt
132} // namespace line
133
134#endif
InputError(const std::string &what)
Definition error.h:39
MT19937(std::uint64_t seed_value)
Definition mt19937.h:35
const std::array< std::uint32_t, state_size > & state_key() const
Definition mt19937.h:122
void seed(std::uint64_t value)
NumPy legacy scalar seeding (init_genrand, or little-endian words).
Definition mt19937.h:38
std::size_t position() const
Definition mt19937.h:123
static constexpr std::size_t state_size
Definition mt19937.h:33
void init_genrand(std::uint32_t value)
Definition mt19937.h:51
void init_by_array(const std::vector< std::uint32_t > &key)
Definition mt19937.h:61
std::uint32_t next_uint32()
Next tempered word, exactly MT19937.nextUint32 in the MATLAB port.
Definition mt19937.h:93
The exception types the port throws.