Skip to content

Commit

Permalink
Merge pull request #3598 from stuartarchibald/wip/npasarray
Browse files Browse the repository at this point in the history
Implement np.asarray()
  • Loading branch information
stuartarchibald committed Jan 3, 2019
2 parents 14d8e85 + b6e8f5a commit 293fb61
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 3 deletions.
1 change: 1 addition & 0 deletions docs/source/reference/numpysupported.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
31 changes: 31 additions & 0 deletions numba/targets/arraymath.py
Original file line number Diff line number Diff line change
Expand Up @@ -2609,3 +2609,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.Number, 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
6 changes: 3 additions & 3 deletions numba/tests/test_errorhandling.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))


Expand Down
74 changes: 74 additions & 0 deletions numba/tests/test_np_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
"""
Expand Down Expand Up @@ -1543,6 +1549,74 @@ 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 1j
yield 1.2
yield False
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

Expand Down

0 comments on commit 293fb61

Please sign in to comment.