Repository: cupy/cupy

Issue:
Setting CUPY_SEED or CHAINER_SEED raises a TypeError
If `CUPY_SEED` or `CHAINER_SEED` is set, `cupy.random` raises a TypeError. I guess it is due to this commit: https://github.com/cupy/cupy/commit/03b2145fbec95166832de56506d8fbc256406e39#diff-bdf8bf88a45064e9d8d316ebd0d0f6fb

```
$ python -c "import cupy; print(cupy.__version__)"
2.1.0
$ python -c "import cupy; cupy.random.rand()"
$ CUPY_SEED=0 python -c "import cupy; cupy.random.rand()"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/fujita/.pyenv/versions/mbrl/lib/python3.6/site-packages/cupy/random/sample.py", line 33, in rand
    return random_sample(size=size, dtype=dtype)
  File "/home/fujita/.pyenv/versions/mbrl/lib/python3.6/site-packages/cupy/random/sample.py", line 153, in random_sample
    rs = generator.get_random_state()
  File "/home/fujita/.pyenv/versions/mbrl/lib/python3.6/site-packages/cupy/random/generator.py", line 412, in get_random_state
    rs = RandomState(seed)
  File "/home/fujita/.pyenv/versions/mbrl/lib/python3.6/site-packages/cupy/random/generator.py", line 47, in __init__
    self.seed(seed)
  File "/home/fujita/.pyenv/versions/mbrl/lib/python3.6/site-packages/cupy/random/generator.py", line 243, in seed
    seed = numpy.asarray(seed).astype(numpy.uint64, casting='safe')
TypeError: Cannot cast array from dtype('<U1') to dtype('uint64') according to the rule 'safe'
$ CHAINER_SEED=0 python -c "import cupy; cupy.random.rand()"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/fujita/.pyenv/versions/mbrl/lib/python3.6/site-packages/cupy/random/sample.py", line 33, in rand
    return random_sample(size=size, dtype=dtype)
  File "/home/fujita/.pyenv/versions/mbrl/lib/python3.6/site-packages/cupy/random/sample.py", line 153, in random_sample
    rs = generator.get_random_state()
  File "/home/fujita/.pyenv/versions/mbrl/lib/python3.6/site-packages/cupy/random/generator.py", line 412, in get_random_state
    rs = RandomState(seed)
  File "/home/fujita/.pyenv/versions/mbrl/lib/python3.6/site-packages/cupy/random/generator.py", line 47, in __init__
    self.seed(seed)
  File "/home/fujita/.pyenv/versions/mbrl/lib/python3.6/site-packages/cupy/random/generator.py", line 243, in seed
    seed = numpy.asarray(seed).astype(numpy.uint64, casting='safe')
TypeError: Cannot cast array from dtype('<U1') to dtype('uint64') according to the rule 'safe'
```


Discussion:

Resolving patch:
diff --git a/cupy/random/generator.py b/cupy/random/generator.py
--- a/cupy/random/generator.py
+++ b/cupy/random/generator.py
@@ -489,6 +489,8 @@ def get_random_state():
         seed = os.getenv('CUPY_SEED')
         if seed is None:
             seed = os.getenv('CHAINER_SEED')
+        if seed is not None:
+            seed = numpy.uint64(int(seed))
         rs = RandomState(seed)
         rs = _random_states.setdefault(dev.id, rs)
     return rs


Test patch:
diff --git a/tests/cupy_tests/random_tests/test_generator.py b/tests/cupy_tests/random_tests/test_generator.py
--- a/tests/cupy_tests/random_tests/test_generator.py
+++ b/tests/cupy_tests/random_tests/test_generator.py
@@ -1,4 +1,3 @@
-import mock
 import os
 import threading
 import unittest
@@ -679,15 +678,12 @@ def test_set_random_state_thread_safe(self):
 class TestGetRandomState2(unittest.TestCase):
 
     def setUp(self):
-        self.rs_tmp = generator.RandomState
-        generator.RandomState = mock.Mock()
         self.rs_dict = generator._random_states
         generator._random_states = {}
         self.cupy_seed = os.getenv('CUPY_SEED')
         self.chainer_seed = os.getenv('CHAINER_SEED')
 
     def tearDown(self, *args):
-        generator.RandomState = self.rs_tmp
         generator._random_states = self.rs_dict
         if self.cupy_seed is None:
             os.environ.pop('CUPY_SEED', None)
@@ -701,26 +697,55 @@ def tearDown(self, *args):
     def test_get_random_state_no_cupy_no_chainer_seed(self):
         os.environ.pop('CUPY_SEED', None)
         os.environ.pop('CHAINER_SEED', None)
-        generator.get_random_state()
-        generator.RandomState.assert_called_with(None)
+        rvs0 = self._get_rvs_reset()
+        rvs1 = self._get_rvs_reset()
+
+        self._check_different(rvs0, rvs1)
 
     def test_get_random_state_no_cupy_with_chainer_seed(self):
+        rvs0 = self._get_rvs(generator.RandomState(5))
+
         os.environ.pop('CUPY_SEED', None)
         os.environ['CHAINER_SEED'] = '5'
-        generator.get_random_state()
-        generator.RandomState.assert_called_with('5')
+        rvs1 = self._get_rvs_reset()
+
+        self._check_same(rvs0, rvs1)
 
     def test_get_random_state_with_cupy_no_chainer_seed(self):
+        rvs0 = self._get_rvs(generator.RandomState(6))
+
         os.environ['CUPY_SEED'] = '6'
         os.environ.pop('CHAINER_SEED', None)
-        generator.get_random_state()
-        generator.RandomState.assert_called_with('6')
+        rvs1 = self._get_rvs_reset()
+
+        self._check_same(rvs0, rvs1)
 
     def test_get_random_state_with_cupy_with_chainer_seed(self):
+        rvs0 = self._get_rvs(generator.RandomState(7))
+
         os.environ['CUPY_SEED'] = '7'
         os.environ['CHAINER_SEED'] = '8'
-        generator.get_random_state()
-        generator.RandomState.assert_called_with('7')
+        rvs1 = self._get_rvs_reset()
+
+        self._check_same(rvs0, rvs1)
+
+    def _get_rvs(self, rs):
+        rvu = rs.rand(4)
+        rvn = rs.randn(4)
+        return rvu, rvn
+
+    def _get_rvs_reset(self):
+        generator.reset_states()
+        return self._get_rvs(generator.get_random_state())
+
+    def _check_same(self, rvs0, rvs1):
+        for rv0, rv1 in zip(rvs0, rvs1):
+            testing.assert_array_equal(rv0, rv1)
+
+    def _check_different(self, rvs0, rvs1):
+        for rv0, rv1 in zip(rvs0, rvs1):
+            for r0, r1 in zip(rv0, rv1):
+                self.assertNotEqual(r0, r1)
 
 
 class TestCheckAndGetDtype(unittest.TestCase):