Repository: cupy/cupy

Issue:
Some `RandomState` methods cannot infer `size`
```
>>> numpy.random.RandomState(42).normal(loc=numpy.zeros(3))
array([ 0.49671415, -0.1382643 ,  0.64768854])
>>> cupy.random.RandomState(42).normal(loc=cupy.zeros(3))
TypeError: only size-1 arrays can be converted to Python scalars
```

while `cupy.random.normal(loc=cupy.zeros(3))` works.


Discussion:
```
>>> np.random.gumbel(np.zeros(3))
array([-1.39836272,  0.64793883, -1.78702616])
>>> cupy.random.gumbel(cupy.zeros(3))
ValueError: Out shape is mismatched
```

Resolving patch:
diff --git a/cupy/random/_generator.py b/cupy/random/_generator.py
--- a/cupy/random/_generator.py
+++ b/cupy/random/_generator.py
@@ -74,8 +74,6 @@ def _generate_normal(self, func, size, dtype, *args):
         # * curand.generateNormalDouble
         # * curand.generateLogNormal
         # * curand.generateLogNormalDouble
-        if size is None:
-            size = ()  # TODO(kataoka): Remove this after #4615 is merged
         size = core.get_size(size)
         element_size = core.internal.prod(size)
         if element_size % 2 == 0:
@@ -470,6 +468,8 @@ def pareto(self, a, size=None, dtype=float):
             - :meth:`numpy.random.RandomState.pareto`
         """
         a = cupy.asarray(a)
+        if size is None:
+            size = a.shape
         x = self._random_sample_raw(size, dtype)
         cupy.log(x, out=x)
         cupy.exp(-x/a, out=x)
@@ -595,8 +595,6 @@ def randn(self, *size, **kwarg):
 
     def _random_sample_raw(self, size, dtype):
         dtype = _check_and_get_dtype(dtype)
-        if size is None:
-            size = ()  # TODO(kataoka): Remove this after #4615 is merged
         out = cupy.empty(size, dtype=dtype)
         if dtype.char == 'f':
             func = curand.generateUniform
@@ -613,6 +611,8 @@ def random_sample(self, size=None, dtype=float):
             - :meth:`numpy.random.RandomState.random_sample`
 
         """
+        if size is None:
+            size = ()
         out = self._random_sample_raw(size, dtype)
         RandomState._mod1_kernel(out)
         return out
@@ -780,6 +780,8 @@ def standard_exponential(self, size=None, dtype=float):
             - :func:`cupy.random.standard_exponential` for full documentation
             - :meth:`numpy.random.RandomState.standard_exponential`
         """
+        if size is None:
+            size = ()
         x = self._random_sample_raw(size, dtype)
         return -cupy.log(x, out=x)
 
@@ -1144,11 +1146,13 @@ def gumbel(self, loc=0.0, scale=1.0, size=None, dtype=float):
             - :func:`cupy.random.gumbel` for full documentation
             - :meth:`numpy.random.RandomState.gumbel`
         """
-        x = self._random_sample_raw(size=size, dtype=dtype)
         if not numpy.isscalar(loc):
             loc = cupy.asarray(loc, dtype)
         if not numpy.isscalar(scale):
             scale = cupy.asarray(scale, dtype)
+        if size is None:
+            size = cupy.broadcast(loc, scale).shape
+        x = self._random_sample_raw(size=size, dtype=dtype)
         RandomState._gumbel_kernel(x, loc, scale, x)
         return x
 


Test patch:
diff --git a/tests/cupy_tests/random_tests/test_distributions.py b/tests/cupy_tests/random_tests/test_distributions.py
--- a/tests/cupy_tests/random_tests/test_distributions.py
+++ b/tests/cupy_tests/random_tests/test_distributions.py
@@ -197,7 +197,7 @@ def test_geometric(self, p_dtype):
 
 
 @testing.parameterize(*testing.product({
-    'shape': [(4, 3, 2), (3, 2)],
+    'shape': [(4, 3, 2), (3, 2), None],
     'loc_shape': [(), (3, 2)],
     'scale_shape': [(), (3, 2)],
 })
@@ -244,7 +244,7 @@ def test_hypergeometric(self, ngood_dtype, nbad_dtype):
 
 
 @testing.parameterize(*testing.product({
-    'shape': [(4, 3, 2), (3, 2)],
+    'shape': [(4, 3, 2), (3, 2), None],
     'loc_shape': [(), (3, 2)],
     'scale_shape': [(), (3, 2)],
 })
@@ -476,7 +476,7 @@ def test_normal(self, loc_dtype, scale_dtype, dtype):
 
 
 @testing.parameterize(*testing.product({
-    'shape': [(4, 3, 2), (3, 2)],
+    'shape': [(4, 3, 2), (3, 2), None],
     'a_shape': [(), (3, 2)],
 })
 )
@@ -486,7 +486,8 @@ class TestDistributionsPareto(unittest.TestCase):
     def check_distribution(self, dist_func, a_dtype, dtype):
         a = cupy.ones(self.a_shape, dtype=a_dtype)
         out = dist_func(a, self.shape, dtype)
-        assert self.shape == out.shape
+        if self.shape is not None:
+            assert self.shape == out.shape
         assert out.dtype == dtype
 
     @cupy.testing.for_float_dtypes('dtype', no_float16=True)
@@ -541,7 +542,7 @@ def test_power_for_negative_a(self, a_dtype, dtype):
 
 
 @testing.parameterize(*testing.product({
-    'shape': [(4, 3, 2), (3, 2)],
+    'shape': [(4, 3, 2), (3, 2), None],
     'scale_shape': [(), (3, 2)],
 })
 )
@@ -584,7 +585,7 @@ def test_standard_cauchy(self, dtype):
 
 
 @testing.parameterize(*testing.product({
-    'shape': [(4, 3, 2), (3, 2)],
+    'shape': [(4, 3, 2), (3, 2), None],
 })
 )
 @testing.gpu