Repository: numba/numba

Issue:
[Feature Request] Support array.conj()
Numba 0.38 supports `np.conj` in `nopython` mode, but it doesn't seem to support `array.conj()`:

```python
In [14]: @numba.jit(nopython=True)
    ...: def f(x):
    ...:     return x.conj()
    ...: 
    ...: x = np.array([3+1j, 4+2j])

In [15]: f(x)
```

raises

```
TypingError: Failed at nopython (nopython frontend)
Unknown attribute 'conj' of type array(complex128, 1d, C)
```

This isn't a big deal, but I find `x.T.conj()` (as a shorthand for the hermitian) clearer and easier to read than `np.conj(x.T)`.


Discussion:
I'm looking at this, but wanted to point out that it appears also to fail for any array type, and works for any number type. I'll keep looking, but if anyone has a pointer as to where to add this to methods, that would be very helpful!

```python
@numba.jit(nopython=True)
def f(x):
    return x.conjugate()

print(f(2j))  # ok
print(f(2))  # ok
print(f(2.j))  # ok
f(np.array(2))  

TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Unknown attribute 'conjugate' of type array(int64, 0d, C)
```

Resolving patch:
diff --git a/numba/targets/arrayobj.py b/numba/targets/arrayobj.py
--- a/numba/targets/arrayobj.py
+++ b/numba/targets/arrayobj.py
@@ -26,7 +26,7 @@
                                     iternext_impl, impl_ret_borrowed,
                                     impl_ret_new_ref, impl_ret_untracked)
 from numba.typing import signature
-from numba.extending import register_jitable, overload
+from numba.extending import register_jitable, overload, overload_method
 from . import quicksort, mergesort, slicing
 
 
@@ -2066,6 +2066,12 @@ def array_imag_part(context, builder, typ, value):
     else:
         raise NotImplementedError('unsupported .imag for {}'.format(type.dtype))
 
+@overload_method(types.Array, 'conj')
+@overload_method(types.Array, 'conjugate')
+def array_conj(arr):
+    def impl(arr):
+        return np.conj(arr)
+    return impl
 
 def array_complex_attr(context, builder, typ, value, attr):
     """


Test patch:
diff --git a/numba/tests/test_array_methods.py b/numba/tests/test_array_methods.py
--- a/numba/tests/test_array_methods.py
+++ b/numba/tests/test_array_methods.py
@@ -171,14 +171,17 @@ def array_cumsum(a, *args):
 def array_cumsum_kws(a, axis):
     return a.cumsum(axis=axis)
 
-
 def array_real(a):
     return np.real(a)
 
-
 def array_imag(a):
     return np.imag(a)
 
+def array_conj(a):
+    return a.conj()
+
+def array_conjugate(a):
+    return a.conjugate()
 
 def np_unique(a):
     return np.unique(a)
@@ -187,7 +190,6 @@ def np_unique(a):
 def array_dot(a, b):
     return a.dot(b)
 
-
 def array_dot_chain(a, b):
     return a.dot(b).dot(b)
 
@@ -892,6 +894,17 @@ def test_imag(self):
         z = x + 1j*y
         np.testing.assert_equal(pyfunc(z), cfunc(z))
 
+    def test_conj(self):
+        for pyfunc in [array_conj, array_conjugate]:
+            cfunc = jit(nopython=True)(pyfunc)
+
+            x = np.linspace(-10, 10)
+            np.testing.assert_equal(pyfunc(x), cfunc(x))
+
+            x, y = np.meshgrid(x, x)
+            z = x + 1j*y
+            np.testing.assert_equal(pyfunc(z), cfunc(z))
+
     def test_unique(self):
         pyfunc = np_unique
         cfunc = jit(nopython=True)(pyfunc)