Skip to content

Instantly share code, notes, and snippets.

@SebastienEske
Last active March 30, 2020 09:13
Show Gist options
  • Save SebastienEske/1f6a280caa2b348a25210a0de303d8f2 to your computer and use it in GitHub Desktop.
Save SebastienEske/1f6a280caa2b348a25210a0de303d8f2 to your computer and use it in GitHub Desktop.
import random
class CMWC(random.Random):
# code from here https://code.activestate.com/recipes/576707/
'Long period random number generator: Complementary Multiply with Carry'
# http://en.wikipedia.org/wiki/Multiply-with-carry
a = 3636507990
logb = 32
b = 2 ** logb
r = 1359
def _gen_word(self):
i = self.i
xc, self.c = divmod(self.a * self.Q[i] + self.c, self.b)
x = self.Q[i] = self.b - 1 - xc
self.i = 0 if i + 1 == self.r else i + 1
return x
def getrandbits(self, k):
while self.bits < k:
self.f = (self.f << self.logb) | self._gen_word()
self.bits += self.logb
x = self.f & ((1 << k) - 1)
self.f >>= k
self.bits -= k
return x
def random(self, RECIP_BPF=random.RECIP_BPF, BPF=random.BPF):
return self.getrandbits(BPF) * RECIP_BPF
def seed(self, seed=None):
seeder = random.Random(seed)
Q = [seeder.randrange(0x100000000) for i in range(self.r)]
c = seeder.randrange(0x100000000)
self.setstate(0, 0, 0, c, Q)
def getstate(self):
return self.f, self.bits, self.i, self.c, tuple(self.Q)
def setstate(self, f, bits, i, c, Q):
self.f, self.bits, self.i, self.c, self.Q = f, bits, i, c, list(Q)
class myrandomtransform():
def __init__(self, seed=None):
self.rng = CMWC()
if seed is not None:
self.rng.seed(seed)
def run(self):
return self.rng.random()
a = myrandomtransform(2)
b = myrandomtransform(2)
avalues = []
bvalues = []
for i in range(10):
if random.random() > 0.5:
avalues.append(a.run())
else:
bvalues.append(b.run())
print(avalues)
print(bvalues)
@mrTsjolder
Copy link

Why so complicated?

class RandomTransform:

    def __init__(self, seed: int = None):
        self.rng = random.Random(seed)

    def run(self):
        return self.rng.random()

should do the same thing, no?

@SebastienEske
Copy link
Author

SebastienEske commented Mar 30, 2020

Hello,

Yes and no. :-) The point here is to control the random number generator (RNG) to prevent:

  • non deterministic behavior due to low level routines, other implementation hidden issues
  • change of behavior between different RNG versions

I was intending to use it to comment on this issue but somehow I did not (can't remember why): pytorch/vision#1234

So it is not trying to be super random, just enough for testing purposes (as long as the testing does not require high quality randomness) while guaranteeing reproducibility of the randomness which is paramount for testing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment