LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
rng_ssj.h File Reference

The two random number generators the Java LDES engine draws from, reproduced exactly: SSJ's MRG32k3a and java.util.Random. More...

#include <cmath>
#include <cstdint>
#include <string>
#include "line/util/error.h"
Include dependency graph for rng_ssj.h:

Go to the source code of this file.

Classes

class  line::rng::Mrg32k3a
 SSJ's umontreal.ssj.rng.MRG32k3a, state and all. More...
class  line::rng::JavaRandom
 java.util.Random, the 48-bit LCG of the Java Language Specification. More...

Namespaces

namespace  line
namespace  line::rng

Detailed Description

The two random number generators the Java LDES engine draws from, reproduced exactly: SSJ's MRG32k3a and java.util.Random.

WHY THIS EXISTS. common/ldes is to become the C++ engine compiled, in place of a GraalVM image of the Java one, and a simulator that answers with a different sample path at the same seed is not a replacement – every seeded golden in MATLAB, Python and the parity harness would re-baseline, and "LDES agrees across the codebases at a given seed", which CLAUDE.md states as an invariant, would weaken to "agrees in distribution". The C++ engine previously drew from std::mt19937_64; this header is the first half of closing that gap, and ldes_sampler.h is the second (the variate algorithms must consume the same uniforms in the same order).

WHAT MADE IT TRACTABLE. Solver_ssj never relies on SSJ's package-level stream sequence: every stream is created and then given an EXPLICIT six-long seed derived from the run seed and a per-(node, class) offset, e.g.

long offset = ((long) (numSources + svcIdx) * numClasses + k) * 10 + 1000;
stream.setSeed(new long[] { seed + offset, ..., seed + offset + 5 });

so none of SSJ's 2^127 jump-ahead machinery is on the path. Matching the engine means matching the recurrence, nextValue/nextDouble, and those offsets – not the stream hierarchy.

MRG32k3a is L'Ecuyer's combined multiple recursive generator (Operations Research 47(1), 1999): two order-three recurrences modulo m1 = 2^32 - 209 and m2 = 2^32 - 22853, combined by subtraction. SSJ computes it in DOUBLES with the multipliers split so every intermediate stays exactly representable, and that arithmetic is reproduced here rather than an integer rewrite: the double form is what the reference runs, and the two agree only if the rounding does.

java.util.Random is the specified 48-bit LCG of the Java Language Specification: seed scrambling by 0x5DEECE66D, next(bits) taking the high bits, nextDouble from a 26-bit and a 27-bit draw, and nextInt(bound) with its rejection loop for non-power-of-two bounds. All of it is normative, so a faithful transcription is exact by construction.

Definition in file rng_ssj.h.