1classdef NumpyRandomState < handle
2 % NumpyRandomState Bit-exact port of
the subset of numpy.random.RandomState
3 % consumed by scipy
's differential_evolution. Backed by opt.de.MT19937.
5 % Implements random_sample, uniform, the default-dtype randint (32-bit
6 % masked rejection), and shuffle/permutation (Fisher-Yates driven by
7 % random_interval), each reproducing numpy's exact draw sequence and word
8 % consumption, so
the optimizer follows
the identical trajectory to
the
9 % native-Python line-opt
for a given integer seed.
12 gen % opt.de.MT19937 handle
16 function obj = NumpyRandomState(seed)
17 obj.gen = opt.de.MT19937(seed);
20 function d = randomSample(obj)
21 a = double(bitshift(obj.gen.nextUint32(), -5)); % 27 bits
22 b = double(bitshift(obj.gen.nextUint32(), -6)); % 26 bits
23 d = (a * 67108864 + b) / 9007199254740992;
26 function out = randomSampleN(obj, n)
29 out(i) = obj.randomSample();
33 function d = uniformScalar(obj, low, high)
34 d = low + (high - low) * obj.randomSample();
37 function out = uniformN(obj, low, high, n)
40 out(i) = low + (high - low) * obj.randomSample();
44 function m = fillMask(~, v)
46 v = bitor(v, bitshift(v, -1));
47 v = bitor(v, bitshift(v, -2));
48 v = bitor(v, bitshift(v, -4));
49 v = bitor(v, bitshift(v, -8));
50 v = bitor(v, bitshift(v, -16));
54 function v = randint(obj, low, high)
55 rng_ = uint64(high) - uint64(1) - uint64(low);
60 mask = obj.fillMask(rng_);
62 w = uint64(obj.gen.nextUint32());
63 val = bitand(w, mask);
65 v = double(low) + double(val);
71 function v = randomInterval(obj, maxv)
77 mask = obj.fillMask(maxv);
79 w = uint64(obj.gen.nextUint32());
80 val = bitand(w, mask);
88 function arr = shuffle(obj, arr)
91 jj = obj.randomInterval(uint64(p - 1)); % 0-based j in [0, p-1]
98 function arr = permutation(obj, n)
100 arr = obj.shuffle(arr);