[Python-Dev] Mersenne Twister

Tim Peters tim.one@comcast.net
Thu, 29 Aug 2002 17:23:37 -0400

> Here's an idea.
> class BaseRandom: implements the end user methods: randrange(),
> choice(), normalvariate(), etc., except random(), which is an abstract
> method, raising NotImplementedError.

That's fine, and close to the intended <wink> way to extend this.
BaseRandom should also leave as abstract seed(), getstate(), setstate() (but
should implement __getstate__ and __setstate__ -- Random already does this
correctly), and jumpahead().

> class WHRandom and class MersenneRandom: add the specific random
> number generator implementation, as random().

seed, getstate, setstate and jumpahead are also initimately connected to the
details of the base generator, so need also to be supplied by subclasses.

> Random is an alias for the random generator class of the day,
> currently MersenneRandom.

I like that better than what we've got now -- I would like to say that
Random may vary across releases, as the state of the art advances, so that
naive users are far less likely to fool themselves.  But users also need to
force use of a specific generator at times, and this scheme caters to both.

> Details: can MersenneRandom support jumpahead()?

Yes, but I don't think *usefully*.  That is, I doubt it could do it faster
than calling the base random() N times.  jumpahead() is easy to implement
efficiently for linear congruential generators, and possible to implement
efficiently for pure lagged Fibonacci generators, but that's about it.

> Should it support whseed(), which is provided only for backwards
> compatibility?

It should not.  whseed() shouldn't even be used by WHRandom users!  It's
solely for bit-for-bit reproducibility of an older and weaker scheme.

> If someone pickles a Random instance with Python 2.2 and tries to
> unpickle it with Python 2.3, this will fail, because (presumably) the
> state for MersenneRandom is different from the state for WHRandom.

That's in part why the concrete classes have to implement getstate() and
setstate() appropriately.  Note that every 2.2 Random pickle starts with the
integer 1 (the then-- and now --value of Random.VERSION).  That's enough
clue so that all future Python versions can know which flavor of random
pickle they're looking at.  A Twister pickle should start with some none-1

> Perhaps there should be a module-level call to make Random an alias
> for WHRandom rather than for MersenneRandom.

I suppose it would also have to replace all the other module globals
appropriately.  I'm thinking of the

_inst = Random()
seed = _inst.seed
random = _inst.random
uniform = _inst.uniform
randint = _inst.randint
choice = _inst.choice
randrange = _inst.randrange
shuffle = _inst.shuffle
normalvariate = _inst.normalvariate
lognormvariate = _inst.lognormvariate
cunifvariate = _inst.cunifvariate
expovariate = _inst.expovariate
vonmisesvariate = _inst.vonmisesvariate
gammavariate = _inst.gammavariate
stdgamma = _inst.stdgamma
gauss = _inst.gauss
betavariate = _inst.betavariate
paretovariate = _inst.paretovariate
weibullvariate = _inst.weibullvariate
getstate = _inst.getstate
setstate = _inst.setstate
jumpahead = _inst.jumpahead
whseed = _inst.whseed

cruft at the end here.