411 lines
11 KiB
Python
411 lines
11 KiB
Python
import numpy as np
|
|
|
|
import unittest
|
|
from numba.np.numpy_support import from_dtype
|
|
from numba import njit, typeof
|
|
from numba.core import types
|
|
from numba.tests.support import (TestCase, MemoryLeakMixin,
|
|
skip_parfors_unsupported)
|
|
from numba.core.errors import TypingError
|
|
from numba.experimental import jitclass
|
|
|
|
|
|
def array_dtype(a):
|
|
return a.dtype
|
|
|
|
|
|
def use_dtype(a, b):
|
|
return a.view(b.dtype)
|
|
|
|
|
|
def dtype_eq_int64(a):
|
|
return a.dtype == np.dtype('int64')
|
|
|
|
|
|
def array_itemsize(a):
|
|
return a.itemsize
|
|
|
|
|
|
def array_nbytes(a):
|
|
return a.nbytes
|
|
|
|
|
|
def array_shape(a, i):
|
|
return a.shape[i]
|
|
|
|
|
|
def array_strides(a, i):
|
|
return a.strides[i]
|
|
|
|
|
|
def array_ndim(a):
|
|
return a.ndim
|
|
|
|
|
|
def array_size(a):
|
|
return a.size
|
|
|
|
|
|
def array_flags_contiguous(a):
|
|
return a.flags.contiguous
|
|
|
|
def array_flags_c_contiguous(a):
|
|
return a.flags.c_contiguous
|
|
|
|
def array_flags_f_contiguous(a):
|
|
return a.flags.f_contiguous
|
|
|
|
|
|
def nested_array_itemsize(a):
|
|
return a.f.itemsize
|
|
|
|
def nested_array_nbytes(a):
|
|
return a.f.nbytes
|
|
|
|
def nested_array_shape(a):
|
|
return a.f.shape
|
|
|
|
|
|
def nested_array_strides(a):
|
|
return a.f.strides
|
|
|
|
|
|
def nested_array_ndim(a):
|
|
return a.f.ndim
|
|
|
|
|
|
def nested_array_size(a):
|
|
return a.f.size
|
|
|
|
|
|
def size_after_slicing_usecase(buf, i):
|
|
sliced = buf[i]
|
|
# Make sure size attribute is not lost
|
|
return sliced.size
|
|
|
|
|
|
def array_ctypes_data(arr):
|
|
return arr.ctypes.data
|
|
|
|
|
|
def array_real(arr):
|
|
return arr.real
|
|
|
|
|
|
def array_imag(arr):
|
|
return arr.imag
|
|
|
|
|
|
class TestArrayAttr(MemoryLeakMixin, TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestArrayAttr, self).setUp()
|
|
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):
|
|
return njit(argspec)(pyfunc)
|
|
|
|
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_nbytes(self):
|
|
self.check_unary_with_arrays(array_nbytes)
|
|
|
|
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_dtype_equal(self):
|
|
# Test checking if a dtype is equal to another dtype
|
|
pyfunc = dtype_eq_int64
|
|
self.check_unary(pyfunc, np.empty(1, dtype=np.int16))
|
|
self.check_unary(pyfunc, np.empty(1, dtype=np.int64))
|
|
|
|
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)
|
|
|
|
|
|
class TestNestedArrayAttr(MemoryLeakMixin, unittest.TestCase):
|
|
def setUp(self):
|
|
super(TestNestedArrayAttr, self).setUp()
|
|
dtype = np.dtype([('a', np.int32), ('f', np.int32, (2, 5))])
|
|
self.a = np.recarray(1, dtype)[0]
|
|
self.nbrecord = from_dtype(self.a.dtype)
|
|
|
|
def get_cfunc(self, pyfunc):
|
|
return njit((self.nbrecord,))(pyfunc)
|
|
|
|
def test_shape(self):
|
|
pyfunc = nested_array_shape
|
|
cfunc = self.get_cfunc(pyfunc)
|
|
|
|
self.assertEqual(pyfunc(self.a), cfunc(self.a))
|
|
|
|
def test_strides(self):
|
|
pyfunc = nested_array_strides
|
|
cfunc = self.get_cfunc(pyfunc)
|
|
|
|
self.assertEqual(pyfunc(self.a), cfunc(self.a))
|
|
|
|
def test_ndim(self):
|
|
pyfunc = nested_array_ndim
|
|
cfunc = self.get_cfunc(pyfunc)
|
|
|
|
self.assertEqual(pyfunc(self.a), cfunc(self.a))
|
|
|
|
def test_nbytes(self):
|
|
pyfunc = nested_array_nbytes
|
|
cfunc = self.get_cfunc(pyfunc)
|
|
|
|
self.assertEqual(pyfunc(self.a), cfunc(self.a))
|
|
|
|
def test_size(self):
|
|
pyfunc = nested_array_size
|
|
cfunc = self.get_cfunc(pyfunc)
|
|
|
|
self.assertEqual(pyfunc(self.a), cfunc(self.a))
|
|
|
|
def test_itemsize(self):
|
|
pyfunc = nested_array_itemsize
|
|
cfunc = self.get_cfunc(pyfunc)
|
|
|
|
self.assertEqual(pyfunc(self.a), cfunc(self.a))
|
|
|
|
|
|
class TestSlicedArrayAttr(MemoryLeakMixin, unittest.TestCase):
|
|
def test_size_after_slicing(self):
|
|
pyfunc = size_after_slicing_usecase
|
|
cfunc = njit(pyfunc)
|
|
arr = np.arange(2 * 5).reshape(2, 5)
|
|
for i in range(arr.shape[0]):
|
|
self.assertEqual(pyfunc(arr, i), cfunc(arr, i))
|
|
arr = np.arange(2 * 5 * 3).reshape(2, 5, 3)
|
|
for i in range(arr.shape[0]):
|
|
self.assertEqual(pyfunc(arr, i), cfunc(arr, i))
|
|
|
|
|
|
class TestArrayCTypes(MemoryLeakMixin, TestCase):
|
|
|
|
_numba_parallel_test_ = False
|
|
|
|
def test_array_ctypes_data(self):
|
|
pyfunc = array_ctypes_data
|
|
cfunc = njit(pyfunc)
|
|
arr = np.arange(3)
|
|
self.assertEqual(pyfunc(arr), cfunc(arr))
|
|
|
|
@skip_parfors_unsupported
|
|
def test_array_ctypes_ref_error_in_parallel(self):
|
|
# Issue #2887
|
|
from ctypes import CFUNCTYPE, c_void_p, c_int32, c_double, c_bool
|
|
|
|
@CFUNCTYPE(c_bool, c_void_p, c_int32, c_void_p)
|
|
def callback(inptr, size, outptr):
|
|
# A ctypes callback that manipulate the incoming pointers.
|
|
try:
|
|
inbuf = (c_double * size).from_address(inptr)
|
|
outbuf = (c_double * 1).from_address(outptr)
|
|
a = np.ndarray(size, buffer=inbuf, dtype=np.float64)
|
|
b = np.ndarray(1, buffer=outbuf, dtype=np.float64)
|
|
b[0] = (a + a.size)[0]
|
|
return True
|
|
except:
|
|
import traceback
|
|
traceback.print_exception()
|
|
return False
|
|
|
|
|
|
# parallel=True is required to reproduce the error.
|
|
@njit(parallel=True)
|
|
def foo(size):
|
|
arr = np.ones(size)
|
|
out = np.empty(1)
|
|
# Exercise array.ctypes
|
|
inct = arr.ctypes
|
|
outct = out.ctypes
|
|
# The reference to `arr` is dead by now
|
|
status = callback(inct.data, size, outct.data)
|
|
return status, out[0]
|
|
|
|
size = 3
|
|
status, got = foo(size)
|
|
self.assertTrue(status)
|
|
self.assertPreciseEqual(got, (np.ones(size) + size)[0])
|
|
|
|
|
|
class TestRealImagAttr(MemoryLeakMixin, TestCase):
|
|
def check_complex(self, pyfunc):
|
|
cfunc = njit(pyfunc)
|
|
# test 1D
|
|
size = 10
|
|
arr = np.arange(size) + np.arange(size) * 10j
|
|
self.assertPreciseEqual(pyfunc(arr), cfunc(arr))
|
|
# test 2D
|
|
arr = arr.reshape(2, 5)
|
|
self.assertPreciseEqual(pyfunc(arr), cfunc(arr))
|
|
|
|
def test_complex_real(self):
|
|
self.check_complex(array_real)
|
|
|
|
def test_complex_imag(self):
|
|
self.check_complex(array_imag)
|
|
|
|
def check_number_real(self, dtype):
|
|
pyfunc = array_real
|
|
cfunc = njit(pyfunc)
|
|
# test 1D
|
|
size = 10
|
|
arr = np.arange(size, dtype=dtype)
|
|
self.assertPreciseEqual(pyfunc(arr), cfunc(arr))
|
|
# test 2D
|
|
arr = arr.reshape(2, 5)
|
|
self.assertPreciseEqual(pyfunc(arr), cfunc(arr))
|
|
# test identity
|
|
self.assertEqual(arr.data, pyfunc(arr).data)
|
|
self.assertEqual(arr.data, cfunc(arr).data)
|
|
# test writable
|
|
real = cfunc(arr)
|
|
self.assertNotEqual(arr[0, 0], 5)
|
|
real[0, 0] = 5
|
|
self.assertEqual(arr[0, 0], 5)
|
|
|
|
def test_number_real(self):
|
|
"""
|
|
Testing .real of non-complex dtypes
|
|
"""
|
|
for dtype in [np.uint8, np.int32, np.float32, np.float64]:
|
|
self.check_number_real(dtype)
|
|
|
|
def check_number_imag(self, dtype):
|
|
pyfunc = array_imag
|
|
cfunc = njit(pyfunc)
|
|
# test 1D
|
|
size = 10
|
|
arr = np.arange(size, dtype=dtype)
|
|
self.assertPreciseEqual(pyfunc(arr), cfunc(arr))
|
|
# test 2D
|
|
arr = arr.reshape(2, 5)
|
|
self.assertPreciseEqual(pyfunc(arr), cfunc(arr))
|
|
# test are zeros
|
|
self.assertEqual(cfunc(arr).tolist(), np.zeros_like(arr).tolist())
|
|
# test readonly
|
|
imag = cfunc(arr)
|
|
with self.assertRaises(ValueError) as raises:
|
|
imag[0] = 1
|
|
self.assertEqual('assignment destination is read-only',
|
|
str(raises.exception))
|
|
|
|
def test_number_imag(self):
|
|
"""
|
|
Testing .imag of non-complex dtypes
|
|
"""
|
|
for dtype in [np.uint8, np.int32, np.float32, np.float64]:
|
|
self.check_number_imag(dtype)
|
|
|
|
def test_record_real(self):
|
|
rectyp = np.dtype([('real', np.float32), ('imag', np.complex64)])
|
|
arr = np.zeros(3, dtype=rectyp)
|
|
arr['real'] = np.random.random(arr.size)
|
|
arr['imag'] = np.random.random(arr.size) * 1.3j
|
|
|
|
# check numpy behavior
|
|
# .real is identity
|
|
self.assertIs(array_real(arr), arr)
|
|
# .imag is zero_like
|
|
self.assertEqual(array_imag(arr).tolist(), np.zeros_like(arr).tolist())
|
|
|
|
# check numba behavior
|
|
# it's most likely a user error, anyway
|
|
jit_array_real = njit(array_real)
|
|
jit_array_imag = njit(array_imag)
|
|
|
|
with self.assertRaises(TypingError) as raises:
|
|
jit_array_real(arr)
|
|
self.assertIn("cannot access .real of array of Record",
|
|
str(raises.exception))
|
|
|
|
with self.assertRaises(TypingError) as raises:
|
|
jit_array_imag(arr)
|
|
self.assertIn("cannot access .imag of array of Record",
|
|
str(raises.exception))
|
|
|
|
class TestJitclassFlagsSegfault(MemoryLeakMixin, TestCase):
|
|
"""Regression test for: https://github.com/numba/numba/issues/4775 """
|
|
|
|
def test(self):
|
|
|
|
@jitclass(dict())
|
|
class B(object):
|
|
|
|
def __init__(self):
|
|
pass
|
|
|
|
def foo(self, X):
|
|
X.flags
|
|
|
|
Z = B()
|
|
Z.foo(np.ones(4))
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|