Repository: numba/numba

Issue:
LoweringError: No definition for lowering <built-in function radians>(float64,) -> float64
<!--

Thanks for opening an issue! To help the Numba team handle your information
efficiently, please first ensure that there is no other issue present that
already describes the issue you have
(search at https://github.com/numba/numba/issues?&q=is%3Aissue).

For more general "how do I do X?" type questions, please speak to us in real
time on https://gitter.im/numba/numba or post to the Numba mailing list
https://groups.google.com/a/continuum.io/forum/#!forum/numba-users.

-->

## Reporting a bug

<!--

Before submitting a bug report please ensure that you can check off these boxes:

-->

- I am using the latest released version of Numba (most recent is visible in
 the change log (https://github.com/numba/numba/blob/master/CHANGE_LOG).
-  I have included below a minimal working reproducer (if you are unsure how
 to write one see http://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports).

<!--

Please include details of the bug here, including, if applicable, what you
expected to happen!

-->
Im trying to calculate sun elevation angle by using numba and math library, this is my code, "lat" and "log" are numpy arrays with the size of (15000000,1) the rest of the input are only single numbers.Type of all input data is float64. This is a code:
```
@vectorize(['float64(float64, float64, float64, float64, float64, float64)'],target='cuda')
def ElevationMultiThreaded(lat, log, LT, LSTM, Eot,delta):
   TC = 4 * (log - LSTM) + Eot
    LST = LT + (TC/60.0)
    HrA = 15 * (LST - 12)
    rad_HrA = math.radians(HrA)
    rad_latitude  =math.radians(lat)
    rad_ElevationAngle = math.asin(( math.sin(delta) * math.sin(rad_latitude)) + ( math.cos(delta) * math.cos(rad_latitude) * math.cos(rad_HrA)))
        elevation = math.degrees(rad_ElevationAngle)
    return elevation
```
and this is the error:
```

  File "/usr/lib/python2.7/dist-packages/spyder/utils/site/sitecustomize.py", line 705, in runfile
    execfile(filename, namespace)

  File "/usr/lib/python2.7/dist-packages/spyder/utils/site/sitecustomize.py", line 94, in execfile
    builtins.execfile(filename, *where)

  File "/media/SVF.py", line 100, in <module>
    @vectorize(['float64(float64, float64, float64, float64, float64, float64)'],target='cuda')

  File "/usr/local/lib/python2.7/dist-packages/numba/npyufunc/decorators.py", line 120, in wrap
    vec.add(sig)

  File "/usr/local/lib/python2.7/dist-packages/numba/npyufunc/deviceufunc.py", line 397, in add
    corefn, return_type = self._compile_core(devfnsig)

  File "/usr/local/lib/python2.7/dist-packages/numba/cuda/vectorizers.py", line 17, in _compile_core
    cudevfn = cuda.jit(sig, device=True, inline=True)(self.pyfunc)

  File "/usr/local/lib/python2.7/dist-packages/numba/cuda/decorators.py", line 104, in device_jit
    debug=debug)

  File "/usr/local/lib/python2.7/dist-packages/numba/cuda/compiler.py", line 190, in compile_device
    return DeviceFunction(pyfunc, return_type, args, inline=True, debug=False)

  File "/usr/local/lib/python2.7/dist-packages/numba/cuda/compiler.py", line 221, in __init__
    debug=self.debug, inline=self.inline)

  File "/usr/local/lib/python2.7/dist-packages/numba/compiler_lock.py", line 32, in _acquire_compile_lock
    return func(*args, **kwargs)

  File "/usr/local/lib/python2.7/dist-packages/numba/cuda/compiler.py", line 51, in compile_cuda
    locals={})

  File "/usr/local/lib/python2.7/dist-packages/numba/compiler.py", line 955, in compile_extra
    return pipeline.compile_extra(func)

  File "/usr/local/lib/python2.7/dist-packages/numba/compiler.py", line 377, in compile_extra
    return self._compile_bytecode()

  File "/usr/local/lib/python2.7/dist-packages/numba/compiler.py", line 886, in _compile_bytecode
    return self._compile_core()

  File "/usr/local/lib/python2.7/dist-packages/numba/compiler.py", line 873, in _compile_core
    res = pm.run(self.status)

  File "/usr/local/lib/python2.7/dist-packages/numba/compiler_lock.py", line 32, in _acquire_compile_lock
    return func(*args, **kwargs)

  File "/usr/local/lib/python2.7/dist-packages/numba/compiler.py", line 254, in run
    raise patched_exception

LoweringError: No definition for lowering <built-in function radians>(float64,) -> float64
```


Discussion:
Thanks for the bug report.  I can reproduce the error. The CUDA target is missing the `math.radians` definition.

Minimal reproducer:
```python
from numba import cuda
import math
import numpy as np

@cuda.jit
def foo(x, y):
    y[0] = math.radians(x[0])


a = np.zeros(10)
foo(a, a)
```

Resolving patch:
diff --git a/numba/cuda/cudaimpl.py b/numba/cuda/cudaimpl.py
--- a/numba/cuda/cudaimpl.py
+++ b/numba/cuda/cudaimpl.py
@@ -2,6 +2,7 @@
 
 from functools import reduce
 import operator
+import math
 
 from llvmlite.llvmpy.core import Type
 import llvmlite.llvmpy.core as lc
@@ -483,6 +484,22 @@ def ptx_round(context, builder, sig, args):
     ])
 
 
+def gen_deg_rad(const):
+    def impl(context, builder, sig, args):
+        argty, = sig.args
+        factor = context.get_constant(argty, const)
+        return builder.fmul(factor, args[0])
+    return impl
+
+
+_deg2rad = math.pi / 180.
+_rad2deg = 180. / math.pi
+lower(math.radians, types.f4)(gen_deg_rad(_deg2rad))
+lower(math.radians, types.f8)(gen_deg_rad(_deg2rad))
+lower(math.degrees, types.f4)(gen_deg_rad(_rad2deg))
+lower(math.degrees, types.f8)(gen_deg_rad(_rad2deg))
+
+
 def _normalize_indices(context, builder, indty, inds):
     """
     Convert integer indices into tuple of intp


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
@@ -163,6 +163,13 @@ def math_isinf(A, B):
     i = cuda.grid(1)
     B[i] = math.isinf(A[i])
 
+def math_degrees(A, B):
+    i = cuda.grid(1)
+    B[i] = math.degrees(A[i])
+
+def math_radians(A, B):
+    i = cuda.grid(1)
+    B[i] = math.radians(A[i])
 
 def math_pow_binop(A, B, C):
     i = cuda.grid(1)
@@ -517,6 +524,20 @@ def test_math_isinf(self):
         self.unary_bool_template_float32(math_isinf, np.isinf)
         self.unary_bool_template_float64(math_isinf, np.isinf)
 
+    #------------------------------------------------------------------------------
+    # test_math_degrees
+
+    def test_math_degrees(self):
+        self.unary_bool_template_float32(math_degrees, np.degrees)
+        self.unary_bool_template_float64(math_degrees, np.degrees)
+
+    #------------------------------------------------------------------------------
+    # test_math_radians
+
+    def test_math_radians(self):
+        self.unary_bool_template_float32(math_radians, np.radians)
+        self.unary_bool_template_float64(math_radians, np.radians)
+
 
 if __name__ == '__main__':
     unittest.main()