Repository: numba/numba

Issue:
Implementing np.random.randn(N)
Hi, I know this is very easy to bypass as a user. 

Nonetheless it would be great if it is possible to pass a size argument to the np.random.randn function

Thank you



Discussion:
You can just use `np.random.standard_normal()` instead.


Resolving patch:
diff --git a/numba/targets/randomimpl.py b/numba/targets/randomimpl.py
--- a/numba/targets/randomimpl.py
+++ b/numba/targets/randomimpl.py
@@ -16,7 +16,7 @@
 from numba.targets.imputils import (Registry, impl_ret_untracked,
                                     impl_ret_new_ref)
 from numba.typing import signature
-from numba import _helperlib, cgutils, types
+from numba import _helperlib, cgutils, types, jit
 
 
 registry = Registry()
@@ -196,7 +196,6 @@ def random_impl(context, builder, sig, args):
     res = get_next_double(context, builder, state_ptr)
     return impl_ret_untracked(context, builder, sig.return_type, res)
 
-@lower("np.random.rand")
 @lower("np.random.random")
 def random_impl(context, builder, sig, args):
     state_ptr = get_state_ptr(context, builder, "np")
@@ -211,7 +210,6 @@ def gauss_impl(context, builder, sig, args):
     return impl_ret_untracked(context, builder, sig.return_type, res)
 
 
-@lower("np.random.randn")
 @lower("np.random.standard_normal")
 @lower("np.random.normal")
 @lower("np.random.normal", types.Float)
@@ -1220,12 +1218,43 @@ def random_arr(context, builder, sig, args, typing_key=typing_key):
         return impl_ret_new_ref(context, builder, sig.return_type, arr._getvalue())
 
 
+# ------------------------------------------------------------------------
+# Irregular aliases: np.random.rand, np.random.randn
+
+@overload(np.random.rand)
+def rand(*size):
+    if len(size) == 0:
+        # Scalar output
+        def rand_impl():
+            return np.random.random()
+
+    else:
+        # Array output
+        def rand_impl(*size):
+            return np.random.random(size)
+
+    return rand_impl
+
+@overload(np.random.randn)
+def randn(*size):
+    if len(size) == 0:
+        # Scalar output
+        def randn_impl():
+            return np.random.standard_normal()
+
+    else:
+        # Array output
+        def randn_impl(*size):
+            return np.random.standard_normal(size)
+
+    return randn_impl
+
+
 # ------------------------------------------------------------------------
 # np.random.choice
 
 @overload(np.random.choice)
 def choice(a, size=None, replace=True):
-    from numba import jit  # Avoid circular imports
 
     if isinstance(a, types.Array):
         # choice() over an array population
@@ -1312,7 +1341,6 @@ def choice_impl(a, size=None, replace=True):
 
 @overload(np.random.multinomial)
 def multinomial(n, pvals, size=None):
-    from numba import jit  # Avoid circular imports
 
     dtype = np.intp
 
diff --git a/numba/typing/randomdecl.py b/numba/typing/randomdecl.py
--- a/numba/typing/randomdecl.py
+++ b/numba/typing/randomdecl.py
@@ -279,13 +279,6 @@ def typer(size=None):
         return typer
 
 
-# These ones have a different (unsupported) way of passing the size
-@infer_global(np.random.rand, typing_key="np.random.rand")
-@infer_global(np.random.randn, typing_key="np.random.randn")
-class Random_nullary_distribution(ConcreteTemplate):
-    cases = [signature(tp) for tp in _float_types]
-
-
 @infer_global(random.triangular, typing_key="random.triangular")
 class Random_triangular(ConcreteTemplate):
     cases = [signature(tp, tp, tp) for tp in _float_types]


Test patch:
diff --git a/numba/tests/test_random.py b/numba/tests/test_random.py
--- a/numba/tests/test_random.py
+++ b/numba/tests/test_random.py
@@ -57,6 +57,20 @@ def numpy_multinomial2(n, pvals):
 def numpy_multinomial3(n, pvals, size):
     return np.random.multinomial(n, pvals=pvals, size=size)
 
+def numpy_check_rand(seed, a, b):
+    np.random.seed(seed)
+    expected = np.random.random((a, b))
+    np.random.seed(seed)
+    got = np.random.rand(a, b)
+    return expected, got
+
+def numpy_check_randn(seed, a, b):
+    np.random.seed(seed)
+    expected = np.random.standard_normal((a, b))
+    np.random.seed(seed)
+    got = np.random.randn(a, b)
+    return expected, got
+
 
 def jit_with_args(name, argstring):
     code = """def func(%(argstring)s):
@@ -982,6 +996,20 @@ def test_numpy_poisson(self):
     def test_numpy_power(self):
         self._check_array_dist("power", (0.8,))
 
+    @tag('important')
+    def test_numpy_rand(self):
+        cfunc = jit(nopython=True)(numpy_check_rand)
+        expected, got = cfunc(42, 2, 3)
+        self.assertEqual(got.shape, (2, 3))
+        self.assertPreciseEqual(expected, got)
+
+    @tag('important')
+    def test_numpy_randn(self):
+        cfunc = jit(nopython=True)(numpy_check_randn)
+        expected, got = cfunc(42, 2, 3)
+        self.assertEqual(got.shape, (2, 3))
+        self.assertPreciseEqual(expected, got)
+
     def test_numpy_rayleigh(self):
         self._check_array_dist("rayleigh", (0.8,))