def setUp(self): self.cache = CompilationCache() # All tests here should run without warnings self.w_cm = warnings.catch_warnings() self.w_cm.__enter__() warnings.simplefilter("error") # some builds of NumPy use a Cython that reports spurious # ufunc object size mismatch warnings. These are safe to # ignore and not generated by later Cython versions. warnings.filterwarnings("ignore", message="numpy.ufunc size changed")
def setUp(self): self.inputs = [ (0, types.uint32), (1, types.uint32), (-1, types.int32), (0, types.int32), (1, types.int32), (0, types.uint64), (1, types.uint64), (-1, types.int64), (0, types.int64), (1, types.int64), (-0.5, types.float32), (0.0, types.float32), (0.5, types.float32), (-0.5, types.float64), (0.0, types.float64), (0.5, types.float64), (np.array([0,1], dtype='u4'), types.Array(types.uint32, 1, 'C')), (np.array([0,1], dtype='u8'), types.Array(types.uint64, 1, 'C')), (np.array([-1,0,1], dtype='i4'), types.Array(types.int32, 1, 'C')), (np.array([-1,0,1], dtype='i8'), types.Array(types.int64, 1, 'C')), (np.array([-0.5, 0.0, 0.5], dtype='f4'), types.Array(types.float32, 1, 'C')), (np.array([-0.5, 0.0, 0.5], dtype='f8'), types.Array(types.float64, 1, 'C')), ] self.cache = CompilationCache()
def setUp(self): super(_TestHeapq, self).setUp() self.ccache = CompilationCache() self.rnd = np.random.RandomState(42)
class TestDataFlow(TestCase): def setUp(self): self.cache = CompilationCache() # All tests here should run without warnings self.w_cm = warnings.catch_warnings() self.w_cm.__enter__() warnings.simplefilter("error") # some builds of NumPy use a Cython that reports spurious # ufunc object size mismatch warnings. These are safe to # ignore and not generated by later Cython versions. warnings.filterwarnings("ignore", message="numpy.ufunc size changed") def tearDown(self): self.w_cm.__exit__(None, None, None) def test_assignments(self, flags=force_pyobj_flags): pyfunc = assignments cr = compile_isolated(pyfunc, (types.int32, ), flags=flags) cfunc = cr.entry_point for x in [-1, 0, 1]: self.assertPreciseEqual(pyfunc(x), cfunc(x)) def test_assignments2(self, flags=force_pyobj_flags): pyfunc = assignments2 cr = compile_isolated(pyfunc, (types.int32, ), flags=flags) cfunc = cr.entry_point for x in [-1, 0, 1]: self.assertPreciseEqual(pyfunc(x), cfunc(x)) if flags is force_pyobj_flags: cfunc("a") # The dataflow analysis must be good enough for native mode # compilation to succeed, hence the no_pyobj_flags in the following tests. def run_propagate_func(self, pyfunc, args): cr = self.cache.compile(pyfunc, (types.int32, types.int32), flags=no_pyobj_flags) cfunc = cr.entry_point self.assertPreciseEqual(cfunc(*args), pyfunc(*args)) def test_var_propagate1(self): self.run_propagate_func(var_propagate1, (2, 3)) self.run_propagate_func(var_propagate1, (3, 2)) def test_var_propagate2(self): self.run_propagate_func(var_propagate2, (2, 3)) self.run_propagate_func(var_propagate2, (3, 2)) def test_var_propagate3(self): self.run_propagate_func(var_propagate3, (2, 3)) self.run_propagate_func(var_propagate3, (3, 2)) self.run_propagate_func(var_propagate3, (2, 0)) self.run_propagate_func(var_propagate3, (-1, 0)) self.run_propagate_func(var_propagate3, (0, 2)) self.run_propagate_func(var_propagate3, (0, -1)) def test_var_propagate4(self): self.run_propagate_func(var_propagate4, (1, 1)) self.run_propagate_func(var_propagate4, (1, 0)) self.run_propagate_func(var_propagate4, (1, -1)) self.run_propagate_func(var_propagate4, (0, 1)) self.run_propagate_func(var_propagate4, (0, 0)) self.run_propagate_func(var_propagate4, (0, -1)) self.run_propagate_func(var_propagate4, (-1, 1)) self.run_propagate_func(var_propagate4, (-1, 0)) self.run_propagate_func(var_propagate4, (-1, -1)) def test_chained_compare(self, flags=force_pyobj_flags): pyfunc = chained_compare cr = compile_isolated(pyfunc, (types.int32, ), flags=flags) cfunc = cr.entry_point for x in [0, 1, 2, 3, 4]: self.assertPreciseEqual(pyfunc(x), cfunc(x)) def test_chained_compare_npm(self): self.test_chained_compare(no_pyobj_flags) def test_stack_effect_error(self, flags=force_pyobj_flags): # Issue #591: POP_BLOCK must undo all stack pushes done inside # the block. pyfunc = stack_effect_error cr = compile_isolated(pyfunc, (types.int32, ), flags=flags) cfunc = cr.entry_point for x in (0, 1, 2, 3): self.assertPreciseEqual(pyfunc(x), cfunc(x)) def test_stack_effect_error_npm(self): self.test_stack_effect_error(no_pyobj_flags) def test_var_swapping(self, flags=force_pyobj_flags): pyfunc = var_swapping cr = compile_isolated(pyfunc, (types.int32, ) * 5, flags=flags) cfunc = cr.entry_point args = tuple(range(0, 10, 2)) self.assertPreciseEqual(pyfunc(*args), cfunc(*args)) def test_var_swapping_npm(self): self.test_var_swapping(no_pyobj_flags) def test_for_break(self, flags=force_pyobj_flags): # BREAK_LOOP must unwind the current inner syntax block. pyfunc = for_break cr = compile_isolated(pyfunc, (types.intp, types.intp), flags=flags) cfunc = cr.entry_point for (n, x) in [(4, 2), (4, 6)]: self.assertPreciseEqual(pyfunc(n, x), cfunc(n, x)) def test_for_break_npm(self): self.test_for_break(no_pyobj_flags) @skip_tryexcept_supported def test_unsupported_op_code(self, flags=force_pyobj_flags): pyfunc = unsupported_op_code with self.assertRaises(errors.UnsupportedError) as raises: compile_isolated(pyfunc, (), flags=flags) msg = "SETUP_EXCEPT" self.assertIn(msg, str(raises.exception))
def setUp(self): super(TestArrayManipulation, self).setUp() self.ccache = CompilationCache()
class TestArrayManipulation(MemoryLeakMixin, TestCase): """ Check shape-changing operations on arrays. """ def setUp(self): super(TestArrayManipulation, self).setUp() self.ccache = CompilationCache() def test_array_reshape(self): pyfuncs_to_use = [array_reshape, numpy_array_reshape] def generic_run(pyfunc, arr, shape): cres = compile_isolated(pyfunc, (typeof(arr), typeof(shape))) return cres.entry_point(arr, shape) @from_generic(pyfuncs_to_use) def check(pyfunc, arr, shape): expected = pyfunc(arr, shape) self.memory_leak_setup() got = generic_run(pyfunc, arr, shape) self.assertPreciseEqual(got, expected) del got self.memory_leak_teardown() @from_generic(pyfuncs_to_use) def check_only_shape(pyfunc, arr, shape, expected_shape): # Only check Numba result to avoid Numpy bugs self.memory_leak_setup() got = generic_run(pyfunc, arr, shape) self.assertEqual(got.shape, expected_shape) self.assertEqual(got.size, arr.size) del got self.memory_leak_teardown() @from_generic(pyfuncs_to_use) def check_err_shape(pyfunc, arr, shape): with self.assertRaises(NotImplementedError) as raises: generic_run(pyfunc, arr, shape) self.assertEqual(str(raises.exception), "incompatible shape for array") @from_generic(pyfuncs_to_use) def check_err_size(pyfunc, arr, shape): with self.assertRaises(ValueError) as raises: generic_run(pyfunc, arr, shape) self.assertEqual(str(raises.exception), "total size of new array must be unchanged") @from_generic(pyfuncs_to_use) def check_err_multiple_negative(pyfunc, arr, shape): with self.assertRaises(ValueError) as raises: generic_run(pyfunc, arr, shape) self.assertEqual(str(raises.exception), "multiple negative shape values") # C-contiguous arr = np.arange(24) check(arr, (24, )) check(arr, (4, 6)) check(arr, (8, 3)) check(arr, (8, 1, 3)) check(arr, (1, 8, 1, 1, 3, 1)) arr = np.arange(24).reshape((2, 3, 4)) check(arr, (24, )) check(arr, (4, 6)) check(arr, (8, 3)) check(arr, (8, 1, 3)) check(arr, (1, 8, 1, 1, 3, 1)) check_err_size(arr, ()) check_err_size(arr, (25, )) check_err_size(arr, (8, 4)) arr = np.arange(24).reshape((1, 8, 1, 1, 3, 1)) check(arr, (24, )) check(arr, (4, 6)) check(arr, (8, 3)) check(arr, (8, 1, 3)) # F-contiguous arr = np.arange(24).reshape((2, 3, 4)).T check(arr, (4, 3, 2)) check(arr, (1, 4, 1, 3, 1, 2, 1)) check_err_shape(arr, (2, 3, 4)) check_err_shape(arr, (6, 4)) check_err_shape(arr, (2, 12)) # Test negative shape value arr = np.arange(25).reshape(5, 5) check(arr, -1) check(arr, (-1, )) check(arr, (-1, 5)) check(arr, (5, -1, 5)) check(arr, (5, 5, -1)) check_err_size(arr, (-1, 4)) check_err_multiple_negative(arr, (-1, -2, 5, 5)) check_err_multiple_negative(arr, (5, 5, -1, -1)) # 0-sized arrays def check_empty(arr): check(arr, 0) check(arr, (0, )) check(arr, (1, 0, 2)) check(arr, (0, 55, 1, 0, 2)) # -1 is buggy in Numpy with 0-sized arrays check_only_shape(arr, -1, (0, )) check_only_shape(arr, (-1, ), (0, )) check_only_shape(arr, (0, -1), (0, 0)) check_only_shape(arr, (4, -1), (4, 0)) check_only_shape(arr, (-1, 0, 4), (0, 0, 4)) check_err_size(arr, ()) check_err_size(arr, 1) check_err_size(arr, (1, 2)) arr = np.array([]) check_empty(arr) check_empty(arr.reshape((3, 2, 0))) # Exceptions leak references self.disable_leak_check() def test_array_transpose_axes(self): pyfuncs_to_use = [ numpy_transpose_array_axes_kwarg, numpy_transpose_array_axes_kwarg_copy, array_transpose_axes, array_transpose_axes_copy ] def run(pyfunc, arr, axes): cres = self.ccache.compile(pyfunc, (typeof(arr), typeof(axes))) return cres.entry_point(arr, axes) @from_generic(pyfuncs_to_use) def check(pyfunc, arr, axes): expected = pyfunc(arr, axes) got = run(pyfunc, arr, axes) self.assertPreciseEqual(got, expected) self.assertEqual(got.flags.f_contiguous, expected.flags.f_contiguous) self.assertEqual(got.flags.c_contiguous, expected.flags.c_contiguous) @from_generic(pyfuncs_to_use) def check_err_axis_repeated(pyfunc, arr, axes): with self.assertRaises(ValueError) as raises: run(pyfunc, arr, axes) self.assertEqual(str(raises.exception), "repeated axis in transpose") @from_generic(pyfuncs_to_use) def check_err_axis_oob(pyfunc, arr, axes): with self.assertRaises(ValueError) as raises: run(pyfunc, arr, axes) self.assertEqual( str(raises.exception), "axis is out of bounds for array of given dimension") @from_generic(pyfuncs_to_use) def check_err_invalid_args(pyfunc, arr, axes): with self.assertRaises((TypeError, TypingError)): run(pyfunc, arr, axes) arrs = [ np.arange(24), np.arange(24).reshape(4, 6), np.arange(24).reshape(2, 3, 4), np.arange(24).reshape(1, 2, 3, 4), np.arange(64).reshape(8, 4, 2)[::3, ::2, :] ] for i in range(len(arrs)): # First check `None`, the default, which is to reverse dims check(arrs[i], None) # Check supplied axis permutations for axes in permutations(tuple(range(arrs[i].ndim))): ndim = len(axes) neg_axes = tuple([x - ndim for x in axes]) check(arrs[i], axes) check(arrs[i], neg_axes) @from_generic([transpose_issue_4708]) def check_issue_4708(pyfunc, m, n): expected = pyfunc(m, n) got = njit(pyfunc)(m, n) # values in arrays are equals, # but stronger assertions not hold (layout and strides equality) np.testing.assert_equal(got, expected) check_issue_4708(3, 2) check_issue_4708(2, 3) check_issue_4708(5, 4) # Exceptions leak references self.disable_leak_check() check_err_invalid_args(arrs[1], "foo") check_err_invalid_args(arrs[1], ("foo", )) check_err_invalid_args(arrs[1], 5.3) check_err_invalid_args(arrs[2], (1.2, 5)) check_err_axis_repeated(arrs[1], (0, 0)) check_err_axis_repeated(arrs[2], (2, 0, 0)) check_err_axis_repeated(arrs[3], (3, 2, 1, 1)) check_err_axis_oob(arrs[0], (1, )) check_err_axis_oob(arrs[0], (-2, )) check_err_axis_oob(arrs[1], (0, 2)) check_err_axis_oob(arrs[1], (-3, 2)) check_err_axis_oob(arrs[1], (0, -3)) check_err_axis_oob(arrs[2], (3, 1, 2)) check_err_axis_oob(arrs[2], (-4, 1, 2)) check_err_axis_oob(arrs[3], (3, 1, 2, 5)) check_err_axis_oob(arrs[3], (3, 1, 2, -5)) with self.assertRaises(TypingError) as e: jit(nopython=True)(numpy_transpose_array)((np.array([0, 1]), )) self.assertIn("np.transpose does not accept tuples", str(e.exception)) def test_expand_dims(self): pyfunc = expand_dims def run(arr, axis): cres = self.ccache.compile(pyfunc, (typeof(arr), typeof(axis))) return cres.entry_point(arr, axis) def check(arr, axis): expected = pyfunc(arr, axis) self.memory_leak_setup() got = run(arr, axis) self.assertPreciseEqual(got, expected) del got self.memory_leak_teardown() def check_all_axes(arr): for axis in range(-arr.ndim - 1, arr.ndim + 1): check(arr, axis) # 1d arr = np.arange(5) check_all_axes(arr) # 3d (C, F, A) arr = np.arange(24).reshape((2, 3, 4)) check_all_axes(arr) check_all_axes(arr.T) check_all_axes(arr[::-1]) # 0d arr = np.array(42) check_all_axes(arr) def check_atleast_nd(self, pyfunc, cfunc): def check_result(got, expected): # We would like to check the result has the same contiguity, # but we can't rely on the "flags" attribute when there are # 1-sized dimensions. self.assertStridesEqual(got, expected) self.assertPreciseEqual(got.flatten(), expected.flatten()) def check_single(arg): check_result(cfunc(arg), pyfunc(arg)) def check_tuple(*args): expected_tuple = pyfunc(*args) got_tuple = cfunc(*args) self.assertEqual(len(got_tuple), len(expected_tuple)) for got, expected in zip(got_tuple, expected_tuple): check_result(got, expected) # 0d a1 = np.array(42) a2 = np.array(5j) check_single(a1) check_tuple(a1, a2) # 1d b1 = np.arange(5) b2 = np.arange(6) + 1j b3 = b1[::-1] check_single(b1) check_tuple(b1, b2, b3) # 2d c1 = np.arange(6).reshape((2, 3)) c2 = c1.T c3 = c1[::-1] check_single(c1) check_tuple(c1, c2, c3) # 3d d1 = np.arange(24).reshape((2, 3, 4)) d2 = d1.T d3 = d1[::-1] check_single(d1) check_tuple(d1, d2, d3) # 4d e = np.arange(16).reshape((2, 2, 2, 2)) check_single(e) # mixed dimensions check_tuple(a1, b2, c3, d2) def test_atleast_1d(self): pyfunc = atleast_1d cfunc = jit(nopython=True)(pyfunc) self.check_atleast_nd(pyfunc, cfunc) def test_atleast_2d(self): pyfunc = atleast_2d cfunc = jit(nopython=True)(pyfunc) self.check_atleast_nd(pyfunc, cfunc) def test_atleast_3d(self): pyfunc = atleast_3d cfunc = jit(nopython=True)(pyfunc) self.check_atleast_nd(pyfunc, cfunc) def check_as_strided(self, pyfunc): def run(arr): cres = self.ccache.compile(pyfunc, (typeof(arr), )) return cres.entry_point(arr) def check(arr): expected = pyfunc(arr) got = run(arr) self.assertPreciseEqual(got, expected) arr = np.arange(24) check(arr) check(arr.reshape((6, 4))) check(arr.reshape((4, 1, 6))) def test_as_strided(self): self.check_as_strided(as_strided1) self.check_as_strided(as_strided2) def test_flatten_array(self, flags=enable_pyobj_flags, layout='C'): a = np.arange(9).reshape(3, 3) if layout == 'F': a = a.T pyfunc = flatten_array arraytype1 = typeof(a) if layout == 'A': # Force A layout arraytype1 = arraytype1.copy(layout='A') self.assertEqual(arraytype1.layout, layout) cr = compile_isolated(pyfunc, (arraytype1, ), flags=flags) cfunc = cr.entry_point expected = pyfunc(a) got = cfunc(a) np.testing.assert_equal(expected, got) def test_flatten_array_npm(self): self.test_flatten_array(flags=no_pyobj_flags) self.test_flatten_array(flags=no_pyobj_flags, layout='F') self.test_flatten_array(flags=no_pyobj_flags, layout='A') def test_ravel_array(self, flags=enable_pyobj_flags): def generic_check(pyfunc, a, assume_layout): # compile arraytype1 = typeof(a) self.assertEqual(arraytype1.layout, assume_layout) cr = compile_isolated(pyfunc, (arraytype1, ), flags=flags) cfunc = cr.entry_point expected = pyfunc(a) got = cfunc(a) # Check result matches np.testing.assert_equal(expected, got) # Check copying behavior py_copied = (a.ctypes.data != expected.ctypes.data) nb_copied = (a.ctypes.data != got.ctypes.data) self.assertEqual(py_copied, assume_layout != 'C') self.assertEqual(py_copied, nb_copied) check_method = partial(generic_check, ravel_array) check_function = partial(generic_check, numpy_ravel_array) def check(*args, **kwargs): check_method(*args, **kwargs) check_function(*args, **kwargs) # Check 2D check(np.arange(9).reshape(3, 3), assume_layout='C') check(np.arange(9).reshape(3, 3, order='F'), assume_layout='F') check(np.arange(18).reshape(3, 3, 2)[:, :, 0], assume_layout='A') # Check 3D check(np.arange(18).reshape(2, 3, 3), assume_layout='C') check(np.arange(18).reshape(2, 3, 3, order='F'), assume_layout='F') check(np.arange(36).reshape(2, 3, 3, 2)[:, :, :, 0], assume_layout='A') def test_ravel_array_size(self, flags=enable_pyobj_flags): a = np.arange(9).reshape(3, 3) pyfunc = ravel_array_size arraytype1 = typeof(a) cr = compile_isolated(pyfunc, (arraytype1, ), flags=flags) cfunc = cr.entry_point expected = pyfunc(a) got = cfunc(a) np.testing.assert_equal(expected, got) def test_ravel_array_npm(self): self.test_ravel_array(flags=no_pyobj_flags) def test_ravel_array_size_npm(self): self.test_ravel_array_size(flags=no_pyobj_flags) def test_transpose_array(self, flags=enable_pyobj_flags): @from_generic([transpose_array, numpy_transpose_array]) def check(pyfunc): a = np.arange(9).reshape(3, 3) arraytype1 = typeof(a) cr = compile_isolated(pyfunc, (arraytype1, ), flags=flags) cfunc = cr.entry_point expected = pyfunc(a) got = cfunc(a) np.testing.assert_equal(expected, got) check() def test_transpose_array_npm(self): self.test_transpose_array(flags=no_pyobj_flags) def test_squeeze_array(self, flags=enable_pyobj_flags): a = np.arange(2 * 1 * 3 * 1 * 4).reshape(2, 1, 3, 1, 4) pyfunc = squeeze_array arraytype1 = typeof(a) cr = compile_isolated(pyfunc, (arraytype1, ), flags=flags) cfunc = cr.entry_point expected = pyfunc(a) got = cfunc(a) np.testing.assert_equal(expected, got) def test_squeeze_array_npm(self): with self.assertRaises(errors.TypingError) as raises: self.test_squeeze_array(flags=no_pyobj_flags) self.assertIn("squeeze", str(raises.exception)) def test_add_axis2(self, flags=enable_pyobj_flags): a = np.arange(9).reshape(3, 3) pyfunc = add_axis2 arraytype1 = typeof(a) cr = compile_isolated(pyfunc, (arraytype1, ), flags=flags) cfunc = cr.entry_point expected = pyfunc(a) got = cfunc(a) np.testing.assert_equal(expected, got) def test_add_axis2_npm(self): with self.assertTypingError() as raises: self.test_add_axis2(flags=no_pyobj_flags) self.assertIn("unsupported array index type none in", str(raises.exception)) def test_bad_index_npm(self): with self.assertTypingError() as raises: arraytype1 = from_dtype( np.dtype([('x', np.int32), ('y', np.int32)])) arraytype2 = types.Array(types.int32, 2, 'C') compile_isolated(bad_index, (arraytype1, arraytype2), flags=no_pyobj_flags) self.assertIn('unsupported array index type', str(raises.exception)) def test_bad_float_index_npm(self): with self.assertTypingError() as raises: compile_isolated(bad_float_index, (types.Array(types.float64, 2, 'C'), )) self.assertIn('unsupported array index type float64', str(raises.exception)) def test_fill_diagonal_basic(self): pyfunc = numpy_fill_diagonal cfunc = jit(nopython=True)(pyfunc) def _shape_variations(n): # square yield (n, n) # tall and thin yield (2 * n, n) # short and fat yield (n, 2 * n) # a bit taller than wide; odd numbers of rows and cols yield ((2 * n + 1), (2 * n - 1)) # 4d, all dimensions same yield (n, n, n, n) # weird edge case yield (1, 1, 1) def _val_variations(): yield 1 yield 3.142 yield np.nan yield -np.inf yield True yield np.arange(4) yield (4, ) yield [8, 9] yield np.arange(54).reshape(9, 3, 2, 1) # contiguous C yield np.asfortranarray(np.arange(9).reshape(3, 3)) # contiguous F yield np.arange(9).reshape(3, 3)[::-1] # non-contiguous # contiguous arrays def _multi_dimensional_array_variations(n): for shape in _shape_variations(n): yield np.zeros(shape, dtype=np.float64) yield np.asfortranarray(np.ones(shape, dtype=np.float64)) # non-contiguous arrays def _multi_dimensional_array_variations_strided(n): for shape in _shape_variations(n): tmp = np.zeros(tuple([x * 2 for x in shape]), dtype=np.float64) slicer = tuple(slice(0, x * 2, 2) for x in shape) yield tmp[slicer] def _check_fill_diagonal(arr, val): for wrap in None, True, False: a = arr.copy() b = arr.copy() if wrap is None: params = {} else: params = {'wrap': wrap} pyfunc(a, val, **params) cfunc(b, val, **params) self.assertPreciseEqual(a, b) for arr in _multi_dimensional_array_variations(3): for val in _val_variations(): _check_fill_diagonal(arr, val) for arr in _multi_dimensional_array_variations_strided(3): for val in _val_variations(): _check_fill_diagonal(arr, val) # non-numeric input arrays arr = np.array([True] * 9).reshape(3, 3) _check_fill_diagonal(arr, False) _check_fill_diagonal(arr, [False, True, False]) _check_fill_diagonal(arr, np.array([True, False, True])) def test_fill_diagonal_exception_cases(self): pyfunc = numpy_fill_diagonal cfunc = jit(nopython=True)(pyfunc) val = 1 # Exceptions leak references self.disable_leak_check() # first argument unsupported number of dimensions for a in np.array([]), np.ones(5): with self.assertRaises(TypingError) as raises: cfunc(a, val) assert "The first argument must be at least 2-D" in str( raises.exception) # multi-dimensional input where dimensions are not all equal with self.assertRaises(ValueError) as raises: a = np.zeros((3, 3, 4)) cfunc(a, val) self.assertEqual("All dimensions of input must be of equal length", str(raises.exception)) # cases where val has incompatible type / value def _assert_raises(arr, val): with self.assertRaises(ValueError) as raises: cfunc(arr, val) self.assertEqual("Unable to safely conform val to a.dtype", str(raises.exception)) arr = np.zeros((3, 3), dtype=np.int32) val = np.nan _assert_raises(arr, val) val = [3.3, np.inf] _assert_raises(arr, val) val = np.array([1, 2, 1e10], dtype=np.int64) _assert_raises(arr, val) arr = np.zeros((3, 3), dtype=np.float32) val = [1.4, 2.6, -1e100] _assert_raises(arr, val) val = 1.1e100 _assert_raises(arr, val) val = np.array([-1e100]) _assert_raises(arr, val) def test_broadcast_to(self): pyfunc = numpy_broadcast_to cfunc = jit(nopython=True)(pyfunc) # Tests taken from # https://github.com/numpy/numpy/blob/75f852edf94a7293e7982ad516bee314d7187c2d/numpy/lib/tests/test_stride_tricks.py#L234-L257 # noqa: E501 data = [ [np.array(0), (0, )], [np.array(0), (1, )], [np.array(0), (3, )], [np.ones(1), (1, )], [np.ones(1), (2, )], [np.ones(1), (1, 2, 3)], [np.arange(3), (3, )], [np.arange(3), (1, 3)], [np.arange(3), (2, 3)], # test if shape is not a tuple [np.ones(0), 0], [np.ones(1), 1], [np.ones(1), 2], # these cases with size 0 are strange, but they reproduce the behavior # of broadcasting with ufuncs [np.ones(1), (0, )], [np.ones((1, 2)), (0, 2)], [np.ones((2, 1)), (2, 0)], # numpy accepts scalar values as first argument to np.broadcast_to [2, (2, 2)], # tuple input [(1, 2), (2, 2)], ] for input_array, shape in data: expected = pyfunc(input_array, shape) got = cfunc(input_array, shape) self.assertPreciseEqual(got, expected) def test_broadcast_to_raises(self): pyfunc = numpy_broadcast_to cfunc = jit(nopython=True)(pyfunc) # Tests taken from # https://github.com/numpy/numpy/blob/75f852edf94a7293e7982ad516bee314d7187c2d/numpy/lib/tests/test_stride_tricks.py#L260-L276 # noqa: E501 data = [ [ np.zeros((0, )), (), TypingError, 'The argument "shape" must be a tuple or an integer.' ], [ np.zeros((1, )), (), TypingError, 'The argument "shape" must be a tuple or an integer.' ], [ np.zeros((3, )), (), TypingError, 'The argument "shape" must be a tuple or an integer.' ], [ np.zeros((3, )), (1, ), ValueError, 'operands could not be broadcast together with remapped shapes' ], [ np.zeros((3, )), (2, ), ValueError, 'operands could not be broadcast together with remapped shapes' ], [ np.zeros((3, )), (4, ), ValueError, 'operands could not be broadcast together with remapped shapes' ], [ np.zeros((1, 2)), (2, 1), ValueError, 'operands could not be broadcast together with remapped shapes' ], [ np.zeros((1, 1)), (1, ), ValueError, 'input operand has more dimensions than allowed by the axis remapping' ], [ np.zeros((2, 2)), (3, ), ValueError, 'input operand has more dimensions than allowed by the axis remapping' ], [ np.zeros((1, )), -1, ValueError, 'all elements of broadcast shape must be non-negative' ], [ np.zeros((1, )), (-1, ), ValueError, 'all elements of broadcast shape must be non-negative' ], [ np.zeros((1, 2)), (-1, 2), ValueError, 'all elements of broadcast shape must be non-negative' ], [ np.zeros((1, 2)), (1.1, 2.2), TypingError, 'The second argument "shape" must be a tuple of integers' ], [ 'hello', (3, ), TypingError, 'The first argument "array" must be array-like' ], ] self.disable_leak_check() for arr, target_shape, err, msg in data: with self.assertRaises(err) as raises: cfunc(arr, target_shape) self.assertIn(msg, str(raises.exception)) def test_broadcast_to_change_view(self): pyfunc = numpy_broadcast_to cfunc = jit(nopython=True)(pyfunc) input_array = np.zeros(2, dtype=np.int32) shape = (2, 2) view = cfunc(input_array, shape) input_array[0] = 10 self.assertEqual(input_array.sum(), 10) self.assertEqual(view.sum(), 20) def test_broadcast_to_indexing(self): pyfunc = numpy_broadcast_to_indexing cfunc = jit(nopython=True)(pyfunc) data = [ [np.ones(2), (2, 2), (1, )], ] for input_array, shape, idx in data: expected = pyfunc(input_array, shape, idx) got = cfunc(input_array, shape, idx) self.assertPreciseEqual(got, expected) @unittest.skipIf(numpy_version < (1, 20), "requires NumPy 1.20 or newer") def test_broadcast_shapes(self): pyfunc = numpy_broadcast_shapes cfunc = jit(nopython=True)(pyfunc) # Tests taken from # https://github.com/numpy/numpy/blob/623bc1fae1d47df24e7f1e29321d0c0ba2771ce0/numpy/lib/tests/test_stride_tricks.py#L296-L334 data = [ # [[], ()], # cannot compute fingerprint of empty list [()], [(), ()], [(7, )], [ (1, 2), ], [(1, 1)], [(1, 1), (3, 4)], [(6, 7), (5, 6, 1), (7, ), (5, 1, 7)], [(5, 6, 1)], [(1, 3), (3, 1)], [(1, 0), (0, 0)], [(0, 1), (0, 0)], [(1, 0), (0, 1)], [(1, 1), (0, 0)], [(1, 1), (1, 0)], [(1, 1), (0, 1)], [(), (0, )], [(0, ), (0, 0)], [(0, ), (0, 1)], [(1, ), (0, 0)], [(), (0, 0)], [(1, 1), (0, )], [(1, ), (0, 1)], [(1, ), (1, 0)], [(), (1, 0)], [(), (0, 1)], [(1, ), (3, )], [2, (3, 2)], ] for input_shape in data: expected = pyfunc(*input_shape) got = cfunc(*input_shape) self.assertIsInstance(got, tuple) self.assertPreciseEqual(expected, got) @unittest.skipIf(numpy_version < (1, 20), "requires NumPy 1.20 or newer") def test_broadcast_shapes_raises(self): pyfunc = numpy_broadcast_shapes cfunc = jit(nopython=True)(pyfunc) self.disable_leak_check() # Tests taken from # https://github.com/numpy/numpy/blob/623bc1fae1d47df24e7f1e29321d0c0ba2771ce0/numpy/lib/tests/test_stride_tricks.py#L337-L351 data = [ [(3, ), (4, )], [(2, 3), (2, )], [(3, ), (3, ), (4, )], [(1, 3, 4), (2, 3, 3)], [(1, 2), (3, 1), (3, 2), (10, 5)], [2, (2, 3)], ] for input_shape in data: with self.assertRaises(ValueError) as raises: cfunc(*input_shape) self.assertIn( "shape mismatch: objects cannot be broadcast to a single shape", str(raises.exception)) @unittest.skipIf(numpy_version < (1, 20), "requires NumPy 1.20 or newer") def test_broadcast_shapes_negative_dimension(self): pyfunc = numpy_broadcast_shapes cfunc = jit(nopython=True)(pyfunc) self.disable_leak_check() with self.assertRaises(ValueError) as raises: cfunc((1, 2), (2), (-2)) self.assertIn("negative dimensions are not allowed", str(raises.exception)) @unittest.skipIf(numpy_version < (1, 20), "requires NumPy 1.20 or newer") def test_broadcast_shapes_invalid_type(self): pyfunc = numpy_broadcast_shapes cfunc = jit(nopython=True)(pyfunc) self.disable_leak_check() inps = [ ((1, 2), ('hello', )), (3.4, ), ('string', ), ((1.2, 'a')), (1, ((1.2, 'a'))), ] for inp in inps: with self.assertRaises(TypingError) as raises: cfunc(*inp) self.assertIn("must be either an int or tuple[int]", str(raises.exception)) def test_shape(self): pyfunc = numpy_shape cfunc = jit(nopython=True)(pyfunc) def check(x): expected = pyfunc(x) got = cfunc(x) self.assertPreciseEqual(got, expected) # check arrays for t in [(), (1, ), ( 2, 3, ), (4, 5, 6)]: arr = np.empty(t) check(arr) # check some types that go via asarray for t in [1, False, [ 1, ], [[ 1, 2, ], [3, 4]], (1, ), (1, 2, 3)]: check(arr) with self.assertRaises(TypingError) as raises: cfunc('a') self.assertIn("The argument to np.shape must be array-like", str(raises.exception)) def test_flatnonzero_basic(self): pyfunc = numpy_flatnonzero cfunc = jit(nopython=True)(pyfunc) def a_variations(): yield np.arange(-5, 5) yield np.full(5, fill_value=0) yield np.array([]) a = self.random.randn(100) a[np.abs(a) > 0.2] = 0.0 yield a yield a.reshape(5, 5, 4) yield a.reshape(50, 2, order='F') yield a.reshape(25, 4)[1::2] yield a * 1j for a in a_variations(): expected = pyfunc(a) got = cfunc(a) self.assertPreciseEqual(expected, got) def test_argwhere_basic(self): pyfunc = numpy_argwhere cfunc = jit(nopython=True)(pyfunc) def a_variations(): yield np.arange(-5, 5) > 2 yield np.full(5, fill_value=0) yield np.full(5, fill_value=1) yield np.array([]) yield np.array([-1.0, 0.0, 1.0]) a = self.random.randn(100) yield a > 0.2 yield a.reshape(5, 5, 4) > 0.5 yield a.reshape(50, 2, order='F') > 0.5 yield a.reshape(25, 4)[1::2] > 0.5 yield a == a - 1 yield a > -a for a in a_variations(): expected = pyfunc(a) got = cfunc(a) self.assertPreciseEqual(expected, got) @staticmethod def array_like_variations(): yield ((1.1, 2.2), (3.3, 4.4), (5.5, 6.6)) yield (0.0, 1.0, 0.0, -6.0) yield ([0, 1], [2, 3]) yield () yield np.nan yield 0 yield 1 yield False yield True yield (True, False, True) yield 2 + 1j # the following are not array-like, but NumPy does not raise yield None yield 'a_string' yield '' def test_flatnonzero_array_like(self): pyfunc = numpy_flatnonzero cfunc = jit(nopython=True)(pyfunc) for a in self.array_like_variations(): expected = pyfunc(a) got = cfunc(a) self.assertPreciseEqual(expected, got) def test_argwhere_array_like(self): pyfunc = numpy_argwhere cfunc = jit(nopython=True)(pyfunc) for a in self.array_like_variations(): expected = pyfunc(a) got = cfunc(a) self.assertPreciseEqual(expected, got) def broadcast_arrays_assert_correct_shape(self, input_shapes, expected_shape): # Broadcast a list of arrays with the given input shapes and check the # common output shape. pyfunc = numpy_broadcast_arrays cfunc = jit(nopython=True)(pyfunc) inarrays = [np.zeros(s) for s in input_shapes] outarrays = cfunc(*inarrays) expected = [expected_shape] * len(inarrays) got = [a.shape for a in outarrays] self.assertPreciseEqual(expected, got) def test_broadcast_arrays_same_input_shapes(self): # Tests taken from # https://github.com/numpy/numpy/blob/623bc1fae1d47df24e7f1e29321d0c0ba2771ce0/numpy/lib/tests/test_stride_tricks.py#L83-L107 # noqa: E501 # Check that the final shape is just the input shape. pyfunc = numpy_broadcast_arrays cfunc = jit(nopython=True)(pyfunc) data = [ # (), ( 1, ), (3, ), (0, 1), (0, 3), (1, 0), (3, 0), (1, 3), (3, 1), (3, 3), ] for shape in data: input_shapes = [shape] # Single input. self.broadcast_arrays_assert_correct_shape(input_shapes, shape) # Double input. input_shapes2 = [shape, shape] self.broadcast_arrays_assert_correct_shape(input_shapes2, shape) # Triple input. input_shapes3 = [shape, shape, shape] self.broadcast_arrays_assert_correct_shape(input_shapes3, shape) def test_broadcast_arrays_two_compatible_by_ones_input_shapes(self): # Tests taken from # https://github.com/numpy/numpy/blob/623bc1fae1d47df24e7f1e29321d0c0ba2771ce0/numpy/lib/tests/test_stride_tricks.py#L110-L132 # Check that two different input shapes of the same length, but some have # ones, broadcast to the correct shape. data = [ [[(1, ), (3, )], (3, )], [[(1, 3), (3, 3)], (3, 3)], [[(3, 1), (3, 3)], (3, 3)], [[(1, 3), (3, 1)], (3, 3)], [[(1, 1), (3, 3)], (3, 3)], [[(1, 1), (1, 3)], (1, 3)], [[(1, 1), (3, 1)], (3, 1)], [[(1, 0), (0, 0)], (0, 0)], [[(0, 1), (0, 0)], (0, 0)], [[(1, 0), (0, 1)], (0, 0)], [[(1, 1), (0, 0)], (0, 0)], [[(1, 1), (1, 0)], (1, 0)], [[(1, 1), (0, 1)], (0, 1)], ] for input_shapes, expected_shape in data: self.broadcast_arrays_assert_correct_shape(input_shapes, expected_shape) # Reverse the input shapes since broadcasting should be symmetric. self.broadcast_arrays_assert_correct_shape(input_shapes[::-1], expected_shape) def test_broadcast_arrays_two_compatible_by_prepending_ones_input_shapes( self): # Tests taken from # https://github.com/numpy/numpy/blob/623bc1fae1d47df24e7f1e29321d0c0ba2771ce0/numpy/lib/tests/test_stride_tricks.py#L135-L164 # Check that two different input shapes (of different lengths) broadcast # to the correct shape. data = [ [[(), (3, )], (3, )], [[(3, ), (3, 3)], (3, 3)], [[(3, ), (3, 1)], (3, 3)], [[(1, ), (3, 3)], (3, 3)], [[(), (3, 3)], (3, 3)], [[(1, 1), (3, )], (1, 3)], [[(1, ), (3, 1)], (3, 1)], [[(1, ), (1, 3)], (1, 3)], [[(), (1, 3)], (1, 3)], [[(), (3, 1)], (3, 1)], [[(), (0, )], (0, )], [[(0, ), (0, 0)], (0, 0)], [[(0, ), (0, 1)], (0, 0)], [[(1, ), (0, 0)], (0, 0)], [[(), (0, 0)], (0, 0)], [[(1, 1), (0, )], (1, 0)], [[(1, ), (0, 1)], (0, 1)], [[(1, ), (1, 0)], (1, 0)], [[(), (1, 0)], (1, 0)], [[(), (0, 1)], (0, 1)], ] for input_shapes, expected_shape in data: self.broadcast_arrays_assert_correct_shape(input_shapes, expected_shape) # Reverse the input shapes since broadcasting should be symmetric. self.broadcast_arrays_assert_correct_shape(input_shapes[::-1], expected_shape) def test_broadcast_arrays_scalar_input(self): pyfunc = numpy_broadcast_arrays cfunc = jit(nopython=True)(pyfunc) data = [ [[True, False], (1, )], [[1, 2], (1, )], [[(1, 2), 2], (2, )], ] for inarrays, expected_shape in data: outarrays = cfunc(*inarrays) got = [a.shape for a in outarrays] expected = [expected_shape] * len(inarrays) self.assertPreciseEqual(expected, got) def test_broadcast_arrays_tuple_input(self): pyfunc = numpy_broadcast_arrays cfunc = jit(nopython=True)(pyfunc) outarrays = cfunc((123, 456), (789, )) expected = [(2, ), (2, )] got = [a.shape for a in outarrays] self.assertPreciseEqual(expected, got) def test_broadcast_arrays_non_array_input(self): pyfunc = numpy_broadcast_arrays cfunc = jit(nopython=True)(pyfunc) outarrays = cfunc(np.intp(2), np.zeros((1, 3), dtype=np.intp)) expected = [(1, 3), (1, 3)] got = [a.shape for a in outarrays] self.assertPreciseEqual(expected, got) def test_broadcast_arrays_invalid_mixed_input_types(self): pyfunc = numpy_broadcast_arrays cfunc = jit(nopython=True)(pyfunc) self.disable_leak_check() with self.assertRaises(TypingError) as raises: arr = np.arange(6).reshape((2, 3)) b = True cfunc(arr, b) self.assertIn('Mismatch of argument types', str(raises.exception)) def test_broadcast_arrays_invalid_input(self): pyfunc = numpy_broadcast_arrays cfunc = jit(nopython=True)(pyfunc) self.disable_leak_check() with self.assertRaises(TypingError) as raises: arr = np.zeros(3, dtype=np.int64) s = 'hello world' cfunc(arr, s) self.assertIn('Argument "1" must be array-like', str(raises.exception)) def test_broadcast_arrays_incompatible_shapes_raise_valueerror(self): # Check that a ValueError is raised for incompatible shapes. pyfunc = numpy_broadcast_arrays cfunc = jit(nopython=True)(pyfunc) self.disable_leak_check() data = [ [(3, ), (4, )], [(2, 3), (2, )], [(3, ), (3, ), (4, )], [(1, 3, 4), (2, 3, 3)], ] for input_shapes in data: for shape in [input_shapes, input_shapes[::-1]]: # Reverse the input shapes since broadcasting should be symmetric. with self.assertRaises(ValueError) as raises: inarrays = [np.zeros(s) for s in shape] cfunc(*inarrays) self.assertIn( "shape mismatch: objects cannot be broadcast to a single shape", str(raises.exception))
class TestArrayManipulation(MemoryLeakMixin, TestCase): """ Check shape-changing operations on arrays. """ def setUp(self): super(TestArrayManipulation, self).setUp() self.ccache = CompilationCache() def test_array_reshape(self): pyfuncs_to_use = [array_reshape, numpy_array_reshape] def generic_run(pyfunc, arr, shape): cres = compile_isolated(pyfunc, (typeof(arr), typeof(shape))) return cres.entry_point(arr, shape) @from_generic(pyfuncs_to_use) def check(pyfunc, arr, shape): expected = pyfunc(arr, shape) self.memory_leak_setup() got = generic_run(pyfunc, arr, shape) self.assertPreciseEqual(got, expected) del got self.memory_leak_teardown() @from_generic(pyfuncs_to_use) def check_only_shape(pyfunc, arr, shape, expected_shape): # Only check Numba result to avoid Numpy bugs self.memory_leak_setup() got = generic_run(pyfunc, arr, shape) self.assertEqual(got.shape, expected_shape) self.assertEqual(got.size, arr.size) del got self.memory_leak_teardown() @from_generic(pyfuncs_to_use) def check_err_shape(pyfunc, arr, shape): with self.assertRaises(NotImplementedError) as raises: generic_run(pyfunc, arr, shape) self.assertEqual(str(raises.exception), "incompatible shape for array") @from_generic(pyfuncs_to_use) def check_err_size(pyfunc, arr, shape): with self.assertRaises(ValueError) as raises: generic_run(pyfunc, arr, shape) self.assertEqual(str(raises.exception), "total size of new array must be unchanged") @from_generic(pyfuncs_to_use) def check_err_multiple_negative(pyfunc, arr, shape): with self.assertRaises(ValueError) as raises: generic_run(pyfunc, arr, shape) self.assertEqual(str(raises.exception), "multiple negative shape values") # C-contiguous arr = np.arange(24) check(arr, (24,)) check(arr, (4, 6)) check(arr, (8, 3)) check(arr, (8, 1, 3)) check(arr, (1, 8, 1, 1, 3, 1)) arr = np.arange(24).reshape((2, 3, 4)) check(arr, (24,)) check(arr, (4, 6)) check(arr, (8, 3)) check(arr, (8, 1, 3)) check(arr, (1, 8, 1, 1, 3, 1)) check_err_size(arr, ()) check_err_size(arr, (25,)) check_err_size(arr, (8, 4)) arr = np.arange(24).reshape((1, 8, 1, 1, 3, 1)) check(arr, (24,)) check(arr, (4, 6)) check(arr, (8, 3)) check(arr, (8, 1, 3)) # F-contiguous arr = np.arange(24).reshape((2, 3, 4)).T check(arr, (4, 3, 2)) check(arr, (1, 4, 1, 3, 1, 2, 1)) check_err_shape(arr, (2, 3, 4)) check_err_shape(arr, (6, 4)) check_err_shape(arr, (2, 12)) # Test negative shape value arr = np.arange(25).reshape(5,5) check(arr, -1) check(arr, (-1,)) check(arr, (-1, 5)) check(arr, (5, -1, 5)) check(arr, (5, 5, -1)) check_err_size(arr, (-1, 4)) check_err_multiple_negative(arr, (-1, -2, 5, 5)) check_err_multiple_negative(arr, (5, 5, -1, -1)) # 0-sized arrays def check_empty(arr): check(arr, 0) check(arr, (0,)) check(arr, (1, 0, 2)) check(arr, (0, 55, 1, 0, 2)) # -1 is buggy in Numpy with 0-sized arrays check_only_shape(arr, -1, (0,)) check_only_shape(arr, (-1,), (0,)) check_only_shape(arr, (0, -1), (0, 0)) check_only_shape(arr, (4, -1), (4, 0)) check_only_shape(arr, (-1, 0, 4), (0, 0, 4)) check_err_size(arr, ()) check_err_size(arr, 1) check_err_size(arr, (1, 2)) arr = np.array([]) check_empty(arr) check_empty(arr.reshape((3, 2, 0))) # Exceptions leak references self.disable_leak_check() def test_array_transpose_axes(self): pyfuncs_to_use = [numpy_transpose_array_axes_kwarg, numpy_transpose_array_axes_kwarg_copy, array_transpose_axes, array_transpose_axes_copy] def run(pyfunc, arr, axes): cres = self.ccache.compile(pyfunc, (typeof(arr), typeof(axes))) return cres.entry_point(arr, axes) @from_generic(pyfuncs_to_use) def check(pyfunc, arr, axes): expected = pyfunc(arr, axes) got = run(pyfunc, arr, axes) self.assertPreciseEqual(got, expected) self.assertEqual(got.flags.f_contiguous, expected.flags.f_contiguous) self.assertEqual(got.flags.c_contiguous, expected.flags.c_contiguous) @from_generic(pyfuncs_to_use) def check_err_axis_repeated(pyfunc, arr, axes): with self.assertRaises(ValueError) as raises: run(pyfunc, arr, axes) self.assertEqual(str(raises.exception), "repeated axis in transpose") @from_generic(pyfuncs_to_use) def check_err_axis_oob(pyfunc, arr, axes): with self.assertRaises(ValueError) as raises: run(pyfunc, arr, axes) self.assertEqual(str(raises.exception), "axis is out of bounds for array of given dimension") @from_generic(pyfuncs_to_use) def check_err_invalid_args(pyfunc, arr, axes): with self.assertRaises((TypeError, TypingError)): run(pyfunc, arr, axes) arrs = [np.arange(24), np.arange(24).reshape(4, 6), np.arange(24).reshape(2, 3, 4), np.arange(24).reshape(1, 2, 3, 4), np.arange(64).reshape(8, 4, 2)[::3,::2,:]] for i in range(len(arrs)): # First check `None`, the default, which is to reverse dims check(arrs[i], None) # Check supplied axis permutations for axes in permutations(tuple(range(arrs[i].ndim))): ndim = len(axes) neg_axes = tuple([x - ndim for x in axes]) check(arrs[i], axes) check(arrs[i], neg_axes) @from_generic([transpose_issue_4708]) def check_issue_4708(pyfunc, m, n): expected = pyfunc(m, n) got = njit(pyfunc)(m, n) # values in arrays are equals, # but stronger assertions not hold (layout and strides equality) np.testing.assert_equal(got, expected) check_issue_4708(3, 2) check_issue_4708(2, 3) check_issue_4708(5, 4) # Exceptions leak references self.disable_leak_check() check_err_invalid_args(arrs[1], "foo") check_err_invalid_args(arrs[1], ("foo",)) check_err_invalid_args(arrs[1], 5.3) check_err_invalid_args(arrs[2], (1.2, 5)) check_err_axis_repeated(arrs[1], (0, 0)) check_err_axis_repeated(arrs[2], (2, 0, 0)) check_err_axis_repeated(arrs[3], (3, 2, 1, 1)) check_err_axis_oob(arrs[0], (1,)) check_err_axis_oob(arrs[0], (-2,)) check_err_axis_oob(arrs[1], (0, 2)) check_err_axis_oob(arrs[1], (-3, 2)) check_err_axis_oob(arrs[1], (0, -3)) check_err_axis_oob(arrs[2], (3, 1, 2)) check_err_axis_oob(arrs[2], (-4, 1, 2)) check_err_axis_oob(arrs[3], (3, 1, 2, 5)) check_err_axis_oob(arrs[3], (3, 1, 2, -5)) with self.assertRaises(TypingError) as e: jit(nopython=True)(numpy_transpose_array)((np.array([0, 1]),)) self.assertIn("np.transpose does not accept tuples", str(e.exception)) def test_expand_dims(self): pyfunc = expand_dims def run(arr, axis): cres = self.ccache.compile(pyfunc, (typeof(arr), typeof(axis))) return cres.entry_point(arr, axis) def check(arr, axis): expected = pyfunc(arr, axis) self.memory_leak_setup() got = run(arr, axis) self.assertPreciseEqual(got, expected) del got self.memory_leak_teardown() def check_all_axes(arr): for axis in range(-arr.ndim - 1, arr.ndim + 1): check(arr, axis) # 1d arr = np.arange(5) check_all_axes(arr) # 3d (C, F, A) arr = np.arange(24).reshape((2, 3, 4)) check_all_axes(arr) check_all_axes(arr.T) check_all_axes(arr[::-1]) # 0d arr = np.array(42) check_all_axes(arr) def check_atleast_nd(self, pyfunc, cfunc): def check_result(got, expected): # We would like to check the result has the same contiguity, # but we can't rely on the "flags" attribute when there are # 1-sized dimensions. self.assertStridesEqual(got, expected) self.assertPreciseEqual(got.flatten(), expected.flatten()) def check_single(arg): check_result(cfunc(arg), pyfunc(arg)) def check_tuple(*args): expected_tuple = pyfunc(*args) got_tuple = cfunc(*args) self.assertEqual(len(got_tuple), len(expected_tuple)) for got, expected in zip(got_tuple, expected_tuple): check_result(got, expected) # 0d a1 = np.array(42) a2 = np.array(5j) check_single(a1) check_tuple(a1, a2) # 1d b1 = np.arange(5) b2 = np.arange(6) + 1j b3 = b1[::-1] check_single(b1) check_tuple(b1, b2, b3) # 2d c1 = np.arange(6).reshape((2, 3)) c2 = c1.T c3 = c1[::-1] check_single(c1) check_tuple(c1, c2, c3) # 3d d1 = np.arange(24).reshape((2, 3, 4)) d2 = d1.T d3 = d1[::-1] check_single(d1) check_tuple(d1, d2, d3) # 4d e = np.arange(16).reshape((2, 2, 2, 2)) check_single(e) # mixed dimensions check_tuple(a1, b2, c3, d2) def test_atleast_1d(self): pyfunc = atleast_1d cfunc = jit(nopython=True)(pyfunc) self.check_atleast_nd(pyfunc, cfunc) def test_atleast_2d(self): pyfunc = atleast_2d cfunc = jit(nopython=True)(pyfunc) self.check_atleast_nd(pyfunc, cfunc) def test_atleast_3d(self): pyfunc = atleast_3d cfunc = jit(nopython=True)(pyfunc) self.check_atleast_nd(pyfunc, cfunc) def check_as_strided(self, pyfunc): def run(arr): cres = self.ccache.compile(pyfunc, (typeof(arr),)) return cres.entry_point(arr) def check(arr): expected = pyfunc(arr) got = run(arr) self.assertPreciseEqual(got, expected) arr = np.arange(24) check(arr) check(arr.reshape((6, 4))) check(arr.reshape((4, 1, 6))) def test_as_strided(self): self.check_as_strided(as_strided1) self.check_as_strided(as_strided2) def test_flatten_array(self, flags=enable_pyobj_flags, layout='C'): a = np.arange(9).reshape(3, 3) if layout == 'F': a = a.T pyfunc = flatten_array arraytype1 = typeof(a) if layout == 'A': # Force A layout arraytype1 = arraytype1.copy(layout='A') self.assertEqual(arraytype1.layout, layout) cr = compile_isolated(pyfunc, (arraytype1,), flags=flags) cfunc = cr.entry_point expected = pyfunc(a) got = cfunc(a) np.testing.assert_equal(expected, got) def test_flatten_array_npm(self): self.test_flatten_array(flags=no_pyobj_flags) self.test_flatten_array(flags=no_pyobj_flags, layout='F') self.test_flatten_array(flags=no_pyobj_flags, layout='A') def test_ravel_array(self, flags=enable_pyobj_flags): def generic_check(pyfunc, a, assume_layout): # compile arraytype1 = typeof(a) self.assertEqual(arraytype1.layout, assume_layout) cr = compile_isolated(pyfunc, (arraytype1,), flags=flags) cfunc = cr.entry_point expected = pyfunc(a) got = cfunc(a) # Check result matches np.testing.assert_equal(expected, got) # Check copying behavior py_copied = (a.ctypes.data != expected.ctypes.data) nb_copied = (a.ctypes.data != got.ctypes.data) self.assertEqual(py_copied, assume_layout != 'C') self.assertEqual(py_copied, nb_copied) check_method = partial(generic_check, ravel_array) check_function = partial(generic_check, numpy_ravel_array) def check(*args, **kwargs): check_method(*args, **kwargs) check_function(*args, **kwargs) # Check 2D check(np.arange(9).reshape(3, 3), assume_layout='C') check(np.arange(9).reshape(3, 3, order='F'), assume_layout='F') check(np.arange(18).reshape(3, 3, 2)[:, :, 0], assume_layout='A') # Check 3D check(np.arange(18).reshape(2, 3, 3), assume_layout='C') check(np.arange(18).reshape(2, 3, 3, order='F'), assume_layout='F') check(np.arange(36).reshape(2, 3, 3, 2)[:, :, :, 0], assume_layout='A') def test_ravel_array_size(self, flags=enable_pyobj_flags): a = np.arange(9).reshape(3, 3) pyfunc = ravel_array_size arraytype1 = typeof(a) cr = compile_isolated(pyfunc, (arraytype1,), flags=flags) cfunc = cr.entry_point expected = pyfunc(a) got = cfunc(a) np.testing.assert_equal(expected, got) def test_ravel_array_npm(self): self.test_ravel_array(flags=no_pyobj_flags) def test_ravel_array_size_npm(self): self.test_ravel_array_size(flags=no_pyobj_flags) def test_transpose_array(self, flags=enable_pyobj_flags): @from_generic([transpose_array, numpy_transpose_array]) def check(pyfunc): a = np.arange(9).reshape(3, 3) arraytype1 = typeof(a) cr = compile_isolated(pyfunc, (arraytype1,), flags=flags) cfunc = cr.entry_point expected = pyfunc(a) got = cfunc(a) np.testing.assert_equal(expected, got) check() def test_transpose_array_npm(self): self.test_transpose_array(flags=no_pyobj_flags) def test_squeeze_array(self, flags=enable_pyobj_flags): a = np.arange(2 * 1 * 3 * 1 * 4).reshape(2, 1, 3, 1, 4) pyfunc = squeeze_array arraytype1 = typeof(a) cr = compile_isolated(pyfunc, (arraytype1,), flags=flags) cfunc = cr.entry_point expected = pyfunc(a) got = cfunc(a) np.testing.assert_equal(expected, got) def test_squeeze_array_npm(self): with self.assertRaises(errors.TypingError) as raises: self.test_squeeze_array(flags=no_pyobj_flags) self.assertIn("squeeze", str(raises.exception)) def test_add_axis2(self, flags=enable_pyobj_flags): a = np.arange(9).reshape(3, 3) pyfunc = add_axis2 arraytype1 = typeof(a) cr = compile_isolated(pyfunc, (arraytype1,), flags=flags) cfunc = cr.entry_point expected = pyfunc(a) got = cfunc(a) np.testing.assert_equal(expected, got) def test_add_axis2_npm(self): with self.assertTypingError() as raises: self.test_add_axis2(flags=no_pyobj_flags) self.assertIn("unsupported array index type none in", str(raises.exception)) def test_bad_index_npm(self): with self.assertTypingError() as raises: arraytype1 = from_dtype(np.dtype([('x', np.int32), ('y', np.int32)])) arraytype2 = types.Array(types.int32, 2, 'C') compile_isolated(bad_index, (arraytype1, arraytype2), flags=no_pyobj_flags) self.assertIn('unsupported array index type', str(raises.exception)) def test_bad_float_index_npm(self): with self.assertTypingError() as raises: compile_isolated(bad_float_index, (types.Array(types.float64, 2, 'C'),)) self.assertIn('unsupported array index type float64', str(raises.exception)) def test_fill_diagonal_basic(self): pyfunc = numpy_fill_diagonal cfunc = jit(nopython=True)(pyfunc) def _shape_variations(n): # square yield (n, n) # tall and thin yield (2 * n, n) # short and fat yield (n, 2 * n) # a bit taller than wide; odd numbers of rows and cols yield ((2 * n + 1), (2 * n - 1)) # 4d, all dimensions same yield (n, n, n, n) # weird edge case yield (1, 1, 1) def _val_variations(): yield 1 yield 3.142 yield np.nan yield -np.inf yield True yield np.arange(4) yield (4,) yield [8, 9] yield np.arange(54).reshape(9, 3, 2, 1) # contiguous C yield np.asfortranarray(np.arange(9).reshape(3, 3)) # contiguous F yield np.arange(9).reshape(3, 3)[::-1] # non-contiguous # contiguous arrays def _multi_dimensional_array_variations(n): for shape in _shape_variations(n): yield np.zeros(shape, dtype=np.float64) yield np.asfortranarray(np.ones(shape, dtype=np.float64)) # non-contiguous arrays def _multi_dimensional_array_variations_strided(n): for shape in _shape_variations(n): tmp = np.zeros(tuple([x * 2 for x in shape]), dtype=np.float64) slicer = tuple(slice(0, x * 2, 2) for x in shape) yield tmp[slicer] def _check_fill_diagonal(arr, val): for wrap in None, True, False: a = arr.copy() b = arr.copy() if wrap is None: params = {} else: params = {'wrap': wrap} pyfunc(a, val, **params) cfunc(b, val, **params) self.assertPreciseEqual(a, b) for arr in _multi_dimensional_array_variations(3): for val in _val_variations(): _check_fill_diagonal(arr, val) for arr in _multi_dimensional_array_variations_strided(3): for val in _val_variations(): _check_fill_diagonal(arr, val) # non-numeric input arrays arr = np.array([True] * 9).reshape(3, 3) _check_fill_diagonal(arr, False) _check_fill_diagonal(arr, [False, True, False]) _check_fill_diagonal(arr, np.array([True, False, True])) def test_fill_diagonal_exception_cases(self): pyfunc = numpy_fill_diagonal cfunc = jit(nopython=True)(pyfunc) val = 1 # Exceptions leak references self.disable_leak_check() # first argument unsupported number of dimensions for a in np.array([]), np.ones(5): with self.assertRaises(TypingError) as raises: cfunc(a, val) assert "The first argument must be at least 2-D" in str(raises.exception) # multi-dimensional input where dimensions are not all equal with self.assertRaises(ValueError) as raises: a = np.zeros((3, 3, 4)) cfunc(a, val) self.assertEqual("All dimensions of input must be of equal length", str(raises.exception)) # cases where val has incompatible type / value def _assert_raises(arr, val): with self.assertRaises(ValueError) as raises: cfunc(arr, val) self.assertEqual("Unable to safely conform val to a.dtype", str(raises.exception)) arr = np.zeros((3, 3), dtype=np.int32) val = np.nan _assert_raises(arr, val) val = [3.3, np.inf] _assert_raises(arr, val) val = np.array([1, 2, 1e10], dtype=np.int64) _assert_raises(arr, val) arr = np.zeros((3, 3), dtype=np.float32) val = [1.4, 2.6, -1e100] _assert_raises(arr, val) val = 1.1e100 _assert_raises(arr, val) val = np.array([-1e100]) _assert_raises(arr, val) def test_shape(self): pyfunc = numpy_shape cfunc = jit(nopython=True)(pyfunc) def check(x): expected = pyfunc(x) got = cfunc(x) self.assertPreciseEqual(got, expected) # check arrays for t in [(), (1,), (2, 3,), (4, 5, 6)]: arr = np.empty(t) check(arr) # check some types that go via asarray for t in [1, False, [1,], [[1, 2,],[3, 4]], (1,), (1, 2, 3)]: check(arr) with self.assertRaises(TypingError) as raises: cfunc('a') self.assertIn("The argument to np.shape must be array-like", str(raises.exception)) def test_flatnonzero_basic(self): pyfunc = numpy_flatnonzero cfunc = jit(nopython=True)(pyfunc) def a_variations(): yield np.arange(-5, 5) yield np.full(5, fill_value=0) yield np.array([]) a = self.random.randn(100) a[np.abs(a) > 0.2] = 0.0 yield a yield a.reshape(5, 5, 4) yield a.reshape(50, 2, order='F') yield a.reshape(25, 4)[1::2] yield a * 1j for a in a_variations(): expected = pyfunc(a) got = cfunc(a) self.assertPreciseEqual(expected, got) def test_argwhere_basic(self): pyfunc = numpy_argwhere cfunc = jit(nopython=True)(pyfunc) def a_variations(): yield np.arange(-5, 5) > 2 yield np.full(5, fill_value=0) yield np.full(5, fill_value=1) yield np.array([]) yield np.array([-1.0, 0.0, 1.0]) a = self.random.randn(100) yield a > 0.2 yield a.reshape(5, 5, 4) > 0.5 yield a.reshape(50, 2, order='F') > 0.5 yield a.reshape(25, 4)[1::2] > 0.5 yield a == a - 1 yield a > -a for a in a_variations(): expected = pyfunc(a) got = cfunc(a) self.assertPreciseEqual(expected, got) @staticmethod def array_like_variations(): yield ((1.1, 2.2), (3.3, 4.4), (5.5, 6.6)) yield (0.0, 1.0, 0.0, -6.0) yield ([0, 1], [2, 3]) yield () yield np.nan yield 0 yield 1 yield False yield True yield (True, False, True) yield 2 + 1j # the following are not array-like, but NumPy does not raise yield None yield 'a_string' yield '' def test_flatnonzero_array_like(self): pyfunc = numpy_flatnonzero cfunc = jit(nopython=True)(pyfunc) for a in self.array_like_variations(): expected = pyfunc(a) got = cfunc(a) self.assertPreciseEqual(expected, got) def test_argwhere_array_like(self): pyfunc = numpy_argwhere cfunc = jit(nopython=True)(pyfunc) for a in self.array_like_variations(): expected = pyfunc(a) got = cfunc(a) self.assertPreciseEqual(expected, got)
class TestMathLib(TestCase): def setUp(self): self.ccache = CompilationCache() def test_constants(self): self.run_nullary_func(get_constants, no_pyobj_flags) def run_unary(self, pyfunc, x_types, x_values, flags=enable_pyobj_flags, prec='exact', **kwargs): for tx, vx in zip(x_types, x_values): cr = self.ccache.compile(pyfunc, (tx, ), flags=flags) cfunc = cr.entry_point got = cfunc(vx) expected = pyfunc(vx) actual_prec = 'single' if tx is types.float32 else prec msg = 'for input %r' % (vx, ) self.assertPreciseEqual(got, expected, prec=actual_prec, msg=msg, **kwargs) def run_binary(self, pyfunc, x_types, x_values, y_values, flags=enable_pyobj_flags, prec='exact'): for ty, x, y in zip(x_types, x_values, y_values): cr = self.ccache.compile(pyfunc, (ty, ty), flags=flags) cfunc = cr.entry_point got = cfunc(x, y) expected = pyfunc(x, y) actual_prec = 'single' if ty is types.float32 else prec msg = 'for inputs (%r, %r)' % (x, y) self.assertPreciseEqual(got, expected, prec=actual_prec, msg=msg) def check_predicate_func(self, pyfunc, flags=enable_pyobj_flags): x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float32, types.float32, types.float64, types.float64, types.float64 ] x_values = [ 0, 0, 0, 0, 0, 0, float('inf'), 0.0, float('nan'), float('inf'), 0.0, float('nan') ] self.run_unary(pyfunc, x_types, x_values, flags) def test_sin(self, flags=enable_pyobj_flags): pyfunc = sin x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [-2, -1, -2, 2, 1, 2, .1, .2] self.run_unary(pyfunc, x_types, x_values, flags) def test_sin_npm(self): self.test_sin(flags=no_pyobj_flags) @unittest.skipIf(sys.platform == 'win32', "not exactly equal on win32 (issue #597)") def test_cos(self, flags=enable_pyobj_flags): pyfunc = cos x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [-2, -1, -2, 2, 1, 2, .1, .2] self.run_unary(pyfunc, x_types, x_values, flags) def test_cos_npm(self): self.test_cos(flags=no_pyobj_flags) def test_tan(self, flags=enable_pyobj_flags): pyfunc = tan x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [-2, -1, -2, 2, 1, 2, .1, .2] self.run_unary(pyfunc, x_types, x_values, flags) def test_tan_npm(self): self.test_tan(flags=no_pyobj_flags) def test_sqrt(self, flags=enable_pyobj_flags): pyfunc = sqrt x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [2, 1, 2, 2, 1, 2, .1, .2] self.run_unary(pyfunc, x_types, x_values, flags) def test_sqrt_npm(self): self.test_sqrt(flags=no_pyobj_flags) def test_npy_sqrt(self, flags=enable_pyobj_flags): pyfunc = npy_sqrt x_values = [2, 1, 2, 2, 1, 2, .1, .2] # XXX poor precision for int16 inputs x_types = [types.int16, types.uint16] self.run_unary(pyfunc, x_types, x_values, flags, prec='single') x_types = [ types.int32, types.int64, types.uint32, types.uint64, types.float32, types.float64 ] self.run_unary(pyfunc, x_types, x_values, flags) def test_npy_sqrt_npm(self): self.test_npy_sqrt(flags=no_pyobj_flags) def test_exp(self, flags=enable_pyobj_flags): pyfunc = exp x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [-2, -1, -2, 2, 1, 2, .1, .2] self.run_unary(pyfunc, x_types, x_values, flags) def test_exp_npm(self): self.test_exp(flags=no_pyobj_flags) def test_expm1(self, flags=enable_pyobj_flags): pyfunc = expm1 x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [-2, -1, -2, 2, 1, 2, .1, .2] self.run_unary(pyfunc, x_types, x_values, flags) def test_expm1_npm(self): self.test_expm1(flags=no_pyobj_flags) def test_log(self, flags=enable_pyobj_flags): pyfunc = log x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [1, 10, 100, 1000, 100000, 1000000, 0.1, 1.1] self.run_unary(pyfunc, x_types, x_values, flags) def test_log_npm(self): self.test_log(flags=no_pyobj_flags) def test_log1p(self, flags=enable_pyobj_flags): pyfunc = log1p x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [1, 10, 100, 1000, 100000, 1000000, 0.1, 1.1] self.run_unary(pyfunc, x_types, x_values, flags) def test_log1p_npm(self): self.test_log1p(flags=no_pyobj_flags) def test_log10(self, flags=enable_pyobj_flags): pyfunc = log10 x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [1, 10, 100, 1000, 100000, 1000000, 0.1, 1.1] self.run_unary(pyfunc, x_types, x_values, flags) def test_log10_npm(self): self.test_log10(flags=no_pyobj_flags) def test_asin(self, flags=enable_pyobj_flags): pyfunc = asin x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [1, 1, 1, 1, 1, 1, 1., 1.] self.run_unary(pyfunc, x_types, x_values, flags) def test_asin_npm(self): self.test_asin(flags=no_pyobj_flags) def test_acos(self, flags=enable_pyobj_flags): pyfunc = acos x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [1, 1, 1, 1, 1, 1, 1., 1.] self.run_unary(pyfunc, x_types, x_values, flags) def test_acos_npm(self): self.test_acos(flags=no_pyobj_flags) def test_atan(self, flags=enable_pyobj_flags): pyfunc = atan x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [-2, -1, -2, 2, 1, 2, .1, .2] self.run_unary(pyfunc, x_types, x_values, flags) def test_atan_npm(self): self.test_atan(flags=no_pyobj_flags) def test_atan2(self, flags=enable_pyobj_flags): pyfunc = atan2 x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [-2, -1, -2, 2, 1, 2, .1, .2] y_values = [x * 2 for x in x_values] self.run_binary(pyfunc, x_types, x_values, y_values, flags) def test_atan2_npm(self): self.test_atan2(flags=no_pyobj_flags) def test_asinh(self, flags=enable_pyobj_flags): pyfunc = asinh x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [1, 1, 1, 1, 1, 1, 1., 1.] self.run_unary(pyfunc, x_types, x_values, flags, prec='double') def test_asinh_npm(self): self.test_asinh(flags=no_pyobj_flags) def test_acosh(self, flags=enable_pyobj_flags): pyfunc = acosh x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [1, 1, 1, 1, 1, 1, 1., 1.] self.run_unary(pyfunc, x_types, x_values, flags) def test_acosh_npm(self): self.test_acosh(flags=no_pyobj_flags) def test_atanh(self, flags=enable_pyobj_flags): pyfunc = atanh x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [0, 0, 0, 0, 0, 0, 0.1, 0.1] self.run_unary(pyfunc, x_types, x_values, flags, prec='double') def test_atanh_npm(self): self.test_atanh(flags=no_pyobj_flags) def test_sinh(self, flags=enable_pyobj_flags): pyfunc = sinh x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [1, 1, 1, 1, 1, 1, 1., 1.] self.run_unary(pyfunc, x_types, x_values, flags) def test_sinh_npm(self): self.test_sinh(flags=no_pyobj_flags) def test_cosh(self, flags=enable_pyobj_flags): pyfunc = cosh x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [1, 1, 1, 1, 1, 1, 1., 1.] self.run_unary(pyfunc, x_types, x_values, flags) def test_cosh_npm(self): self.test_cosh(flags=no_pyobj_flags) def test_tanh(self, flags=enable_pyobj_flags): pyfunc = tanh x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [0, 0, 0, 0, 0, 0, 0.1, 0.1] self.run_unary(pyfunc, x_types, x_values, flags) def test_tanh_npm(self): self.test_tanh(flags=no_pyobj_flags) def test_floor(self, flags=enable_pyobj_flags): pyfunc = floor x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [0, 0, 0, 0, 0, 0, 0.1, 1.9] self.run_unary(pyfunc, x_types, x_values, flags) def test_floor_npm(self): self.test_floor(flags=no_pyobj_flags) def test_ceil(self, flags=enable_pyobj_flags): pyfunc = ceil x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [0, 0, 0, 0, 0, 0, 0.1, 1.9] self.run_unary(pyfunc, x_types, x_values, flags) def test_ceil_npm(self): self.test_ceil(flags=no_pyobj_flags) def test_trunc(self, flags=enable_pyobj_flags): pyfunc = trunc x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [0, 0, 0, 0, 0, 0, 0.1, 1.9] self.run_unary(pyfunc, x_types, x_values, flags) def test_trunc_npm(self): self.test_trunc(flags=no_pyobj_flags) def test_isnan(self): self.check_predicate_func(isnan, flags=enable_pyobj_flags) def test_isnan_npm(self): self.check_predicate_func(isnan, flags=no_pyobj_flags) def test_isinf(self): self.check_predicate_func(isinf, flags=enable_pyobj_flags) def test_isinf_npm(self): self.check_predicate_func(isinf, flags=no_pyobj_flags) def test_isfinite(self): self.check_predicate_func(isfinite, flags=enable_pyobj_flags) def test_isfinite_npm(self): self.check_predicate_func(isfinite, flags=no_pyobj_flags) def test_hypot(self, flags=enable_pyobj_flags): pyfunc = hypot x_types = [types.int64, types.uint64, types.float32, types.float64] x_values = [1, 2, 3, 4, 5, 6, .21, .34] y_values = [x + 2 for x in x_values] # Issue #563: precision issues with math.hypot() under Windows. prec = 'single' self.run_binary(pyfunc, x_types, x_values, y_values, flags, prec) # Check that values that overflow in naive implementations do not # in the numba impl def naive_hypot(x, y): return math.sqrt(x * x + y * y) for fltty in (types.float32, types.float64): cr = self.ccache.compile(pyfunc, (fltty, fltty), flags=flags) cfunc = cr.entry_point dt = numpy_support.as_dtype(fltty).type val = dt(np.finfo(dt).max / 30.) nb_ans = cfunc(val, val) self.assertPreciseEqual(nb_ans, pyfunc(val, val), prec='single') self.assertTrue(np.isfinite(nb_ans)) with warnings.catch_warnings(): warnings.simplefilter("error", RuntimeWarning) self.assertRaisesRegexp(RuntimeWarning, 'overflow encountered in .*_scalars', naive_hypot, val, val) def test_hypot_npm(self): self.test_hypot(flags=no_pyobj_flags) def test_degrees(self, flags=enable_pyobj_flags): pyfunc = degrees x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [1, 1, 1, 1, 1, 1, 1., 1.] self.run_unary(pyfunc, x_types, x_values, flags) def test_degrees_npm(self): self.test_degrees(flags=no_pyobj_flags) def test_radians(self, flags=enable_pyobj_flags): pyfunc = radians x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [1, 1, 1, 1, 1, 1, 1., 1.] self.run_unary(pyfunc, x_types, x_values, flags) def test_radians_npm(self): self.test_radians(flags=no_pyobj_flags) def test_erf(self, flags=enable_pyobj_flags): pyfunc = erf x_values = [1., 1., -1., -0.0, 0.0, 0.5, 5, float('inf')] x_types = [types.float32, types.float64] * (len(x_values) // 2) self.run_unary(pyfunc, x_types, x_values, flags, prec='double', ulps=2) def test_erf_npm(self): self.test_erf(flags=no_pyobj_flags) def test_erfc(self, flags=enable_pyobj_flags): pyfunc = erfc x_values = [1., 1., -1., -0.0, 0.0, 0.5, 5, float('inf')] x_types = [types.float32, types.float64] * (len(x_values) // 2) self.run_unary(pyfunc, x_types, x_values, flags, prec='double', ulps=4) def test_erfc_npm(self): self.test_erfc(flags=no_pyobj_flags) def test_gamma(self, flags=enable_pyobj_flags): pyfunc = gamma x_values = [1., -0.9, -0.5, 0.5] x_types = [types.float32, types.float64] * (len(x_values) // 2) self.run_unary(pyfunc, x_types, x_values, flags, prec='double', ulps=3) x_values = [-0.1, 0.1, 2.5, 10.1, 50., float('inf')] x_types = [types.float64] * len(x_values) self.run_unary(pyfunc, x_types, x_values, flags, prec='double', ulps=8) def test_gamma_npm(self): self.test_gamma(flags=no_pyobj_flags) def test_lgamma(self, flags=enable_pyobj_flags): pyfunc = lgamma x_values = [1., -0.9, -0.1, 0.1, 200., 1e10, 1e30, float('inf')] x_types = [types.float32, types.float64] * (len(x_values) // 2) self.run_unary(pyfunc, x_types, x_values, flags, prec='double') def test_lgamma_npm(self): self.test_lgamma(flags=no_pyobj_flags) def test_pow(self, flags=enable_pyobj_flags): pyfunc = pow x_types = [ types.int16, types.int32, types.int64, types.uint16, types.uint32, types.uint64, types.float32, types.float64 ] x_values = [-2, -1, -2, 2, 1, 2, .1, .2] y_values = [x * 2 for x in x_values] self.run_binary(pyfunc, x_types, x_values, y_values, flags) def test_gcd(self, flags=enable_pyobj_flags): from itertools import product, repeat, chain pyfunc = gcd signed_args = product(sorted(types.signed_domain), *repeat((-2, -1, 0, 1, 2, 7, 10), 2)) unsigned_args = product(sorted(types.unsigned_domain), *repeat((0, 1, 2, 7, 9, 16), 2)) x_types, x_values, y_values = zip(*chain(signed_args, unsigned_args)) self.run_binary(pyfunc, x_types, x_values, y_values, flags) def test_gcd_npm(self): self.test_gcd(flags=no_pyobj_flags) def test_pow_npm(self): self.test_pow(flags=no_pyobj_flags) def test_copysign(self, flags=enable_pyobj_flags): pyfunc = copysign value_types = [types.float32, types.float64] values = [ -2, -1, -0.0, 0.0, 1, 2, float('-inf'), float('inf'), float('nan') ] x_types, x_values, y_values = list( zip(*itertools.product(value_types, values, values))) self.run_binary(pyfunc, x_types, x_values, y_values, flags) def test_copysign_npm(self): self.test_copysign(flags=no_pyobj_flags) def test_frexp(self, flags=enable_pyobj_flags): pyfunc = frexp x_types = [types.float32, types.float64] x_values = [ -2.5, -0.0, 0.0, 3.5, float('-inf'), float('inf'), float('nan') ] self.run_unary(pyfunc, x_types, x_values, flags, prec='exact') def test_frexp_npm(self): self.test_frexp(flags=no_pyobj_flags) def test_ldexp(self, flags=enable_pyobj_flags): pyfunc = ldexp for fltty in (types.float32, types.float64): cr = self.ccache.compile(pyfunc, (fltty, types.int32), flags=flags) cfunc = cr.entry_point for args in [(2.5, -2), (2.5, 1), (0.0, 0), (0.0, 1), (-0.0, 0), (-0.0, 1), (float('inf'), 0), (float('-inf'), 0), (float('nan'), 0)]: msg = 'for input %r' % (args, ) self.assertPreciseEqual(cfunc(*args), pyfunc(*args)) def test_ldexp_npm(self): self.test_ldexp(flags=no_pyobj_flags)
class TestUFuncs(TestCase): def setUp(self): self.inputs = [ (0, types.uint32), (1, types.uint32), (-1, types.int32), (0, types.int32), (1, types.int32), (0, types.uint64), (1, types.uint64), (-1, types.int64), (0, types.int64), (1, types.int64), (-0.5, types.float32), (0.0, types.float32), (0.5, types.float32), (-0.5, types.float64), (0.0, types.float64), (0.5, types.float64), (np.array([0,1], dtype='u4'), types.Array(types.uint32, 1, 'C')), (np.array([0,1], dtype='u8'), types.Array(types.uint64, 1, 'C')), (np.array([-1,0,1], dtype='i4'), types.Array(types.int32, 1, 'C')), (np.array([-1,0,1], dtype='i8'), types.Array(types.int64, 1, 'C')), (np.array([-0.5, 0.0, 0.5], dtype='f4'), types.Array(types.float32, 1, 'C')), (np.array([-0.5, 0.0, 0.5], dtype='f8'), types.Array(types.float64, 1, 'C')), ] self.cache = CompilationCache() def unary_ufunc_test(self, ufunc_name, flags=enable_pyobj_flags, skip_inputs=[], additional_inputs=[], int_output_type=None, float_output_type=None): ufunc = _make_unary_ufunc_usecase(ufunc_name) inputs = list(self.inputs) inputs.extend(additional_inputs) pyfunc = ufunc for input_tuple in inputs: input_operand = input_tuple[0] input_type = input_tuple[1] if input_type in skip_inputs: continue ty = input_type if isinstance(ty, types.Array): ty = ty.dtype if ty in types.signed_domain: if int_output_type: output_type = types.Array(int_output_type, 1, 'C') else: output_type = types.Array(types.int64, 1, 'C') elif ty in types.unsigned_domain: if int_output_type: output_type = types.Array(int_output_type, 1, 'C') else: output_type = types.Array(types.uint64, 1, 'C') else: if float_output_type: output_type = types.Array(float_output_type, 1, 'C') else: output_type = types.Array(types.float64, 1, 'C') # Due to __ftol2 llvm bug, skip testing uint64 output on windows. # (llvm translates fptoui call to ftol2 call on windows which # causes a crash later. if iswindows and output_type.dtype is types.uint64: continue cr = self.cache.compile(pyfunc, (input_type, output_type), flags=flags) cfunc = cr.entry_point if isinstance(input_operand, np.ndarray): result = np.zeros(input_operand.size, dtype=output_type.dtype.name) expected = np.zeros(input_operand.size, dtype=output_type.dtype.name) else: result = np.zeros(1, dtype=output_type.dtype.name) expected = np.zeros(1, dtype=output_type.dtype.name) invalid_flag = False with warnings.catch_warnings(record=True) as warnlist: warnings.simplefilter('always') pyfunc(input_operand, expected) warnmsg = "invalid value encountered" for thiswarn in warnlist: if (issubclass(thiswarn.category, RuntimeWarning) and str(thiswarn.message).startswith(warnmsg)): invalid_flag = True cfunc(input_operand, result) # Need special checks if NaNs are in results if np.isnan(expected).any() or np.isnan(result).any(): self.assertTrue(np.allclose(np.isnan(result), np.isnan(expected))) if not np.isnan(expected).all() and not np.isnan(result).all(): self.assertTrue(np.allclose(result[np.invert(np.isnan(result))], expected[np.invert(np.isnan(expected))])) else: match = np.all(result == expected) or np.allclose(result, expected) if not match: if invalid_flag: # Allow output to mismatch for invalid input print("Output mismatch for invalid input", input_tuple, result, expected) else: self.fail("%s != %s" % (result, expected)) def binary_ufunc_test(self, ufunc_name, flags=enable_pyobj_flags, skip_inputs=[], additional_inputs=[], int_output_type=None, float_output_type=None): ufunc = _make_binary_ufunc_usecase(ufunc_name) # ufunc = globals()[ufunc_name + '_usecase'] inputs = list(self.inputs) + additional_inputs pyfunc = ufunc for input_tuple in inputs: input_operand = input_tuple[0] input_type = input_tuple[1] if input_type in skip_inputs: continue ty = input_type if isinstance(ty, types.Array): ty = ty.dtype if ty in types.signed_domain: if int_output_type: output_type = types.Array(int_output_type, 1, 'C') else: output_type = types.Array(types.int64, 1, 'C') elif ty in types.unsigned_domain: if int_output_type: output_type = types.Array(int_output_type, 1, 'C') else: output_type = types.Array(types.uint64, 1, 'C') else: if float_output_type: output_type = types.Array(float_output_type, 1, 'C') else: output_type = types.Array(types.float64, 1, 'C') # Due to __ftol2 llvm bug, skip testing uint64 output on windows. # (llvm translates fptoui call to ftol2 call on windows which # causes a crash later. if iswindows and output_type.dtype is types.uint64: continue cr = self.cache.compile(pyfunc, (input_type, input_type, output_type), flags=flags) cfunc = cr.entry_point if isinstance(input_operand, np.ndarray): result = np.zeros(input_operand.size, dtype=output_type.dtype.name) expected = np.zeros(input_operand.size, dtype=output_type.dtype.name) else: result = np.zeros(1, dtype=output_type.dtype.name) expected = np.zeros(1, dtype=output_type.dtype.name) cfunc(input_operand, input_operand, result) pyfunc(input_operand, input_operand, expected) # Need special checks if NaNs are in results if np.isnan(expected).any() or np.isnan(result).any(): self.assertTrue(np.allclose(np.isnan(result), np.isnan(expected))) if not np.isnan(expected).all() and not np.isnan(result).all(): self.assertTrue(np.allclose(result[np.invert(np.isnan(result))], expected[np.invert(np.isnan(expected))])) else: self.assertTrue(np.all(result == expected) or np.allclose(result, expected)) def unary_int_ufunc_test(self, name=None, flags=enable_pyobj_flags): self.unary_ufunc_test(name, flags=flags, skip_inputs=[types.float32, types.float64, types.Array(types.float32, 1, 'C'), types.Array(types.float64, 1, 'C')]) def binary_int_ufunc_test(self, name=None, flags=enable_pyobj_flags): self.binary_ufunc_test(name, flags=flags, skip_inputs=[types.float32, types.float64, types.Array(types.float32, 1, 'C'), types.Array(types.float64, 1, 'C')]) ############################################################################ # Math operations def test_add_ufunc(self, flags=enable_pyobj_flags): self.binary_ufunc_test('add', flags=flags) def test_add_ufunc_npm(self): self.test_add_ufunc(flags=no_pyobj_flags) def test_subtract_ufunc(self, flags=enable_pyobj_flags): self.binary_ufunc_test('subtract', flags=flags) def test_subtract_ufunc_npm(self): self.test_subtract_ufunc(flags=no_pyobj_flags) def test_multiply_ufunc(self, flags=enable_pyobj_flags): self.binary_ufunc_test('multiply', flags=flags) def test_multiply_ufunc_npm(self): self.test_multiply_ufunc(flags=no_pyobj_flags) def test_divide_ufunc(self, flags=enable_pyobj_flags): # Bear in mind that in python3 divide IS true_divide # so the out type for int types will be a double int_out_type = None if PYVERSION >= (3, 0): int_out_type = types.float64 self.binary_ufunc_test('divide', flags=flags, int_output_type=int_out_type) def test_divide_ufunc_npm(self): self.test_divide_ufunc(flags=no_pyobj_flags) def test_logaddexp_ufunc(self): self.binary_ufunc_test('logaddexp') @_unimplemented def test_logaddexp_ufunc_npm(self): self.binary_ufunc_test('logaddexp', flags=no_pyobj_flags) def test_logaddexp2_ufunc(self): self.binary_ufunc_test('logaddexp2') @_unimplemented def test_logaddexp2_ufunc_npm(self): self.binary_ufunc_test('logaddexp2', flags=no_pyobj_flags) def test_true_divide_ufunc(self, flags=enable_pyobj_flags): self.binary_ufunc_test('true_divide', flags=flags, int_output_type=types.float64) def test_true_divide_ufunc_npm(self): self.test_true_divide_ufunc(flags=no_pyobj_flags) def test_floor_divide_ufunc(self): self.binary_ufunc_test('floor_divide') @_unimplemented def test_floor_divide_ufunc_npm(self): self.binary_ufunc_test('floor_divide', flags=no_pyobj_flags) def test_negative_ufunc(self, flags=enable_pyobj_flags): # NumPy ufunc has bug with uint32 as input and int64 as output, # so skip uint32 input. self.unary_ufunc_test('negative', int_output_type=types.int64, skip_inputs=[types.Array(types.uint32, 1, 'C')], flags=flags) def test_negative_ufunc_npm(self): self.test_negative_ufunc(flags=no_pyobj_flags) def test_power_ufunc(self): self.binary_ufunc_test('power') def test_power_ufunc_npm(self): self.binary_ufunc_test('power', flags=no_pyobj_flags) def test_remainder_ufunc(self): self.binary_ufunc_test('remainder') @_unimplemented def test_remainder_ufunc_npm(self): self.binary_ufunc_test('remainder', flags=no_pyobj_flags) def test_mod_ufunc(self): self.binary_ufunc_test('mod') @_unimplemented def test_mod_ufunc_npm(self): self.binary_ufunc_test('mod', flags=no_pyobj_flags) def test_fmod_ufunc(self): self.binary_ufunc_test('fmod') @_unimplemented def test_fmod_ufunc_npm(self): self.binary_ufunc_test('fmod', flags=no_pyobj_flags) def test_abs_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('abs', flags=flags, additional_inputs = [(np.iinfo(np.uint32).max, types.uint32), (np.iinfo(np.uint64).max, types.uint64), (np.finfo(np.float32).min, types.float32), (np.finfo(np.float64).min, types.float64) ]) @_unimplemented def test_abs_ufunc_npm(self): self.test_abs_ufunc(flags=no_pyobj_flags) def test_absolute_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('absolute', flags=flags, additional_inputs = [(np.iinfo(np.uint32).max, types.uint32), (np.iinfo(np.uint64).max, types.uint64), (np.finfo(np.float32).min, types.float32), (np.finfo(np.float64).min, types.float64) ]) @_unimplemented def test_absolute_ufunc_npm(self): self.test_absolute_ufunc(flags=no_pyobj_flags) def test_rint_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('rint', flags=flags) @_unimplemented def test_rint_ufunc_npm(self): self.test_rint_ufunc(flags=no_pyobj_flags) def test_sign_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('sign', flags=flags) def test_sign_ufunc_npm(self): self.test_sign_ufunc(flags=no_pyobj_flags) def test_conj_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('conj', flags=flags) @_unimplemented def test_conj_ufunc_npm(self): self.test_conj_ufunc(flags=no_pyobj_flags) def test_exp_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('exp', flags=flags) def test_exp_ufunc_npm(self): self.test_exp_ufunc(flags=no_pyobj_flags) def test_exp2_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('exp2', flags=flags) def test_exp2_ufunc_npm(self): self.test_exp2_ufunc(flags=no_pyobj_flags) def test_log_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('log', flags=flags) def test_log_ufunc_npm(self): self.test_log_ufunc(flags=no_pyobj_flags) def test_log2_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('log2', flags=flags) def test_log2_ufunc_npm(self): self.test_log2_ufunc(flags=no_pyobj_flags) def test_log10_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('log10', flags=flags) def test_log10_ufunc_npm(self): self.test_log10_ufunc(flags=no_pyobj_flags) def test_expm1_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('expm1', flags=flags) def test_expm1_ufunc_npm(self): self.test_expm1_ufunc(flags=no_pyobj_flags) def test_log1p_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('log1p', flags=flags) def test_log1p_ufunc_npm(self): self.test_log1p_ufunc(flags=no_pyobj_flags) def test_sqrt_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('sqrt', flags=flags) def test_sqrt_ufunc_npm(self): self.test_sqrt_ufunc(flags=no_pyobj_flags) def test_square_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('square', flags=flags) @_unimplemented def test_square_ufunc_npm(self): self.test_square_ufunc(flags=no_pyobj_flags) def test_reciprocal_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('reciprocal', flags=flags) @_unimplemented def test_reciprocal_ufunc_npm(self): self.test_reciprocal_ufunc(flags=no_pyobj_flags) def test_conjugate_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('reciprocal', flags=flags) @_unimplemented def test_conjugate_ufunc_npm(self): self.test_reciprocal_ufunc(flags=no_pyobj_flags) ############################################################################ # Trigonometric Functions def test_sin_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('sin', flags=flags) def test_sin_ufunc_npm(self): self.test_sin_ufunc(flags=no_pyobj_flags) def test_cos_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('cos', flags=flags) def test_cos_ufunc_npm(self): self.test_cos_ufunc(flags=no_pyobj_flags) def test_tan_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('tan', flags=flags) def test_tan_ufunc_npm(self): self.test_tan_ufunc(flags=no_pyobj_flags) def test_arcsin_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('arcsin', flags=flags) def test_arcsin_ufunc_npm(self): self.test_arcsin_ufunc(flags=no_pyobj_flags) def test_arccos_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('arccos', flags=flags) def test_arccos_ufunc_npm(self): self.test_arccos_ufunc(flags=no_pyobj_flags) def test_arctan_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('arctan', flags=flags) def test_arctan_ufunc_npm(self): self.test_arctan_ufunc(flags=no_pyobj_flags) def test_arctan2_ufunc(self): self.binary_ufunc_test('arctan2') def test_arctan2_ufunc_npm(self): self.binary_ufunc_test('arctan2', flags=no_pyobj_flags) def test_hypot_ufunc(self): self.binary_ufunc_test('hypot') @_unimplemented def test_hypot_ufunc_npm(self): self.binary_ufunc_test('hypot', flags=no_pyobj_flags) def test_sinh_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('sinh', flags=flags) def test_sinh_ufunc_npm(self): self.test_sinh_ufunc(flags=no_pyobj_flags) def test_cosh_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('cosh', flags=flags) def test_cosh_ufunc_npm(self): self.test_cosh_ufunc(flags=no_pyobj_flags) def test_tanh_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('tanh', flags=flags) def test_tanh_ufunc_npm(self): self.test_tanh_ufunc(flags=no_pyobj_flags) def test_arcsinh_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('arcsinh', flags=flags) def test_arcsinh_ufunc_npm(self): self.test_arcsinh_ufunc(flags=no_pyobj_flags) def test_arccosh_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('arccosh', flags=flags) def test_arccosh_ufunc_npm(self): self.test_arccosh_ufunc(flags=no_pyobj_flags) def test_arctanh_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('arctanh', flags=flags) def test_arctanh_ufunc_npm(self): self.test_arctanh_ufunc(flags=no_pyobj_flags) def test_deg2rad_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('deg2rad', flags=flags) def test_deg2rad_ufunc_npm(self): self.test_deg2rad_ufunc(flags=no_pyobj_flags) def test_rad2deg_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('rad2deg', flags=flags) def test_rad2deg_ufunc_npm(self): self.test_rad2deg_ufunc(flags=no_pyobj_flags) def test_degrees_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('degrees', flags=flags) @_unimplemented def test_degrees_ufunc_npm(self): self.test_degrees_ufunc(flags=no_pyobj_flags) def test_radians_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('radians', flags=flags) @_unimplemented def test_radians_ufunc_npm(self): self.test_radians_ufunc(flags=no_pyobj_flags) ############################################################################ # Bit-twiddling Functions def test_bitwise_and_ufunc(self): self.binary_int_ufunc_test('bitwise_and') @_unimplemented def test_bitwise_and_ufunc_npm(self): self.binary_int_ufunc_test('bitwise_and', flags=no_pyobj_flags) def test_bitwise_or_ufunc(self): self.binary_int_ufunc_test('bitwise_or') @_unimplemented def test_bitwise_or_ufunc_npm(self): self.binary_int_ufunc_test('bitwise_or', flags=no_pyobj_flags) def test_bitwise_xor_ufunc(self): self.binary_int_ufunc_test('bitwise_xor') @_unimplemented def test_bitwise_xor_ufunc_npm(self): self.binary_int_ufunc_test('bitwise_xor', flags=no_pyobj_flags) def test_invert_ufunc(self, flags=enable_pyobj_flags): self.unary_int_ufunc_test('invert', flags=flags) @_unimplemented def test_invert_ufunc_npm(self): self.test_invert_ufunc(flags=no_pyobj_flags) def test_bitwise_not_ufunc(self, flags=enable_pyobj_flags): self.unary_int_ufunc_test('bitwise_not', flags=flags) @_unimplemented def test_bitwise_not_ufunc_npm(self): self.test_bitwise_not_ufunc(flags=no_pyobj_flags) def test_left_shift_ufunc(self): self.binary_int_ufunc_test('left_shift') @_unimplemented def test_left_shift_ufunc_npm(self): self.binary_int_ufunc_test('left_shift', flags=no_pyobj_flags) def test_right_shift_ufunc(self): self.binary_int_ufunc_test('right_shift') @_unimplemented def test_right_shift_ufunc_npm(self): self.binary_int_ufunc_test('right_shift', flags=no_pyobj_flags) ############################################################################ # Comparison functions def test_greater_ufunc(self): self.binary_ufunc_test('greater') @_unimplemented def test_greater_ufunc_npm(self): self.binary_ufunc_test('greater', flags=no_pyobj_flags) def test_greater_equal_ufunc(self): self.binary_ufunc_test('greater_equal') @_unimplemented def test_greater_equal_ufunc_npm(self): self.binary_ufunc_test('greater_equal', flags=no_pyobj_flags) def test_less_ufunc(self): self.binary_ufunc_test('less') @_unimplemented def test_less_ufunc_npm(self): self.binary_ufunc_test('less', flags=no_pyobj_flags) def test_less_equal_ufunc(self): self.binary_ufunc_test('less_equal') @_unimplemented def test_less_equal_ufunc_npm(self): self.binary_ufunc_test('less_equal', flags=no_pyobj_flags) def test_not_equal_ufunc(self): self.binary_ufunc_test('not_equal') @_unimplemented def test_not_equal_ufunc_npm(self): self.binary_ufunc_test('not_equal', flags=no_pyobj_flags) def test_equal_ufunc(self): self.binary_ufunc_test('equal') @_unimplemented def test_equal_ufunc_npm(self): self.binary_ufunc_test('equal', flags=no_pyobj_flags) def test_logical_and_ufunc(self): self.binary_ufunc_test('logical_and') @_unimplemented def test_logical_and_ufunc_npm(self): self.binary_ufunc_test('logical_and', flags=no_pyobj_flags) def test_logical_or_ufunc(self): self.binary_ufunc_test('logical_or') @_unimplemented def test_logical_or_ufunc_npm(self): self.binary_ufunc_test('logical_or', flags=no_pyobj_flags) def test_logical_xor_ufunc(self): self.binary_ufunc_test('logical_xor') @_unimplemented def test_logical_xor_ufunc_npm(self): self.binary_ufunc_test('logical_xor', flags=no_pyobj_flags) #logical_not support should be coming soon def test_logical_not_ufunc(self): self.unary_ufunc_test('logical_not') @_unimplemented def test_logical_not_ufunc_npm(self): self.unary_ufunc_test('logical_not', flags=no_pyobj_flags) def test_maximum_ufunc(self): self.binary_ufunc_test('maximum') @_unimplemented def test_maximum_ufunc_npm(self): self.binary_ufunc_test('maximum', flags=no_pyobj_flags) def test_minimum_ufunc(self): self.binary_ufunc_test('minimum') @_unimplemented def test_minimum_ufunc_npm(self): self.binary_ufunc_test('minimum', flags=no_pyobj_flags) def test_fmax_ufunc(self): self.binary_ufunc_test('fmax') @_unimplemented def test_fmax_ufunc_npm(self): self.binary_ufunc_test('fmax', flags=no_pyobj_flags) def test_fmin_ufunc(self): self.binary_ufunc_test('fmin') @_unimplemented def test_fmin_ufunc_npm(self): self.binary_ufunc_test('fmin', flags=no_pyobj_flags) ############################################################################ # Floating functions def test_isfinite_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('isfinite', flags=flags) @_unimplemented def test_isfinite_ufunc_npm(self): self.test_isfinite_ufunc(flags=no_pyobj_flags) def test_isinf_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('isinf', flags=flags) @_unimplemented def test_isinf_ufunc_npm(self): self.test_isinf_ufunc(flags=no_pyobj_flags) def test_isnan_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('isnan', flags=flags) @_unimplemented def test_isnan_ufunc_npm(self): self.test_isnan_ufunc(flags=no_pyobj_flags) def test_signbit_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('signbit', flags=flags) @_unimplemented def test_signbit_ufunc_npm(self): self.test_signbit_ufunc(flags=no_pyobj_flags) def test_copysign_ufunc(self, flags=enable_pyobj_flags): self.binary_ufunc_test('copysign') def test_copysign_ufunc_npm(self): self.test_copysign_ufunc(flags=no_pyobj_flags) @_unimplemented def test_nextafter_ufunc(self, flags=enable_pyobj_flags): self.binary_ufunc_test('nextafter', flags=flags) @_unimplemented def test_nextafter_ufunc_npm(self): self.test_nextafter_ufunc(flags=no_pyobj_flags) def test_modf_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('modf', flags=flags) @_unimplemented def test_modf_ufunc_npm(self): self.test_modf_ufunc(flags=no_pyobj_flags) # FIXME - ldexp does not have homogeneous arguments, so the usual tests won't # work as they reuse both inputs @unittest.skipIf(is32bits or iswindows, "Some types are not supported on " "32-bit " "platform") @unittest.skip("this test needs fixing") def test_ldexp_ufunc(self): self.binary_int_ufunc_test('ldexp') # FIXME @unittest.skipIf(is32bits or iswindows, "Some types are not supported on 32-bit platform") @unittest.skip("this tests needs fixing") def test_ldexp_ufunc_npm(self): self.binary_int_ufunc_test('ldexp', flags=no_pyobj_flags) def test_frexp_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('frexp', flags=flags) @_unimplemented def test_frexp_ufunc_npm(self): self.test_frexp_ufunc(flags=no_pyobj_flags) def test_floor_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('floor', flags=flags) def test_floor_ufunc_npm(self): self.test_floor_ufunc(flags=no_pyobj_flags) def test_ceil_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('ceil', flags=flags) def test_ceil_ufunc_npm(self): self.test_ceil_ufunc(flags=no_pyobj_flags) def test_trunc_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('trunc', flags=flags) def test_trunc_ufunc_npm(self): self.test_trunc_ufunc(flags=no_pyobj_flags) def test_spacing_ufunc(self, flags=enable_pyobj_flags): self.unary_ufunc_test('spacing', flags=flags) @_unimplemented def test_spacing_ufunc_npm(self): self.test_spacing_ufunc(flags=nopyobj_flags) ############################################################################ # Other tests def test_binary_ufunc_performance(self): pyfunc = _make_binary_ufunc_usecase('add') arraytype = types.Array(types.float32, 1, 'C') cr = compile_isolated(pyfunc, (arraytype, arraytype, arraytype)) cfunc = cr.entry_point nelem = 5000 x_operand = np.arange(nelem, dtype=np.float32) y_operand = np.arange(nelem, dtype=np.float32) control = np.empty_like(x_operand) result = np.empty_like(x_operand) def bm_python(): pyfunc(x_operand, y_operand, control) def bm_numba(): cfunc(x_operand, y_operand, result) print(utils.benchmark(bm_python, maxsec=.1)) print(utils.benchmark(bm_numba, maxsec=.1)) assert np.allclose(control, result) def binary_ufunc_mixed_types_test(self, ufunc_name, flags=enable_pyobj_flags): ufunc = _make_binary_ufunc_usecase(ufunc_name) #ufunc = globals()[ufunc_name + '_usecase'] inputs1 = [ (1, types.uint64), (-1, types.int64), (0.5, types.float64), (np.array([0, 1], dtype='u8'), types.Array(types.uint64, 1, 'C')), (np.array([-1, 1], dtype='i8'), types.Array(types.int64, 1, 'C')), (np.array([-0.5, 0.5], dtype='f8'), types.Array(types.float64, 1, 'C'))] inputs2 = inputs1 output_types = [types.Array(types.int64, 1, 'C'), types.Array(types.float64, 1, 'C')] pyfunc = ufunc for input1, input2, output_type in itertools.product(inputs1, inputs2, output_types): input1_operand = input1[0] input1_type = input1[1] input2_operand = input2[0] input2_type = input2[1] # Skip division by unsigned int because of NumPy bugs if ufunc_name == 'divide' and (input2_type == types.Array(types.uint32, 1, 'C') or input2_type == types.Array(types.uint64, 1, 'C')): continue # Skip some subtraction tests because of NumPy bugs if ufunc_name == 'subtract' and input1_type == types.Array(types.uint32, 1, 'C') and \ input2_type == types.uint32 and types.Array(types.int64, 1, 'C'): continue if ufunc_name == 'subtract' and input1_type == types.Array(types.uint32, 1, 'C') and \ input2_type == types.uint64 and types.Array(types.int64, 1, 'C'): continue if ((isinstance(input1_type, types.Array) or isinstance(input2_type, types.Array)) and not isinstance(output_type, types.Array)): continue cr = self.cache.compile(pyfunc, (input1_type, input2_type, output_type), flags=flags) cfunc = cr.entry_point if isinstance(input1_operand, np.ndarray): result = np.zeros(input1_operand.size, dtype=output_type.dtype.name) expected = np.zeros(input1_operand.size, dtype=output_type.dtype.name) elif isinstance(input2_operand, np.ndarray): result = np.zeros(input2_operand.size, dtype=output_type.dtype.name) expected = np.zeros(input2_operand.size, dtype=output_type.dtype.name) else: result = np.zeros(1, dtype=output_type.dtype.name) expected = np.zeros(1, dtype=output_type.dtype.name) cfunc(input1_operand, input2_operand, result) pyfunc(input1_operand, input2_operand, expected) # Need special checks if NaNs are in results if np.isnan(expected).any() or np.isnan(result).any(): self.assertTrue(np.allclose(np.isnan(result), np.isnan(expected))) if not np.isnan(expected).all() and not np.isnan(result).all(): self.assertTrue(np.allclose(result[np.invert(np.isnan(result))], expected[np.invert(np.isnan(expected))])) else: self.assertTrue(np.all(result == expected) or np.allclose(result, expected)) def test_mixed_types(self): self.binary_ufunc_mixed_types_test('divide', flags=no_pyobj_flags) def test_broadcasting(self): # Test unary ufunc pyfunc = _make_unary_ufunc_usecase('negative') input_operands = [ np.arange(3, dtype='i8'), np.arange(3, dtype='i8').reshape(3,1), np.arange(3, dtype='i8').reshape(1,3), np.arange(3, dtype='i8').reshape(3,1), np.arange(3, dtype='i8').reshape(1,3), np.arange(3*3, dtype='i8').reshape(3,3)] output_operands = [ np.zeros(3*3, dtype='i8').reshape(3,3), np.zeros(3*3, dtype='i8').reshape(3,3), np.zeros(3*3, dtype='i8').reshape(3,3), np.zeros(3*3*3, dtype='i8').reshape(3,3,3), np.zeros(3*3*3, dtype='i8').reshape(3,3,3), np.zeros(3*3*3, dtype='i8').reshape(3,3,3)] for x, result in zip(input_operands, output_operands): input_type = types.Array(types.uint64, x.ndim, 'C') output_type = types.Array(types.int64, result.ndim, 'C') cr = self.cache.compile(pyfunc, (input_type, output_type), flags=no_pyobj_flags) cfunc = cr.entry_point expected = np.zeros(result.shape, dtype=result.dtype) np.negative(x, expected) cfunc(x, result) self.assertTrue(np.all(result == expected)) # Test binary ufunc pyfunc = _make_binary_ufunc_usecase('add') input1_operands = [ np.arange(3, dtype='u8'), np.arange(3*3, dtype='u8').reshape(3,3), np.arange(3*3*3, dtype='u8').reshape(3,3,3), np.arange(3, dtype='u8').reshape(3,1), np.arange(3, dtype='u8').reshape(1,3), np.arange(3, dtype='u8').reshape(3,1,1), np.arange(3*3, dtype='u8').reshape(3,3,1), np.arange(3*3, dtype='u8').reshape(3,1,3), np.arange(3*3, dtype='u8').reshape(1,3,3)] input2_operands = input1_operands for x, y in itertools.product(input1_operands, input2_operands): input1_type = types.Array(types.uint64, x.ndim, 'C') input2_type = types.Array(types.uint64, y.ndim, 'C') output_type = types.Array(types.uint64, max(x.ndim, y.ndim), 'C') cr = self.cache.compile(pyfunc, (input1_type, input2_type, output_type), flags=no_pyobj_flags) cfunc = cr.entry_point expected = np.add(x, y) result = np.zeros(expected.shape, dtype='u8') cfunc(x, y, result) self.assertTrue(np.all(result == expected))
def setUp(self): super(TestArrayIterators, self).setUp() self.ccache = CompilationCache()
class TestArrayIterators(MemoryLeakMixin, TestCase): """ Test array.flat, np.ndenumerate(), etc. """ def setUp(self): super(TestArrayIterators, self).setUp() self.ccache = CompilationCache() def check_array_iter_1d(self, arr): pyfunc = array_iter cres = compile_isolated(pyfunc, [typeof(arr)]) cfunc = cres.entry_point expected = pyfunc(arr) self.assertPreciseEqual(cfunc(arr), expected) def check_array_iter_items(self, arr): pyfunc = array_iter_items cres = compile_isolated(pyfunc, [typeof(arr)]) cfunc = cres.entry_point expected = pyfunc(arr) self.assertPreciseEqual(cfunc(arr), expected) def check_array_view_iter(self, arr, index): pyfunc = array_view_iter cres = compile_isolated(pyfunc, [typeof(arr), typeof(index)]) cfunc = cres.entry_point expected = pyfunc(arr, index) self.assertPreciseEqual(cfunc(arr, index), expected) def check_array_flat(self, arr, arrty=None): out = np.zeros(arr.size, dtype=arr.dtype) nb_out = out.copy() if arrty is None: arrty = typeof(arr) cres = compile_isolated(array_flat, [arrty, typeof(out)]) cfunc = cres.entry_point array_flat(arr, out) cfunc(arr, nb_out) self.assertPreciseEqual(out, nb_out) def check_array_unary(self, arr, arrty, func): cres = compile_isolated(func, [arrty]) cfunc = cres.entry_point self.assertPreciseEqual(cfunc(arr), func(arr)) def check_array_flat_sum(self, arr, arrty): self.check_array_unary(arr, arrty, array_flat_sum) def check_array_ndenumerate_sum(self, arr, arrty): self.check_array_unary(arr, arrty, array_ndenumerate_sum) def test_array_iter(self): # Test iterating over a 1d array arr = np.arange(6) self.check_array_iter_1d(arr) self.check_array_iter_items(arr) arr = arr[::2] self.assertFalse(arr.flags.c_contiguous) self.assertFalse(arr.flags.f_contiguous) self.check_array_iter_1d(arr) self.check_array_iter_items(arr) arr = np.bool_([1, 0, 0, 1]) self.check_array_iter_1d(arr) self.check_array_iter_items(arr) arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) self.check_array_iter_items(arr) self.check_array_iter_items(arr.T) def test_array_view_iter(self): # Test iterating over a 1d view over a 2d array arr = np.arange(12).reshape((3, 4)) self.check_array_view_iter(arr, 1) self.check_array_view_iter(arr.T, 1) arr = arr[::2] self.check_array_view_iter(arr, 1) arr = np.bool_([1, 0, 0, 1]).reshape((2, 2)) self.check_array_view_iter(arr, 1) def test_array_flat_3d(self): arr = np.arange(24).reshape(4, 2, 3) arrty = typeof(arr) self.assertEqual(arrty.ndim, 3) self.assertEqual(arrty.layout, 'C') self.assertTrue(arr.flags.c_contiguous) # Test with C-contiguous array self.check_array_flat(arr) # Test with Fortran-contiguous array arr = arr.transpose() self.assertFalse(arr.flags.c_contiguous) self.assertTrue(arr.flags.f_contiguous) self.assertEqual(typeof(arr).layout, 'F') self.check_array_flat(arr) # Test with non-contiguous array arr = arr[::2] self.assertFalse(arr.flags.c_contiguous) self.assertFalse(arr.flags.f_contiguous) self.assertEqual(typeof(arr).layout, 'A') self.check_array_flat(arr) # Boolean array arr = np.bool_([1, 0, 0, 1] * 2).reshape((2, 2, 2)) self.check_array_flat(arr) def test_array_flat_empty(self): # Test .flat with various shapes of empty arrays, contiguous # and non-contiguous (see issue #846). arr = np.zeros(0, dtype=np.int32) arr = arr.reshape(0, 2) arrty = types.Array(types.int32, 2, layout='C') self.check_array_flat_sum(arr, arrty) arrty = types.Array(types.int32, 2, layout='F') self.check_array_flat_sum(arr, arrty) arrty = types.Array(types.int32, 2, layout='A') self.check_array_flat_sum(arr, arrty) arr = arr.reshape(2, 0) arrty = types.Array(types.int32, 2, layout='C') self.check_array_flat_sum(arr, arrty) arrty = types.Array(types.int32, 2, layout='F') self.check_array_flat_sum(arr, arrty) arrty = types.Array(types.int32, 2, layout='A') self.check_array_flat_sum(arr, arrty) def test_array_flat_getitem(self): # Test indexing of array.flat object pyfunc = array_flat_getitem def check(arr, ind): cr = self.ccache.compile(pyfunc, (typeof(arr), typeof(ind))) expected = pyfunc(arr, ind) self.assertEqual(cr.entry_point(arr, ind), expected) arr = np.arange(24).reshape(4, 2, 3) for i in range(arr.size): check(arr, i) arr = arr.T for i in range(arr.size): check(arr, i) arr = arr[::2] for i in range(arr.size): check(arr, i) arr = np.array([42]).reshape(()) for i in range(arr.size): check(arr, i) # Boolean array arr = np.bool_([1, 0, 0, 1]) for i in range(arr.size): check(arr, i) arr = arr[::2] for i in range(arr.size): check(arr, i) def test_array_flat_setitem(self): # Test indexing of array.flat object pyfunc = array_flat_setitem def check(arr, ind): arrty = typeof(arr) cr = self.ccache.compile(pyfunc, (arrty, typeof(ind), arrty.dtype)) # Use np.copy() to keep the layout expected = np.copy(arr) got = np.copy(arr) pyfunc(expected, ind, 123) cr.entry_point(got, ind, 123) self.assertPreciseEqual(got, expected) arr = np.arange(24).reshape(4, 2, 3) for i in range(arr.size): check(arr, i) arr = arr.T for i in range(arr.size): check(arr, i) arr = arr[::2] for i in range(arr.size): check(arr, i) arr = np.array([42]).reshape(()) for i in range(arr.size): check(arr, i) # Boolean array arr = np.bool_([1, 0, 0, 1]) for i in range(arr.size): check(arr, i) arr = arr[::2] for i in range(arr.size): check(arr, i) def test_array_flat_len(self): # Test len(array.flat) pyfunc = array_flat_len def check(arr): cr = self.ccache.compile(pyfunc, (typeof(arr), )) expected = pyfunc(arr) self.assertPreciseEqual(cr.entry_point(arr), expected) arr = np.arange(24).reshape(4, 2, 3) check(arr) arr = arr.T check(arr) arr = arr[::2] check(arr) arr = np.array([42]).reshape(()) check(arr) def test_array_flat_premature_free(self): cres = compile_isolated(array_flat_premature_free, [types.intp]) cfunc = cres.entry_point expect = array_flat_premature_free(6) got = cfunc(6) self.assertTrue(got.sum()) self.assertPreciseEqual(expect, got) def test_array_ndenumerate_2d(self): arr = np.arange(12).reshape(4, 3) arrty = typeof(arr) self.assertEqual(arrty.ndim, 2) self.assertEqual(arrty.layout, 'C') self.assertTrue(arr.flags.c_contiguous) # Test with C-contiguous array self.check_array_ndenumerate_sum(arr, arrty) # Test with Fortran-contiguous array arr = arr.transpose() self.assertFalse(arr.flags.c_contiguous) self.assertTrue(arr.flags.f_contiguous) arrty = typeof(arr) self.assertEqual(arrty.layout, 'F') self.check_array_ndenumerate_sum(arr, arrty) # Test with non-contiguous array arr = arr[::2] self.assertFalse(arr.flags.c_contiguous) self.assertFalse(arr.flags.f_contiguous) arrty = typeof(arr) self.assertEqual(arrty.layout, 'A') self.check_array_ndenumerate_sum(arr, arrty) # Boolean array arr = np.bool_([1, 0, 0, 1]).reshape((2, 2)) self.check_array_ndenumerate_sum(arr, typeof(arr)) def test_array_ndenumerate_empty(self): arr = np.zeros(0, dtype=np.int32) arr = arr.reshape(0, 2) arrty = types.Array(types.int32, 2, layout='C') self.check_array_ndenumerate_sum(arr, arrty) arrty = types.Array(types.int32, 2, layout='F') self.check_array_ndenumerate_sum(arr, arrty) arrty = types.Array(types.int32, 2, layout='A') self.check_array_ndenumerate_sum(arr, arrty) arr = arr.reshape(2, 0) arrty = types.Array(types.int32, 2, layout='C') self.check_array_flat_sum(arr, arrty) arrty = types.Array(types.int32, 2, layout='F') self.check_array_flat_sum(arr, arrty) arrty = types.Array(types.int32, 2, layout='A') self.check_array_flat_sum(arr, arrty) def test_array_ndenumerate_premature_free(self): cres = compile_isolated(array_ndenumerate_premature_free, [types.intp]) cfunc = cres.entry_point expect = array_ndenumerate_premature_free(6) got = cfunc(6) self.assertTrue(got.sum()) self.assertPreciseEqual(expect, got) def test_np_ndindex(self): func = np_ndindex cres = compile_isolated(func, [types.int32, types.int32]) cfunc = cres.entry_point self.assertPreciseEqual(cfunc(3, 4), func(3, 4)) self.assertPreciseEqual(cfunc(3, 0), func(3, 0)) self.assertPreciseEqual(cfunc(0, 3), func(0, 3)) self.assertPreciseEqual(cfunc(0, 0), func(0, 0)) def test_np_ndindex_array(self): func = np_ndindex_array arr = np.arange(12, dtype=np.int32) + 10 self.check_array_unary(arr, typeof(arr), func) arr = arr.reshape((4, 3)) self.check_array_unary(arr, typeof(arr), func) arr = arr.reshape((2, 2, 3)) self.check_array_unary(arr, typeof(arr), func) def test_np_ndindex_empty(self): func = np_ndindex_empty cres = compile_isolated(func, []) cfunc = cres.entry_point self.assertPreciseEqual(cfunc(), func()) def test_iter_next(self): # This also checks memory management with iter() and next() func = iter_next arr = np.arange(12, dtype=np.int32) + 10 self.check_array_unary(arr, typeof(arr), func)
def setUp(self): super(TestArrayAttr, self).setUp() self.ccache = CompilationCache() self.a = np.arange(20, dtype=np.int32).reshape(4, 5)
class TestArrayAttr(MemoryLeakMixin, TestCase): def setUp(self): super(TestArrayAttr, self).setUp() self.ccache = CompilationCache() self.a = np.arange(20, dtype=np.int32).reshape(4, 5) def check_unary(self, pyfunc, arr): aryty = typeof(arr) cfunc = self.get_cfunc(pyfunc, (aryty,)) expected = pyfunc(arr) self.assertPreciseEqual(cfunc(arr), expected) # Retry with forced any layout cfunc = self.get_cfunc(pyfunc, (aryty.copy(layout='A'),)) self.assertPreciseEqual(cfunc(arr), expected) def check_unary_with_arrays(self, pyfunc,): self.check_unary(pyfunc, self.a) self.check_unary(pyfunc, self.a.T) self.check_unary(pyfunc, self.a[::2]) # 0-d array arr = np.array([42]).reshape(()) self.check_unary(pyfunc, arr) # array with an empty dimension arr = np.zeros(0) self.check_unary(pyfunc, arr) # check with reshape self.check_unary(pyfunc, arr.reshape((1, 0, 2))) def get_cfunc(self, pyfunc, argspec): cres = self.ccache.compile(pyfunc, argspec) return cres.entry_point def test_shape(self): pyfunc = array_shape cfunc = self.get_cfunc(pyfunc, (types.int32[:,:], types.int32)) for i in range(self.a.ndim): self.assertEqual(pyfunc(self.a, i), cfunc(self.a, i)) def test_strides(self): pyfunc = array_strides cfunc = self.get_cfunc(pyfunc, (types.int32[:,:], types.int32)) for i in range(self.a.ndim): self.assertEqual(pyfunc(self.a, i), cfunc(self.a, i)) def test_ndim(self): self.check_unary_with_arrays(array_ndim) def test_size(self): self.check_unary_with_arrays(array_size) def test_itemsize(self): self.check_unary_with_arrays(array_itemsize) def test_dtype(self): pyfunc = array_dtype self.check_unary(pyfunc, self.a) dtype = np.dtype([('x', np.int8), ('y', np.int8)]) arr = np.zeros(4, dtype=dtype) self.check_unary(pyfunc, arr) def test_use_dtype(self): # Test using the dtype attribute inside the Numba function itself b = np.empty(1, dtype=np.int16) pyfunc = use_dtype cfunc = self.get_cfunc(pyfunc, (typeof(self.a), typeof(b))) expected = pyfunc(self.a, b) self.assertPreciseEqual(cfunc(self.a, b), expected) def test_flags_contiguous(self): self.check_unary_with_arrays(array_flags_contiguous) def test_flags_c_contiguous(self): self.check_unary_with_arrays(array_flags_c_contiguous) def test_flags_f_contiguous(self): self.check_unary_with_arrays(array_flags_f_contiguous)
def setUp(self): self.ccache = CompilationCache()
class TestArrayMethods(MemoryLeakMixin, TestCase): """ Test various array methods and array-related functions. """ def setUp(self): super(TestArrayMethods, self).setUp() self.ccache = CompilationCache() 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): cres = compile_isolated(pyfunc, (ty, types.int32)) cfunc = cres.entry_point 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): cres = compile_isolated(pyfunc, (ty, )) cfunc = cres.entry_point 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): cres = compile_isolated(pyfunc, (types.Array( inty, 1, 'A'), types.int32, types.Array(outty, 1, 'A'))) cfunc = cres.entry_point check_round(cres.entry_point, values, inty, outty, 0) check_round(cres.entry_point, values, inty, outty, 1) if not isinstance(outty, types.Integer): check_round(cres.entry_point, 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_array_view(self): def run(arr, dtype): pyfunc = make_array_view(dtype) cres = self.ccache.compile(pyfunc, (typeof(arr), )) return cres.entry_point(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") 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)]) # 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_err(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_err(arr, dt2) check_err(arr, np.complex128) # F-contiguous arr = np.arange(24, dtype=np.int8).reshape((3, 8)).T check(arr, np.int8) check(arr, np.float32) check(arr, np.complex64) check(arr, dt1) check_err(arr, dt2) check_err(arr, np.complex128) # 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_err(arr, np.int8) check_err(arr, np.int16) check_err(arr, np.int64) check_err(arr, dt1) check_err(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_err(arr, np.int8) check_err(arr, np.int16) check_err(arr, np.int64) check_err(arr, dt1) check_err(arr, dt2) # 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 cres = self.ccache.compile(pyfunc, (types.uint8[:], )) cfunc = cres.entry_point 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) cres = self.ccache.compile(pyfunc, (typeof(arr), )) return cres.entry_point(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) # 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)) def check_np_frombuffer(self, pyfunc): def run(buf): cres = self.ccache.compile(pyfunc, (typeof(buf), )) return cres.entry_point(buf) def check(buf): old_refcnt = sys.getrefcount(buf) expected = pyfunc(buf) self.memory_leak_setup() got = run(buf) self.assertPreciseEqual(got, expected) del expected self.assertEqual(sys.getrefcount(buf), old_refcnt + 1) del got 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: run(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) self.assertIn('No match', excstr) self.assertIn( 'frombuffer(bytearray(uint8, 1d, C), dtype=unicode_type)', excstr) 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): cres = compile_isolated(pyfunc, (typeof(arr), )) expected = pyfunc(arr) got = cres.entry_point(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 test_np_asfortranarray(self): self.check_layout_dependent_func(np_asfortranarray) def test_np_ascontiguousarray(self): self.check_layout_dependent_func(np_ascontiguousarray) def check_np_frombuffer_allocated(self, pyfunc): def run(shape): cres = self.ccache.compile(pyfunc, (typeof(shape), )) return cres.entry_point(shape) def check(shape): expected = pyfunc(shape) got = run(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): cres = compile_isolated(pyfunc, (typeof(arr), )) expected = pyfunc(arr) expected = [a.copy() for a in expected] self.assertPreciseEqual(cres.entry_point(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) cres = compile_isolated(pyfunc, (typeof(arr), typeof(x), typeof(y))) expected = pyfunc(arr, x, y) got = cres.entry_point(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) cres = compile_isolated(pyfunc, (typeof(scal), typeof(x), typeof(y))) expected = pyfunc(scal, x, y) got = cres.entry_point(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_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(np.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(np.complex(1, 1), np.complex(4, 4), pyfunc, cfunc) check_ok(np.complex(4, 4), np.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, np.complex(4, 4), np.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, np.complex(4, 4), np.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_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, 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] 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], np.dtype(TIMEDELTA_M): [np.dtype(TIMEDELTA_M)] } 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, 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] 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], np.dtype(TIMEDELTA_M): [np.dtype(TIMEDELTA_M)], np.dtype(TIMEDELTA_Y): [np.dtype(TIMEDELTA_Y)] } 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(LoweringError) as raises: foo(a) errmsg = "'axis' entry 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 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))
def setUp(self): super(TestArrayMethods, self).setUp() self.ccache = CompilationCache()
class TestDataFlow(TestCase): def setUp(self): self.cache = CompilationCache() def test_assignments(self, flags=force_pyobj_flags): pyfunc = assignments cr = compile_isolated(pyfunc, (types.int32, ), flags=flags) cfunc = cr.entry_point for x in [-1, 0, 1]: self.assertPreciseEqual(pyfunc(x), cfunc(x)) def test_assignments2(self, flags=force_pyobj_flags): pyfunc = assignments2 cr = compile_isolated(pyfunc, (types.int32, ), flags=flags) cfunc = cr.entry_point for x in [-1, 0, 1]: self.assertPreciseEqual(pyfunc(x), cfunc(x)) if flags is force_pyobj_flags: cfunc("a") # The dataflow analysis must be good enough for native mode # compilation to succeed, hence the no_pyobj_flags in the following tests. def run_propagate_func(self, pyfunc, args): cr = self.cache.compile(pyfunc, (types.int32, types.int32), flags=no_pyobj_flags) cfunc = cr.entry_point self.assertPreciseEqual(cfunc(*args), pyfunc(*args)) def test_var_propagate1(self): self.run_propagate_func(var_propagate1, (2, 3)) self.run_propagate_func(var_propagate1, (3, 2)) def test_var_propagate2(self): self.run_propagate_func(var_propagate2, (2, 3)) self.run_propagate_func(var_propagate2, (3, 2)) def test_var_propagate3(self): self.run_propagate_func(var_propagate3, (2, 3)) self.run_propagate_func(var_propagate3, (3, 2)) self.run_propagate_func(var_propagate3, (2, 0)) self.run_propagate_func(var_propagate3, (-1, 0)) self.run_propagate_func(var_propagate3, (0, 2)) self.run_propagate_func(var_propagate3, (0, -1)) def test_var_propagate4(self): self.run_propagate_func(var_propagate4, (1, 1)) self.run_propagate_func(var_propagate4, (1, 0)) self.run_propagate_func(var_propagate4, (1, -1)) self.run_propagate_func(var_propagate4, (0, 1)) self.run_propagate_func(var_propagate4, (0, 0)) self.run_propagate_func(var_propagate4, (0, -1)) self.run_propagate_func(var_propagate4, (-1, 1)) self.run_propagate_func(var_propagate4, (-1, 0)) self.run_propagate_func(var_propagate4, (-1, -1)) def test_chained_compare(self, flags=force_pyobj_flags): pyfunc = chained_compare cr = compile_isolated(pyfunc, (types.int32, ), flags=flags) cfunc = cr.entry_point for x in [0, 1, 2, 3, 4]: self.assertPreciseEqual(pyfunc(x), cfunc(x)) def test_chained_compare_npm(self): self.test_chained_compare(no_pyobj_flags) def test_stack_effect_error(self, flags=force_pyobj_flags): # Issue #591: POP_BLOCK must undo all stack pushes done inside # the block. pyfunc = stack_effect_error cr = compile_isolated(pyfunc, (types.int32, ), flags=flags) cfunc = cr.entry_point for x in (0, 1, 2, 3): self.assertPreciseEqual(pyfunc(x), cfunc(x)) def test_stack_effect_error_npm(self): self.test_stack_effect_error(no_pyobj_flags) def test_var_swapping(self, flags=force_pyobj_flags): pyfunc = var_swapping cr = compile_isolated(pyfunc, (types.int32, ) * 5, flags=flags) cfunc = cr.entry_point args = tuple(range(0, 10, 2)) self.assertPreciseEqual(pyfunc(*args), cfunc(*args)) def test_var_swapping_npm(self): self.test_var_swapping(no_pyobj_flags) def test_for_break(self, flags=force_pyobj_flags): # BREAK_LOOP must unwind the current inner syntax block. pyfunc = for_break cr = compile_isolated(pyfunc, (types.intp, types.intp), flags=flags) cfunc = cr.entry_point for (n, x) in [(4, 2), (4, 6)]: self.assertPreciseEqual(pyfunc(n, x), cfunc(n, x)) def test_for_break_npm(self): self.test_for_break(no_pyobj_flags)