ai-content-maker/.venv/Lib/site-packages/numba/tests/test_array_iterators.py

556 lines
17 KiB
Python
Raw Normal View History

2024-05-03 04:18:51 +03:00
import itertools
import numpy as np
from numba import jit, njit, typeof
from numba.core import types
from numba.tests.support import TestCase, MemoryLeakMixin
import unittest
def array_iter(arr):
total = 0
for i, v in enumerate(arr):
total += i * v
return total
def array_iter_items(arr):
return list(iter(arr))
def array_view_iter(arr, idx):
total = 0
for i, v in enumerate(arr[idx]):
total += i * v
return total
def array_flat(arr, out):
for i, v in enumerate(arr.flat):
out[i] = v
def array_flat_getitem(arr, ind):
return arr.flat[ind]
def array_flat_setitem(arr, ind, val):
arr.flat[ind] = val
def array_flat_sum(arr):
s = 0
for i, v in enumerate(arr.flat):
s = s + (i + 1) * v
return s
def array_flat_len(arr):
return len(arr.flat)
def array_ndenumerate_sum(arr):
s = 0
for (i, j), v in np.ndenumerate(arr):
s = s + (i + 1) * (j + 1) * v
return s
def np_ndindex_empty():
s = 0
for ind in np.ndindex(()):
s += s + len(ind) + 1
return s
def np_ndindex(x, y):
s = 0
n = 0
for i, j in np.ndindex(x, y):
s = s + (i + 1) * (j + 1)
return s
def np_ndindex_array(arr):
s = 0
n = 0
for indices in np.ndindex(arr.shape):
for i, j in enumerate(indices):
s = s + (i + 1) * (j + 1)
return s
def np_nditer1(a):
res = []
for u in np.nditer(a):
res.append(u.item())
return res
def np_nditer2(a, b):
res = []
for u, v in np.nditer((a, b)):
res.append((u.item(), v.item()))
return res
def np_nditer3(a, b, c):
res = []
for u, v, w in np.nditer((a, b, c)):
res.append((u.item(), v.item(), w.item()))
return res
def iter_next(arr):
it = iter(arr)
it2 = iter(arr)
return next(it), next(it), next(it2)
#
# Test premature free (see issue #2112).
# The following test allocates an array ``x`` inside the body.
# The compiler will put a ``del x`` right after the last use of ``x``,
# which is right after the creation of the array iterator and
# before the loop is entered. If the iterator does not incref the array,
# the iterator will be reading garbage data of free'ed memory.
#
def array_flat_premature_free(size):
x = np.arange(size)
res = np.zeros_like(x, dtype=np.intp)
for i, v in enumerate(x.flat):
res[i] = v
return res
def array_ndenumerate_premature_free(size):
x = np.arange(size)
res = np.zeros_like(x, dtype=np.intp)
for i, v in np.ndenumerate(x):
res[i] = v
return res
class TestArrayIterators(MemoryLeakMixin, TestCase):
"""
Test array.flat, np.ndenumerate(), etc.
"""
def setUp(self):
super(TestArrayIterators, self).setUp()
def check_array_iter_1d(self, arr):
pyfunc = array_iter
cfunc = njit((typeof(arr),))(pyfunc)
expected = pyfunc(arr)
self.assertPreciseEqual(cfunc(arr), expected)
def check_array_iter_items(self, arr):
pyfunc = array_iter_items
cfunc = njit((typeof(arr),))(pyfunc)
expected = pyfunc(arr)
self.assertPreciseEqual(cfunc(arr), expected)
def check_array_view_iter(self, arr, index):
pyfunc = array_view_iter
cfunc = njit((typeof(arr), typeof(index),))(pyfunc)
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)
cfunc = njit((arrty, typeof(out),))(array_flat)
array_flat(arr, out)
cfunc(arr, nb_out)
self.assertPreciseEqual(out, nb_out)
def check_array_unary(self, arr, arrty, func):
cfunc = njit((arrty,))(func)
self.assertPreciseEqual(cfunc(arr), func(arr))
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 arrays
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_iter_yielded_order(self):
# See issue #5692
@jit(nopython=True)
def foo(arr):
t = []
for y1 in arr:
for y2 in y1:
t.append(y2.ravel())
return t
# 'F' ordered
arr = np.arange(24).reshape((2, 3, 4), order='F')
expected = foo.py_func(arr)
got = foo(arr)
self.assertPreciseEqual(expected, got)
# 'A' ordered, outer strided
arr = np.arange(64).reshape((4, 8, 2), order='F')[::2, :, :]
expected = foo.py_func(arr)
got = foo(arr)
self.assertPreciseEqual(expected, got)
# 'A' ordered, middle strided
arr = np.arange(64).reshape((4, 8, 2), order='F')[:, ::2, :]
expected = foo.py_func(arr)
got = foo(arr)
self.assertPreciseEqual(expected, got)
# 'A' ordered, inner strided
arr = np.arange(64).reshape((4, 8, 2), order='F')[:, :, ::2]
expected = foo.py_func(arr)
got = foo(arr)
self.assertPreciseEqual(expected, got)
@jit(nopython=True)
def flag_check(arr):
out = []
for sub in arr:
out.append((sub, sub.flags.c_contiguous,
sub.flags.f_contiguous))
return out
arr = np.arange(10).reshape((2, 5), order='F')
expected = flag_check.py_func(arr)
got = flag_check(arr)
self.assertEqual(len(expected), len(got))
ex_arr, e_flag_c, e_flag_f = expected[0]
go_arr, g_flag_c, g_flag_f = got[0]
np.testing.assert_allclose(ex_arr, go_arr)
self.assertEqual(e_flag_c, g_flag_c)
self.assertEqual(e_flag_f, g_flag_f)
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).
# Define a local checking function, Numba's `typeof` ends up aliasing
# 0d C and F ordered arrays, so the check needs to go via the compile
# result entry point to bypass type checking.
def check(arr, arrty):
cfunc = njit((arrty,))(array_flat_sum)
cres = cfunc.overloads[(arrty,)]
got = cres.entry_point(arr)
expected = cfunc.py_func(arr)
self.assertPreciseEqual(expected, got)
arr = np.zeros(0, dtype=np.int32)
arr = arr.reshape(0, 2)
arrty = types.Array(types.int32, 2, layout='C')
check(arr, arrty)
arrty = types.Array(types.int32, 2, layout='F')
check(arr, arrty)
arrty = types.Array(types.int32, 2, layout='A')
check(arr, arrty)
arr = arr.reshape(2, 0)
arrty = types.Array(types.int32, 2, layout='C')
check(arr, arrty)
arrty = types.Array(types.int32, 2, layout='F')
check(arr, arrty)
arrty = types.Array(types.int32, 2, layout='A')
check(arr, arrty)
def test_array_flat_getitem(self):
# Test indexing of array.flat object
pyfunc = array_flat_getitem
cfunc = njit(pyfunc)
def check(arr, ind):
expected = pyfunc(arr, ind)
self.assertEqual(cfunc(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
cfunc = njit(pyfunc)
def check(arr, ind):
# Use np.copy() to keep the layout
expected = np.copy(arr)
got = np.copy(arr)
pyfunc(expected, ind, 123)
cfunc(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
cfunc = njit(array_flat_len)
def check(arr):
expected = pyfunc(arr)
self.assertPreciseEqual(cfunc(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):
cfunc = njit((types.intp,))(array_flat_premature_free)
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):
# Define a local checking function, Numba's `typeof` ends up aliasing
# 0d C and F ordered arrays, so the check needs to go via the compile
# result entry point to bypass type checking.
def check(arr, arrty):
cfunc = njit((arrty,))(array_ndenumerate_sum)
cres = cfunc.overloads[(arrty,)]
got = cres.entry_point(arr)
expected = cfunc.py_func(arr)
np.testing.assert_allclose(expected, got)
arr = np.zeros(0, dtype=np.int32)
arr = arr.reshape(0, 2)
arrty = types.Array(types.int32, 2, layout='C')
check(arr, arrty)
arrty = types.Array(types.int32, 2, layout='F')
check(arr, arrty)
arrty = types.Array(types.int32, 2, layout='A')
check(arr, arrty)
arr = arr.reshape(2, 0)
arrty = types.Array(types.int32, 2, layout='C')
check(arr, arrty)
arrty = types.Array(types.int32, 2, layout='F')
check(arr, arrty)
arrty = types.Array(types.int32, 2, layout='A')
check(arr, arrty)
def test_array_ndenumerate_premature_free(self):
cfunc = njit((types.intp,))(array_ndenumerate_premature_free)
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
cfunc = njit((types.int32, types.int32,))(func)
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
cfunc = njit((),)(func)
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)
class TestNdIter(MemoryLeakMixin, TestCase):
"""
Test np.nditer()
"""
def inputs(self):
# All those inputs are compatible with a (3, 4) main shape
# scalars
yield np.float32(100)
# 0-d arrays
yield np.array(102, dtype=np.int16)
# 1-d arrays
yield np.arange(4).astype(np.complex64)
yield np.arange(8)[::2]
# 2-d arrays
a = np.arange(12).reshape((3, 4))
yield a
yield a.copy(order='F')
a = np.arange(24).reshape((6, 4))[::2]
yield a
def basic_inputs(self):
yield np.arange(4).astype(np.complex64)
yield np.arange(8)[::2]
a = np.arange(12).reshape((3, 4))
yield a
yield a.copy(order='F')
def check_result(self, got, expected):
self.assertEqual(set(got), set(expected), (got, expected))
def test_nditer1(self):
pyfunc = np_nditer1
cfunc = jit(nopython=True)(pyfunc)
for a in self.inputs():
expected = pyfunc(a)
got = cfunc(a)
self.check_result(got, expected)
def test_nditer2(self):
pyfunc = np_nditer2
cfunc = jit(nopython=True)(pyfunc)
for a, b in itertools.product(self.inputs(), self.inputs()):
expected = pyfunc(a, b)
got = cfunc(a, b)
self.check_result(got, expected)
def test_nditer3(self):
pyfunc = np_nditer3
cfunc = jit(nopython=True)(pyfunc)
# Use a restricted set of inputs, to shorten test time
inputs = self.basic_inputs
for a, b, c in itertools.product(inputs(), inputs(), inputs()):
expected = pyfunc(a, b, c)
got = cfunc(a, b, c)
self.check_result(got, expected)
def test_errors(self):
# Incompatible shapes
pyfunc = np_nditer2
cfunc = jit(nopython=True)(pyfunc)
self.disable_leak_check()
def check_incompatible(a, b):
with self.assertRaises(ValueError) as raises:
cfunc(a, b)
self.assertIn("operands could not be broadcast together",
str(raises.exception))
check_incompatible(np.arange(2), np.arange(3))
a = np.arange(12).reshape((3, 4))
b = np.arange(3)
check_incompatible(a, b)
if __name__ == '__main__':
unittest.main()