-
-
Notifications
You must be signed in to change notification settings - Fork 12.2k
ENH: hot-swapping a BitGenerator #21808
Description
Proposed new feature or change:
One of the requirements in NEP 19 was
In order to allow certain workarounds, it MUST be possible to replace the BitGenerator underneath the global RandomState with any other BitGenerator object (we leave the precise API details up to the new subsystem).
We partially overlooked this in the hectic flood of new features that we implemented. IIRC, I did successfully insist on making the _bit_generator attribute cdef public rather than cdef readonly, but failed to communicate the full intended use, so it's not really functional.
As people are transitioning away from the np.random.* global functions, they may need a transition where they are using code, especially third-party code that they can't change, that still uses the np.random.* functions. We want to give them the ability to use a single BitGenerator instance shared between their Generator-using newer code and the np.random.*-using older code. That way, they don't have to manage two different seeds to get reproducible results.
Currently, we can create a new RandomState with one of the newer BitGenerators, but we can't change the BitGenerator underneath the pre-created global instance np.random.mtrand._rand. So I would like to be able to write code that looks like this:
def synch_legacy_randomstate(rng):
np.random.mtrand._rand._bit_generator = rng.bit_generator
rng = np.random.default_rng(one_single_seed)
synch_legacy_randomstate(rng)
# newer code
rng.uniform(100)
# older code
np.random.uniform(100)The _bit_generator attribute is cdef public, so we can technically assign a new BitGenerator to it, but this is essentially a no-op because the bitgen_t * is extracted from the BitGenerator object only in the __init__(). After re-assigning _bit_generator, all of the distribution methods still draw from the old bitgen_t *.
We can probably implement this by lifting the cdef public _bit_generator attribute to a property and factoring out the bitgen_t * extraction so that it can be used in both the __init__() and the setter.
@bashtage Any thoughts?