From e9f79c3e7965cfc41eef30c8b0f7c1be7a813b11 Mon Sep 17 00:00:00 2001 From: Stuart Archibald Date: Fri, 14 Dec 2018 12:32:13 +0000 Subject: [PATCH 1/3] Implement np.asarray() This implements np.asarray() and adds tests. --- docs/source/reference/numpysupported.rst | 1 + numba/targets/arraymath.py | 31 +++++++++++ numba/tests/test_np_functions.py | 71 ++++++++++++++++++++++++ 3 files changed, 103 insertions(+) diff --git a/docs/source/reference/numpysupported.rst b/docs/source/reference/numpysupported.rst index 25173cafd90..78db595387e 100644 --- a/docs/source/reference/numpysupported.rst +++ b/docs/source/reference/numpysupported.rst @@ -255,6 +255,7 @@ The following top-level functions are supported: * :func:`numpy.argsort` (``kind`` key word argument supported for values ``'quicksort'`` and ``'mergesort'``) * :func:`numpy.array` (only the 2 first arguments) +* :func:`numpy.asarray` (only the 2 first arguments) * :func:`numpy.asfortranarray` (only the first argument) * :func:`numpy.atleast_1d` * :func:`numpy.atleast_2d` diff --git a/numba/targets/arraymath.py b/numba/targets/arraymath.py index 547136ab115..425f2b8a1a4 100644 --- a/numba/targets/arraymath.py +++ b/numba/targets/arraymath.py @@ -2523,3 +2523,34 @@ def impl(a, v): return _np_correlate_core(a, v[::-1], Mode.FULL, 1) return impl + +def _is_nonelike(ty): + return (ty is None) or isinstance(ty, types.NoneType) + +@overload(np.asarray) +def np_asarray(a, dtype=None): + impl = None + if isinstance(a, types.Array): + if _is_nonelike(dtype) or a.dtype == dtype.dtype: + def impl(a, dtype=None): + return a + else: + def impl(a, dtype=None): + return a.astype(dtype) + elif isinstance(a, (types.Sequence, types.Tuple)): + # Nested lists cannot be unpacked, therefore only single lists are + # permitted and these conform to Sequence and can be unpacked along on + # the same path as Tuple. + if _is_nonelike(dtype): + def impl(a, dtype=None): + return np.array(a) + else: + def impl(a, dtype=None): + return np.array(a, dtype) + elif isinstance(a, (types.Float, types.Integer, types.Boolean)): + dt_conv = a if _is_nonelike(dtype) else dtype + ty = as_dtype(dt_conv) + def impl(a, dtype=None): + return np.array(a, ty) + + return impl diff --git a/numba/tests/test_np_functions.py b/numba/tests/test_np_functions.py index 073f051fe8f..0768151cf6a 100644 --- a/numba/tests/test_np_functions.py +++ b/numba/tests/test_np_functions.py @@ -113,6 +113,12 @@ def corrcoef(x, y=None, rowvar=True): def ediff1d(ary, to_end=None, to_begin=None): return np.ediff1d(ary, to_end, to_begin) +def asarray(a): + return np.asarray(a) + +def asarray_kws(a, dtype): + return np.asarray(a, dtype=dtype) + class TestNPFunctions(MemoryLeakMixin, TestCase): """ @@ -1543,6 +1549,71 @@ def test_ediff1d_exceptions(self): assert msg in str(e.exception) + def test_asarray(self): + + def input_variations(): + """ + To quote from: https://docs.scipy.org/doc/numpy/reference/generated/numpy.asarray.html + Input data, in any form that can be converted to an array. + This includes: + * lists + * lists of tuples + * tuples + * tuples of tuples + * tuples of lists + * ndarrays + """ + yield 1 + yield [1, 2, 3] + yield [(1, 2, 3), (1, 2, 3)] + yield (1, 2, 3) + yield ((1, 2, 3), (1, 2, 3)) + yield ([1, 2, 3], [1, 2, 3]) + yield np.array([]) + yield np.arange(4) + yield np.arange(12).reshape(3, 4) + yield np.arange(12).reshape(3, 4).T + + # used to check that if the input is already an array and the dtype is + # the same as that of the input/omitted then the array itself is + # returned. + def check_pass_through(jitted, expect_same, params): + returned = jitted(**params) + if expect_same: + self.assertTrue(returned is params['a']) + else: + self.assertTrue(returned is not params['a']) + # should be numerically the same, just different dtype + np.testing.assert_allclose(returned, params['a']) + self.assertTrue(returned.dtype == params['dtype']) + + for pyfunc in [asarray, asarray_kws]: + cfunc = jit(nopython=True)(pyfunc) + _check = partial(self._check_output, pyfunc, cfunc) + + for x in input_variations(): + params = {'a': x} + if 'kws' in pyfunc.__name__: + for dt in [None, np.complex128]: + params['dtype'] = dt + _check(params) + else: + _check(params) + + # check the behaviour over a dtype change (or not!) + x = np.arange(10, dtype=np.float32) + params = {'a': x} + if 'kws' in pyfunc.__name__: + params['dtype'] = None + check_pass_through(cfunc, True, params) + params['dtype'] = np.complex128 + check_pass_through(cfunc, False, params) + params['dtype'] = np.float32 + check_pass_through(cfunc, True, params) + else: + check_pass_through(cfunc, True, params) + + class TestNPMachineParameters(TestCase): # tests np.finfo, np.iinfo, np.MachAr From c910ea6f1773e8b366a128801384bd29674a23f7 Mon Sep 17 00:00:00 2001 From: Stuart Archibald Date: Fri, 14 Dec 2018 18:21:54 +0000 Subject: [PATCH 2/3] Fix failing test. As title. --- numba/tests/test_errorhandling.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/numba/tests/test_errorhandling.py b/numba/tests/test_errorhandling.py index 44b2421a79b..c124acdb3c0 100644 --- a/numba/tests/test_errorhandling.py +++ b/numba/tests/test_errorhandling.py @@ -46,15 +46,15 @@ def inner(x): class TestUnsupportedReporting(unittest.TestCase): def test_unsupported_numpy_function(self): - # np.asarray(list) currently unsupported + # np.asanyarray(list) currently unsupported @njit def func(): - np.asarray([1,2,3]) + np.asanyarray([1,2,3]) with self.assertRaises(errors.TypingError) as raises: func() - expected = "Use of unsupported NumPy function 'numpy.asarray'" + expected = "Use of unsupported NumPy function 'numpy.asanyarray'" self.assertIn(expected, str(raises.exception)) From b6e8f5afa0386de4d63a43d4a23abf931c13973f Mon Sep 17 00:00:00 2001 From: Stuart Archibald Date: Mon, 31 Dec 2018 20:48:51 +0000 Subject: [PATCH 3/3] Add more tests --- numba/targets/arraymath.py | 2 +- numba/tests/test_np_functions.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/numba/targets/arraymath.py b/numba/targets/arraymath.py index 425f2b8a1a4..02078928e64 100644 --- a/numba/targets/arraymath.py +++ b/numba/targets/arraymath.py @@ -2547,7 +2547,7 @@ def impl(a, dtype=None): else: def impl(a, dtype=None): return np.array(a, dtype) - elif isinstance(a, (types.Float, types.Integer, types.Boolean)): + elif isinstance(a, (types.Number, types.Boolean)): dt_conv = a if _is_nonelike(dtype) else dtype ty = as_dtype(dt_conv) def impl(a, dtype=None): diff --git a/numba/tests/test_np_functions.py b/numba/tests/test_np_functions.py index 0768151cf6a..ea5e646b969 100644 --- a/numba/tests/test_np_functions.py +++ b/numba/tests/test_np_functions.py @@ -1563,6 +1563,9 @@ def input_variations(): * tuples of lists * ndarrays """ + yield 1j + yield 1.2 + yield False yield 1 yield [1, 2, 3] yield [(1, 2, 3), (1, 2, 3)]