Reproducible random numbers

Reproducible random numbers#

Fill an array with seeded normal draws, and show that the same seed reproduces the same stream – the exact sequence of numbers it draws.

Time: ~2 min · Runs on: CPU · You need: Random numbers

Hide code cell source

%run ../_shared/setup.py
running on: cpu

Generator(seed) plus .normal<Real, D>(mean, sd) draws a D-component normal sample.

Each draw is addressed by a SampleIndex – SampleIndex::make(idx) wraps a plain index so a View can be indexed by it (va[i]), the same identity a GPU kernel would use per thread.

Two different Generator values, same seed, must draw the identical stream:

RNG_TOP = r"""
    using aether::Array;
    using aether::SampleIndex;
    using aether::random::Generator;
    constexpr std::size_t N = 5;
"""
out = run_cpp(r"""
    Array<double, 3> a(N);
    auto va = a.hostView();
    Generator rng1(42);
    for (std::size_t idx = 0; idx < N; ++idx)
        va[SampleIndex::make(idx)] = rng1.normal<double, 3>(0.0, 1.0);
    std::printf("sample 0: (%+.6f, %+.6f, %+.6f)\n", va(0, 0), va(1, 0), va(2, 0));
""", top=RNG_TOP)
print(out)
sample 0: (-0.341393, +0.165468, +0.343431)
out = run_cpp(r"""
    Array<double, 3> a(N), b(N);
    auto va = a.hostView(), vb = b.hostView();
    Generator rng1(42), rng2(42);   // two independent values, same seed
    bool identical = true;
    for (std::size_t idx = 0; idx < N; ++idx) {
        va[SampleIndex::make(idx)] = rng1.normal<double, 3>(0.0, 1.0);
        vb[SampleIndex::make(idx)] = rng2.normal<double, 3>(0.0, 1.0);
        for (std::size_t c = 0; c < 3; ++c)
            identical &= (va(c, idx) == vb(c, idx));
    }
    std::printf("two Generators, same seed, same stream: %s\n", identical ? "true" : "false");
""", top=RNG_TOP)
print(out)
two Generators, same seed, same stream: true

Two independent Generator values, same seed, draw bit-for-bit the same stream. For a genuinely different second draw per sample, rng.substream(k) derives an independent sub-stream from the same seed – the sub-counter its identity is built from (seed, sample id, sub-counter).