9

I need to create a class which takes in a random number generator (i.e. a numpy.random.RandomState object) as a parameter. In the case this argument is not specified, I would like to assign it to the random generator that numpy uses when we run numpy.random.<random-method>. How do I access this global generator? Currently I am doing this by just assigning the module object as the random generator (since they share methods / duck typing). However this causes issues when pickling (unable to pickle module object) and deep-copying. I would like to use the RandomState object behind numpy.random

PS: I'm using python-3.4

Bellerofont
  • 1,081
  • 18
  • 17
  • 16
Atimaharjun
  • 349
  • 2
  • 10
  • @user2357112 In general I would not expect modules to be picklable, since they can contain all manner of unpicklable objects (C extensions, lambdas, closures etc.) – ali_m Feb 01 '17 at 22:23
  • @ali_m: I could've sworn they were pickled and unpickled by name, just like functions and classes, but apparently not. When I try it, I get an error too. – user2357112 Feb 01 '17 at 22:29
  • @user2357112 There's nothing *intrinsically* unpicklable about modules. As long as they contain only picklable objects then you're fine, but for most non-trivial modules this isn't the case. For example, numpy is riddled with unpicklable C extensions. – ali_m Feb 01 '17 at 22:36

3 Answers3

5

As well as what kazemakase suggests, we can take advantage of the fact that module-level functions like numpy.random.random are really methods of a hidden numpy.random.RandomState by pulling the __self__ directly from one of those methods:

numpy_default_rng = numpy.random.random.__self__
user2357112
  • 260,549
  • 28
  • 431
  • 505
  • 1
    Indeed, this seems to be more future-proof than directly using _rand. Thanks, I didnt know hat there was such a thing as a `__self__` attribute. – Atimaharjun Feb 07 '17 at 16:39
2

numpy.random imports * from numpy.random.mtrand, which is an extension module written in Cython. The source code shows that the global state is stored in the variable _rand. This variable is not imported into the numpy.random scope but you can get it directly from mtrand.

import numpy as np
from numpy.random.mtrand import _rand as global_randstate

np.random.seed(42)
print(np.random.rand())
# 0.3745401188473625

np.random.RandomState().seed(42)  # Different object, does not influence global state
print(np.random.rand())
# 0.9507143064099162

global_randstate.seed(42)  # this changes the global state
print(np.random.rand())
# 0.3745401188473625
MB-F
  • 22,770
  • 4
  • 61
  • 116
  • This is what I decided to do when I posted the question, however I was hoping that there was some way I could acheive this without tapping hidden members (for future-proofness). user2357112's method seems to allow that. So I've chosen that as the answer. Thanks for the response nonetheless. – Atimaharjun Feb 07 '17 at 16:44
0

I don't know how to access the global state. However, you can use a RandomState object and pass it along. Random distributions are attached to it, so you call them as methods.

Example:

import numpy as np

def computation(parameter, rs):
    return parameter*np.sum(rs.uniform(size=5)-0.5)

my_state = np.random.RandomState(seed=3)

print(computation(3, my_state))
Pierre de Buyl
  • 7,074
  • 2
  • 16
  • 22