Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement np.asarray() #3598

Merged
merged 3 commits into from
Jan 3, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -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)):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace types.Float and types.Integer with types.Number so that complex dtype also work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

dt_conv = a if _is_nonelike(dtype) else dtype
ty = as_dtype(dt_conv)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ty is frozen as a compile-time constant. the first dt_conv will always be used afterwards

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes, thanks, that explains some of the weirdness

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized that my explanation is wrong. The cache is per signature. A different a should not reach into the same cache.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the problem here is due to this #3612

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

b6e8f5a has some more tests for different scalar types, merging #3612 into this branch permits them to pass.

def impl(a, dtype=None):
return np.array(a, ty)

return impl
71 changes: 71 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,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

Expand Down