8000 ENH: move dSFMT, MT19937 and PCG32 to SeedSequence · numpy/numpy@4724fb0 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4724fb0

Browse files
committed
ENH: move dSFMT, MT19937 and PCG32 to SeedSequence
1 parent 109db70 commit 4724fb0

21 files changed

+6271
-6644
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
:orphan:
2+
3+
BitGenerator
4+
------------
5+
6+
.. currentmodule:: numpy.random.bit_generator
7+
8+
.. autosummary::
9+
:toctree: generated/
10+
11+
BitGenerator

doc/source/reference/random/bit_generators/dsfmt.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ Seeding and State
1515
.. autosummary::
1616
:toctree: generated/
1717

18-
~DSFMT.seed
1918
~DSFMT.state
2019

2120
Parallel generation
Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
11
.. _bit_generator:
22

3+
.. currentmodule:: numpy.random
4+
35
Bit Generators
46
--------------
57

6-
.. currentmodule:: numpy.random
7-
88
The random values produced by :class:`~Generator`
99
orignate in a BitGenerator. The BitGenerators do not directly provide
1010
random numbers and only contains methods used for seeding, getting or
1111
setting the state, jumping or advancing the state, and for accessing
1212
low-level wrappers for consumption by code that can efficiently
1313
access the functions provided, e.g., `numba <https://numba.pydata.org>`_.
1414

15-
Stable RNGs
16-
===========
17-
1815
.. toctree::
1916
:maxdepth: 1
2017

18+
BitGenerator <bitgenerators>
2119
DSFMT <dsfmt>
2220
MT19937 <mt19937>
2321
PCG32 <pcg32>
@@ -27,3 +25,20 @@ Stable RNGs
2725
Xoshiro256** <xoshiro256>
2826
Xoshiro512** <xoshiro512>
2927

28+
Seeding and Entropy
29+
-------------------
30+
31+
A BitGenerator provides a stream of random values. In order to generate
32+
reproducableis streams, BitGenerators support setting their initial state via a
33+
seed. But how best to seed the BitGenerator? On first impulse one would like to
34+
do something like ``[bg(i) for i in range(12)]`` to obtain 12 non-correlated,
35+
independent BitGenerators. However using a highly correlated set of seed could
36+
generate BitGenerators that are correlated or overlap within a few samples.
37+
NumPy uses a `SeedSequence` class to mix the seed in a reproducable way that
38+
introduces the necesarry entroy to produce independent and largely non-
39+
overlapping streams.
40+
41+
.. autosummary::
42+
:toctree: generated/
43+
44+
SeedSequence

doc/source/reference/random/bit_generators/pcg32.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ Seeding and State
1414
.. autosummary::
1515
:toctree: generated/
1616

17-
~PCG32.seed
1817
~PCG32.state
1918

2019
Parallel generation

numpy/random/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@
167167
from .mtrand import *
168168
from .dsfmt import DSFMT
169169
from .generator import Generator
170+
from .bit_generator import SeedSequence
170171
from .mt19937 import MT19937
171172
from .pcg32 import PCG32
172173
from .pcg64 import PCG64
@@ -176,8 +177,8 @@
176177
from .xoshiro512 import Xoshiro512
177178
from .mtrand import RandomState
178179

179-
__all__ += ['Generator', 'DSFMT', 'MT19937', 'Philox', 'PCG64', 'PCG32',
180-
'ThreeFry', 'Xoshiro256', 'Xoshiro512', 'RandomState']
180+
__all__ += ['Generator', 'RandomState', 'SeedSequence', 'DSFMT', 'MT19937',
181+
'Philox', 'PCG64', 'PCG32', 'ThreeFry', 'Xoshiro256', 'Xoshiro512']
181182

182183

183184
def __RandomState_ctor():

numpy/random/bit_generator.pxd

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
from .distributions cimport bitgen_t
3+
cimport numpy as np
34

45
cdef class BitGenerator():
56
cdef public object _seed_seq
@@ -8,3 +9,15 @@ cdef class BitGenerator():
89
cdef public object _ctypes
910
cdef public object _cffi
1011
cdef public object capsule
12+
13+
14+
cdef class SeedSequence():
15+
cdef readonly object entropy
16+
cdef readonly object program_entropy
17+
cdef readonly tuple spawn_key
18+
cdef readonly int pool_size
19+
cdef readonly object pool
20+
cdef readonly int n_children_spawned
21+
22+
cdef mix_entropy(self, np.ndarray[np.npy_uint32, ndim=1] mixer,
23+
np.ndarray[np.npy_uint32, ndim=1] entropy_array)

numpy/random/bit_generator.pyx

