Repository URL to install this package:
|
Version:
0.36.2 ▾
|
from __future__ import print_function
from functools import partial
import numba.unittest_support as unittest
import numpy as np
from numba.compiler import compile_isolated, Flags
from numba import jit, types, from_dtype, errors, typeof
from .support import TestCase, MemoryLeakMixin, CompilationCache, tag
enable_pyobj_flags = Flags()
enable_pyobj_flags.set("enable_pyobject")
no_pyobj_flags = Flags()
no_pyobj_flags.set('nrt')
def array_reshape(arr, newshape):
return arr.reshape(newshape)
def flatten_array(a):
return a.flatten()
def ravel_array(a):
return a.ravel()
def ravel_array_size(a):
return a.ravel().size
def numpy_ravel_array(a):
return np.ravel(a)
def transpose_array(a):
return a.transpose()
def squeeze_array(a):
return a.squeeze()
def expand_dims(a, axis):
return np.expand_dims(a, axis)
def atleast_1d(*args):
return np.atleast_1d(*args)
def atleast_2d(*args):
return np.atleast_2d(*args)
def atleast_3d(*args):
return np.atleast_3d(*args)
def as_strided1(a):
# as_strided() with implicit shape
strides = (a.strides[0] // 2,) + a.strides[1:]
return np.lib.stride_tricks.as_strided(a, strides=strides)
def as_strided2(a):
# Rolling window example as in https://github.com/numba/numba/issues/1884
window = 3
shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
strides = a.strides + (a.strides[-1],)
return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
def add_axis2(a):
return a[np.newaxis, :]
def bad_index(arr, arr2d):
x = arr.x,
y = arr.y
# note that `x` is a tuple, which causes a new axis to be created.
arr2d[x, y] = 1.0
def bad_float_index(arr):
# 2D index required for this function because 1D index
# fails typing
return arr[1, 2.0]
class TestArrayManipulation(MemoryLeakMixin, TestCase):
"""
Check shape-changing operations on arrays.
"""
def setUp(self):
super(TestArrayManipulation, self).setUp()
self.ccache = CompilationCache()
@tag('important')
def test_array_reshape(self):
pyfunc = array_reshape
def run(arr, shape):
cres = self.ccache.compile(pyfunc, (typeof(arr), typeof(shape)))
return cres.entry_point(arr, shape)
def check(arr, shape):
expected = pyfunc(arr, shape)
self.memory_leak_setup()
got = run(arr, shape)
self.assertPreciseEqual(got, expected)
del got
self.memory_leak_teardown()
def check_only_shape(arr, shape, expected_shape):
# Only check Numba result to avoid Numpy bugs
self.memory_leak_setup()
got = run(arr, shape)
self.assertEqual(got.shape, expected_shape)
self.assertEqual(got.size, arr.size)
del got
self.memory_leak_teardown()
def check_err_shape(arr, shape):
with self.assertRaises(NotImplementedError) as raises:
run(arr, shape)
self.assertEqual(str(raises.exception),
"incompatible shape for array")
def check_err_size(arr, shape):
with self.assertRaises(ValueError) as raises:
run(arr, shape)
self.assertEqual(str(raises.exception),
"total size of new array must be unchanged")
def check_err_multiple_negative(arr, shape):
with self.assertRaises(ValueError) as raises:
run(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()
@tag('important')
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):
a = np.arange(9).reshape(3, 3)
pyfunc = transpose_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_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.UntypedAttributeError) 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))
if __name__ == '__main__':
unittest.main()