summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2020-06-10 12:07:52 -0600
committerGitHub <noreply@github.com>2020-06-10 12:07:52 -0600
commit073316d25d24b7cb4ffc09fc705448b0e17dc2dc (patch)
tree5204939b8990a34ecb8cd41bfae0340509f1ead7
parentc0c7c42014edac6135cbadc89577c4b662fb5c19 (diff)
parente1db72c2c99d23982551def864b24d277b297aa6 (diff)
downloadnumpy-073316d25d24b7cb4ffc09fc705448b0e17dc2dc.tar.gz
Merge pull request #16551 from numpy/fix/seed-sequence-zeros
BUG: Ensure SeedSequence 0-padding does not collide with spawn keys
-rw-r--r--doc/source/release/1.19.0-notes.rst13
-rw-r--r--numpy/random/bit_generator.pyx11
-rw-r--r--numpy/random/tests/test_seed_sequence.py28
3 files changed, 50 insertions, 2 deletions
diff --git a/doc/source/release/1.19.0-notes.rst b/doc/source/release/1.19.0-notes.rst
index 35aaf8e4a..b40969550 100644
--- a/doc/source/release/1.19.0-notes.rst
+++ b/doc/source/release/1.19.0-notes.rst
@@ -267,6 +267,19 @@ of users.
(`gh-16068 <https://github.com/numpy/numpy/pull/16068>`__)
+``SeedSequence`` with small seeds no longer conflicts with spawning
+-------------------------------------------------------------------
+Small seeds (less than ``2**96``) are implicitly 0-padded out to 128 bits, the
+size of the internal entropy pool. When spawned, the spawn key was concatenated
+before the 0-padding. Since the first spawn key is ``(0,)``, small seeds
+before the spawn created the same states as the first spawned ``SeedSequence``.
+Now, the seed is explicitly 0-padded out to the internal pool size before
+concatenating the spawn key. Spawned ``SeedSequences`` will produce different
+results than in the previous release. Unspawned ``SeedSequences`` will still
+produce the same results.
+
+(`gh-16551 <https://github.com/numpy/numpy/pull/16551>`__)
+
C API changes
=============
diff --git a/numpy/random/bit_generator.pyx b/numpy/random/bit_generator.pyx
index f145ec13d..3c52a9933 100644
--- a/numpy/random/bit_generator.pyx
+++ b/numpy/random/bit_generator.pyx
@@ -382,13 +382,22 @@ cdef class SeedSequence():
-------
entropy_array : 1D uint32 array
"""
- # Convert run-entropy, program-entropy, and the spawn key into uint32
+ # Convert run-entropy and the spawn key into uint32
# arrays and concatenate them.
# We MUST have at least some run-entropy. The others are optional.
assert self.entropy is not None
run_entropy = _coerce_to_uint32_array(self.entropy)
spawn_entropy = _coerce_to_uint32_array(self.spawn_key)
+ if len(spawn_entropy) > 0 and len(run_entropy) < self.pool_size:
+ # Explicitly fill out the entropy with 0s to the pool size to avoid
+ # conflict with spawn keys. We changed this in 1.19.0 to fix
+ # gh-16539. In order to preserve stream-compatibility with
+ # unspawned SeedSequences with small entropy inputs, we only do
+ # this when a spawn_key is specified.
+ diff = self.pool_size - len(run_entropy)
+ run_entropy = np.concatenate(
+ [run_entropy, np.zeros(diff, dtype=np.uint32)])
entropy_array = np.concatenate([run_entropy, spawn_entropy])
return entropy_array
diff --git a/numpy/random/tests/test_seed_sequence.py b/numpy/random/tests/test_seed_sequence.py
index fe23680ed..f08cf80fa 100644
--- a/numpy/random/tests/test_seed_sequence.py
+++ b/numpy/random/tests/test_seed_sequence.py
@@ -1,5 +1,5 @@
import numpy as np
-from numpy.testing import assert_array_equal
+from numpy.testing import assert_array_equal, assert_array_compare
from numpy.random import SeedSequence
@@ -52,3 +52,29 @@ def test_reference_data():
assert_array_equal(state, expected)
state64 = ss.generate_state(len(expected64), dtype=np.uint64)
assert_array_equal(state64, expected64)
+
+
+def test_zero_padding():
+ """ Ensure that the implicit zero-padding does not cause problems.
+ """
+ # Ensure that large integers are inserted in little-endian fashion to avoid
+ # trailing 0s.
+ ss0 = SeedSequence(42)
+ ss1 = SeedSequence(42 << 32)
+ assert_array_compare(
+ np.not_equal,
+ ss0.generate_state(4),
+ ss1.generate_state(4))
+
+ # Ensure backwards compatibility with the original 0.17 release for small
+ # integers and no spawn key.
+ expected42 = np.array([3444837047, 2669555309, 2046530742, 3581440988],
+ dtype=np.uint32)
+ assert_array_equal(SeedSequence(42).generate_state(4), expected42)
+
+ # Regression test for gh-16539 to ensure that the implicit 0s don't
+ # conflict with spawn keys.
+ assert_array_compare(
+ np.not_equal,
+ SeedSequence(42, spawn_key=(0,)).generate_state(4),
+ expected42)