Lines changed: 23 additions & 21 deletions
327
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ def _coerce_to_uint32_array(x):
132132
raise ValueError("unrecognized seed string")
133133
if isinstance(x, (int, np.integer)):
134134
return _int_to_uint32_array(x)
135-
elif isinstance(x, (float, np.float)):
136-
raise ValueError('seed must be integer')
135+
elif isinstance(x, (float, np.inexact)):
136+
raise TypeError('seed must be integer')
137137
else:
138138
if len(x) == 0:
139139
return np.array([], dtype=np.uint32)
@@ -161,8 +161,9 @@ cdef class SeedSequence():
161161
"""
162162
SeedSequence(entropy=None, program_entropy=None, spawn_key=(), pool_size=%d)
163163
creates an appropriate seed sequence for BitGenerators via the
164-
generate_state() method. Calling spawn(n) will create n SeedSequences that
165-
can be used to seed independent BitGenerators, i.e. for different threads.
164+
`generate_state` method. Calling `spawn(n) <spawn>` will create n
165+
SeedSequences that can be used to seed independent BitGenerators, i.e. for
166+
different threads.
166167
167168
Parameters
168169
----------
@@ -175,15 +176,8 @@ cdef class SeedSequence():
175176
spawn_key: {(), sequence[int]}, optional
176177
A third source of entropy, used internally when calling
177178
`SeedSequence.spawn`
178-
179-
""" % DEFAULT_POOL_SIZE
180179
181-
cdef readonly object entropy
182-
cdef readonly object program_entropy
183-
cdef readonly tuple spawn_key
184-
cdef readonly int pool_size
185-
cdef readonly object pool
186-
cdef readonly int n_children_spawned
180+
""" % DEFAULT_POOL_SIZE
187181

188182
def __init__(self, entropy=None, program_entropy=None, spawn_key=(),
189183
pool_size=DEFAULT_POOL_SIZE):
@@ -192,7 +186,8 @@ cdef class SeedSequence():
192186
f"{DEFAULT_POOL_SIZE}")
193187
if entropy is None:
194188
entropy = randbits(pool_size * 32)
195-
elif not isinstance(entropy, (int, np.integer, list, tuple, np.ndarray)):
189+
elif not isinstance(entropy, (int, np.integer, list, tuple, range,
190+
np.ndarray)):
196191
raise TypeError('SeedSequence expects int or sequence of ints for '
197192
'entropy not {}'.format(entropy))
198193
self.entropy = entropy
@@ -221,14 +216,14 @@ cdef class SeedSequence():
221216
text = '\n'.join(lines)
222217
return text
223218

224-
cdef mix_entropy(self, np.ndarray[uint32_t, ndim=1] mixer,
225-
np.ndarray[uint32_t, ndim=1] entropy_array):
219+
cdef mix_entropy(self, np.ndarray[np.npy_uint32, ndim=1] mixer,
220+
np.ndarray[np.npy_uint32, ndim=1] entropy_array):
226221
""" Mix in the given entropy to mixer.
227222
Parameters
228223
----------
229-
224+
230225
mixer: 1D uint32 array, modified in-place
231-
226+
232227
entropy_array : 1D uint32 array
233228
"""
234229
cdef uint32_t hash_const[1]
@@ -284,7 +279,10 @@ cdef class SeedSequence():
284279

285280
@np.errstate(over='ignore')
286281
def generate_state(self, n_words, dtype=np.uint32):
287-
""" Return the requested number of words for PRNG seeding.
282+
"""
283+
generate_state(n_words, dtype=np.uint32)
284+
285+
Return the requested number of words for PRNG seeding.
288286
289287
A BitGenerator should call this method in its constructor with
290288
an appropriate `n_words` parameter to properly seed itself.
@@ -298,6 +296,7 @@ cdef class SeedSequence():
298296
requesting `uint64` will draw twice as many bits as `uint32` for
299297
the same `n_words`. This is a convenience for `BitGenerator`s that
300298
express their states as `uint64` arrays.
299+
301300
Returns
302301
-------
303302
state : uint32 or uint64 array, shape=(n_words,)
@@ -326,15 +325,18 @@ cdef class SeedSequence():
326325
return state
326

328327
def spawn(self, n_children):
329-
""" Spawn a number of child `SeedSequence`s by extending the
328+
"""
329+
spawn(n_children)
330+
331+
Spawn a number of child `SeedSequence` s by extending the
330332
`spawn_key`.
331333
332334
Parameters
333335
----------
334336
n_children : int
335337
Returns
336338
-------
337-
seqs : list of `SeedSequence`s
339+
seqs : list of `SeedSequence` s
338340
"""
339341
seqs = []
340342
for i in range(self.n_children_spawned,
@@ -397,7 +399,7 @@ cdef class BitGenerator():
397399
def __reduce__(self):
398400
from ._pickle import __bit_generator_ctor
399401
return __bit_generator_ctor, (self.state['bit_generator'],), self.state
400-
402+
401403
@property
402404
def state(self):
403405
"""

0 commit comments

Comments
 (0)
0