Repository: numba/numba

Issue:
Add erff and erfc to CUDA Targets
The erff and erfc family of functions are missing from the CUDA target.
Originally posted on the google-groups.
https://groups.google.com/a/continuum.io/forum/#!topic/numba-users/2wupabM4vJ4



Discussion:

Resolving patch:
diff --git a/numba/cuda/cudamath.py b/numba/cuda/cudamath.py
--- a/numba/cuda/cudamath.py
+++ b/numba/cuda/cudamath.py
@@ -18,10 +18,14 @@
 @infer_global(math.cos)
 @infer_global(math.cosh)
 @infer_global(math.degrees)
+@infer_global(math.erf)
+@infer_global(math.erfc)
 @infer_global(math.exp)
 @infer_global(math.expm1)
 @infer_global(math.fabs)
 @infer_global(math.floor)
+@infer_global(math.gamma)
+@infer_global(math.lgamma)
 @infer_global(math.log)
 @infer_global(math.log10)
 @infer_global(math.log1p)
diff --git a/numba/cuda/libdevice.py b/numba/cuda/libdevice.py
--- a/numba/cuda/libdevice.py
+++ b/numba/cuda/libdevice.py
@@ -76,6 +76,10 @@ def core(context, builder, sig, args):
 unarys += [('__nv_fabs', '__nv_fabsf', math.fabs)]
 unarys += [('__nv_exp', '__nv_expf', math.exp)]
 unarys += [('__nv_expm1', '__nv_expm1f', math.expm1)]
+unarys += [('__nv_erf', '__nv_erff', math.erf)]
+unarys += [('__nv_erfc', '__nv_erfcf', math.erfc)]
+unarys += [('__nv_tgamma', '__nv_tgammaf', math.gamma)]
+unarys += [('__nv_lgamma', '__nv_lgammaf', math.lgamma)]
 unarys += [('__nv_sqrt', '__nv_sqrtf', math.sqrt)]
 unarys += [('__nv_log', '__nv_logf', math.log)]
 unarys += [('__nv_log10', '__nv_log10f', math.log10)]


Test patch:
diff --git a/numba/cuda/tests/cudapy/test_math.py b/numba/cuda/tests/cudapy/test_math.py
--- a/numba/cuda/tests/cudapy/test_math.py
+++ b/numba/cuda/tests/cudapy/test_math.py
@@ -75,16 +75,29 @@ def math_exp(A, B):
     i = cuda.grid(1)
     B[i] = math.exp(A[i])
 
+def math_erf(A, B):
+    i = cuda.grid(1)
+    B[i] = math.erf(A[i])
+
+def math_erfc(A, B):
+    i = cuda.grid(1)
+    B[i] = math.erfc(A[i])
 
 def math_expm1(A, B):
     i = cuda.grid(1)
     B[i] = math.expm1(A[i])
 
-
 def math_fabs(A, B):
     i = cuda.grid(1)
     B[i] = math.fabs(A[i])
 
+def math_gamma(A, B):
+    i = cuda.grid(1)
+    B[i] = math.gamma(A[i])
+
+def math_lgamma(A, B):
+    i = cuda.grid(1)
+    B[i] = math.lgamma(A[i])
 
 def math_log(A, B):
     i = cuda.grid(1)
@@ -215,6 +228,13 @@ def binary_template(self, func, npfunc, npdtype, npmtype, start, stop):
         cfunc[1, nelem](A, A, B)
         self.assertTrue(np.allclose(npfunc(A, A), B))
 
+    # Test helper for math functions when no ufunc exists
+    # and dtype specificity is required.
+    def _math_vectorize(self, mathfunc, x):
+        ret = np.zeros_like(x)
+        for k in range(len(x)):
+            ret[k] = mathfunc(x[k])
+        return ret
 
     #------------------------------------------------------------------------------
     # test_math_acos
@@ -320,6 +340,25 @@ def test_math_atan2(self):
         self.binary_template_float32(math_atan2, np.arctan2)
         self.binary_template_float64(math_atan2, np.arctan2)
 
+    #------------------------------------------------------------------------------
+    # test_math_erf
+
+
+    def test_math_erf(self):
+        def ufunc(x):
+            return self._math_vectorize(math.erf, x)
+        self.unary_template_float32(math_erf, ufunc)
+        self.unary_template_float64(math_erf, ufunc)
+
+    #------------------------------------------------------------------------------
+    # test_math_erfc
+
+
+    def test_math_erfc(self):
+        def ufunc(x):
+            return self._math_vectorize(math.erfc, x)
+        self.unary_template_float32(math_erfc, ufunc)
+        self.unary_template_float64(math_erfc, ufunc)
 
     #------------------------------------------------------------------------------
     # test_math_exp
@@ -344,6 +383,25 @@ def test_math_fabs(self):
         self.unary_template_float32(math_fabs, np.fabs, start=-1)
         self.unary_template_float64(math_fabs, np.fabs, start=-1)
 
+    #------------------------------------------------------------------------------
+    # test_math_gamma
+
+
+    def test_math_gamma(self):
+        def ufunc(x):
+            return self._math_vectorize(math.gamma, x)
+        self.unary_template_float32(math_gamma, ufunc, start=0.1)
+        self.unary_template_float64(math_gamma, ufunc, start=0.1)
+
+    #------------------------------------------------------------------------------
+    # test_math_lgamma
+
+
+    def test_math_lgamma(self):
+        def ufunc(x):
+            return self._math_vectorize(math.lgamma, x)
+        self.unary_template_float32(math_lgamma, ufunc, start=0.1)
+        self.unary_template_float64(math_lgamma, ufunc, start=0.1)
 
     #------------------------------------------------------------------------------
     # test_math_log