Repository: cupy/cupy
Pull request: Add support of complex dtypes for `sinc`
Closes #2645 

`sinpi` is a cuda only function that does not have an equivalent in thrust for complex numbers.
Note that the original numpy implementation uses the product of pi instead of an optimized sin.

Question:
Should we split the routines using a dispatcher, as the ufuncs doesnt seem to support overloading functions, one for complex and one for non-complex numbers?

Problem statement:
cp.sinc fails for complex input
Unlike the numpy version, `cupy.sinc` fails on complex inputs:

```python
>>> np.sinc(1j)
(3.676077910374978+0j)
>>> cp.sinc(1j)
TypeError                                 Traceback (most recent call last)
----> 1 cp.sinc(1j)
cupy/core/_kernel.pyx in cupy.core._kernel.ufunc.__call__()
cupy/core/_kernel.pyx in cupy.core._kernel._guess_routine()
TypeError: Wrong type ((<class 'numpy.complex128'>,)) of arguments for cupy_sinc
```

Either the docs should be updated or the underlying implementation should be fixed.

```python
>>> cp.show_config()
CuPy Version          : 6.0.0
CUDA Root             : /usr/local/cuda
CUDA Build Version    : 10000
CUDA Driver Version   : 10010
CUDA Runtime Version  : 10000
cuDNN Build Version   : 7301
cuDNN Version         : 7604
NCCL Build Version    : 1000
NCCL Runtime Version  : (unknown)
```

Hints from issue discussion:

Commit message: Per dtype implementations

Patch to review:
diff --git a/cupy/math/special.py b/cupy/math/special.py
index 1631962db88..345dabed221 100644
--- a/cupy/math/special.py
+++ b/cupy/math/special.py
@@ -12,7 +12,12 @@
 
 
 sinc = core.create_ufunc(
-    'cupy_sinc', ('e->e', 'f->f', 'd->d'),
+    'cupy_sinc',
+    ('e->e', 'f->f', 'd->',
+     ('F->F', 'in0_type pi_in0 = (in0_type) M_PI * in0;'
+              'out0 = abs(in0) > 1e-9 ? sin(pi_in0) / (pi_in0) : 1'),
+     ('D->D', 'in0_type pi_in0 = (in0_type) M_PI * in0;'
+              'out0 = abs(in0) > 1e-9 ? sin(pi_in0) / (pi_in0) : 1')),
     'out0 = abs(in0) > 1e-9 ? sinpi(in0) / (M_PI * in0) : 1',
     doc='''Elementwise sinc function.
 
diff --git a/tests/cupy_tests/math_tests/test_special.py b/tests/cupy_tests/math_tests/test_special.py
index 2f4a698d9be..3a1fb875f6e 100644
--- a/tests/cupy_tests/math_tests/test_special.py
+++ b/tests/cupy_tests/math_tests/test_special.py
@@ -13,13 +13,13 @@ def test_i0(self, xp, dtype):
         a = testing.shaped_random((2, 3), xp, dtype)
         return xp.i0(a)
 
-    @testing.for_dtypes(['e', 'f', 'd'])
+    @testing.for_dtypes(['e', 'f', 'd', 'F', 'D'])
     @testing.numpy_cupy_allclose(atol=1e-3)
     def test_sinc(self, xp, dtype):
-        a = testing.shaped_random((2, 3), xp, dtype)
+        a = testing.shaped_random((2, 3), xp, dtype, scale=1)
         return xp.sinc(a)
 
-    @testing.for_dtypes(['e', 'f', 'd'])
+    @testing.for_dtypes(['e', 'f', 'd', 'F', 'D'])
     def test_sinc_zero(self, dtype):
         a = cupy.sinc(cupy.zeros(1, dtype=dtype))
         testing.assert_array_equal(a, cupy.ones(1, dtype=dtype))


Code review comments:
diff_hunk: @@ -12,7 +12,12 @@
 
 
 sinc = core.create_ufunc(
-    'cupy_sinc', ('e->e', 'f->f', 'd->d'),
+    'cupy_sinc',
+    ('e->e', 'f->f', 'd->',
path: cupy/math/special.py
text: @user1:
```suggestion
    ('e->e', 'f->f', 'd->d',
```