1788 lines
62 KiB
Python
1788 lines
62 KiB
Python
|
from itertools import product, cycle
|
||
|
import gc
|
||
|
import sys
|
||
|
import unittest
|
||
|
import warnings
|
||
|
|
||
|
import numpy as np
|
||
|
|
||
|
from numba import jit, njit, typeof
|
||
|
from numba.core import types
|
||
|
from numba.core.errors import TypingError, NumbaValueError
|
||
|
from numba.np.numpy_support import as_dtype, numpy_version
|
||
|
from numba.tests.support import TestCase, MemoryLeakMixin, needs_blas
|
||
|
|
||
|
TIMEDELTA_M = 'timedelta64[M]'
|
||
|
TIMEDELTA_Y = 'timedelta64[Y]'
|
||
|
|
||
|
|
||
|
def np_around_array(arr, decimals, out):
|
||
|
np.around(arr, decimals, out)
|
||
|
|
||
|
def np_around_binary(val, decimals):
|
||
|
return np.around(val, decimals)
|
||
|
|
||
|
def np_around_unary(val):
|
||
|
return np.around(val)
|
||
|
|
||
|
def np_round_array(arr, decimals, out):
|
||
|
np.round(arr, decimals, out)
|
||
|
|
||
|
def np_round__array(arr, decimals, out):
|
||
|
np.round_(arr, decimals, out)
|
||
|
|
||
|
def np_round_binary(val, decimals):
|
||
|
return np.round(val, decimals)
|
||
|
|
||
|
def np_round_unary(val):
|
||
|
return np.round(val)
|
||
|
|
||
|
def _fixed_np_round(arr, decimals=0, out=None):
|
||
|
"""
|
||
|
A slightly bugfixed version of np.round().
|
||
|
"""
|
||
|
if out is not None and arr.dtype.kind == 'c':
|
||
|
# workaround for https://github.com/numpy/numpy/issues/5779
|
||
|
_fixed_np_round(arr.real, decimals, out.real)
|
||
|
_fixed_np_round(arr.imag, decimals, out.imag)
|
||
|
return out
|
||
|
else:
|
||
|
res = np.round(arr, decimals, out)
|
||
|
if out is None:
|
||
|
# workaround for https://github.com/numpy/numpy/issues/5780
|
||
|
def fixup_signed_zero(arg, res):
|
||
|
if res == 0.0 and arg < 0:
|
||
|
return -np.abs(res)
|
||
|
else:
|
||
|
return res
|
||
|
if isinstance(arr, (complex, np.complexfloating)):
|
||
|
res = complex(fixup_signed_zero(arr.real, res.real),
|
||
|
fixup_signed_zero(arr.imag, res.imag))
|
||
|
else:
|
||
|
res = fixup_signed_zero(arr, res)
|
||
|
return res
|
||
|
|
||
|
|
||
|
def array_T(arr):
|
||
|
return arr.T
|
||
|
|
||
|
def array_transpose(arr):
|
||
|
return arr.transpose()
|
||
|
|
||
|
def array_copy(arr):
|
||
|
return arr.copy()
|
||
|
|
||
|
def np_copy(arr):
|
||
|
return np.copy(arr)
|
||
|
|
||
|
def np_asfortranarray(arr):
|
||
|
return np.asfortranarray(arr)
|
||
|
|
||
|
def np_ascontiguousarray(arr):
|
||
|
return np.ascontiguousarray(arr)
|
||
|
|
||
|
def array_view(arr, newtype):
|
||
|
return arr.view(newtype)
|
||
|
|
||
|
def array_take(arr, indices):
|
||
|
return arr.take(indices)
|
||
|
|
||
|
def array_take_kws(arr, indices, axis):
|
||
|
return arr.take(indices, axis=axis)
|
||
|
|
||
|
def np_arange_1(arg0):
|
||
|
return np.arange(arg0)
|
||
|
|
||
|
def np_arange_2(arg0, arg1):
|
||
|
return np.arange(arg0, arg1)
|
||
|
|
||
|
def np_arange_3(arg0, arg1, arg2):
|
||
|
return np.arange(arg0, arg1, arg2)
|
||
|
|
||
|
def np_arange_4(arg0, arg1, arg2, arg3):
|
||
|
return np.arange(arg0, arg1, arg2, arg3)
|
||
|
|
||
|
def np_arange_1_stop(arg0, stop):
|
||
|
return np.arange(arg0, stop=stop)
|
||
|
|
||
|
def np_arange_1_step(arg0, step):
|
||
|
return np.arange(arg0, step=step)
|
||
|
|
||
|
def np_arange_1_dtype(arg0, dtype):
|
||
|
return np.arange(arg0, dtype=dtype)
|
||
|
|
||
|
def np_arange_2_step(arg0, arg1, step):
|
||
|
return np.arange(arg0, arg1, step=step)
|
||
|
|
||
|
def np_arange_2_dtype(arg0, arg1, dtype):
|
||
|
return np.arange(arg0, arg1, dtype=dtype)
|
||
|
|
||
|
def np_arange_start_stop(start, stop):
|
||
|
return np.arange(start=start, stop=stop)
|
||
|
|
||
|
def np_arange_start_stop_step(start, stop, step):
|
||
|
return np.arange(start=start, stop=stop, step=step)
|
||
|
|
||
|
def np_arange_start_stop_step_dtype(start, stop, step, dtype):
|
||
|
return np.arange(start=start, stop=stop, step=step, dtype=dtype)
|
||
|
|
||
|
def array_fill(arr, val):
|
||
|
return arr.fill(val)
|
||
|
|
||
|
# XXX Can't pass a dtype as a Dispatcher argument for now
|
||
|
def make_array_view(newtype):
|
||
|
def array_view(arr):
|
||
|
return arr.view(newtype)
|
||
|
return array_view
|
||
|
|
||
|
def array_sliced_view(arr, ):
|
||
|
return arr[0:4].view(np.float32)[0]
|
||
|
|
||
|
def make_array_astype(newtype):
|
||
|
def array_astype(arr):
|
||
|
return arr.astype(newtype)
|
||
|
return array_astype
|
||
|
|
||
|
|
||
|
def np_frombuffer(b):
|
||
|
"""
|
||
|
np.frombuffer() on a Python-allocated buffer.
|
||
|
"""
|
||
|
return np.frombuffer(b)
|
||
|
|
||
|
def np_frombuffer_dtype(b):
|
||
|
return np.frombuffer(b, dtype=np.complex64)
|
||
|
|
||
|
def np_frombuffer_dtype_str(b):
|
||
|
return np.frombuffer(b, dtype='complex64')
|
||
|
|
||
|
def np_frombuffer_allocated(shape):
|
||
|
"""
|
||
|
np.frombuffer() on a Numba-allocated buffer.
|
||
|
"""
|
||
|
arr = np.ones(shape, dtype=np.int32)
|
||
|
return np.frombuffer(arr)
|
||
|
|
||
|
def np_frombuffer_allocated_dtype(shape):
|
||
|
arr = np.ones(shape, dtype=np.int32)
|
||
|
return np.frombuffer(arr, dtype=np.complex64)
|
||
|
|
||
|
def identity_usecase(a, b):
|
||
|
return (a is b), (a is not b)
|
||
|
|
||
|
def array_nonzero(a):
|
||
|
return a.nonzero()
|
||
|
|
||
|
def np_nonzero(a):
|
||
|
return np.nonzero(a)
|
||
|
|
||
|
def np_where_1(c):
|
||
|
return np.where(c)
|
||
|
|
||
|
def np_where_3(c, x, y):
|
||
|
return np.where(c, x, y)
|
||
|
|
||
|
def array_item(a):
|
||
|
return a.item()
|
||
|
|
||
|
def array_itemset(a, v):
|
||
|
a.itemset(v)
|
||
|
|
||
|
def array_sum(a, *args):
|
||
|
return a.sum(*args)
|
||
|
|
||
|
def array_sum_axis_kws(a, axis):
|
||
|
return a.sum(axis=axis)
|
||
|
|
||
|
def array_sum_dtype_kws(a, dtype):
|
||
|
return a.sum(dtype=dtype)
|
||
|
|
||
|
def array_sum_axis_dtype_kws(a, dtype, axis):
|
||
|
return a.sum(axis=axis, dtype=dtype)
|
||
|
|
||
|
def array_sum_axis_dtype_pos(a, a1, a2):
|
||
|
return a.sum(a1, a2)
|
||
|
|
||
|
def array_sum_const_multi(arr, axis):
|
||
|
# use np.sum with different constant args multiple times to check
|
||
|
# for internal compile cache to see if constant-specialization is
|
||
|
# applied properly.
|
||
|
a = np.sum(arr, axis=4)
|
||
|
b = np.sum(arr, 3)
|
||
|
# the last invocation uses runtime-variable
|
||
|
c = np.sum(arr, axis)
|
||
|
# as method
|
||
|
d = arr.sum(axis=5)
|
||
|
# negative const axis
|
||
|
e = np.sum(arr, axis=-1)
|
||
|
return a, b, c, d, e
|
||
|
|
||
|
def array_sum_const_axis_neg_one(a, axis):
|
||
|
# use .sum with -1 axis, this is for use with 1D arrays where the above
|
||
|
# "const_multi" variant would raise errors
|
||
|
return a.sum(axis=-1)
|
||
|
|
||
|
def array_cumsum(a, *args):
|
||
|
return a.cumsum(*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 np_clip_no_out(a, a_min, a_max):
|
||
|
return np.clip(a, a_min, a_max)
|
||
|
|
||
|
def np_clip(a, a_min, a_max, out=None):
|
||
|
return np.clip(a, a_min, a_max, out)
|
||
|
|
||
|
def np_clip_kwargs(a, a_min, a_max, out=None):
|
||
|
return np.clip(a, a_min, a_max, out=out)
|
||
|
|
||
|
def array_clip(a, a_min=None, a_max=None, out=None):
|
||
|
return a.clip(a_min, a_max, out)
|
||
|
|
||
|
def array_clip_kwargs(a, a_min=None, a_max=None, out=None):
|
||
|
return a.clip(a_min, a_max, out=out)
|
||
|
|
||
|
def array_clip_no_out(a, a_min, a_max):
|
||
|
return a.clip(a_min, a_max)
|
||
|
|
||
|
def array_conj(a):
|
||
|
return a.conj()
|
||
|
|
||
|
def array_conjugate(a):
|
||
|
return a.conjugate()
|
||
|
|
||
|
def np_unique(a):
|
||
|
return np.unique(a)
|
||
|
|
||
|
|
||
|
def array_dot(a, b):
|
||
|
return a.dot(b)
|
||
|
|
||
|
def array_dot_chain(a, b):
|
||
|
return a.dot(b).dot(b)
|
||
|
|
||
|
def array_ctor(n, dtype):
|
||
|
return np.ones(n, dtype=dtype)
|
||
|
|
||
|
class TestArrayMethods(MemoryLeakMixin, TestCase):
|
||
|
"""
|
||
|
Test various array methods and array-related functions.
|
||
|
"""
|
||
|
|
||
|
def setUp(self):
|
||
|
super(TestArrayMethods, self).setUp()
|
||
|
|
||
|
def check_round_scalar(self, unary_pyfunc, binary_pyfunc):
|
||
|
base_values = [-3.0, -2.5, -2.25, -1.5, 1.5, 2.25, 2.5, 2.75]
|
||
|
complex_values = [x * (1 - 1j) for x in base_values]
|
||
|
int_values = [int(x) for x in base_values]
|
||
|
argtypes = (types.float64, types.float32, types.int32,
|
||
|
types.complex64, types.complex128)
|
||
|
argvalues = [base_values, base_values, int_values,
|
||
|
complex_values, complex_values]
|
||
|
|
||
|
pyfunc = binary_pyfunc
|
||
|
for ty, values in zip(argtypes, argvalues):
|
||
|
cfunc = njit((ty, types.int32))(pyfunc)
|
||
|
for decimals in (1, 0, -1):
|
||
|
for v in values:
|
||
|
if decimals > 0:
|
||
|
v *= 10
|
||
|
expected = _fixed_np_round(v, decimals)
|
||
|
got = cfunc(v, decimals)
|
||
|
self.assertPreciseEqual(got, expected)
|
||
|
|
||
|
pyfunc = unary_pyfunc
|
||
|
for ty, values in zip(argtypes, argvalues):
|
||
|
cfunc = njit((ty,))(pyfunc)
|
||
|
for v in values:
|
||
|
expected = _fixed_np_round(v)
|
||
|
got = cfunc(v)
|
||
|
self.assertPreciseEqual(got, expected)
|
||
|
|
||
|
def test_round_scalar(self):
|
||
|
self.check_round_scalar(np_round_unary, np_round_binary)
|
||
|
|
||
|
def test_around_scalar(self):
|
||
|
self.check_round_scalar(np_around_unary, np_around_binary)
|
||
|
|
||
|
def check_round_array(self, pyfunc):
|
||
|
def check_round(cfunc, values, inty, outty, decimals):
|
||
|
# Create input and output arrays of the right type
|
||
|
arr = values.astype(as_dtype(inty))
|
||
|
out = np.zeros_like(arr).astype(as_dtype(outty))
|
||
|
pyout = out.copy()
|
||
|
_fixed_np_round(arr, decimals, pyout)
|
||
|
self.memory_leak_setup()
|
||
|
cfunc(arr, decimals, out)
|
||
|
self.memory_leak_teardown()
|
||
|
np.testing.assert_allclose(out, pyout)
|
||
|
# Output shape mismatch
|
||
|
with self.assertRaises(ValueError) as raises:
|
||
|
cfunc(arr, decimals, out[1:])
|
||
|
self.assertEqual(str(raises.exception),
|
||
|
"invalid output shape")
|
||
|
|
||
|
def check_types(argtypes, outtypes, values):
|
||
|
for inty, outty in product(argtypes, outtypes):
|
||
|
argtys = (types.Array(inty, 1, 'A'), types.int32,
|
||
|
types.Array(outty, 1, 'A'))
|
||
|
cfunc = njit(argtys)(pyfunc)
|
||
|
check_round(cfunc, values, inty, outty, 0)
|
||
|
check_round(cfunc, values, inty, outty, 1)
|
||
|
if not isinstance(outty, types.Integer):
|
||
|
check_round(cfunc, values * 10, inty, outty, -1)
|
||
|
else:
|
||
|
# Avoid Numpy bug when output is an int:
|
||
|
# https://github.com/numpy/numpy/issues/5777
|
||
|
pass
|
||
|
|
||
|
values = np.array([-3.0, -2.5, -2.25, -1.5, 1.5, 2.25, 2.5, 2.75])
|
||
|
|
||
|
argtypes = (types.float64, types.float32)
|
||
|
check_types(argtypes, argtypes, values)
|
||
|
|
||
|
argtypes = (types.complex64, types.complex128)
|
||
|
check_types(argtypes, argtypes, values * (1 - 1j))
|
||
|
|
||
|
# Exceptions leak references
|
||
|
self.disable_leak_check()
|
||
|
|
||
|
def test_round_array(self):
|
||
|
self.check_round_array(np_round_array)
|
||
|
|
||
|
def test_around_array(self):
|
||
|
self.check_round_array(np_around_array)
|
||
|
|
||
|
def test_round__array(self):
|
||
|
self.check_round_array(np_round__array)
|
||
|
|
||
|
def test_around_bad_array(self):
|
||
|
for pyfunc in (np_round_unary, np_around_unary):
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
msg = '.*The argument "a" must be array-like.*'
|
||
|
with self.assertRaisesRegex(TypingError, msg):
|
||
|
cfunc(None)
|
||
|
|
||
|
def test_around_bad_out(self):
|
||
|
for py_func in (np_round_array, np_around_array, np_round__array):
|
||
|
cfunc = jit(nopython=True)(py_func)
|
||
|
msg = '.*The argument "out" must be an array if it is provided.*'
|
||
|
with self.assertRaisesRegex(TypingError, msg):
|
||
|
cfunc(5, 0, out=6)
|
||
|
|
||
|
def test_array_view(self):
|
||
|
|
||
|
def run(arr, dtype):
|
||
|
pyfunc = make_array_view(dtype)
|
||
|
return njit(pyfunc)(arr)
|
||
|
|
||
|
def check(arr, dtype):
|
||
|
expected = arr.view(dtype)
|
||
|
self.memory_leak_setup()
|
||
|
got = run(arr, dtype)
|
||
|
self.assertPreciseEqual(got, expected)
|
||
|
del got
|
||
|
self.memory_leak_teardown()
|
||
|
|
||
|
def check_err(arr, dtype):
|
||
|
with self.assertRaises(ValueError) as raises:
|
||
|
run(arr, dtype)
|
||
|
self.assertEqual(str(raises.exception),
|
||
|
"new type not compatible with array")
|
||
|
|
||
|
def check_err_noncontig_last_axis(arr, dtype):
|
||
|
# check NumPy interpreted version raises
|
||
|
msg = ("To change to a dtype of a different size, the last axis "
|
||
|
"must be contiguous")
|
||
|
with self.assertRaises(ValueError) as raises:
|
||
|
make_array_view(dtype)(arr)
|
||
|
self.assertEqual(str(raises.exception), msg)
|
||
|
# check Numba version raises
|
||
|
with self.assertRaises(ValueError) as raises:
|
||
|
run(arr, dtype)
|
||
|
self.assertEqual(str(raises.exception), msg)
|
||
|
|
||
|
def check_err_0d(arr, dtype):
|
||
|
# check NumPy interpreted version raises
|
||
|
msg = ("Changing the dtype of a 0d array is only supported "
|
||
|
"if the itemsize is unchanged")
|
||
|
with self.assertRaises(ValueError) as raises:
|
||
|
make_array_view(dtype)(arr)
|
||
|
self.assertEqual(str(raises.exception), msg)
|
||
|
# check Numba version raises
|
||
|
with self.assertRaises(ValueError) as raises:
|
||
|
run(arr, dtype)
|
||
|
self.assertEqual(str(raises.exception), msg)
|
||
|
|
||
|
def check_err_smaller_dtype(arr, dtype):
|
||
|
# check NumPy interpreted version raises
|
||
|
msg = ("When changing to a smaller dtype, its size must be a "
|
||
|
"divisor of the size of original dtype")
|
||
|
with self.assertRaises(ValueError) as raises:
|
||
|
make_array_view(dtype)(arr)
|
||
|
self.assertEqual(str(raises.exception), msg)
|
||
|
# check Numba version raises
|
||
|
with self.assertRaises(ValueError) as raises:
|
||
|
run(arr, dtype)
|
||
|
self.assertEqual(str(raises.exception), msg)
|
||
|
|
||
|
def check_err_larger_dtype(arr, dtype):
|
||
|
# check NumPy interpreted version raises
|
||
|
msg = ("When changing to a larger dtype, its size must be a "
|
||
|
"divisor of the total size in bytes of the last axis "
|
||
|
"of the array.")
|
||
|
with self.assertRaises(ValueError) as raises:
|
||
|
make_array_view(dtype)(arr)
|
||
|
self.assertEqual(str(raises.exception), msg)
|
||
|
# check Numba version raises
|
||
|
with self.assertRaises(ValueError) as raises:
|
||
|
run(arr, dtype)
|
||
|
self.assertEqual(str(raises.exception), msg)
|
||
|
|
||
|
dt1 = np.dtype([('a', np.int8), ('b', np.int8)])
|
||
|
dt2 = np.dtype([('u', np.int16), ('v', np.int8)])
|
||
|
dt3 = np.dtype([('x', np.int16), ('y', np.int16)])
|
||
|
|
||
|
# The checking routines are much more specific from NumPy 1.23 onwards
|
||
|
# as the granularity of error reporing is improved in Numba to match
|
||
|
# that of NumPy.
|
||
|
if numpy_version >= (1, 23):
|
||
|
check_error_larger_dt = check_err_larger_dtype
|
||
|
check_error_smaller_dt = check_err_smaller_dtype
|
||
|
check_error_noncontig = check_err_noncontig_last_axis
|
||
|
check_error_0d = check_err_0d
|
||
|
else:
|
||
|
check_error_larger_dt = check_err
|
||
|
check_error_smaller_dt = check_err
|
||
|
check_error_noncontig = check_err
|
||
|
check_error_0d = check_err
|
||
|
|
||
|
# C-contiguous
|
||
|
arr = np.arange(24, dtype=np.int8)
|
||
|
check(arr, np.dtype('int16'))
|
||
|
check(arr, np.int16)
|
||
|
check(arr, np.int8)
|
||
|
check(arr, np.float32)
|
||
|
check(arr, np.complex64)
|
||
|
check(arr, dt1)
|
||
|
check(arr, dt2)
|
||
|
check_error_larger_dt(arr, np.complex128)
|
||
|
|
||
|
# Last dimension must have a compatible size
|
||
|
arr = arr.reshape((3, 8))
|
||
|
check(arr, np.int8)
|
||
|
check(arr, np.float32)
|
||
|
check(arr, np.complex64)
|
||
|
check(arr, dt1)
|
||
|
check_error_larger_dt(arr, dt2)
|
||
|
check_error_larger_dt(arr, np.complex128)
|
||
|
|
||
|
# F-contiguous
|
||
|
f_arr = np.arange(24, dtype=np.int8).reshape((3, 8)).T
|
||
|
# neither F or C contiguous
|
||
|
not_f_or_c_arr = np.zeros((4, 4)).T[::2, ::2]
|
||
|
|
||
|
# NumPy 1.23 does not allow views with different size dtype for
|
||
|
# non-contiguous last axis.
|
||
|
if numpy_version >= (1, 23):
|
||
|
check_maybe_error = check_err_noncontig_last_axis
|
||
|
else:
|
||
|
check_maybe_error = check
|
||
|
|
||
|
check(f_arr, np.int8)
|
||
|
check(not_f_or_c_arr, np.uint64)
|
||
|
check_maybe_error(f_arr, np.float32)
|
||
|
check_maybe_error(f_arr, np.complex64)
|
||
|
check_maybe_error(f_arr, dt1)
|
||
|
|
||
|
check_error_noncontig(f_arr, dt2)
|
||
|
check_error_noncontig(f_arr, np.complex128)
|
||
|
check_error_noncontig(not_f_or_c_arr, np.int8)
|
||
|
|
||
|
# Non-contiguous: only a type with the same itemsize can be used
|
||
|
arr = np.arange(16, dtype=np.int32)[::2]
|
||
|
check(arr, np.uint32)
|
||
|
check(arr, np.float32)
|
||
|
check(arr, dt3)
|
||
|
check_error_noncontig(arr, np.int8)
|
||
|
check_error_noncontig(arr, np.int16)
|
||
|
check_error_noncontig(arr, np.int64)
|
||
|
check_error_noncontig(arr, dt1)
|
||
|
check_error_noncontig(arr, dt2)
|
||
|
|
||
|
## Zero-dim array: only a type with the same itemsize can be used
|
||
|
arr = np.array([42], dtype=np.int32).reshape(())
|
||
|
check(arr, np.uint32)
|
||
|
check(arr, np.float32)
|
||
|
check(arr, dt3)
|
||
|
check_error_0d(arr, np.int8)
|
||
|
check_error_0d(arr, np.int16)
|
||
|
check_error_0d(arr, np.int64)
|
||
|
check_error_0d(arr, dt1)
|
||
|
check_error_0d(arr, dt2)
|
||
|
|
||
|
# Changing to smaller dtype
|
||
|
arr = np.array(['abcdef'])
|
||
|
check_error_smaller_dt(arr, np.complex128)
|
||
|
|
||
|
# Exceptions leak references
|
||
|
self.disable_leak_check()
|
||
|
|
||
|
def test_array_sliced_view(self):
|
||
|
"""
|
||
|
Test .view() on A layout array but has contiguous innermost dimension.
|
||
|
"""
|
||
|
pyfunc = array_sliced_view
|
||
|
cfunc = njit((types.uint8[:],))(pyfunc)
|
||
|
|
||
|
orig = np.array([1.5, 2], dtype=np.float32)
|
||
|
byteary = orig.view(np.uint8)
|
||
|
|
||
|
expect = pyfunc(byteary)
|
||
|
got = cfunc(byteary)
|
||
|
|
||
|
self.assertEqual(expect, got)
|
||
|
|
||
|
def test_array_astype(self):
|
||
|
|
||
|
def run(arr, dtype):
|
||
|
pyfunc = make_array_astype(dtype)
|
||
|
return njit(pyfunc)(arr)
|
||
|
|
||
|
def check(arr, dtype):
|
||
|
expected = arr.astype(dtype).copy(order='A')
|
||
|
got = run(arr, dtype)
|
||
|
self.assertPreciseEqual(got, expected)
|
||
|
|
||
|
# C-contiguous
|
||
|
arr = np.arange(24, dtype=np.int8)
|
||
|
check(arr, np.dtype('int16'))
|
||
|
check(arr, np.int32)
|
||
|
check(arr, np.float32)
|
||
|
check(arr, np.complex128)
|
||
|
check(arr, "float32")
|
||
|
|
||
|
# F-contiguous
|
||
|
arr = np.arange(24, dtype=np.int8).reshape((3, 8)).T
|
||
|
check(arr, np.float32)
|
||
|
|
||
|
# Non-contiguous
|
||
|
arr = np.arange(16, dtype=np.int32)[::2]
|
||
|
check(arr, np.uint64)
|
||
|
|
||
|
# check read only attr does not get copied
|
||
|
arr = np.arange(16, dtype=np.int32)
|
||
|
arr.flags.writeable = False
|
||
|
check(arr, np.int32)
|
||
|
|
||
|
# Invalid conversion
|
||
|
dt = np.dtype([('x', np.int8)])
|
||
|
with self.assertTypingError() as raises:
|
||
|
check(arr, dt)
|
||
|
self.assertIn('cannot convert from int32 to Record',
|
||
|
str(raises.exception))
|
||
|
# Check non-Literal string raises
|
||
|
unicode_val = "float32"
|
||
|
with self.assertTypingError() as raises:
|
||
|
@jit(nopython=True)
|
||
|
def foo(dtype):
|
||
|
np.array([1]).astype(dtype)
|
||
|
foo(unicode_val)
|
||
|
self.assertIn('array.astype if dtype is a string it must be constant',
|
||
|
str(raises.exception))
|
||
|
|
||
|
def check_np_frombuffer(self, pyfunc):
|
||
|
|
||
|
cfunc = njit(pyfunc)
|
||
|
|
||
|
def check(buf):
|
||
|
old_refcnt = sys.getrefcount(buf)
|
||
|
expected = pyfunc(buf)
|
||
|
self.memory_leak_setup()
|
||
|
got = cfunc(buf)
|
||
|
self.assertPreciseEqual(got, expected)
|
||
|
del expected
|
||
|
# Note gc.collect is due to references in `except ... as e` that
|
||
|
# aren't immediately cleared
|
||
|
gc.collect()
|
||
|
self.assertEqual(sys.getrefcount(buf), old_refcnt + 1)
|
||
|
del got
|
||
|
gc.collect()
|
||
|
self.assertEqual(sys.getrefcount(buf), old_refcnt)
|
||
|
self.memory_leak_teardown()
|
||
|
|
||
|
b = bytearray(range(16))
|
||
|
check(b)
|
||
|
check(bytes(b))
|
||
|
check(memoryview(b))
|
||
|
check(np.arange(12))
|
||
|
b = np.arange(12).reshape((3, 4))
|
||
|
check(b)
|
||
|
|
||
|
# Exceptions leak references
|
||
|
self.disable_leak_check()
|
||
|
|
||
|
with self.assertRaises(ValueError) as raises:
|
||
|
cfunc(bytearray(b"xxx"))
|
||
|
self.assertEqual("buffer size must be a multiple of element size",
|
||
|
str(raises.exception))
|
||
|
|
||
|
def test_np_frombuffer(self):
|
||
|
self.check_np_frombuffer(np_frombuffer)
|
||
|
|
||
|
def test_np_frombuffer_dtype(self):
|
||
|
self.check_np_frombuffer(np_frombuffer_dtype)
|
||
|
|
||
|
def test_np_frombuffer_dtype_str(self):
|
||
|
self.check_np_frombuffer(np_frombuffer_dtype_str)
|
||
|
|
||
|
def test_np_frombuffer_dtype_non_const_str(self):
|
||
|
@jit(nopython=True)
|
||
|
def func(buf, dt):
|
||
|
np.frombuffer(buf, dtype=dt)
|
||
|
|
||
|
with self.assertRaises(TypingError) as raises:
|
||
|
func(bytearray(range(16)), 'int32')
|
||
|
|
||
|
excstr = str(raises.exception)
|
||
|
msg = ("If np.frombuffer dtype is a string it must be a "
|
||
|
"string constant.")
|
||
|
self.assertIn(msg, excstr)
|
||
|
|
||
|
def test_np_frombuffer_bad_buffer(self):
|
||
|
@jit(nopython=True)
|
||
|
def func(buf):
|
||
|
return np.frombuffer(buf)
|
||
|
|
||
|
msg = '.*Argument "buffer" must be buffer-like.*'
|
||
|
with self.assertRaisesRegex(TypingError, msg) as raises:
|
||
|
func(None)
|
||
|
|
||
|
def check_layout_dependent_func(self, pyfunc, fac=np.arange):
|
||
|
def is_same(a, b):
|
||
|
return a.ctypes.data == b.ctypes.data
|
||
|
def check_arr(arr):
|
||
|
cfunc = njit((typeof(arr),))(pyfunc)
|
||
|
expected = pyfunc(arr)
|
||
|
got = cfunc(arr)
|
||
|
self.assertPreciseEqual(expected, got)
|
||
|
self.assertEqual(is_same(expected, arr), is_same(got, arr))
|
||
|
arr = fac(24)
|
||
|
check_arr(arr)
|
||
|
check_arr(arr.reshape((3, 8)))
|
||
|
check_arr(arr.reshape((3, 8)).T)
|
||
|
check_arr(arr.reshape((3, 8))[::2])
|
||
|
check_arr(arr.reshape((2, 3, 4)))
|
||
|
check_arr(arr.reshape((2, 3, 4)).T)
|
||
|
check_arr(arr.reshape((2, 3, 4))[::2])
|
||
|
arr = np.array([0]).reshape(())
|
||
|
check_arr(arr)
|
||
|
|
||
|
def test_array_transpose(self):
|
||
|
self.check_layout_dependent_func(array_transpose)
|
||
|
|
||
|
def test_array_T(self):
|
||
|
self.check_layout_dependent_func(array_T)
|
||
|
|
||
|
def test_array_copy(self):
|
||
|
self.check_layout_dependent_func(array_copy)
|
||
|
|
||
|
def test_np_copy(self):
|
||
|
self.check_layout_dependent_func(np_copy)
|
||
|
|
||
|
def check_ascontiguousarray_scalar(self, pyfunc):
|
||
|
def check_scalar(x):
|
||
|
cfunc = njit((typeof(x),))(pyfunc)
|
||
|
expected = pyfunc(x)
|
||
|
got = cfunc(x)
|
||
|
self.assertPreciseEqual(expected, got)
|
||
|
for x in [42, 42.0, 42j, np.float32(42), np.float64(42), True]:
|
||
|
check_scalar(x)
|
||
|
|
||
|
def check_bad_array(self, pyfunc):
|
||
|
msg = '.*The argument "a" must be array-like.*'
|
||
|
with self.assertRaisesRegex(TypingError, msg) as raises:
|
||
|
njit((typeof('hello'), ))(pyfunc)
|
||
|
|
||
|
def test_np_asfortranarray(self):
|
||
|
self.check_layout_dependent_func(np_asfortranarray)
|
||
|
self.check_bad_array(np_asfortranarray)
|
||
|
self.check_ascontiguousarray_scalar(np_asfortranarray)
|
||
|
|
||
|
def test_np_ascontiguousarray(self):
|
||
|
self.check_layout_dependent_func(np_ascontiguousarray)
|
||
|
self.check_bad_array(np_asfortranarray)
|
||
|
self.check_ascontiguousarray_scalar(np_ascontiguousarray)
|
||
|
|
||
|
def check_np_frombuffer_allocated(self, pyfunc):
|
||
|
|
||
|
cfunc = njit(pyfunc)
|
||
|
|
||
|
def check(shape):
|
||
|
expected = pyfunc(shape)
|
||
|
got = cfunc(shape)
|
||
|
self.assertPreciseEqual(got, expected)
|
||
|
|
||
|
check((16,))
|
||
|
check((4, 4))
|
||
|
check((1, 0, 1))
|
||
|
|
||
|
def test_np_frombuffer_allocated(self):
|
||
|
self.check_np_frombuffer_allocated(np_frombuffer_allocated)
|
||
|
|
||
|
def test_np_frombuffer_allocated2(self):
|
||
|
self.check_np_frombuffer_allocated(np_frombuffer_allocated_dtype)
|
||
|
|
||
|
def check_nonzero(self, pyfunc):
|
||
|
def fac(N):
|
||
|
np.random.seed(42)
|
||
|
arr = np.random.random(N)
|
||
|
arr[arr < 0.3] = 0.0
|
||
|
arr[arr > 0.7] = float('nan')
|
||
|
return arr
|
||
|
|
||
|
def check_arr(arr):
|
||
|
cfunc = njit((typeof(arr),))(pyfunc)
|
||
|
expected = pyfunc(arr)
|
||
|
expected = [a.copy() for a in expected]
|
||
|
self.assertPreciseEqual(cfunc(arr), expected)
|
||
|
|
||
|
arr = np.int16([1, 0, -1, 0])
|
||
|
check_arr(arr)
|
||
|
arr = np.bool_([1, 0, 1])
|
||
|
check_arr(arr)
|
||
|
|
||
|
arr = fac(24)
|
||
|
check_arr(arr)
|
||
|
check_arr(arr.reshape((3, 8)))
|
||
|
check_arr(arr.reshape((3, 8)).T)
|
||
|
check_arr(arr.reshape((3, 8))[::2])
|
||
|
check_arr(arr.reshape((2, 3, 4)))
|
||
|
check_arr(arr.reshape((2, 3, 4)).T)
|
||
|
check_arr(arr.reshape((2, 3, 4))[::2])
|
||
|
for v in (0.0, 1.5, float('nan')):
|
||
|
arr = np.array([v]).reshape(())
|
||
|
check_arr(arr)
|
||
|
|
||
|
arr = np.array(["Hello", "", "world"])
|
||
|
check_arr(arr)
|
||
|
|
||
|
def test_array_nonzero(self):
|
||
|
self.check_nonzero(array_nonzero)
|
||
|
|
||
|
def test_np_nonzero(self):
|
||
|
self.check_nonzero(np_nonzero)
|
||
|
|
||
|
def test_np_where_1(self):
|
||
|
self.check_nonzero(np_where_1)
|
||
|
|
||
|
def test_np_where_3(self):
|
||
|
pyfunc = np_where_3
|
||
|
def fac(N):
|
||
|
np.random.seed(42)
|
||
|
arr = np.random.random(N)
|
||
|
arr[arr < 0.3] = 0.0
|
||
|
arr[arr > 0.7] = float('nan')
|
||
|
return arr
|
||
|
|
||
|
layouts = cycle(['C', 'F', 'A'])
|
||
|
_types = [np.int32, np.int64, np.float32, np.float64, np.complex64,
|
||
|
np.complex128]
|
||
|
|
||
|
np.random.seed(42)
|
||
|
|
||
|
def check_arr(arr, layout=False):
|
||
|
np.random.shuffle(_types)
|
||
|
if layout != False:
|
||
|
x = np.zeros_like(arr, dtype=_types[0], order=layout)
|
||
|
y = np.zeros_like(arr, dtype=_types[1], order=layout)
|
||
|
arr = arr.copy(order=layout)
|
||
|
else:
|
||
|
x = np.zeros_like(arr, dtype=_types[0], order=next(layouts))
|
||
|
y = np.zeros_like(arr, dtype=_types[1], order=next(layouts))
|
||
|
x.fill(4)
|
||
|
y.fill(9)
|
||
|
cfunc = njit((typeof(arr), typeof(x), typeof(y)))(pyfunc)
|
||
|
expected = pyfunc(arr, x, y)
|
||
|
got = cfunc(arr, x, y)
|
||
|
self.assertPreciseEqual(got, expected)
|
||
|
|
||
|
def check_scal(scal):
|
||
|
x = 4
|
||
|
y = 5
|
||
|
np.random.shuffle(_types)
|
||
|
x = _types[0](4)
|
||
|
y = _types[1](5)
|
||
|
cfunc = njit((typeof(scal), typeof(x), typeof(y)))(pyfunc)
|
||
|
expected = pyfunc(scal, x, y)
|
||
|
got = cfunc(scal, x, y)
|
||
|
self.assertPreciseEqual(got, expected)
|
||
|
|
||
|
arr = np.int16([1, 0, -1, 0])
|
||
|
check_arr(arr)
|
||
|
arr = np.bool_([1, 0, 1])
|
||
|
check_arr(arr)
|
||
|
|
||
|
arr = fac(24)
|
||
|
check_arr(arr)
|
||
|
check_arr(arr.reshape((3, 8)))
|
||
|
check_arr(arr.reshape((3, 8)).T)
|
||
|
check_arr(arr.reshape((3, 8))[::2])
|
||
|
check_arr(arr.reshape((2, 3, 4)))
|
||
|
check_arr(arr.reshape((2, 3, 4)).T)
|
||
|
check_arr(arr.reshape((2, 3, 4))[::2])
|
||
|
|
||
|
check_arr(arr.reshape((2, 3, 4)), layout='F')
|
||
|
check_arr(arr.reshape((2, 3, 4)).T, layout='F')
|
||
|
check_arr(arr.reshape((2, 3, 4))[::2], layout='F')
|
||
|
|
||
|
for v in (0.0, 1.5, float('nan')):
|
||
|
arr = np.array([v]).reshape(())
|
||
|
check_arr(arr)
|
||
|
|
||
|
for x in (0, 1, True, False, 2.5, 0j):
|
||
|
check_scal(x)
|
||
|
|
||
|
def test_np_where_3_broadcast_x_y_scalar(self):
|
||
|
pyfunc = np_where_3
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
def check_ok(args):
|
||
|
expected = pyfunc(*args)
|
||
|
got = cfunc(*args)
|
||
|
self.assertPreciseEqual(got, expected)
|
||
|
|
||
|
def a_variations():
|
||
|
a = np.linspace(-2, 4, 20)
|
||
|
self.random.shuffle(a)
|
||
|
yield a
|
||
|
yield a.reshape(2, 5, 2)
|
||
|
yield a.reshape(4, 5, order='F')
|
||
|
yield a.reshape(2, 5, 2)[::-1]
|
||
|
|
||
|
for a in a_variations():
|
||
|
params = (a > 0, 0, 1)
|
||
|
check_ok(params)
|
||
|
|
||
|
params = (a < 0, np.nan, 1 + 4j)
|
||
|
check_ok(params)
|
||
|
|
||
|
params = (a > 1, True, False)
|
||
|
check_ok(params)
|
||
|
|
||
|
def test_np_where_3_broadcast_x_or_y_scalar(self):
|
||
|
pyfunc = np_where_3
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
def check_ok(args):
|
||
|
condition, x, y = args
|
||
|
|
||
|
expected = pyfunc(condition, x, y)
|
||
|
got = cfunc(condition, x, y)
|
||
|
self.assertPreciseEqual(got, expected)
|
||
|
|
||
|
# swap x and y
|
||
|
expected = pyfunc(condition, y, x)
|
||
|
got = cfunc(condition, y, x)
|
||
|
self.assertPreciseEqual(got, expected)
|
||
|
|
||
|
def array_permutations():
|
||
|
x = np.arange(9).reshape(3, 3)
|
||
|
yield x
|
||
|
yield x * 1.1
|
||
|
yield np.asfortranarray(x)
|
||
|
yield x[::-1]
|
||
|
yield np.linspace(-10, 10, 60).reshape(3, 4, 5) * 1j
|
||
|
|
||
|
def scalar_permutations():
|
||
|
yield 0
|
||
|
yield 4.3
|
||
|
yield np.nan
|
||
|
yield True
|
||
|
yield 8 + 4j
|
||
|
|
||
|
for x in array_permutations():
|
||
|
for y in scalar_permutations():
|
||
|
x_mean = np.mean(x)
|
||
|
condition = x > x_mean
|
||
|
params = (condition, x, y)
|
||
|
check_ok(params)
|
||
|
|
||
|
def test_np_where_numpy_basic(self):
|
||
|
# https://github.com/numpy/numpy/blob/fe2bb380fd9a084b622ff3f00cb6f245e8c1a10e/numpy/core/tests/test_multiarray.py#L8670-L8694
|
||
|
pyfunc = np_where_3
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
# skipping unsupported dtypes:
|
||
|
# np.longdouble, np.clongdouble
|
||
|
dts = [bool, np.int16, np.int32, np.int64, np.double, np.complex128]
|
||
|
for dt in dts:
|
||
|
c = np.ones(53, dtype=bool)
|
||
|
np.testing.assert_equal(cfunc( c, dt(0), dt(1)), dt(0))
|
||
|
np.testing.assert_equal(cfunc(~c, dt(0), dt(1)), dt(1))
|
||
|
np.testing.assert_equal(cfunc(True, dt(0), dt(1)), dt(0))
|
||
|
np.testing.assert_equal(cfunc(False, dt(0), dt(1)), dt(1))
|
||
|
d = np.ones_like(c).astype(dt)
|
||
|
e = np.zeros_like(d)
|
||
|
r = d.astype(dt)
|
||
|
c[7] = False
|
||
|
r[7] = e[7]
|
||
|
np.testing.assert_equal(cfunc(c, e, e), e)
|
||
|
np.testing.assert_equal(cfunc(c, d, e), r)
|
||
|
np.testing.assert_equal(cfunc(c, d, e[0]), r)
|
||
|
np.testing.assert_equal(cfunc(c, d[0], e), r)
|
||
|
np.testing.assert_equal(cfunc(c[::2], d[::2], e[::2]), r[::2])
|
||
|
np.testing.assert_equal(cfunc(c[1::2], d[1::2], e[1::2]), r[1::2])
|
||
|
np.testing.assert_equal(cfunc(c[::3], d[::3], e[::3]), r[::3])
|
||
|
np.testing.assert_equal(cfunc(c[1::3], d[1::3], e[1::3]), r[1::3])
|
||
|
np.testing.assert_equal(cfunc(c[::-2], d[::-2], e[::-2]), r[::-2])
|
||
|
np.testing.assert_equal(cfunc(c[::-3], d[::-3], e[::-3]), r[::-3])
|
||
|
np.testing.assert_equal(cfunc(c[1::-3], d[1::-3], e[1::-3]), r[1::-3])
|
||
|
|
||
|
def test_np_where_numpy_ndim(self):
|
||
|
# https://github.com/numpy/numpy/blob/fe2bb380fd9a084b622ff3f00cb6f245e8c1a10e/numpy/core/tests/test_multiarray.py#L8737-L8749
|
||
|
pyfunc = np_where_3
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
c = [True, False]
|
||
|
a = np.zeros((2, 25))
|
||
|
b = np.ones((2, 25))
|
||
|
r = cfunc(np.array(c)[:,np.newaxis], a, b)
|
||
|
np.testing.assert_array_equal(r[0], a[0])
|
||
|
np.testing.assert_array_equal(r[1], b[0])
|
||
|
|
||
|
a = a.T
|
||
|
b = b.T
|
||
|
r = cfunc(c, a, b)
|
||
|
np.testing.assert_array_equal(r[:,0], a[:,0])
|
||
|
np.testing.assert_array_equal(r[:,1], b[:,0])
|
||
|
|
||
|
def test_np_where_numpy_dtype_mix(self):
|
||
|
# https://github.com/numpy/numpy/blob/fe2bb380fd9a084b622ff3f00cb6f245e8c1a10e/numpy/core/tests/test_multiarray.py#L8751-L8773
|
||
|
pyfunc = np_where_3
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
c = np.array([False, True, False, False, False, False, True, False,
|
||
|
False, False, True, False])
|
||
|
a = np.uint32(1)
|
||
|
b = np.array([5., 0., 3., 2., -1., -4., 0., -10., 10., 1., 0., 3.],
|
||
|
dtype=np.float64)
|
||
|
r = np.array([5., 1., 3., 2., -1., -4., 1., -10., 10., 1., 1., 3.],
|
||
|
dtype=np.float64)
|
||
|
np.testing.assert_equal(cfunc(c, a, b), r)
|
||
|
|
||
|
a = a.astype(np.float32)
|
||
|
b = b.astype(np.int64)
|
||
|
np.testing.assert_equal(cfunc(c, a, b), r)
|
||
|
|
||
|
# non bool mask
|
||
|
c = c.astype(int)
|
||
|
c[c != 0] = 34242324
|
||
|
np.testing.assert_equal(cfunc(c, a, b), r)
|
||
|
# invert
|
||
|
tmpmask = c != 0
|
||
|
c[c == 0] = 41247212
|
||
|
c[tmpmask] = 0
|
||
|
np.testing.assert_equal(cfunc(c, b, a), r)
|
||
|
|
||
|
def test_np_where_numpy_test_error(self):
|
||
|
# https://github.com/numpy/numpy/blob/fe2bb380fd9a084b622ff3f00cb6f245e8c1a10e/numpy/core/tests/test_multiarray.py#L8794-L8799
|
||
|
pyfunc = np_where_3
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
c = [True, True]
|
||
|
a = np.ones((4, 5))
|
||
|
b = np.ones((5, 5))
|
||
|
|
||
|
self.disable_leak_check()
|
||
|
with self.assertRaisesRegex(ValueError, "objects cannot be broadcast"):
|
||
|
cfunc(c, a, b)
|
||
|
|
||
|
with self.assertRaisesRegex(ValueError, "objects cannot be broadcast"):
|
||
|
cfunc(c[0], a, b)
|
||
|
|
||
|
def test_np_where_invalid_inputs(self):
|
||
|
pyfunc = np_where_3
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
msg = 'The argument "condition" must be array-like'
|
||
|
with self.assertRaisesRegex(TypingError, msg):
|
||
|
cfunc(None, 2, 3)
|
||
|
|
||
|
msg = 'The argument "x" must be array-like if provided'
|
||
|
with self.assertRaisesRegex(TypingError, msg):
|
||
|
cfunc(1, 'hello', 3)
|
||
|
|
||
|
msg = 'The argument "y" must be array-like if provided'
|
||
|
with self.assertRaisesRegex(TypingError, msg):
|
||
|
cfunc(1, 2, 'world')
|
||
|
|
||
|
# None values are not yet supported in np.where
|
||
|
msg = 'Argument "x" or "y" cannot be None'
|
||
|
with self.assertRaisesRegex(TypingError, msg):
|
||
|
cfunc(1, None, None)
|
||
|
|
||
|
def test_arange_1_arg(self):
|
||
|
|
||
|
all_pyfuncs = (
|
||
|
np_arange_1,
|
||
|
lambda x: np.arange(x, 10),
|
||
|
lambda x: np.arange(7, step=max(1, abs(x)))
|
||
|
)
|
||
|
|
||
|
for pyfunc in all_pyfuncs:
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
def check_ok(arg0):
|
||
|
expected = pyfunc(arg0)
|
||
|
got = cfunc(arg0)
|
||
|
np.testing.assert_allclose(expected, got)
|
||
|
|
||
|
check_ok(0)
|
||
|
check_ok(1)
|
||
|
check_ok(4)
|
||
|
check_ok(5.5)
|
||
|
check_ok(-3)
|
||
|
check_ok(complex(4, 4))
|
||
|
check_ok(np.int8(0))
|
||
|
|
||
|
def test_arange_2_arg(self):
|
||
|
def check_ok(arg0, arg1, pyfunc, cfunc):
|
||
|
expected = pyfunc(arg0, arg1)
|
||
|
got = cfunc(arg0, arg1)
|
||
|
np.testing.assert_allclose(expected, got)
|
||
|
|
||
|
all_pyfuncs = (
|
||
|
np_arange_2,
|
||
|
np_arange_start_stop,
|
||
|
np_arange_1_stop,
|
||
|
np_arange_1_step,
|
||
|
lambda x, y: np.arange(x, y, 5),
|
||
|
lambda x, y: np.arange(2, y, step=x),
|
||
|
)
|
||
|
|
||
|
for pyfunc in all_pyfuncs:
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
check_ok(-1, 5, pyfunc, cfunc)
|
||
|
check_ok(-8, -1, pyfunc, cfunc)
|
||
|
check_ok(4, 0.5, pyfunc, cfunc)
|
||
|
check_ok(0.5, 4, pyfunc, cfunc)
|
||
|
check_ok(complex(1, 1), complex(4, 4), pyfunc, cfunc)
|
||
|
check_ok(complex(4, 4), complex(1, 1), pyfunc, cfunc)
|
||
|
check_ok(3, None, pyfunc, cfunc)
|
||
|
|
||
|
pyfunc = np_arange_1_dtype
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
check_ok(5, np.float32, pyfunc, cfunc)
|
||
|
check_ok(2.0, np.int32, pyfunc, cfunc)
|
||
|
check_ok(10, np.complex128, pyfunc, cfunc)
|
||
|
check_ok(np.complex64(10), np.complex128, pyfunc, cfunc)
|
||
|
check_ok(7, None, pyfunc, cfunc)
|
||
|
check_ok(np.int8(0), None, pyfunc, cfunc)
|
||
|
|
||
|
def test_arange_3_arg(self):
|
||
|
windows64 = sys.platform.startswith('win32') and sys.maxsize > 2 ** 32
|
||
|
|
||
|
def check_ok(arg0, arg1, arg2, pyfunc, cfunc, check_dtype=False):
|
||
|
expected = pyfunc(arg0, arg1, arg2)
|
||
|
got = cfunc(arg0, arg1, arg2)
|
||
|
np.testing.assert_allclose(expected, got)
|
||
|
# windows 64 cannot differentiate between a python int and a
|
||
|
# np.int64 which means the result from numba is int64 more often
|
||
|
# than in NumPy.
|
||
|
if not windows64:
|
||
|
self.assertEqual(expected.dtype, got.dtype)
|
||
|
|
||
|
for pyfunc in (np_arange_3, np_arange_2_step, np_arange_start_stop_step):
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
check_ok(0, 5, 1, pyfunc, cfunc)
|
||
|
check_ok(-8, -1, 3, pyfunc, cfunc)
|
||
|
check_ok(0, -10, -2, pyfunc, cfunc)
|
||
|
check_ok(0.5, 4, 2, pyfunc, cfunc)
|
||
|
check_ok(0, 1, 0.1, pyfunc, cfunc)
|
||
|
check_ok(0, complex(4, 4), complex(1, 1), pyfunc, cfunc)
|
||
|
check_ok(3, 6, None, pyfunc, cfunc)
|
||
|
check_ok(3, None, None, pyfunc, cfunc)
|
||
|
check_ok(np.int8(0), np.int8(5), np.int8(1), pyfunc, cfunc)
|
||
|
check_ok(np.int8(0), np.int16(5), np.int32(1), pyfunc, cfunc)
|
||
|
# check upcasting logic, this matters most on windows
|
||
|
i8 = np.int8
|
||
|
check_ok(i8(0), i8(5), i8(1), pyfunc, cfunc, True) # C int
|
||
|
check_ok(np.int64(0), i8(5), i8(1), pyfunc, cfunc, True) # int64
|
||
|
|
||
|
pyfunc = np_arange_2_dtype
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
check_ok(1, 5, np.float32, pyfunc, cfunc)
|
||
|
check_ok(2.0, 8, np.int32, pyfunc, cfunc)
|
||
|
check_ok(-2, 10, np.complex128, pyfunc, cfunc)
|
||
|
check_ok(3, np.complex64(10), np.complex128, pyfunc, cfunc)
|
||
|
check_ok(1, 7, None, pyfunc, cfunc)
|
||
|
check_ok(np.int8(0), np.int32(5), None, pyfunc, cfunc, True)
|
||
|
|
||
|
def test_arange_4_arg(self):
|
||
|
for pyfunc in (np_arange_4, np_arange_start_stop_step_dtype):
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
def check_ok(arg0, arg1, arg2, arg3):
|
||
|
expected = pyfunc(arg0, arg1, arg2, arg3)
|
||
|
got = cfunc(arg0, arg1, arg2, arg3)
|
||
|
np.testing.assert_allclose(expected, got)
|
||
|
|
||
|
check_ok(0, 5, 1, np.float64)
|
||
|
check_ok(-8, -1, 3, np.int32)
|
||
|
check_ok(0, -10, -2, np.float32)
|
||
|
check_ok(0.5, 4, 2, None)
|
||
|
check_ok(0, 1, 0.1, np.complex128)
|
||
|
check_ok(0, complex(4, 4), complex(1, 1), np.complex128)
|
||
|
check_ok(3, 6, None, None)
|
||
|
check_ok(3, None, None, None)
|
||
|
|
||
|
def test_arange_throws(self):
|
||
|
# Exceptions leak references
|
||
|
self.disable_leak_check()
|
||
|
|
||
|
bad_funcs_1 = [
|
||
|
lambda x: np.arange(stop=x),
|
||
|
lambda x: np.arange(step=x),
|
||
|
lambda x: np.arange(dtype=x),
|
||
|
]
|
||
|
bad_funcs_2 = [
|
||
|
lambda x, y: np.arange(stop=x, step=y),
|
||
|
lambda x, y: np.arange(stop=x, dtype=y),
|
||
|
]
|
||
|
|
||
|
for pyfunc in bad_funcs_1:
|
||
|
with self.assertRaises(TypingError) as raises:
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
cfunc(2)
|
||
|
for pyfunc in bad_funcs_2:
|
||
|
with self.assertRaises(TypingError) as raises:
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
cfunc(2, 6)
|
||
|
|
||
|
# check step size = 0, this is nonsense
|
||
|
pyfunc = np_arange_3
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
for f in (pyfunc, cfunc,):
|
||
|
for inputs in [(1, np.int16(2), 0), (1, 2, 0)]:
|
||
|
# there's a different error depending on whether any of the
|
||
|
# input values are np scalars
|
||
|
permitted_errors = (ZeroDivisionError, ValueError)
|
||
|
with self.assertRaises(permitted_errors) as raises:
|
||
|
# this will raise RuntimeWarning's about zero division
|
||
|
with warnings.catch_warnings():
|
||
|
warnings.simplefilter("ignore")
|
||
|
f(*inputs)
|
||
|
self.assertIn("Maximum allowed size exceeded",
|
||
|
str(raises.exception))
|
||
|
|
||
|
def test_arange_accuracy(self):
|
||
|
# Checking arange reasonably replicates NumPy's algorithm
|
||
|
# see https://github.com/numba/numba/issues/6768
|
||
|
@jit(nopython=True)
|
||
|
def foo(step):
|
||
|
return np.arange(0, 1 + step, step)
|
||
|
|
||
|
x = 0.010101010101010102
|
||
|
self.assertPreciseEqual(foo(x), foo.py_func(x))
|
||
|
|
||
|
def test_item(self):
|
||
|
pyfunc = array_item
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
def check_ok(arg):
|
||
|
expected = pyfunc(arg)
|
||
|
got = cfunc(arg)
|
||
|
self.assertPreciseEqual(got, expected)
|
||
|
|
||
|
def check_err(arg):
|
||
|
with self.assertRaises(ValueError) as raises:
|
||
|
cfunc(arg)
|
||
|
self.assertIn("item(): can only convert an array of size 1 to a Python scalar",
|
||
|
str(raises.exception))
|
||
|
|
||
|
# Exceptions leak references
|
||
|
self.disable_leak_check()
|
||
|
|
||
|
# Test on different kinds of scalars and 1-item arrays
|
||
|
check_ok(np.float32([1.5]))
|
||
|
check_ok(np.complex128([[1.5j]]))
|
||
|
check_ok(np.array(1.5))
|
||
|
check_ok(np.bool_(True))
|
||
|
check_ok(np.float32(1.5))
|
||
|
|
||
|
check_err(np.array([1, 2]))
|
||
|
check_err(np.array([]))
|
||
|
|
||
|
def test_itemset(self):
|
||
|
pyfunc = array_itemset
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
def check_ok(a, v):
|
||
|
expected = a.copy()
|
||
|
got = a.copy()
|
||
|
pyfunc(expected, v)
|
||
|
cfunc(got, v)
|
||
|
self.assertPreciseEqual(got, expected)
|
||
|
|
||
|
def check_err(a):
|
||
|
with self.assertRaises(ValueError) as raises:
|
||
|
cfunc(a, 42)
|
||
|
self.assertIn("itemset(): can only write to an array of size 1",
|
||
|
str(raises.exception))
|
||
|
|
||
|
# Exceptions leak references
|
||
|
self.disable_leak_check()
|
||
|
|
||
|
# Test on different kinds of 1-item arrays
|
||
|
check_ok(np.float32([1.5]), 42)
|
||
|
check_ok(np.complex128([[1.5j]]), 42)
|
||
|
check_ok(np.array(1.5), 42)
|
||
|
|
||
|
check_err(np.array([1, 2]))
|
||
|
check_err(np.array([]))
|
||
|
|
||
|
def test_sum(self):
|
||
|
""" test sum over a whole range of dtypes, no axis or dtype parameter
|
||
|
"""
|
||
|
pyfunc = array_sum
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
all_dtypes = [np.float64, np.float32, np.int64, np.int32,
|
||
|
np.complex64, np.complex128, np.uint32, np.uint64, np.timedelta64]
|
||
|
all_test_arrays = [
|
||
|
[np.ones((7, 6, 5, 4, 3), arr_dtype),
|
||
|
np.ones(1, arr_dtype),
|
||
|
np.ones((7, 3), arr_dtype) * -5]
|
||
|
for arr_dtype in all_dtypes]
|
||
|
|
||
|
for arr_list in all_test_arrays:
|
||
|
for arr in arr_list:
|
||
|
with self.subTest("Test np.sum with {} input ".format(arr.dtype)):
|
||
|
self.assertPreciseEqual(pyfunc(arr), cfunc(arr))
|
||
|
|
||
|
def test_sum_axis_kws1(self):
|
||
|
""" test sum with axis parameter over a whole range of dtypes """
|
||
|
pyfunc = array_sum_axis_kws
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
all_dtypes = [np.float64, np.float32, np.int64, np.uint64, np.complex64,
|
||
|
np.complex128, TIMEDELTA_M]
|
||
|
all_test_arrays = [
|
||
|
[np.ones((7, 6, 5, 4, 3), arr_dtype),
|
||
|
np.ones(1, arr_dtype),
|
||
|
np.ones((7, 3), arr_dtype) * -5]
|
||
|
for arr_dtype in all_dtypes]
|
||
|
for arr_list in all_test_arrays:
|
||
|
for arr in arr_list:
|
||
|
for axis in (0, 1, 2):
|
||
|
if axis > len(arr.shape)-1:
|
||
|
continue
|
||
|
with self.subTest("Testing np.sum(axis) with {} "
|
||
|
"input ".format(arr.dtype)):
|
||
|
self.assertPreciseEqual(pyfunc(arr, axis=axis),
|
||
|
cfunc(arr, axis=axis))
|
||
|
|
||
|
def test_sum_axis_kws2(self):
|
||
|
""" testing uint32 and int32 separately
|
||
|
|
||
|
uint32 and int32 must be tested separately because Numpy's current
|
||
|
behaviour is different in 64bits Windows (accumulates as int32)
|
||
|
and 64bits Linux (accumulates as int64), while Numba has decided to always
|
||
|
accumulate as int64, when the OS is 64bits. No testing has been done
|
||
|
for behaviours in 32 bits platforms.
|
||
|
"""
|
||
|
pyfunc = array_sum_axis_kws
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
all_dtypes = [np.int32, np.uint32, ]
|
||
|
# expected return dtypes in Numba
|
||
|
out_dtypes = {np.dtype('int32'): np.int64, np.dtype('uint32'): np.uint64,
|
||
|
np.dtype('int64'): np.int64,
|
||
|
np.dtype(TIMEDELTA_M): np.dtype(TIMEDELTA_M)}
|
||
|
all_test_arrays = [
|
||
|
[np.ones((7, 6, 5, 4, 3), arr_dtype),
|
||
|
np.ones(1, arr_dtype),
|
||
|
np.ones((7, 3), arr_dtype) * -5]
|
||
|
for arr_dtype in all_dtypes]
|
||
|
|
||
|
for arr_list in all_test_arrays:
|
||
|
for arr in arr_list:
|
||
|
for axis in (0, 1, 2):
|
||
|
if axis > len(arr.shape)-1:
|
||
|
continue
|
||
|
with self.subTest("Testing np.sum(axis) with {} "
|
||
|
"input ".format(arr.dtype)):
|
||
|
npy_res = pyfunc(arr, axis=axis)
|
||
|
numba_res = cfunc(arr, axis=axis)
|
||
|
if isinstance(numba_res, np.ndarray):
|
||
|
self.assertPreciseEqual(
|
||
|
npy_res.astype(out_dtypes[arr.dtype]),
|
||
|
numba_res.astype(out_dtypes[arr.dtype]))
|
||
|
else:
|
||
|
# the results are scalars
|
||
|
self.assertEqual(npy_res, numba_res)
|
||
|
|
||
|
def test_sum_dtype_kws(self):
|
||
|
""" test sum with dtype parameter over a whole range of dtypes """
|
||
|
pyfunc = array_sum_dtype_kws
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
all_dtypes = [np.float64, np.float32, np.int64, np.int32, np.uint32,
|
||
|
np.uint64, np.complex64, np.complex128]
|
||
|
all_test_arrays = [
|
||
|
[np.ones((7, 6, 5, 4, 3), arr_dtype),
|
||
|
np.ones(1, arr_dtype),
|
||
|
np.ones((7, 3), arr_dtype) * -5]
|
||
|
for arr_dtype in all_dtypes]
|
||
|
|
||
|
out_dtypes = {np.dtype('float64'): [np.float64],
|
||
|
np.dtype('float32'): [np.float64, np.float32],
|
||
|
np.dtype('int64'): [np.float64, np.int64, np.float32],
|
||
|
np.dtype('int32'): [np.float64, np.int64, np.float32, np.int32],
|
||
|
np.dtype('uint32'): [np.float64, np.int64, np.float32],
|
||
|
np.dtype('uint64'): [np.float64, np.int64],
|
||
|
np.dtype('complex64'): [np.complex64, np.complex128],
|
||
|
np.dtype('complex128'): [np.complex128]}
|
||
|
|
||
|
for arr_list in all_test_arrays:
|
||
|
for arr in arr_list:
|
||
|
for out_dtype in out_dtypes[arr.dtype]:
|
||
|
subtest_str = ("Testing np.sum with {} input and {} output"
|
||
|
.format(arr.dtype, out_dtype))
|
||
|
with self.subTest(subtest_str):
|
||
|
self.assertPreciseEqual(pyfunc(arr, dtype=out_dtype),
|
||
|
cfunc(arr, dtype=out_dtype))
|
||
|
|
||
|
def test_sum_axis_dtype_kws(self):
|
||
|
""" test sum with axis and dtype parameters over a whole range of dtypes """
|
||
|
pyfunc = array_sum_axis_dtype_kws
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
all_dtypes = [np.float64, np.float32, np.int64, np.int32, np.uint32,
|
||
|
np.uint64, np.complex64, np.complex128]
|
||
|
all_test_arrays = [
|
||
|
[np.ones((7, 6, 5, 4, 3), arr_dtype),
|
||
|
np.ones(1, arr_dtype),
|
||
|
np.ones((7, 3), arr_dtype) * -5]
|
||
|
for arr_dtype in all_dtypes]
|
||
|
|
||
|
out_dtypes = {np.dtype('float64'): [np.float64],
|
||
|
np.dtype('float32'): [np.float64, np.float32],
|
||
|
np.dtype('int64'): [np.float64, np.int64, np.float32],
|
||
|
np.dtype('int32'): [np.float64, np.int64, np.float32, np.int32],
|
||
|
np.dtype('uint32'): [np.float64, np.int64, np.float32],
|
||
|
np.dtype('uint64'): [np.float64, np.uint64],
|
||
|
np.dtype('complex64'): [np.complex64, np.complex128],
|
||
|
np.dtype('complex128'): [np.complex128]}
|
||
|
|
||
|
for arr_list in all_test_arrays:
|
||
|
for arr in arr_list:
|
||
|
for out_dtype in out_dtypes[arr.dtype]:
|
||
|
for axis in (0, 1, 2):
|
||
|
if axis > len(arr.shape) - 1:
|
||
|
continue
|
||
|
subtest_str = ("Testing np.sum with {} input and {} output "
|
||
|
.format(arr.dtype, out_dtype))
|
||
|
with self.subTest(subtest_str):
|
||
|
py_res = pyfunc(arr, axis=axis, dtype=out_dtype)
|
||
|
nb_res = cfunc(arr, axis=axis, dtype=out_dtype)
|
||
|
self.assertPreciseEqual(py_res, nb_res)
|
||
|
|
||
|
def test_sum_axis_dtype_pos_arg(self):
|
||
|
""" testing that axis and dtype inputs work when passed as positional """
|
||
|
pyfunc = array_sum_axis_dtype_pos
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
dtype = np.float64
|
||
|
# OK
|
||
|
a = np.ones((7, 6, 5, 4, 3))
|
||
|
self.assertPreciseEqual(pyfunc(a, 1, dtype),
|
||
|
cfunc(a, 1, dtype))
|
||
|
|
||
|
self.assertPreciseEqual(pyfunc(a, 2, dtype),
|
||
|
cfunc(a, 2, dtype))
|
||
|
|
||
|
def test_sum_1d_kws(self):
|
||
|
# check 1d reduces to scalar
|
||
|
pyfunc = array_sum_axis_kws
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
a = np.arange(10.)
|
||
|
self.assertPreciseEqual(pyfunc(a, axis=0), cfunc(a, axis=0))
|
||
|
pyfunc = array_sum_const_axis_neg_one
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
a = np.arange(10.)
|
||
|
self.assertPreciseEqual(pyfunc(a, axis=-1), cfunc(a, axis=-1))
|
||
|
|
||
|
def test_sum_const(self):
|
||
|
pyfunc = array_sum_const_multi
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
arr = np.ones((3, 4, 5, 6, 7, 8))
|
||
|
axis = 1
|
||
|
self.assertPreciseEqual(pyfunc(arr, axis), cfunc(arr, axis))
|
||
|
axis = 2
|
||
|
self.assertPreciseEqual(pyfunc(arr, axis), cfunc(arr, axis))
|
||
|
|
||
|
def test_sum_exceptions(self):
|
||
|
# Exceptions leak references
|
||
|
self.disable_leak_check()
|
||
|
pyfunc = array_sum
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
a = np.ones((7, 6, 5, 4, 3))
|
||
|
b = np.ones((4, 3))
|
||
|
# BAD: axis > dimensions
|
||
|
with self.assertRaises(ValueError):
|
||
|
cfunc(b, 2)
|
||
|
# BAD: negative axis
|
||
|
with self.assertRaises(ValueError):
|
||
|
cfunc(a, -1)
|
||
|
# BAD: axis greater than 3
|
||
|
with self.assertRaises(ValueError):
|
||
|
cfunc(a, 4)
|
||
|
|
||
|
def test_sum_const_negative(self):
|
||
|
# Exceptions leak references
|
||
|
self.disable_leak_check()
|
||
|
|
||
|
@jit(nopython=True)
|
||
|
def foo(arr):
|
||
|
return arr.sum(axis=-3)
|
||
|
|
||
|
# ndim == 4, axis == -3, OK
|
||
|
a = np.ones((1, 2, 3, 4))
|
||
|
self.assertPreciseEqual(foo(a), foo.py_func(a))
|
||
|
# ndim == 3, axis == -3, OK
|
||
|
a = np.ones((1, 2, 3))
|
||
|
self.assertPreciseEqual(foo(a), foo.py_func(a))
|
||
|
# ndim == 2, axis == -3, BAD
|
||
|
a = np.ones((1, 2))
|
||
|
with self.assertRaises(NumbaValueError) as raises:
|
||
|
foo(a)
|
||
|
errmsg = "'axis' entry (-1) is out of bounds"
|
||
|
self.assertIn(errmsg, str(raises.exception))
|
||
|
with self.assertRaises(ValueError) as raises:
|
||
|
foo.py_func(a)
|
||
|
self.assertIn("out of bounds", str(raises.exception))
|
||
|
|
||
|
def test_cumsum(self):
|
||
|
pyfunc = array_cumsum
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
# OK
|
||
|
a = np.ones((2, 3))
|
||
|
self.assertPreciseEqual(pyfunc(a), cfunc(a))
|
||
|
# BAD: with axis
|
||
|
with self.assertRaises(TypingError):
|
||
|
cfunc(a, 1)
|
||
|
# BAD: with kw axis
|
||
|
pyfunc = array_cumsum_kws
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
with self.assertRaises(TypingError):
|
||
|
cfunc(a, axis=1)
|
||
|
|
||
|
def test_take(self):
|
||
|
pyfunc = array_take
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
def check(arr, ind):
|
||
|
expected = pyfunc(arr, ind)
|
||
|
got = cfunc(arr, ind)
|
||
|
self.assertPreciseEqual(expected, got)
|
||
|
if hasattr(expected, 'order'):
|
||
|
self.assertEqual(expected.order == got.order)
|
||
|
|
||
|
# need to check:
|
||
|
# 1. scalar index
|
||
|
# 2. 1d array index
|
||
|
# 3. nd array index, >2d and F order
|
||
|
# 4. reflected list
|
||
|
# 5. tuples
|
||
|
|
||
|
test_indices = []
|
||
|
test_indices.append(1)
|
||
|
test_indices.append(5)
|
||
|
test_indices.append(11)
|
||
|
test_indices.append(-2)
|
||
|
test_indices.append(np.array([1, 5, 1, 11, 3]))
|
||
|
test_indices.append(np.array([[1, 5, 1], [11, 3, 0]], order='F'))
|
||
|
test_indices.append(np.array([[[1, 5, 1], [11, 3, 0]]]))
|
||
|
test_indices.append(np.array([[[[1, 5]], [[11, 0]], [[1, 2]]]]))
|
||
|
test_indices.append([1, 5, 1, 11, 3])
|
||
|
test_indices.append((1, 5, 1))
|
||
|
test_indices.append(((1, 5, 1), (11, 3, 2)))
|
||
|
test_indices.append((((1,), (5,), (1,)), ((11,), (3,), (2,))))
|
||
|
|
||
|
layouts = cycle(['C', 'F', 'A'])
|
||
|
|
||
|
for dt in [np.float64, np.int64, np.complex128]:
|
||
|
A = np.arange(12, dtype=dt).reshape((4, 3), order=next(layouts))
|
||
|
for ind in test_indices:
|
||
|
check(A, ind)
|
||
|
|
||
|
#check illegal access raises
|
||
|
A = np.arange(12, dtype=dt).reshape((4, 3), order=next(layouts))
|
||
|
szA = A.size
|
||
|
illegal_indices = [szA, -szA - 1, np.array(szA), np.array(-szA - 1),
|
||
|
[szA], [-szA - 1]]
|
||
|
for x in illegal_indices:
|
||
|
with self.assertRaises(IndexError):
|
||
|
cfunc(A, x) # oob raises
|
||
|
|
||
|
# check float indexing raises
|
||
|
with self.assertRaises(TypingError):
|
||
|
cfunc(A, [1.7])
|
||
|
|
||
|
# check unsupported arg raises
|
||
|
with self.assertRaises(TypingError):
|
||
|
take_kws = jit(nopython=True)(array_take_kws)
|
||
|
take_kws(A, 1, 1)
|
||
|
|
||
|
# check kwarg unsupported raises
|
||
|
with self.assertRaises(TypingError):
|
||
|
take_kws = jit(nopython=True)(array_take_kws)
|
||
|
take_kws(A, 1, axis=1)
|
||
|
|
||
|
#exceptions leak refs
|
||
|
self.disable_leak_check()
|
||
|
|
||
|
def test_fill(self):
|
||
|
pyfunc = array_fill
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
def check(arr, val):
|
||
|
expected = np.copy(arr)
|
||
|
erv = pyfunc(expected, val)
|
||
|
self.assertTrue(erv is None)
|
||
|
got = np.copy(arr)
|
||
|
grv = cfunc(got, val)
|
||
|
self.assertTrue(grv is None)
|
||
|
# check mutation is the same
|
||
|
self.assertPreciseEqual(expected, got)
|
||
|
|
||
|
# scalar
|
||
|
A = np.arange(1)
|
||
|
for x in [np.float64, np.bool_]:
|
||
|
check(A, x(10))
|
||
|
|
||
|
# 2d
|
||
|
A = np.arange(12).reshape(3, 4)
|
||
|
for x in [np.float64, np.bool_]:
|
||
|
check(A, x(10))
|
||
|
|
||
|
# 4d
|
||
|
A = np.arange(48, dtype=np.complex64).reshape(2, 3, 4, 2)
|
||
|
for x in [np.float64, np.complex128, np.bool_]:
|
||
|
check(A, x(10))
|
||
|
|
||
|
def test_real(self):
|
||
|
pyfunc = array_real
|
||
|
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_imag(self):
|
||
|
pyfunc = array_imag
|
||
|
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 _lower_clip_result_test_util(self, func, a, a_min, a_max):
|
||
|
# verifies that type-inference is working on the return value
|
||
|
# this used to trigger issue #3489
|
||
|
def lower_clip_result(a):
|
||
|
return np.expm1(func(a, a_min, a_max))
|
||
|
|
||
|
np.testing.assert_almost_equal(
|
||
|
lower_clip_result(a),
|
||
|
jit(nopython=True)(lower_clip_result)(a))
|
||
|
|
||
|
def test_clip(self):
|
||
|
has_out = (np_clip, np_clip_kwargs, array_clip, array_clip_kwargs)
|
||
|
has_no_out = (np_clip_no_out, array_clip_no_out)
|
||
|
# TODO: scalars are not tested (issue #3469)
|
||
|
for a in (np.linspace(-10, 10, 101),
|
||
|
np.linspace(-10, 10, 40).reshape(5, 2, 4)):
|
||
|
for pyfunc in has_out + has_no_out:
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
msg = "array_clip: must set either max or min"
|
||
|
with self.assertRaisesRegex(ValueError, msg):
|
||
|
cfunc(a, None, None)
|
||
|
|
||
|
np.testing.assert_equal(pyfunc(a, 0, None), cfunc(a, 0, None))
|
||
|
np.testing.assert_equal(pyfunc(a, None, 0), cfunc(a, None, 0))
|
||
|
|
||
|
np.testing.assert_equal(pyfunc(a, -5, 5), cfunc(a, -5, 5))
|
||
|
|
||
|
if pyfunc in has_out:
|
||
|
pyout = np.empty_like(a)
|
||
|
cout = np.empty_like(a)
|
||
|
np.testing.assert_equal(pyfunc(a, -5, 5, pyout),
|
||
|
cfunc(a, -5, 5, cout))
|
||
|
np.testing.assert_equal(pyout, cout)
|
||
|
|
||
|
self._lower_clip_result_test_util(cfunc, a, -5, 5)
|
||
|
|
||
|
def test_clip_array_min_max(self):
|
||
|
has_out = (np_clip, np_clip_kwargs, array_clip, array_clip_kwargs)
|
||
|
has_no_out = (np_clip_no_out, array_clip_no_out)
|
||
|
# TODO: scalars are not tested (issue #3469)
|
||
|
a = np.linspace(-10, 10, 40).reshape(5, 2, 4)
|
||
|
a_min_arr = np.arange(-8, 0).astype(a.dtype).reshape(2, 4)
|
||
|
a_max_arr = np.arange(0, 8).astype(a.dtype).reshape(2, 4)
|
||
|
mins = [0, -5, a_min_arr, None]
|
||
|
maxs = [0, 5, a_max_arr, None]
|
||
|
for pyfunc in has_out + has_no_out:
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
|
||
|
for a_min in mins:
|
||
|
for a_max in maxs:
|
||
|
|
||
|
if a_min is None and a_max is None:
|
||
|
msg = "array_clip: must set either max or min"
|
||
|
with self.assertRaisesRegex(ValueError, msg):
|
||
|
cfunc(a, None, None)
|
||
|
continue
|
||
|
|
||
|
np.testing.assert_equal(pyfunc(a, a_min, a_max), cfunc(a, a_min, a_max))
|
||
|
|
||
|
if pyfunc in has_out:
|
||
|
pyout = np.empty_like(a)
|
||
|
cout = np.empty_like(a)
|
||
|
np.testing.assert_equal(pyfunc(a, a_min, a_max, pyout),
|
||
|
cfunc(a, a_min, a_max, cout))
|
||
|
np.testing.assert_equal(pyout, cout)
|
||
|
|
||
|
self._lower_clip_result_test_util(cfunc, a, a_min, a_max)
|
||
|
|
||
|
def test_clip_bad_array(self):
|
||
|
cfunc = jit(nopython=True)(np_clip)
|
||
|
msg = '.*The argument "a" must be array-like.*'
|
||
|
with self.assertRaisesRegex(TypingError, msg):
|
||
|
cfunc(None, 0, 10)
|
||
|
|
||
|
def test_clip_bad_min(self):
|
||
|
cfunc = jit(nopython=True)(np_clip)
|
||
|
msg = '.*The argument "a_min" must be a number.*'
|
||
|
with self.assertRaisesRegex(TypingError, msg):
|
||
|
cfunc(1, 'a', 10)
|
||
|
|
||
|
def test_clip_bad_max(self):
|
||
|
cfunc = jit(nopython=True)(np_clip)
|
||
|
msg = '.*The argument "a_max" must be a number.*'
|
||
|
with self.assertRaisesRegex(TypingError, msg):
|
||
|
cfunc(1, 1, 'b')
|
||
|
|
||
|
def test_clip_bad_out(self):
|
||
|
cfunc = jit(nopython=True)(np_clip)
|
||
|
msg = '.*The argument "out" must be an array if it is provided.*'
|
||
|
with self.assertRaisesRegex(TypingError, msg):
|
||
|
cfunc(5, 1, 10, out=6)
|
||
|
|
||
|
def test_clip_no_broadcast(self):
|
||
|
self.disable_leak_check()
|
||
|
cfunc = jit(nopython=True)(np_clip)
|
||
|
msg = ".*shape mismatch: objects cannot be broadcast to a single shape.*"
|
||
|
a = np.linspace(-10, 10, 40).reshape(5, 2, 4)
|
||
|
a_min_arr = np.arange(-5, 0).astype(a.dtype).reshape(5, 1)
|
||
|
a_max_arr = np.arange(0, 5).astype(a.dtype).reshape(5, 1)
|
||
|
min_max = [(0, a_max_arr), (-5, a_max_arr),
|
||
|
(a_min_arr, a_max_arr),
|
||
|
(a_min_arr, 0), (a_min_arr, 5)]
|
||
|
for a_min, a_max in min_max:
|
||
|
with self.assertRaisesRegex(ValueError, msg):
|
||
|
cfunc(a, a_min, a_max)
|
||
|
|
||
|
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)
|
||
|
|
||
|
def check(a):
|
||
|
np.testing.assert_equal(pyfunc(a), cfunc(a))
|
||
|
|
||
|
check(np.array([[1, 1, 3], [3, 4, 5]]))
|
||
|
check(np.array(np.zeros(5)))
|
||
|
check(np.array([[3.1, 3.1], [1.7, 2.29], [3.3, 1.7]]))
|
||
|
check(np.array([]))
|
||
|
|
||
|
@needs_blas
|
||
|
def test_array_dot(self):
|
||
|
# just ensure that the dot impl dispatches correctly, do
|
||
|
# not test dot itself, this is done in test_linalg.
|
||
|
pyfunc = array_dot
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
a = np.arange(20.).reshape(4, 5)
|
||
|
b = np.arange(5.)
|
||
|
np.testing.assert_equal(pyfunc(a, b), cfunc(a, b))
|
||
|
|
||
|
# check that chaining works
|
||
|
pyfunc = array_dot_chain
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
a = np.arange(16.).reshape(4, 4)
|
||
|
np.testing.assert_equal(pyfunc(a, a), cfunc(a, a))
|
||
|
|
||
|
def test_array_ctor_with_dtype_arg(self):
|
||
|
# Test using np.dtype and np.generic (i.e. np.dtype.type) has args
|
||
|
pyfunc = array_ctor
|
||
|
cfunc = jit(nopython=True)(pyfunc)
|
||
|
n = 2
|
||
|
args = n, np.int32
|
||
|
np.testing.assert_array_equal(pyfunc(*args), cfunc(*args))
|
||
|
args = n, np.dtype('int32')
|
||
|
np.testing.assert_array_equal(pyfunc(*args), cfunc(*args))
|
||
|
args = n, np.float32
|
||
|
np.testing.assert_array_equal(pyfunc(*args), cfunc(*args))
|
||
|
args = n, np.dtype('f4')
|
||
|
np.testing.assert_array_equal(pyfunc(*args), cfunc(*args))
|
||
|
|
||
|
class TestArrayComparisons(TestCase):
|
||
|
|
||
|
def test_identity(self):
|
||
|
def check(a, b, expected):
|
||
|
cfunc = njit((typeof(a), typeof(b)))(pyfunc)
|
||
|
self.assertPreciseEqual(cfunc(a, b),
|
||
|
(expected, not expected))
|
||
|
|
||
|
pyfunc = identity_usecase
|
||
|
|
||
|
arr = np.zeros(10, dtype=np.int32).reshape((2, 5))
|
||
|
check(arr, arr, True)
|
||
|
check(arr, arr[:], True)
|
||
|
check(arr, arr.copy(), False)
|
||
|
check(arr, arr.view('uint32'), False)
|
||
|
check(arr, arr.T, False)
|
||
|
check(arr, arr[:-1], False)
|
||
|
|
||
|
# Other comparison operators ('==', etc.) are tested in test_ufuncs
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
unittest.main()
|