LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
matlab_rng.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_GEN_MATLAB_RNG_H
6#define LINE_GEN_MATLAB_RNG_H
7
8/**
9 * @file
10 * @ingroup line_gen
11 * MATLAB-faithful random draws for the model generators: the C++ twin of the
12 * JAR `jline.gen.MatlabRandom` and the native Python `line_solver.gen.matlab_rng`.
13 *
14 * A `MatlabRng` seeded with s yields the stream MATLAB yields after `rng(s)`
15 * (MT19937 `init_genrand`, numpy's legacy `RandomState(s)`). `rand` is numpy's
16 * `random_sample`, `randi(lo, hi)` is `lo-1+ceil((hi-lo+1)*rand)` (a degenerate
17 * range still consumes a draw), `randperm(n)` is the stable sort order of
18 * `rand(1,n)` and `randfixedsum` is Roger Stafford's original, draw for draw.
19 * Checked against MATLAB R2026a on 2026-10-13.
20 *
21 * Unlike MATLAB's global generator the stream here belongs to its owner, so two
22 * generators never share one; within one generator the draw sequence is MATLAB's.
23 */
24
25#include <algorithm>
26#include <cmath>
27#include <cstddef>
28#include <cstdint>
29#include <limits>
30#include <numeric>
31#include <vector>
32
34
35namespace line {
36namespace gen {
37
38/** One MATLAB global random stream, as left by `rng(seed)`. */
39class MatlabRng {
40public:
41 explicit MatlabRng(long long seed = 0) : state_(std::uint64_t(seed) & 0xffffffffULL) {}
42
43 /** MATLAB `rng(seed)`. */
44 void reseed(long long seed) { state_ = opt::de::NumpyRandomState(std::uint64_t(seed) & 0xffffffffULL); }
45
46 /** One MATLAB `rand` draw. */
47 double rand() { return state_.random_sample(); }
48
49 /** MATLAB `randi([lo, hi])`. */
50 int randi(int lo, int hi) { return lo - 1 + int(std::ceil(double(hi - lo + 1) * rand())); }
51
52 /** MATLAB `randperm(n)`, returned 0-based. */
53 std::vector<std::size_t> randperm(std::size_t n) {
54 std::vector<double> u(n);
55 for (std::size_t i = 0; i < n; ++i) u[i] = rand();
56 std::vector<std::size_t> idx(n);
57 std::iota(idx.begin(), idx.end(), std::size_t(0));
58 std::stable_sort(idx.begin(), idx.end(),
59 [&u](std::size_t a, std::size_t b) { return u[a] < u[b]; });
60 return idx;
61 }
62
63 /**
64 * One column of `randfixedsum(n,1,s,a,b)` (matlab/lib/thirdparty/randfixedsum.m):
65 * draws `rand(n-1,1)` twice, then `rand(n,1)` for the permutation.
66 */
67 std::vector<double> randfixedsum(std::size_t n, double s, double a, double b) {
68 const double nn = double(n);
69 s = (s - nn * a) / (b - a);
70 const int k = std::max(std::min(int(std::floor(s)), int(n) - 1), 0);
71 s = std::max(std::min(s, double(k + 1)), double(k));
72 std::vector<double> s1(n), s2(n);
73 for (std::size_t i = 0; i < n; ++i) {
74 s1[i] = s - double(k - int(i));
75 s2[i] = double(k + int(n) - int(i)) - s;
76 }
77 const double tiny = std::numeric_limits<double>::denorm_min();
78 std::vector<std::vector<double>> w(n, std::vector<double>(n + 1, 0.0));
79 w[0][1] = std::numeric_limits<double>::max();
80 std::vector<std::vector<double>> t(n > 1 ? n - 1 : 0, std::vector<double>(n, 0.0));
81 for (std::size_t i = 2; i <= n; ++i) {
82 const double di = double(i);
83 for (std::size_t c = 0; c < i; ++c) {
84 const double tmp1 = w[i - 2][c + 1] * s1[c] / di;
85 const double tmp2 = w[i - 2][c] * s2[n - i + c] / di;
86 w[i - 1][c + 1] = tmp1 + tmp2;
87 const double tmp3 = w[i - 1][c + 1] + tiny;
88 const bool tmp4 = s2[n - i + c] > s1[c];
89 t[i - 2][c] = tmp4 ? tmp2 / tmp3 : 1.0 - tmp1 / tmp3;
90 }
91 }
92 std::vector<double> x(n, 0.0);
93 std::vector<double> rt(n > 1 ? n - 1 : 0), rs(n > 1 ? n - 1 : 0);
94 for (double& v : rt) v = rand();
95 for (double& v : rs) v = rand();
96 int j = k + 1;
97 double sm = 0.0, pr = 1.0;
98 for (std::size_t i = n - 1; i >= 1; --i) {
99 const double e = rt[n - i - 1] <= t[i - 1][std::size_t(j - 1)] ? 1.0 : 0.0;
100 const double sx = std::pow(rs[n - i - 1], 1.0 / double(i));
101 sm += (1.0 - sx) * pr * s / double(i + 1);
102 pr *= sx;
103 x[n - i - 1] = sm + pr * e;
104 s -= e;
105 j -= int(e);
106 }
107 x[n - 1] = sm + pr * s;
108 const std::vector<std::size_t> p = randperm(n);
109 std::vector<double> out(n);
110 for (std::size_t i = 0; i < n; ++i) out[i] = (b - a) * x[p[i]] + a;
111 return out;
112 }
113
114private:
116};
117
118} // namespace gen
119} // namespace line
120
121#endif // LINE_GEN_MATLAB_RNG_H
double rand()
One MATLAB rand draw.
Definition matlab_rng.h:47
std::vector< std::size_t > randperm(std::size_t n)
MATLAB randperm(n), returned 0-based.
Definition matlab_rng.h:53
int randi(int lo, int hi)
MATLAB randi([lo, hi]).
Definition matlab_rng.h:50
MatlabRng(long long seed=0)
Definition matlab_rng.h:41
std::vector< double > randfixedsum(std::size_t n, double s, double a, double b)
One column of randfixedsum(n,1,s,a,b) (matlab/lib/thirdparty/randfixedsum.m): draws rand(n-1,...
Definition matlab_rng.h:67
void reseed(long long seed)
MATLAB rng(seed).
Definition matlab_rng.h:44
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
Bit-exact port of matlab/src/opt/+opt/+de/NumpyRandomState.m.