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

6276 lines
203 KiB
Python

# Tests numpy methods of <class 'function'>
import itertools
import math
import platform
from functools import partial
from itertools import product
import warnings
from textwrap import dedent
import numpy as np
from numba import jit, njit, typeof
from numba.core import types
from numba.typed import List, Dict
from numba.np.numpy_support import numpy_version
from numba.core.errors import TypingError, NumbaDeprecationWarning
from numba.core.config import IS_32BITS
from numba.core.utils import pysignature
from numba.np.extensions import cross2d
from numba.tests.support import (TestCase, MemoryLeakMixin,
needs_blas, run_in_subprocess)
import unittest
def sinc(x):
return np.sinc(x)
def angle1(x):
return np.angle(x)
def angle2(x, deg):
return np.angle(x, deg)
def array_equal(a, b):
return np.array_equal(a, b)
def intersect1d(a, b):
return np.intersect1d(a, b)
def append(arr, values, axis):
return np.append(arr, values, axis=axis)
def count_nonzero(arr, axis):
return np.count_nonzero(arr, axis=axis)
def delete(arr, obj):
return np.delete(arr, obj)
def diff1(a):
return np.diff(a)
def diff2(a, n):
return np.diff(a, n)
def bincount1(a):
return np.bincount(a)
def bincount2(a, w):
return np.bincount(a, weights=w)
def bincount3(a, w=None, minlength=0):
return np.bincount(a, w, minlength)
def searchsorted(a, v):
return np.searchsorted(a, v)
def searchsorted_left(a, v):
return np.searchsorted(a, v, side='left')
def searchsorted_right(a, v):
return np.searchsorted(a, v, side='right')
def digitize(*args):
return np.digitize(*args)
def histogram(*args):
return np.histogram(*args)
def machar(*args):
return np.MachAr()
def iscomplex(x):
return np.iscomplex(x)
def iscomplexobj(x):
return np.iscomplexobj(x)
def isscalar(x):
return np.isscalar(x)
def isreal(x):
return np.isreal(x)
def isrealobj(x):
return np.isrealobj(x)
def isneginf(x, out=None):
return np.isneginf(x, out)
def isposinf(x, out=None):
return np.isposinf(x, out)
def isclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False):
return np.isclose(a, b, rtol, atol, equal_nan)
def isnat(x):
return np.isnat(x)
def iinfo(*args):
return np.iinfo(*args)
def finfo(*args):
return np.finfo(*args)
def finfo_machar(*args):
return np.finfo(*args).machar
def fliplr(a):
return np.fliplr(a)
def flipud(a):
return np.flipud(a)
def flip(a):
return np.flip(a)
def logspace2(start, stop):
return np.logspace(start, stop)
def logspace3(start, stop, num=50):
return np.logspace(start, stop, num=num)
def geomspace2(start, stop):
return np.geomspace(start, stop)
def geomspace3(start, stop, num=50):
return np.geomspace(start, stop, num=num)
def rot90(a):
return np.rot90(a)
def rot90_k(a, k=1):
return np.rot90(a, k)
def array_split(a, indices, axis=0):
return np.array_split(a, indices, axis=axis)
def split(a, indices, axis=0):
return np.split(a, indices, axis=axis)
def vsplit(a, ind_or_sec):
return np.vsplit(a, ind_or_sec)
def hsplit(a, ind_or_sec):
return np.hsplit(a, ind_or_sec)
def dsplit(a, ind_or_sec):
return np.dsplit(a, ind_or_sec)
def correlate(a, v, mode="valid"):
return np.correlate(a, v, mode=mode)
def convolve(a, v, mode="full"):
return np.convolve(a, v, mode=mode)
def tri_n(N):
return np.tri(N)
def tri_n_m(N, M=None):
return np.tri(N, M)
def tri_n_k(N, k=0):
return np.tri(N, k)
def tri_n_m_k(N, M=None, k=0):
return np.tri(N, M, k)
def tril_m(m):
return np.tril(m)
def tril_m_k(m, k=0):
return np.tril(m, k)
def tril_indices_n(n):
return np.tril_indices(n)
def tril_indices_n_k(n, k=0):
return np.tril_indices(n, k)
def tril_indices_n_m(n, m=None):
return np.tril_indices(n, m=m)
def tril_indices_n_k_m(n, k=0, m=None):
return np.tril_indices(n, k, m)
def tril_indices_from_arr(arr):
return np.tril_indices_from(arr)
def tril_indices_from_arr_k(arr, k=0):
return np.tril_indices_from(arr, k)
def triu_m(m):
return np.triu(m)
def triu_m_k(m, k=0):
return np.triu(m, k)
def triu_indices_n(n):
return np.triu_indices(n)
def triu_indices_n_k(n, k=0):
return np.triu_indices(n, k)
def triu_indices_n_m(n, m=None):
return np.triu_indices(n, m=m)
def triu_indices_n_k_m(n, k=0, m=None):
return np.triu_indices(n, k, m)
def triu_indices_from_arr(arr):
return np.triu_indices_from(arr)
def triu_indices_from_arr_k(arr, k=0):
return np.triu_indices_from(arr, k)
def vander(x, N=None, increasing=False):
return np.vander(x, N, increasing)
def partition(a, kth):
return np.partition(a, kth)
def argpartition(a, kth):
return np.argpartition(a, kth)
def cov(m, y=None, rowvar=True, bias=False, ddof=None):
return np.cov(m, y, rowvar, bias, ddof)
def corrcoef(x, y=None, rowvar=True):
return np.corrcoef(x, y, rowvar)
def ediff1d(ary, to_end=None, to_begin=None):
return np.ediff1d(ary, to_end, to_begin)
def roll(a, shift):
return np.roll(a, shift)
def asarray(a):
return np.asarray(a)
def asarray_kws(a, dtype):
return np.asarray(a, dtype=dtype)
def asfarray(a, dtype=np.float64):
return np.asfarray(a, dtype=dtype)
def asfarray_default_kwarg(a):
return np.asfarray(a)
def extract(condition, arr):
return np.extract(condition, arr)
def np_trapz(y):
return np.trapz(y)
def np_trapz_x(y, x):
return np.trapz(y, x)
def np_trapz_dx(y, dx):
return np.trapz(y, dx=dx)
def np_trapz_x_dx(y, x, dx):
return np.trapz(y, x, dx)
def np_allclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False):
return np.allclose(a, b, rtol, atol, equal_nan)
def np_average(a, axis=None, weights=None):
return np.average(a, axis=axis, weights=weights)
def interp(x, xp, fp):
return np.interp(x, xp, fp)
def np_repeat(a, repeats):
return np.repeat(a, repeats)
def array_repeat(a, repeats):
return np.asarray(a).repeat(repeats)
def np_select(condlist, choicelist, default=0):
return np.select(condlist, choicelist, default=default)
def np_select_defaults(condlist, choicelist):
return np.select(condlist, choicelist)
def np_bartlett(M):
return np.bartlett(M)
def np_blackman(M):
return np.blackman(M)
def np_hamming(M):
return np.hamming(M)
def np_hanning(M):
return np.hanning(M)
def np_kaiser(M, beta):
return np.kaiser(M, beta)
def np_cross(a, b):
return np.cross(a, b)
def np_trim_zeros(a, trim='fb'):
return np.trim_zeros(a, trim)
def nb_cross2d(a, b):
return cross2d(a, b)
def flip_lr(a):
return np.fliplr(a)
def flip_ud(a):
return np.flipud(a)
def np_union1d(a, b):
return np.union1d(a,b)
def np_asarray_chkfinite(a, dtype=None):
return np.asarray_chkfinite(a, dtype)
def unwrap(p, discont=None, axis=-1, period=6.283185307179586):
return np.unwrap(p, discont, axis, period=period)
def unwrap1(p):
return np.unwrap(p)
def unwrap13(p, period):
return np.unwrap(p, period=period)
def unwrap123(p, period, discont):
return np.unwrap(p, period=period, discont=discont)
def array_contains(a, key):
return key in a
def swapaxes(a, a1, a2):
return np.swapaxes(a, a1, a2)
def nan_to_num(X, copy=True, nan=0.0):
return np.nan_to_num(X, copy=copy, nan=nan)
def np_indices(dimensions):
return np.indices(dimensions)
def diagflat1(v):
return np.diagflat(v)
def diagflat2(v, k=0):
return np.diagflat(v, k)
class TestNPFunctions(MemoryLeakMixin, TestCase):
"""
Tests for various Numpy functions.
"""
def setUp(self):
super(TestNPFunctions, self).setUp()
self.rnd = np.random.RandomState(42)
def run_unary(self, pyfunc, x_types, x_values, func_extra_types=None,
func_extra_args=None, ignore_sign_on_zero=False, abs_tol=None,
**kwargs):
"""
Runs tests for a unary function operating in the numerical real space.
Parameters
----------
pyfunc : a python function definition holding that calls the numpy
functions to be tested.
x_types: the types of the values being tested, see numba.types
x_values: the numerical values of the values to be tested
func_extra_types: the types of additional arguments to the numpy
function
func_extra_args: additional arguments to the numpy function
ignore_sign_on_zero: boolean as to whether to allow zero values
with incorrect signs to be considered equal
prec: the required precision match, see assertPreciseEqual
Notes:
------
x_types and x_values must have the same length
"""
for tx, vx in zip(x_types, x_values):
if func_extra_args is None:
func_extra_types = func_extra_args = [()]
for xtypes, xargs in zip(func_extra_types, func_extra_args):
cfunc = njit((tx,) + xtypes,)(pyfunc)
got = cfunc(vx, *xargs)
expected = pyfunc(vx, *xargs)
try:
scalty = tx.dtype
except AttributeError:
scalty = tx
prec = ('single'
if scalty in (types.float32, types.complex64)
else 'double')
msg = 'for input %r with prec %r' % (vx, prec)
self.assertPreciseEqual(got, expected,
prec=prec,
msg=msg,
ignore_sign_on_zero=ignore_sign_on_zero,
abs_tol=abs_tol, **kwargs)
def test_sinc(self):
"""
Tests the sinc() function.
This test is purely to assert numerical computations are correct.
"""
# Ignore sign of zeros, this will need masking depending on numpy
# version once the fix to numpy complex division is in upstream
# See: https://github.com/numpy/numpy/pull/6699
isoz = True
# Testing sinc(1.) leads to sin(pi)/pi, which is below machine
# precision in practice on most machines. Small floating point
# differences in sin() etc. may lead to large differences in the result
# that are at a range that is inaccessible using standard width
# floating point representations.
# e.g. Assume float64 type.
# sin(pi) ~= 1e-16, but should be zero
# sin(pi)/pi ~= 1e-17, should be zero, error carried from above
# float64 has log10(2^53)~=15.9 digits of precision and the magnitude
# change in the alg is > 16 digits (1.0...0 -> 0.0...0),
# so comparison via ULP is invalid.
# We therefore opt to assume that values under machine precision are
# equal in this case.
tol = "eps"
pyfunc = sinc
def check(x_types, x_values, **kwargs):
self.run_unary(pyfunc, x_types, x_values,
ignore_sign_on_zero=isoz, abs_tol=tol,
**kwargs)
# real domain scalar context
x_values = [1., -1., 0.0, -0.0, 0.5, -0.5, 5, -5, 5e-21, -5e-21]
x_types = [types.float32, types.float64] * (len(x_values) // 2)
check(x_types, x_values)
# real domain vector context
x_values = [np.array(x_values, dtype=np.float64)]
x_types = [typeof(v) for v in x_values]
check(x_types, x_values)
# complex domain scalar context
x_values = [1.+0j, -1+0j, 0.0+0.0j, -0.0+0.0j, 0+1j, 0-1j, 0.5+0.0j, # noqa
-0.5+0.0j, 0.5+0.5j, -0.5-0.5j, 5+5j, -5-5j, # noqa
# the following are to test sin(x)/x for small x
5e-21+0j, -5e-21+0j, 5e-21j, +(0-5e-21j) # noqa
]
x_types = [types.complex64, types.complex128] * (len(x_values) // 2)
check(x_types, x_values, ulps=2)
# complex domain vector context
x_values = [np.array(x_values, dtype=np.complex128)]
x_types = [typeof(v) for v in x_values]
check(x_types, x_values, ulps=2)
def test_sinc_exceptions(self):
pyfunc = sinc
cfunc = jit(nopython=True)(pyfunc)
with self.assertRaises(TypingError) as raises:
cfunc('str')
self.assertIn('Argument "x" must be a Number or array-like',
str(raises.exception))
# Exceptions leak references
self.disable_leak_check()
def test_contains(self):
def arrs():
a_0 = np.arange(10, 50)
k_0 = 20
yield a_0, k_0
a_1 = np.arange(6)
k_1 = 10
yield a_1, k_1
single_val_a = np.asarray([20])
k_in = 20
k_out = 13
yield single_val_a, k_in
yield single_val_a, k_out
empty_arr = np.asarray([])
yield empty_arr, k_out
# np scalars
bool_arr = np.array([True, False])
yield bool_arr, True
yield bool_arr, k_0
np.random.seed(2)
float_arr = np.random.rand(10)
np.random.seed(2)
rand_k = np.random.rand()
present_k = float_arr[0]
yield float_arr, rand_k
yield float_arr, present_k
complx_arr = float_arr.view(np.complex128)
yield complx_arr, complx_arr[0]
yield complx_arr, rand_k
np.random.seed(2)
uint_arr = np.random.randint(10, size=15, dtype=np.uint8)
yield uint_arr, 5
yield uint_arr, 25
pyfunc = array_contains
cfunc = jit(nopython=True)(pyfunc)
for arr, key in arrs():
expected = pyfunc(arr, key)
received = cfunc(arr, key)
self.assertPreciseEqual(expected, received)
def test_angle(self):
"""
Tests the angle() function.
This test is purely to assert numerical computations are correct.
"""
pyfunc1 = angle1
pyfunc2 = angle2
def check(x_types, x_values):
# angle(x)
self.run_unary(pyfunc1, x_types, x_values)
# angle(x, deg)
xtra_values = [(True,), (False,)]
xtra_types = [(types.bool_,)] * len(xtra_values)
self.run_unary(pyfunc2, x_types, x_values,
func_extra_types=xtra_types,
func_extra_args=xtra_values,)
# real domain scalar context
x_values = [1., -1., 0.0, -0.0, 0.5, -0.5, 5, -5]
x_types = [types.float32, types.float64] * (len(x_values) // 2 + 1)
check(x_types, x_values)
# real domain vector context
x_values = [np.array(x_values, dtype=np.float64)]
x_types = [typeof(v) for v in x_values]
check(x_types, x_values)
# complex domain scalar context
x_values = [1.+0j, -1+0j, 0.0+0.0j, -0.0+0.0j, 1j, -1j, 0.5+0.0j, # noqa
-0.5+0.0j, 0.5+0.5j, -0.5-0.5j, 5+5j, -5-5j] # noqa
x_types = [types.complex64, types.complex128] * (len(x_values) // 2 + 1)
check(x_types, x_values)
# complex domain vector context
x_values = np.array(x_values)
x_types = [types.complex64, types.complex128]
check(x_types, x_values)
def test_angle_return_type(self):
# see issue #8949
def numba_angle(x):
r = np.angle(x)
return r.dtype
pyfunc = numba_angle
x_values = [1., -1., 1. + 0j, -5 - 5j]
x_types = ['f4', 'f8', 'c8', 'c16']
for val, typ in zip(x_values, x_types):
x = np.array([val], dtype=typ)
cfunc = jit(nopython=True)(pyfunc)
expected = pyfunc(x)
got = cfunc(x)
self.assertEqual(expected, got)
def test_angle_exceptions(self):
pyfunc = angle1
cfunc = jit(nopython=True)(pyfunc)
with self.assertRaises(TypingError) as raises:
cfunc('hello')
self.assertIn('Argument "z" must be a complex or Array[complex]',
str(raises.exception))
# Exceptions leak references
self.disable_leak_check()
def test_array_equal(self):
def arrays():
yield np.array([]), np.array([])
yield np.array([1, 2]), np.array([1, 2])
yield np.array([]), np.array([1])
x = np.arange(10).reshape(5, 2)
x[1][1] = 30
yield np.arange(10).reshape(5, 2), x
yield x, x
yield (1, 2, 3), (1, 2, 3)
yield 2, 2
yield 3, 2
yield True, True
yield True, False
yield True, 2
yield True, 1
yield False, 0
pyfunc = array_equal
cfunc = jit(nopython=True)(pyfunc)
for arr, obj in arrays():
expected = pyfunc(arr, obj)
got = cfunc(arr, obj)
self.assertPreciseEqual(expected, got)
def test_array_equal_exception(self):
pyfunc = array_equal
cfunc = jit(nopython=True)(pyfunc)
with self.assertRaises(TypingError) as raises:
cfunc(np.arange(3 * 4).reshape(3, 4), None)
self.assertIn(
'Both arguments to "array_equals" must be array-like',
str(raises.exception)
)
def test_intersect1d(self):
def arrays():
yield [], [] # two empty arrays
yield [1], [] # empty right
yield [], [1] # empty left
yield [1], [2] # singletons no intersection
yield [1], [1] # singletons one intersection
yield [1, 2], [1]
yield [1, 2, 2], [2, 2]
yield [1, 2], [2, 1]
yield [1, 2, 3], [1, 2, 3]
pyfunc = intersect1d
cfunc = jit(nopython=True)(pyfunc)
for a, b in arrays():
a = np.array(a)
b = np.array(b)
expected = pyfunc(a, b)
got = cfunc(a, b)
self.assertPreciseEqual(expected, got)
def test_count_nonzero(self):
def arrays():
yield np.array([]), None
yield np.zeros(10), None
yield np.arange(10), None
yield np.arange(3 * 4 * 5).reshape(3, 4, 5), None
yield np.arange(3 * 4).reshape(3, 4), 0
yield np.arange(3 * 4).reshape(3, 4), 1
pyfunc = count_nonzero
cfunc = jit(nopython=True)(pyfunc)
for arr, axis in arrays():
expected = pyfunc(arr, axis)
got = cfunc(arr, axis)
self.assertPreciseEqual(expected, got)
def test_np_append(self):
def arrays():
yield 2, 2, None
yield np.arange(10), 3, None
yield np.arange(10), np.arange(3), None
yield np.arange(10).reshape(5, 2), np.arange(3), None
yield np.array([[1, 2, 3], [4, 5, 6]]), np.array([[7, 8, 9]]), 0
arr = np.array([[1, 2, 3], [4, 5, 6]])
yield arr, arr, 1
pyfunc = append
cfunc = jit(nopython=True)(pyfunc)
for arr, obj, axis in arrays():
expected = pyfunc(arr, obj, axis)
got = cfunc(arr, obj, axis)
self.assertPreciseEqual(expected, got)
def test_np_append_exceptions(self):
pyfunc = append
cfunc = jit(nopython=True)(pyfunc)
arr = np.array([[1, 2, 3], [4, 5, 6]])
values = np.array([[7, 8, 9]])
axis = 0
# first argument must be array-like
with self.assertRaises(TypingError) as raises:
cfunc(None, values, axis)
self.assertIn(
'The first argument "arr" must be array-like',
str(raises.exception)
)
# second argument must also be array-like
with self.assertRaises(TypingError) as raises:
cfunc(arr, None, axis)
self.assertIn(
'The second argument "values" must be array-like',
str(raises.exception)
)
# third argument must be either nonelike or an integer
with self.assertRaises(TypingError) as raises:
cfunc(arr, values, axis=0.0)
self.assertIn(
'The third argument "axis" must be an integer',
str(raises.exception)
)
# Exceptions leak references
self.disable_leak_check()
def test_delete(self):
def arrays():
# array, obj
#
# an array-like type
yield [1, 2, 3, 4, 5], 3
yield [1, 2, 3, 4, 5], [2, 3]
# 1d array, scalar
yield np.arange(10), 3
yield np.arange(10), -3 # Negative obj
# 1d array, list
yield np.arange(10), [3, 5, 6]
yield np.arange(10), [2, 3, 4, 5]
# 3d array, scalar
yield np.arange(3 * 4 * 5).reshape(3, 4, 5), 2
# 3d array, list
yield np.arange(3 * 4 * 5).reshape(3, 4, 5), [5, 30, 27, 8]
# slices
yield [1, 2, 3, 4], slice(1, 3, 1)
yield np.arange(10), slice(10)
pyfunc = delete
cfunc = jit(nopython=True)(pyfunc)
for arr, obj in arrays():
expected = pyfunc(arr, obj)
got = cfunc(arr, obj)
self.assertPreciseEqual(expected, got)
def test_delete_exceptions(self):
pyfunc = delete
cfunc = jit(nopython=True)(pyfunc)
self.disable_leak_check()
with self.assertRaises(TypingError) as raises:
cfunc([1, 2], 3.14)
self.assertIn(
'obj should be of Integer dtype',
str(raises.exception)
)
with self.assertRaises(TypingError) as raises:
cfunc(np.arange(10), [3.5, 5.6, 6.2])
self.assertIn(
'obj should be of Integer dtype',
str(raises.exception)
)
with self.assertRaises(TypingError) as raises:
cfunc(2, 3)
self.assertIn(
'arr must be either an Array or a Sequence',
str(raises.exception)
)
with self.assertRaises(IndexError) as raises:
cfunc([1, 2], 3)
self.assertIn(
'obj must be less than the len(arr)',
str(raises.exception),
)
# Exceptions leak references
self.disable_leak_check()
def diff_arrays(self):
"""
Some test arrays for np.diff()
"""
a = np.arange(12) ** 3
yield a
b = a.reshape((3, 4))
yield b
c = np.arange(24).reshape((3, 2, 4)) ** 3
yield c
def test_diff1(self):
pyfunc = diff1
cfunc = jit(nopython=True)(pyfunc)
for arr in self.diff_arrays():
expected = pyfunc(arr)
got = cfunc(arr)
self.assertPreciseEqual(expected, got)
# 0-dim array
a = np.array(42)
with self.assertTypingError():
cfunc(a)
def test_diff2(self):
pyfunc = diff2
cfunc = jit(nopython=True)(pyfunc)
for arr in self.diff_arrays():
size = arr.shape[-1]
for n in (0, 1, 2, 3, size - 1, size, size + 1, 421):
expected = pyfunc(arr, n)
got = cfunc(arr, n)
self.assertPreciseEqual(expected, got)
def test_diff2_exceptions(self):
pyfunc = diff2
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
# 0-dim array
arr = np.array(42)
with self.assertTypingError():
cfunc(arr, 1)
# Invalid `n`
arr = np.arange(10)
for n in (-1, -2, -42):
with self.assertRaises(ValueError) as raises:
cfunc(arr, n)
self.assertIn("order must be non-negative", str(raises.exception))
# Exceptions leak references
self.disable_leak_check()
def test_isscalar(self):
def values():
yield 3
yield np.asarray([3])
yield (3,)
yield 3j
yield 'numba'
yield int(10)
yield np.int16(12345)
yield 4.234
yield True
yield None
yield np.timedelta64(10, 'Y')
yield np.datetime64('nat')
yield np.datetime64(1, 'Y')
pyfunc = isscalar
cfunc = jit(nopython=True)(pyfunc)
for x in values():
expected = pyfunc(x)
got = cfunc(x)
self.assertEqual(expected, got, x)
def test_isobj_functions(self):
def values():
yield 1
yield 1 + 0j
yield np.asarray([3, 1 + 0j, True])
yield "hello world"
@jit(nopython=True)
def optional_fn(x, cond, cfunc):
y = x if cond else None
return cfunc(y)
pyfuncs = [iscomplexobj, isrealobj]
for pyfunc in pyfuncs:
cfunc = jit(nopython=True)(pyfunc)
for x in values():
expected = pyfunc(x)
got = cfunc(x)
self.assertEqual(expected, got)
# optional type
expected_optional = optional_fn.py_func(x, True, pyfunc)
got_optional = optional_fn(x, True, cfunc)
self.assertEqual(expected_optional, got_optional)
# none type
expected_none = optional_fn.py_func(x, False, pyfunc)
got_none = optional_fn(x, False, cfunc)
self.assertEqual(expected_none, got_none)
self.assertEqual(len(cfunc.signatures), 8)
def test_is_real_or_complex(self):
def values():
yield np.array([1 + 1j, 1 + 0j, 4.5, 3, 2, 2j])
yield np.array([1, 2, 3])
yield 3
yield 12j
yield 1 + 4j
yield 10 + 0j
yield (1 + 4j, 2 + 0j)
yield np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
pyfuncs = [iscomplex, isreal]
for pyfunc in pyfuncs:
cfunc = jit(nopython=True)(pyfunc)
for x in values():
expected = pyfunc(x)
got = cfunc(x)
self.assertPreciseEqual(expected, got)
def test_isneg_or_ispos_inf(self):
def values():
yield np.NINF, None
yield np.inf, None
yield np.PINF, None
yield np.asarray([-np.inf, 0., np.inf]), None
yield np.NINF, np.zeros(1, dtype=np.bool_)
yield np.inf, np.zeros(1, dtype=np.bool_)
yield np.PINF, np.zeros(1, dtype=np.bool_)
yield np.NINF, np.empty(12)
yield np.asarray([-np.inf, 0., np.inf]), np.zeros(3, dtype=np.bool_)
pyfuncs = [isneginf, isposinf]
for pyfunc in pyfuncs:
cfunc = jit(nopython=True)(pyfunc)
for x, out in values():
expected = pyfunc(x, out)
got = cfunc(x, out)
self.assertPreciseEqual(expected, got)
def test_isclose(self):
rtol = 1e-5
atol = 1e-8
arr = np.array([100, 1000])
aran = np.arange(8).reshape((2, 2, 2))
kw = {'rtol': rtol, 'atol': atol}
def values():
yield 1e10, 1.00001e10, {}
yield 1e10, np.nan, {}
yield np.array([1e-8, 1e-7]), np.array([0.0, 0.0]), {}
yield np.array([1e10, 1e-7]), np.array([1.00001e10, 1e-8]), {}
yield np.array([1e10, 1e-8]), np.array([1.00001e10, 1e-9]), {}
yield np.array([1e10, 1e-8]), np.array([1.0001e10, 1e-9]), {}
yield np.array([1.0, np.nan]), np.array([1.0, np.nan]), {}
yield np.array([1.0, np.nan]), np.array([1.0, np.nan]), {'equal_nan': True} # noqa
yield np.array([np.nan, np.nan]), np.array([1.0, np.nan]), {'equal_nan': True} # noqa
yield np.array([1e-100, 1e-7]), np.array([0.0, 0.0]), {'atol': 0.0}
yield np.array([1e-10, 1e-10]), np.array([1e-20, 0.0]), {}
yield np.array([1e-10, 1e-10]), np.array([1e-20, 0.999999e-10]), {'atol': 0.0} # noqa
yield np.array([1, np.inf, 2]), np.array([3, np.inf, 4]), kw
yield np.array([atol, np.inf, -np.inf, np.nan]), np.array([0]), kw
yield np.array([atol, np.inf, -np.inf, np.nan]), 0, kw
yield 0, np.array([atol, np.inf, -np.inf, np.nan]), kw
# tests taken from
# https://github.com/numpy/numpy/blob/aac965af6032b69d5cb515ad785cc9a331e816f4/numpy/core/tests/test_numeric.py#L2298-L2335 # noqa: E501
# all close tests
yield np.array([0, 1]), np.array([1, 0]), kw
yield arr, arr, kw
yield np.array([1]), np.array([1 + rtol + atol]), kw
yield arr, arr + arr * rtol, kw
yield arr, arr + arr * rtol + atol, kw
yield aran, aran + aran * rtol, kw
yield np.inf, np.inf, kw
yield -np.inf, np.inf, kw
yield np.inf, np.array([np.inf]), kw
yield np.array([np.inf, -np.inf]), np.array([np.inf, -np.inf]), kw
# none close tests
yield np.array([np.inf, 0]), np.array([1, np.inf]), kw
yield np.array([np.inf, -np.inf]), np.array([1, 0]), kw
yield np.array([np.inf, np.inf]), np.array([1, -np.inf]), kw
yield np.array([np.inf, np.inf]), np.array([1, 0]), kw
yield np.array([np.nan, 0]), np.array([np.nan, -np.inf]), kw
yield np.array([atol * 2]), np.array([0]), kw
yield np.array([1]), np.array([1 + rtol + atol * 2]), kw
yield aran, aran + rtol * 1.1 * aran + atol * 1.1, kw
yield np.array(np.array([np.inf, 1])), np.array(np.array([0, np.inf])), kw # noqa
# some close tests
yield np.array([np.inf, 0]), np.array([atol * 2, atol * 2]), kw
yield np.array([np.inf, 0]), np.array([np.inf, atol * 2]), kw
yield np.array([atol, 1, 1e6 * (1 + 2 * rtol) + atol]), np.array([0, np.nan, 1e6]), kw # noqa
yield np.arange(3), np.array([0, 1, 2.1]), kw
yield np.nan, np.array([np.nan, np.nan, np.nan]), kw
yield np.array([0]), np.array([atol, np.inf, -np.inf, np.nan]), kw
yield 0, np.array([atol, np.inf, -np.inf, np.nan]), kw
pyfunc = isclose
cfunc = jit(nopython=True)(pyfunc)
for a, b, kwargs in values():
expected = pyfunc(a, b, **kwargs)
got = cfunc(a, b, **kwargs)
if isinstance(expected, np.bool_):
self.assertEqual(expected, got)
else:
self.assertTrue(np.array_equal(expected, got))
def isclose_exception(self):
pyfunc = isclose
cfunc = jit(nopython=True)(pyfunc)
inps = [
(np.asarray([1e10, 1e-9, np.nan]),
np.asarray([1.0001e10, 1e-9]),
1e-05, 1e-08, False,
"shape mismatch: objects cannot be broadcast to a single shape",
ValueError),
('hello', 3, False, 1e-08, False,
'The first argument "a" must be array-like',
TypingError),
(3, 'hello', False, 1e-08, False,
'The second argument "b" must be array-like',
TypingError),
(2, 3, False, 1e-08, False,
'The third argument "rtol" must be a floating point',
TypingError),
(2, 3, 1e-05, False, False,
'The fourth argument "atol" must be a floating point',
TypingError),
(2, 3, 1e-05, 1e-08, 1,
'The fifth argument "equal_nan" must be a boolean',
TypingError),
]
for a, b, rtol, atol, equal_nan, exc_msg, exc in inps:
with self.assertRaisesRegex(exc, exc_msg):
cfunc(a, b, rtol, atol, equal_nan)
def bincount_sequences(self):
"""
Some test sequences for np.bincount()
"""
a = [1, 2, 5, 2, 3, 20]
b = np.array([5, 8, 42, 5])
c = self.rnd.randint(0, 100, size=300).astype(np.int8)
return (a, b, c)
def test_bincount1(self):
pyfunc = bincount1
cfunc = jit(nopython=True)(pyfunc)
for seq in self.bincount_sequences():
expected = pyfunc(seq)
got = cfunc(seq)
self.assertPreciseEqual(expected, got)
def test_bincount1_exceptions(self):
pyfunc = bincount1
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
# Negative input
with self.assertRaises(ValueError) as raises:
cfunc([2, -1])
self.assertIn("first argument must be non-negative",
str(raises.exception))
# Exceptions leak references
self.disable_leak_check()
def test_bincount2(self):
pyfunc = bincount2
cfunc = jit(nopython=True)(pyfunc)
for seq in self.bincount_sequences():
w = [math.sqrt(x) - 2 for x in seq]
# weights as list, then array, mixed types, check upcast is ok
for weights in (w, np.array(w), seq, np.array(seq)):
expected = pyfunc(seq, weights)
got = cfunc(seq, weights)
self.assertPreciseEqual(expected, got)
def test_bincount2_exceptions(self):
pyfunc = bincount2
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
# Negative input
with self.assertRaises(ValueError) as raises:
cfunc([2, -1], [0, 0])
self.assertIn("first argument must be non-negative",
str(raises.exception))
# Mismatching input sizes
with self.assertRaises(ValueError) as raises:
cfunc([2, -1], [0])
self.assertIn("weights and list don't have the same length",
str(raises.exception))
def test_bincount3(self):
pyfunc = bincount3
cfunc = jit(nopython=True)(pyfunc)
for seq in self.bincount_sequences():
a_max = max(seq)
# Length should be a_max in the first case, minlength in the second
for minlength in (a_max, a_max + 2):
expected = pyfunc(seq, None, minlength)
got = cfunc(seq, None, minlength)
self.assertEqual(len(expected), len(got))
self.assertPreciseEqual(expected, got)
def test_bincount3_exceptions(self):
pyfunc = bincount3
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
# Negative input
with self.assertRaises(ValueError) as raises:
cfunc([2, -1], [0, 0])
self.assertIn("first argument must be non-negative",
str(raises.exception))
# Negative minlength
with self.assertRaises(ValueError) as raises:
cfunc([17, 38], None, -1)
self.assertIn("'minlength' must not be negative",
str(raises.exception))
def test_searchsorted(self):
pyfunc = searchsorted
cfunc = jit(nopython=True)(pyfunc)
pyfunc_left = searchsorted_left
cfunc_left = jit(nopython=True)(pyfunc_left)
pyfunc_right = searchsorted_right
cfunc_right = jit(nopython=True)(pyfunc_right)
def check(a, v):
expected = pyfunc(a, v)
got = cfunc(a, v)
self.assertPreciseEqual(expected, got)
expected = pyfunc_left(a, v)
got = cfunc_left(a, v)
self.assertPreciseEqual(expected, got)
expected = pyfunc_right(a, v)
got = cfunc_right(a, v)
self.assertPreciseEqual(expected, got)
# First with integer values (no NaNs)
bins = np.arange(5) ** 2
values = np.arange(20) - 1
for a in (bins, list(bins)):
# Scalar values
for v in values:
check(a, v)
# Array values
for v in (values, values.reshape((4, 5))):
check(a, v)
# Sequence values
check(a, list(values))
# Second with float values (including NaNs)
bins = np.float64(list(bins) + [float('nan')] * 7) / 2.0
values = np.arange(20) - 0.5
for a in (bins, list(bins)):
# Scalar values
for v in values:
check(a, v)
# Array values
for v in (values, values.reshape((4, 5))):
check(a, v)
# Sequence values
check(a, list(values))
# nonsense value for 'side' raises TypingError
def bad_side(a, v):
return np.searchsorted(a, v, side='nonsense')
cfunc = jit(nopython=True)(bad_side)
with self.assertTypingError():
cfunc([1,2], 1)
# non-constant value for 'side' raises TypingError
def nonconst_side(a, v, side='left'):
return np.searchsorted(a, v, side=side)
cfunc = jit(nopython=True)(nonconst_side)
with self.assertTypingError():
cfunc([1,2], 1, side='right')
# Test unordered values
a = np.array([1, 2, 0])
v = np.array(
[
[5, 4],
[6, 7],
[2, 1],
[0, 3],
]
)
check(a, v)
a = np.array([9, 1, 4, 2, 0, 3, 7, 6, 8])
v = np.array(
[
[5, 10],
[10, 5],
[-1, 5],
]
)
check(a, v)
def test_searchsorted_supplemental(self):
pyfunc = searchsorted
cfunc = jit(nopython=True)(pyfunc)
pyfunc_left = searchsorted_left
cfunc_left = jit(nopython=True)(pyfunc_left)
pyfunc_right = searchsorted_right
cfunc_right = jit(nopython=True)(pyfunc_right)
def check(a, v):
expected = pyfunc(a, v)
got = cfunc(a, v)
self.assertPreciseEqual(expected, got)
expected = pyfunc_left(a, v)
got = cfunc_left(a, v)
self.assertPreciseEqual(expected, got)
expected = pyfunc_right(a, v)
got = cfunc_right(a, v)
self.assertPreciseEqual(expected, got)
element_pool = list(range(-5, 50))
element_pool += [np.nan] * 5 + [np.inf] * 3 + [-np.inf] * 3
for i in range(1000):
sample_size = self.rnd.choice([5, 10, 25])
# `a` and `v` not sorted; either may have repeating values
a = self.rnd.choice(element_pool, sample_size)
v = self.rnd.choice(element_pool, sample_size + (i % 3 - 1))
# output should match numpy regardless of whether `a` is sorted
check(a, v)
check(np.sort(a), v)
ones = np.ones(5)
nans = np.full(len(ones), fill_value=np.nan)
check(ones, ones)
# `a` and / or `v` full of nans
check(ones, nans)
check(nans, ones)
check(nans, nans)
# `v` is zero size
a = np.arange(1)
v = np.arange(0)
check(a, v)
# `a` and `v` booleans
a = np.array([False, False, True, True])
v = np.array([False, True])
check(a, v)
# `v` is a (scalar) boolean
a = [1, 2, 3]
v = True
check(a, v)
# `a` and `v` arrays of strings
a = np.array(['1', '2', '3'])
v = np.array(['2', '4'])
check(a, v)
def test_searchsorted_complex(self):
pyfunc = searchsorted
cfunc = jit(nopython=True)(pyfunc)
pyfunc_left = searchsorted_left
cfunc_left = jit(nopython=True)(pyfunc_left)
pyfunc_right = searchsorted_right
cfunc_right = jit(nopython=True)(pyfunc_right)
def check(a, v):
expected = pyfunc(a, v)
got = cfunc(a, v)
self.assertPreciseEqual(expected, got)
expected = pyfunc_left(a, v)
got = cfunc_left(a, v)
self.assertPreciseEqual(expected, got)
expected = pyfunc_right(a, v)
got = cfunc_right(a, v)
self.assertPreciseEqual(expected, got)
pool = [0, 1, np.nan]
element_pool = [complex(*c) for c in itertools.product(pool, pool)]
for i in range(100):
sample_size = self.rnd.choice([3, 5, len(element_pool)])
# `a` and `v` not sorted; either may have repeating values
a = self.rnd.choice(element_pool, sample_size)
v = self.rnd.choice(element_pool, sample_size + (i % 3 - 1))
# output should match numpy regardless of whether `a` is sorted
check(a, v)
check(np.sort(a), v)
# check type promotion (a complex; v not so much)
check(a=np.array(element_pool), v=np.arange(2))
def test_digitize(self):
pyfunc = digitize
cfunc = jit(nopython=True)(pyfunc)
def check(*args):
expected = pyfunc(*args)
got = cfunc(*args)
self.assertPreciseEqual(expected, got)
values = np.float64((0, 0.99, 1, 4.4, 4.5, 7, 8, 9, 9.5,
float('inf'), float('-inf'), float('nan')))
assert len(values) == 12
self.rnd.shuffle(values)
bins1 = np.float64([1, 3, 4.5, 8])
bins2 = np.float64([1, 3, 4.5, 8, float('inf'), float('-inf')])
bins3 = np.float64([1, 3, 4.5, 8, float('inf'), float('-inf')]
+ [float('nan')] * 10)
all_bins = [bins1, bins2, bins3]
xs = [values, values.reshape((3, 4))]
# 2-ary digitize()
for bins in all_bins:
bins.sort()
for x in xs:
check(x, bins)
check(x, bins[::-1])
# 3-ary digitize()
for bins in all_bins:
for right in (True, False):
check(values, bins, right)
check(values, bins[::-1], right)
# Sequence input
check(list(values), bins1)
# per https://github.com/numba/numba/issues/8768
check(np.array([np.nan, 1]), np.array([1.5, np.nan]))
def test_digitize_non_monotonic_bins(self):
# Exceptions leak references
self.disable_leak_check()
pyfunc = digitize
cfunc = jit(nopython=True)(pyfunc)
def check_error(*args):
for fn in (pyfunc, cfunc):
with self.assertRaises(ValueError) as raises:
fn(*args)
msg = 'bins must be monotonically increasing or decreasing'
self.assertIn(msg, str(raises.exception))
x = np.array([np.nan, 1])
bins = np.array([np.nan, 1.5, 2.3, np.nan])
check_error(x, bins)
x = [-1, 0, 1, 2]
bins = [0, 0, 1, 0]
check_error(x, bins)
bins = [1, 1, 0, 1]
check_error(x, bins)
def test_digitize_supplemental(self):
# inspired by the tests in
# https://github.com/numpy/numpy/blob/a277f62/numpy/lib/tests/test_function_base.py
pyfunc = digitize
cfunc = jit(nopython=True)(pyfunc)
def check(*args):
expected = pyfunc(*args)
got = cfunc(*args)
self.assertPreciseEqual(expected, got)
# forward
x = np.arange(-6, 5)
bins = np.arange(-5, 5)
check(x, bins)
# reverse
x = np.arange(5, -6, -1)
bins = np.arange(5, -5, -1)
check(x, bins)
# random
x = self.rnd.rand(10)
bins = np.linspace(x.min(), x.max(), 10)
check(x, bins)
# right_basic
x = [1, 5, 4, 10, 8, 11, 0]
bins = [1, 5, 10]
check(x, bins)
# right_open
x = np.arange(-6, 5)
bins = np.arange(-6, 4)
check(x, bins, True)
# right_open_reverse
x = np.arange(5, -6, -1)
bins = np.arange(4, -6, -1)
check(x, bins, True)
# right_open_random
x = self.rnd.rand(10)
bins = np.linspace(x.min(), x.max(), 10)
check(x, bins, True)
# monotonic
x = [-1, 0, 1, 2]
bins = [0, 0, 1]
check(x, bins)
bins = [1, 1, 0]
check(x, bins)
bins = [1, 1, 1, 1]
check(x, bins)
# large_integers_increasing
x = 2 ** 54 # loses precision in a float
check([x], [x - 1, x + 1])
def test_digitize_raise_if_x_complex(self):
# Exceptions leak references
self.disable_leak_check()
pyfunc = digitize
cfunc = jit(nopython=True)(pyfunc)
x = np.array([1 + 1j])
y = np.array([1., 3., 4.5, 8.])
msg = 'x may not be complex'
for func in pyfunc, cfunc:
with self.assertTypingError() as raises:
func(x, y)
self.assertIn(msg, str(raises.exception))
def test_histogram(self):
pyfunc = histogram
cfunc = jit(nopython=True)(pyfunc)
def check(*args):
pyhist, pybins = pyfunc(*args)
chist, cbins = cfunc(*args)
self.assertPreciseEqual(pyhist, chist)
# There can be a slight discrepancy in the linspace() result
# when `bins` is an integer...
self.assertPreciseEqual(pybins, cbins, prec='double', ulps=2)
def check_values(values):
# Explicit bins array
# (note Numpy seems to not support NaN bins)
bins = np.float64([1, 3, 4.5, 8])
check(values, bins)
check(values.reshape((3, 4)), bins)
# Explicit number of bins
check(values, 7)
# Explicit number of bins and bins range
check(values, 7, (1.0, 13.5))
# Implicit bins=10
check(values)
values = np.float64((0, 0.99, 1, 4.4, 4.5, 7, 8,
9, 9.5, 42.5, -1.0, -0.0))
assert len(values) == 12
self.rnd.shuffle(values)
check_values(values)
def _test_correlate_convolve(self, pyfunc):
cfunc = jit(nopython=True)(pyfunc)
# only 1d arrays are accepted, test varying lengths
# and varying dtype
lengths = (1, 2, 3, 7)
dts = [np.int8, np.int32, np.int64, np.float32, np.float64,
np.complex64, np.complex128]
modes = ["full", "valid", "same"]
for dt1, dt2, n, m, mode in itertools.product(
dts, dts, lengths, lengths, modes
):
a = np.arange(n, dtype=dt1)
v = np.arange(m, dtype=dt2)
if np.issubdtype(dt1, np.complexfloating):
a = (a + 1j * a).astype(dt1)
if np.issubdtype(dt2, np.complexfloating):
v = (v + 1j * v).astype(dt2)
expected = pyfunc(a, v, mode=mode)
got = cfunc(a, v, mode=mode)
self.assertPreciseEqual(expected, got)
_a = np.arange(12).reshape(4, 3)
_b = np.arange(12)
for x, y in [(_a, _b), (_b, _a)]:
with self.assertRaises(TypingError) as raises:
cfunc(x, y)
msg = 'only supported on 1D arrays'
self.assertIn(msg, str(raises.exception))
def test_correlate(self):
self._test_correlate_convolve(correlate)
def _test_correlate_convolve_exceptions(self, fn):
# Exceptions leak references
self.disable_leak_check()
# convolve raises if either array has a 0 dimension
_a = np.ones(shape=(0,))
_b = np.arange(5)
cfunc = jit(nopython=True)(fn)
for x, y in [(_a, _b), (_b, _a)]:
with self.assertRaises(ValueError) as raises:
cfunc(x, y)
if len(x) == 0:
self.assertIn("'a' cannot be empty", str(raises.exception))
else:
self.assertIn("'v' cannot be empty", str(raises.exception))
with self.assertRaises(ValueError) as raises:
cfunc(_b, _b, mode="invalid mode")
self.assertIn("Invalid 'mode'", str(raises.exception))
def test_correlate_exceptions(self):
# correlate supported 0 dimension arrays until 1.18
self._test_correlate_convolve_exceptions(correlate)
def test_convolve(self):
self._test_correlate_convolve(convolve)
def test_convolve_exceptions(self):
self._test_correlate_convolve_exceptions(convolve)
def _check_output(self, pyfunc, cfunc, params, abs_tol=None):
expected = pyfunc(**params)
got = cfunc(**params)
self.assertPreciseEqual(expected, got, abs_tol=abs_tol)
def test_vander_basic(self):
pyfunc = vander
cfunc = jit(nopython=True)(pyfunc)
_check_output = partial(self._check_output, pyfunc, cfunc)
def _check(x):
n_choices = [None, 0, 1, 2, 3, 4]
increasing_choices = [True, False]
# N and increasing defaulted
params = {'x': x}
_check_output(params)
# N provided and increasing defaulted
for n in n_choices:
params = {'x': x, 'N': n}
_check_output(params)
# increasing provided and N defaulted:
for increasing in increasing_choices:
params = {'x': x, 'increasing': increasing}
_check_output(params)
# both n and increasing supplied
for n in n_choices:
for increasing in increasing_choices:
params = {'x': x, 'N': n, 'increasing': increasing}
_check_output(params)
_check(np.array([1, 2, 3, 5]))
_check(np.arange(7) - 10.5)
_check(np.linspace(3, 10, 5))
_check(np.array([1.2, np.nan, np.inf, -np.inf]))
_check(np.array([]))
_check(np.arange(-5, 5) - 0.3)
# # boolean array
_check(np.array([True] * 5 + [False] * 4))
# cycle through dtypes to check type promotion a la numpy
for dtype in np.int32, np.int64, np.float32, np.float64:
_check(np.arange(10, dtype=dtype))
# non array inputs
_check([0, 1, 2, 3])
_check((4, 5, 6, 7))
_check((0.0, 1.0, 2.0))
_check(())
# edge cases
_check((3, 4.444, 3.142))
_check((True, False, 4))
def test_vander_exceptions(self):
pyfunc = vander
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
x = np.arange(5) - 0.5
def _check_n(N):
with self.assertTypingError() as raises:
cfunc(x, N=N)
self.assertIn("Second argument N must be None or an integer",
str(raises.exception))
for N in 1.1, True, np.inf, [1, 2]:
_check_n(N)
with self.assertRaises(ValueError) as raises:
cfunc(x, N=-1)
self.assertIn("Negative dimensions are not allowed",
str(raises.exception))
def _check_1d(x):
with self.assertRaises(ValueError) as raises:
cfunc(x)
self.assertEqual("x must be a one-dimensional array or sequence.",
str(raises.exception))
x = np.arange(27).reshape((3, 3, 3))
_check_1d(x)
x = ((2, 3), (4, 5))
_check_1d(x)
def test_tri_n_basic(self):
pyfunc = tri_n
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc)
def n_variations():
return np.arange(-4, 8) # number of rows
# N supplied, M and k defaulted
for n in n_variations():
params = {'N': n}
_check(params)
def test_tri_n_m_basic(self):
pyfunc = tri_n_m
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc)
def n_variations():
return np.arange(-4, 8) # number of rows
def m_variations():
# number of columns
return itertools.chain.from_iterable(([None], range(-5, 9)))
# N supplied, M and k defaulted
for n in n_variations():
params = {'N': n}
_check(params)
# N and M supplied, k defaulted
for n in n_variations():
for m in m_variations():
params = {'N': n, 'M': m}
_check(params)
def test_tri_n_k_basic(self):
pyfunc = tri_n_k
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc)
def n_variations():
return np.arange(-4, 8) # number of rows
def k_variations():
return np.arange(-10, 10) # offset
# N supplied, M and k defaulted
for n in n_variations():
params = {'N': n}
_check(params)
# N and k supplied, M defaulted
for n in n_variations():
for k in k_variations():
params = {'N': n, 'k': k}
_check(params)
def test_tri_n_m_k_basic(self):
pyfunc = tri_n_m_k
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc)
def n_variations():
return np.arange(-4, 8) # number of rows
def m_variations():
# number of columns
return itertools.chain.from_iterable(([None], range(-5, 9)))
def k_variations():
return np.arange(-10, 10) # offset
# N supplied, M and k defaulted
for n in n_variations():
params = {'N': n}
_check(params)
# N and M supplied, k defaulted
for n in n_variations():
for m in m_variations():
params = {'N': n, 'M': m}
_check(params)
# N and k supplied, M defaulted
for n in n_variations():
for k in k_variations():
params = {'N': n, 'k': k}
_check(params)
# N, M and k supplied
for n in n_variations():
for k in k_variations():
for m in m_variations():
params = {'N': n, 'M': m, 'k': k}
_check(params)
def test_tri_exceptions(self):
pyfunc = tri_n_m_k
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
def _check(k):
with self.assertTypingError() as raises:
cfunc(5, 6, k=k)
assert "k must be an integer" in str(raises.exception)
for k in 1.5, True, np.inf, [1, 2]:
_check(k)
def _triangular_matrix_tests_m(self, pyfunc):
cfunc = jit(nopython=True)(pyfunc)
def _check(arr):
expected = pyfunc(arr)
got = cfunc(arr)
# TODO: Contiguity of result not consistent with numpy
self.assertEqual(got.dtype, expected.dtype)
np.testing.assert_array_equal(got, expected)
return self._triangular_matrix_tests_inner(self, pyfunc, _check)
def _triangular_matrix_tests_m_k(self, pyfunc):
cfunc = jit(nopython=True)(pyfunc)
def _check(arr):
for k in itertools.chain.from_iterable(([None], range(-10, 10))):
if k is None:
params = {}
else:
params = {'k': k}
expected = pyfunc(arr, **params)
got = cfunc(arr, **params)
# TODO: Contiguity of result not consistent with numpy
self.assertEqual(got.dtype, expected.dtype)
np.testing.assert_array_equal(got, expected)
return self._triangular_matrix_tests_inner(self, pyfunc, _check)
@staticmethod
def _triangular_matrix_tests_inner(self, pyfunc, _check):
def check_odd(a):
_check(a)
a = a.reshape((9, 7))
_check(a)
a = a.reshape((7, 1, 3, 3))
_check(a)
_check(a.T)
def check_even(a):
_check(a)
a = a.reshape((4, 16))
_check(a)
a = a.reshape((4, 2, 2, 4))
_check(a)
_check(a.T)
check_odd(np.arange(63) + 10.5)
check_even(np.arange(64) - 10.5)
# edge cases
_check(np.arange(360).reshape(3, 4, 5, 6))
_check(np.array([]))
_check(np.arange(9).reshape((3, 3))[::-1])
_check(np.arange(9).reshape((3, 3), order='F'))
arr = (np.arange(64) - 10.5).reshape((4, 2, 2, 4))
_check(arr)
_check(np.asfortranarray(arr))
def _triangular_matrix_exceptions(self, pyfunc):
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
a = np.ones((5, 6))
with self.assertTypingError() as raises:
cfunc(a, k=1.5)
self.assertIn("k must be an integer", str(raises.exception))
def _triangular_indices_tests_base(self, pyfunc, args):
cfunc = jit(nopython=True)(pyfunc)
for x in args:
expected = pyfunc(*x)
got = cfunc(*x)
self.assertEqual(type(expected), type(got))
self.assertEqual(len(expected), len(got))
for e, g in zip(expected, got):
np.testing.assert_array_equal(e, g)
def _triangular_indices_tests_n(self, pyfunc):
self._triangular_indices_tests_base(
pyfunc,
[[n] for n in range(10)]
)
def _triangular_indices_tests_n_k(self, pyfunc):
self._triangular_indices_tests_base(
pyfunc,
[[n, k] for n in range(10) for k in range(-n - 1, n + 2)]
)
def _triangular_indices_tests_n_m(self, pyfunc):
self._triangular_indices_tests_base(
pyfunc,
[[n, m] for n in range(10) for m in range(2 * n)]
)
def _triangular_indices_tests_n_k_m(self, pyfunc):
self._triangular_indices_tests_base(
pyfunc,
[[n, k, m] for n in range(10)
for k in range(-n - 1, n + 2)
for m in range(2 * n)]
)
# Check jitted version works with default values for kwargs
cfunc = jit(nopython=True)(pyfunc)
cfunc(1)
def _triangular_indices_from_tests_arr(self, pyfunc):
cfunc = jit(nopython=True)(pyfunc)
for dtype in [int, float, bool]:
for n,m in itertools.product(range(10), range(10)):
arr = np.ones((n, m), dtype)
expected = pyfunc(arr)
got = cfunc(arr)
self.assertEqual(type(expected), type(got))
self.assertEqual(len(expected), len(got))
for e, g in zip(expected, got):
np.testing.assert_array_equal(e, g)
def _triangular_indices_from_tests_arr_k(self, pyfunc):
cfunc = jit(nopython=True)(pyfunc)
for dtype in [int, float, bool]:
for n,m in itertools.product(range(10), range(10)):
arr = np.ones((n, m), dtype)
for k in range(-10, 10):
expected = pyfunc(arr)
got = cfunc(arr)
self.assertEqual(type(expected), type(got))
self.assertEqual(len(expected), len(got))
for e, g in zip(expected, got):
np.testing.assert_array_equal(e, g)
def _triangular_indices_exceptions(self, pyfunc):
cfunc = jit(nopython=True)(pyfunc)
parameters = pysignature(pyfunc).parameters
with self.assertTypingError() as raises:
cfunc(1.0)
self.assertIn("n must be an integer", str(raises.exception))
if 'k' in parameters:
with self.assertTypingError() as raises:
cfunc(1, k=1.0)
self.assertIn("k must be an integer", str(raises.exception))
if 'm' in parameters:
with self.assertTypingError() as raises:
cfunc(1, m=1.0)
self.assertIn("m must be an integer", str(raises.exception))
def _triangular_indices_from_exceptions(self, pyfunc, test_k=True):
cfunc = jit(nopython=True)(pyfunc)
for ndims in [0, 1, 3]:
a = np.ones([5] * ndims)
with self.assertTypingError() as raises:
cfunc(a)
self.assertIn("input array must be 2-d", str(raises.exception))
if test_k:
a = np.ones([5, 5])
with self.assertTypingError() as raises:
cfunc(a, k=0.5)
self.assertIn("k must be an integer", str(raises.exception))
def test_tril_basic(self):
self._triangular_matrix_tests_m(tril_m)
self._triangular_matrix_tests_m_k(tril_m_k)
def test_tril_exceptions(self):
self._triangular_matrix_exceptions(tril_m_k)
def test_tril_indices(self):
self._triangular_indices_tests_n(tril_indices_n)
self._triangular_indices_tests_n_k(tril_indices_n_k)
self._triangular_indices_tests_n_m(tril_indices_n_m)
self._triangular_indices_tests_n_k_m(tril_indices_n_k_m)
self._triangular_indices_exceptions(tril_indices_n)
self._triangular_indices_exceptions(tril_indices_n_k)
self._triangular_indices_exceptions(tril_indices_n_m)
self._triangular_indices_exceptions(tril_indices_n_k_m)
def test_tril_indices_from(self):
self._triangular_indices_from_tests_arr(tril_indices_from_arr)
self._triangular_indices_from_tests_arr_k(tril_indices_from_arr_k)
self._triangular_indices_from_exceptions(tril_indices_from_arr, False)
self._triangular_indices_from_exceptions(tril_indices_from_arr_k, True)
def test_triu_basic(self):
self._triangular_matrix_tests_m(triu_m)
self._triangular_matrix_tests_m_k(triu_m_k)
def test_triu_exceptions(self):
self._triangular_matrix_exceptions(triu_m_k)
def test_triu_indices(self):
self._triangular_indices_tests_n(triu_indices_n)
self._triangular_indices_tests_n_k(triu_indices_n_k)
self._triangular_indices_tests_n_m(triu_indices_n_m)
self._triangular_indices_tests_n_k_m(triu_indices_n_k_m)
self._triangular_indices_exceptions(triu_indices_n)
self._triangular_indices_exceptions(triu_indices_n_k)
self._triangular_indices_exceptions(triu_indices_n_m)
self._triangular_indices_exceptions(triu_indices_n_k_m)
def test_triu_indices_from(self):
self._triangular_indices_from_tests_arr(triu_indices_from_arr)
self._triangular_indices_from_tests_arr_k(triu_indices_from_arr_k)
self._triangular_indices_from_exceptions(triu_indices_from_arr, False)
self._triangular_indices_from_exceptions(triu_indices_from_arr_k, True)
def test_indices_basic(self):
pyfunc = np_indices
cfunc = njit(np_indices)
def inputs():
# Taken from https://github.com/numpy/numpy/blob/db4f43983cb938f12c311e1f5b7165e270c393b4/numpy/core/tests/test_numeric.py#L3383-L3407 # noqa: E501
yield (4, 3)
yield (4,)
yield (0,)
yield (2, 2, 3, 5)
for dims in inputs():
self.assertPreciseEqual(pyfunc(dims), cfunc(dims))
def test_indices_exception(self):
cfunc = njit(np_indices)
self.disable_leak_check()
errmsg = 'The argument "dimensions" must be a tuple of integers'
with self.assertRaises(TypingError) as raises:
cfunc("abc")
self.assertIn(errmsg,
str(raises.exception))
with self.assertRaises(TypingError) as raises:
cfunc((2.0, 3.0))
self.assertIn(errmsg,
str(raises.exception))
with self.assertRaises(TypingError) as raises:
cfunc((2, 3.0))
self.assertIn(errmsg,
str(raises.exception))
def partition_sanity_check(self, pyfunc, cfunc, a, kth):
# as NumPy uses a different algorithm, we do not expect to
# match outputs exactly...
expected = pyfunc(a, kth)
got = cfunc(a, kth)
# but we do expect the unordered collection of elements up to the
# kth to tie out
self.assertPreciseEqual(np.unique(expected[:kth]), np.unique(got[:kth]))
# likewise the unordered collection of elements from the kth onwards
self.assertPreciseEqual(np.unique(expected[kth:]), np.unique(got[kth:]))
def argpartition_sanity_check(self, pyfunc, cfunc, a, kth):
# as NumPy uses a different algorithm, we do not expect to
# match outputs exactly...
expected = pyfunc(a, kth)
got = cfunc(a, kth)
# but we do expect the unordered collection of elements up to the
# kth to tie out
self.assertPreciseEqual(np.unique(a[expected[:kth]]),
np.unique(a[got[:kth]]))
# likewise the unordered collection of elements from the kth onwards
self.assertPreciseEqual(np.unique(a[expected[kth:]]),
np.unique(a[got[kth:]]))
def test_partition_fuzz(self):
# inspired by the test of the same name in:
# https://github.com/numpy/numpy/blob/043a840/numpy/core/tests/test_multiarray.py # noqa: E501
pyfunc = partition
cfunc = jit(nopython=True)(pyfunc)
for j in range(10, 30):
for i in range(1, j - 2):
d = np.arange(j)
self.rnd.shuffle(d)
d = d % self.rnd.randint(2, 30)
idx = self.rnd.randint(d.size)
kth = [0, idx, i, i + 1, -idx, -i] # include negative kth's
tgt = np.sort(d)[kth]
self.assertPreciseEqual(cfunc(d, kth)[kth],
tgt) # a -> array
self.assertPreciseEqual(cfunc(d.tolist(), kth)[kth],
tgt) # a -> list
self.assertPreciseEqual(cfunc(tuple(d.tolist()), kth)[kth],
tgt) # a -> tuple
for k in kth:
self.partition_sanity_check(pyfunc, cfunc, d, k)
def test_argpartition_fuzz(self):
# inspired by the test of the same name in:
# https://github.com/numpy/numpy/blob/043a840/numpy/core/tests/test_multiarray.py # noqa: E501
pyfunc = argpartition
cfunc = jit(nopython=True)(pyfunc)
for j in range(10, 30):
for i in range(1, j - 2):
d = np.arange(j)
self.rnd.shuffle(d)
d = d % self.rnd.randint(2, 30)
idx = self.rnd.randint(d.size)
kth = [0, idx, i, i + 1, -idx, -i] # include negative kth's
tgt = np.argsort(d)[kth]
self.assertPreciseEqual(d[cfunc(d, kth)[kth]],
d[tgt]) # a -> array
self.assertPreciseEqual(d[cfunc(d.tolist(), kth)[kth]],
d[tgt]) # a -> list
self.assertPreciseEqual(d[cfunc(tuple(d.tolist()), kth)[kth]],
d[tgt]) # a -> tuple
for k in kth:
self.argpartition_sanity_check(pyfunc, cfunc, d, k)
def test_partition_exception_out_of_range(self):
# inspired by the test of the same name in:
# https://github.com/numpy/numpy/blob/043a840/numpy/core/tests/test_multiarray.py # noqa: E501
pyfunc = partition
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
# Test out of range values in kth raise an error
a = np.arange(10)
def _check(a, kth):
with self.assertRaises(ValueError) as e:
cfunc(a, kth)
assert str(e.exception) == "kth out of bounds"
_check(a, 10)
_check(a, -11)
_check(a, (3, 30))
def test_argpartition_exception_out_of_range(self):
# inspired by the test of the same name in:
# https://github.com/numpy/numpy/blob/043a840/numpy/core/tests/test_multiarray.py # noqa: E501
pyfunc = argpartition
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
# Test out of range values in kth raise an error
a = np.arange(10)
def _check(a, kth):
with self.assertRaises(ValueError) as e:
cfunc(a, kth)
assert str(e.exception) == "kth out of bounds"
_check(a, 10)
_check(a, -11)
_check(a, (3, 30))
def test_partition_exception_non_integer_kth(self):
# inspired by the test of the same name in:
# https://github.com/numpy/numpy/blob/043a840/numpy/core/tests/test_multiarray.py # noqa: E501
pyfunc = partition
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
def _check(a, kth):
with self.assertTypingError() as raises:
cfunc(a, kth)
self.assertIn("Partition index must be integer",
str(raises.exception))
a = np.arange(10)
_check(a, 9.0)
_check(a, (3.3, 4.4))
_check(a, np.array((1, 2, np.nan)))
def test_argpartition_exception_non_integer_kth(self):
# inspired by the test of the same name in:
# https://github.com/numpy/numpy/blob/043a840/numpy/core/tests/test_multiarray.py # noqa: E501
pyfunc = argpartition
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
def _check(a, kth):
with self.assertTypingError() as raises:
cfunc(a, kth)
self.assertIn("Partition index must be integer",
str(raises.exception))
a = np.arange(10)
_check(a, 9.0)
_check(a, (3.3, 4.4))
_check(a, np.array((1, 2, np.nan)))
def test_partition_exception_a_not_array_like(self):
pyfunc = partition
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
def _check(a, kth):
with self.assertTypingError() as raises:
cfunc(a, kth)
self.assertIn('The first argument must be an array-like',
str(raises.exception))
_check(4, 0)
_check('Sausages', 0)
def test_argpartition_exception_a_not_array_like(self):
pyfunc = argpartition
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
def _check(a, kth):
with self.assertTypingError() as raises:
cfunc(a, kth)
self.assertIn('The first argument must be an array-like',
str(raises.exception))
_check(4, 0)
_check('Sausages', 0)
def test_partition_exception_a_zero_dim(self):
pyfunc = partition
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
def _check(a, kth):
with self.assertTypingError() as raises:
cfunc(a, kth)
self.assertIn('The first argument must be at least 1-D (found 0-D)',
str(raises.exception))
_check(np.array(1), 0)
def test_argpartition_exception_a_zero_dim(self):
pyfunc = argpartition
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
def _check(a, kth):
with self.assertTypingError() as raises:
cfunc(a, kth)
self.assertIn('The first argument must be at least 1-D (found 0-D)',
str(raises.exception))
_check(np.array(1), 0)
def test_partition_exception_kth_multi_dimensional(self):
pyfunc = partition
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
def _check(a, kth):
with self.assertRaises(ValueError) as raises:
cfunc(a, kth)
self.assertIn('kth must be scalar or 1-D', str(raises.exception))
_check(np.arange(10), kth=np.arange(6).reshape(3, 2))
def test_argpartition_exception_kth_multi_dimensional(self):
pyfunc = argpartition
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
def _check(a, kth):
with self.assertRaises(ValueError) as raises:
cfunc(a, kth)
self.assertIn('kth must be scalar or 1-D', str(raises.exception))
_check(np.arange(10), kth=np.arange(6).reshape(3, 2))
def test_partition_empty_array(self):
# inspired by the test of the same name in:
# https://github.com/numpy/numpy/blob/043a840/numpy/core/tests/test_multiarray.py # noqa: E501
pyfunc = partition
cfunc = jit(nopython=True)(pyfunc)
def check(a, kth=0):
expected = pyfunc(a, kth)
got = cfunc(a, kth)
self.assertPreciseEqual(expected, got)
# check axis handling for multidimensional empty arrays
a = np.array([])
a.shape = (3, 2, 1, 0)
# include this with some other empty data structures
for arr in a, (), np.array([]):
check(arr)
def test_argpartition_empty_array(self):
# inspired by the test of the same name in:
# https://github.com/numpy/numpy/blob/043a840/numpy/core/tests/test_multiarray.py # noqa: E501
pyfunc = argpartition
cfunc = jit(nopython=True)(pyfunc)
def check(a, kth=0):
expected = pyfunc(a, kth)
got = cfunc(a, kth)
self.assertPreciseEqual(expected, got)
# check axis handling for multidimensional empty arrays
a = np.array([])
a.shape = (3, 2, 1, 0)
# include this with some other empty data structures
for arr in a, (), np.array([]):
check(arr)
def test_partition_basic(self):
# inspired by the test of the same name in:
# https://github.com/numpy/numpy/blob/043a840/numpy/core/tests/test_multiarray.py # noqa: E501
pyfunc = partition
cfunc = jit(nopython=True)(pyfunc)
d = np.array([])
got = cfunc(d, 0)
self.assertPreciseEqual(d, got)
d = np.ones(1)
got = cfunc(d, 0)
self.assertPreciseEqual(d, got)
# kth not modified
kth = np.array([30, 15, 5])
okth = kth.copy()
cfunc(np.arange(40), kth)
self.assertPreciseEqual(kth, okth)
for r in ([2, 1], [1, 2], [1, 1]):
d = np.array(r)
tgt = np.sort(d)
for k in 0, 1:
self.assertPreciseEqual(cfunc(d, k)[k], tgt[k])
self.partition_sanity_check(pyfunc, cfunc, d, k)
for r in ([3, 2, 1], [1, 2, 3], [2, 1, 3], [2, 3, 1],
[1, 1, 1], [1, 2, 2], [2, 2, 1], [1, 2, 1]):
d = np.array(r)
tgt = np.sort(d)
for k in 0, 1, 2:
self.assertPreciseEqual(cfunc(d, k)[k], tgt[k])
self.partition_sanity_check(pyfunc, cfunc, d, k)
d = np.ones(50)
self.assertPreciseEqual(cfunc(d, 0), d)
# sorted
d = np.arange(49)
for k in 5, 15:
self.assertEqual(cfunc(d, k)[k], k)
self.partition_sanity_check(pyfunc, cfunc, d, k)
# rsorted, with input flavours: array, list and tuple
d = np.arange(47)[::-1]
for a in d, d.tolist(), tuple(d.tolist()):
self.assertEqual(cfunc(a, 6)[6], 6)
self.assertEqual(cfunc(a, 16)[16], 16)
self.assertPreciseEqual(cfunc(a, -6), cfunc(a, 41))
self.assertPreciseEqual(cfunc(a, -16), cfunc(a, 31))
self.partition_sanity_check(pyfunc, cfunc, d, -16)
# median of 3 killer, O(n^2) on pure median 3 pivot quickselect
# exercises the median of median of 5 code used to keep O(n)
d = np.arange(1000000)
x = np.roll(d, d.size // 2)
mid = x.size // 2 + 1
self.assertEqual(cfunc(x, mid)[mid], mid)
d = np.arange(1000001)
x = np.roll(d, d.size // 2 + 1)
mid = x.size // 2 + 1
self.assertEqual(cfunc(x, mid)[mid], mid)
# max
d = np.ones(10)
d[1] = 4
self.assertEqual(cfunc(d, (2, -1))[-1], 4)
self.assertEqual(cfunc(d, (2, -1))[2], 1)
d[1] = np.nan
assert np.isnan(cfunc(d, (2, -1))[-1])
# equal elements
d = np.arange(47) % 7
tgt = np.sort(np.arange(47) % 7)
self.rnd.shuffle(d)
for i in range(d.size):
self.assertEqual(cfunc(d, i)[i], tgt[i])
self.partition_sanity_check(pyfunc, cfunc, d, i)
d = np.array([0, 1, 2, 3, 4, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 9])
kth = [0, 3, 19, 20]
self.assertEqual(tuple(cfunc(d, kth)[kth]), (0, 3, 7, 7))
td = [(dt, s) for dt in [np.int32, np.float32] for s in (9, 16)]
for dt, s in td:
d = np.arange(s, dtype=dt)
self.rnd.shuffle(d)
d1 = np.tile(np.arange(s, dtype=dt), (4, 1))
map(self.rnd.shuffle, d1)
for i in range(d.size):
p = cfunc(d, i)
self.assertEqual(p[i], i)
# all before are smaller
np.testing.assert_array_less(p[:i], p[i])
# all after are larger
np.testing.assert_array_less(p[i], p[i + 1:])
# sanity check
self.partition_sanity_check(pyfunc, cfunc, d, i)
def test_argpartition_basic(self):
# inspired by the test of the same name in:
# https://github.com/numpy/numpy/blob/043a840/numpy/core/tests/test_multiarray.py # noqa: E501
pyfunc = argpartition
cfunc = jit(nopython=True)(pyfunc)
d = np.array([], dtype=np.int64)
expected = pyfunc(d, 0)
got = cfunc(d, 0)
self.assertPreciseEqual(expected, got)
d = np.ones(1, dtype=np.int64)
expected = pyfunc(d, 0)
got = cfunc(d, 0)
self.assertPreciseEqual(expected, got)
# kth not modified
kth = np.array([30, 15, 5])
okth = kth.copy()
cfunc(np.arange(40), kth)
self.assertPreciseEqual(kth, okth)
for r in ([2, 1], [1, 2], [1, 1]):
d = np.array(r)
tgt = np.argsort(d)
for k in 0, 1:
self.assertPreciseEqual(d[cfunc(d, k)[k]], d[tgt[k]])
self.argpartition_sanity_check(pyfunc, cfunc, d, k)
for r in ([3, 2, 1], [1, 2, 3], [2, 1, 3], [2, 3, 1],
[1, 1, 1], [1, 2, 2], [2, 2, 1], [1, 2, 1]):
d = np.array(r)
tgt = np.argsort(d)
for k in 0, 1, 2:
self.assertPreciseEqual(d[cfunc(d, k)[k]], d[tgt[k]])
self.argpartition_sanity_check(pyfunc, cfunc, d, k)
d = np.ones(50)
self.assertPreciseEqual(d[cfunc(d, 0)], d)
# sorted
d = np.arange(49)
for k in 5, 15:
self.assertEqual(cfunc(d, k)[k], k)
self.partition_sanity_check(pyfunc, cfunc, d, k)
# rsorted, with input flavours: array, list and tuple
d = np.arange(47)[::-1]
for a in d, d.tolist(), tuple(d.tolist()):
self.assertEqual(cfunc(a, 6)[6], 40)
self.assertEqual(cfunc(a, 16)[16], 30)
self.assertPreciseEqual(cfunc(a, -6), cfunc(a, 41))
self.assertPreciseEqual(cfunc(a, -16), cfunc(a, 31))
self.argpartition_sanity_check(pyfunc, cfunc, d, -16)
# median of 3 killer, O(n^2) on pure median 3 pivot quickselect
# exercises the median of median of 5 code used to keep O(n)
d = np.arange(1000000)
x = np.roll(d, d.size // 2)
mid = x.size // 2 + 1
self.assertEqual(x[cfunc(x, mid)[mid]], mid)
d = np.arange(1000001)
x = np.roll(d, d.size // 2 + 1)
mid = x.size // 2 + 1
self.assertEqual(x[cfunc(x, mid)[mid]], mid)
# max
d = np.ones(10)
d[1] = 4
self.assertEqual(d[cfunc(d, (2, -1))[-1]], 4)
self.assertEqual(d[cfunc(d, (2, -1))[2]], 1)
d[1] = np.nan
assert np.isnan(d[cfunc(d, (2, -1))[-1]])
# equal elements
d = np.arange(47) % 7
tgt = np.sort(np.arange(47) % 7)
self.rnd.shuffle(d)
for i in range(d.size):
self.assertEqual(d[cfunc(d, i)[i]], tgt[i])
self.argpartition_sanity_check(pyfunc, cfunc, d, i)
d = np.array([0, 1, 2, 3, 4, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 9])
kth = [0, 3, 19, 20]
self.assertEqual(tuple(d[cfunc(d, kth)[kth]]), (0, 3, 7, 7))
td = [(dt, s) for dt in [np.int32, np.float32] for s in (9, 16)]
for dt, s in td:
d = np.arange(s, dtype=dt)
self.rnd.shuffle(d)
d1 = np.tile(np.arange(s, dtype=dt), (4, 1))
map(self.rnd.shuffle, d1)
for i in range(d.size):
p = d[cfunc(d, i)]
self.assertEqual(p[i], i)
# all before are smaller
np.testing.assert_array_less(p[:i], p[i])
# all after are larger
np.testing.assert_array_less(p[i], p[i + 1:])
# sanity check
self.argpartition_sanity_check(pyfunc, cfunc, d, i)
def assert_partitioned(self, pyfunc, cfunc, d, kth):
prev = 0
for k in np.sort(kth):
np.testing.assert_array_less(d[prev:k], d[k],
err_msg='kth %d' % k)
self.assertTrue((d[k:] >= d[k]).all(),
msg=("kth %d, %r not greater equal "
"%d" % (k, d[k:], d[k])))
prev = k + 1
self.partition_sanity_check(pyfunc, cfunc, d, k)
def assert_argpartitioned(self, pyfunc, cfunc, d, kth):
prev = 0
for k in np.sort(kth):
np.testing.assert_array_less(d[prev:k], d[k],
err_msg='kth %d' % k)
self.assertTrue((d[k:] >= d[k]).all(),
msg=("kth %d, %r not greater equal "
"%d" % (k, d[k:], d[k])))
prev = k + 1
self.argpartition_sanity_check(pyfunc, cfunc, d, k)
def test_partition_iterative(self):
# inspired by the test of the same name in:
# https://github.com/numpy/numpy/blob/043a840/numpy/core/tests/test_multiarray.py
pyfunc = partition
cfunc = jit(nopython=True)(pyfunc)
assert_partitioned = partial(self.assert_partitioned, pyfunc, cfunc)
d = np.array([3, 4, 2, 1])
p = cfunc(d, (0, 3))
assert_partitioned(p, (0, 3))
assert_partitioned(d[np.argpartition(d, (0, 3))], (0, 3))
self.assertPreciseEqual(p, cfunc(d, (-3, -1)))
d = np.arange(17)
self.rnd.shuffle(d)
self.assertPreciseEqual(np.arange(17), cfunc(d, list(range(d.size))))
# test unsorted kth
d = np.arange(17)
self.rnd.shuffle(d)
keys = np.array([1, 3, 8, -2])
self.rnd.shuffle(d)
p = cfunc(d, keys)
assert_partitioned(p, keys)
self.rnd.shuffle(keys)
self.assertPreciseEqual(cfunc(d, keys), p)
# equal kth
d = np.arange(20)[::-1]
assert_partitioned(cfunc(d, [5] * 4), [5])
assert_partitioned(cfunc(d, [5] * 4 + [6, 13]), [5] * 4 + [6, 13])
def test_argpartition_iterative(self):
# inspired by the test of the same name in:
# https://github.com/numpy/numpy/blob/043a840/numpy/core/tests/test_multiarray.py
pyfunc = argpartition
cfunc = jit(nopython=True)(pyfunc)
assert_argpartitioned = partial(self.assert_argpartitioned,
pyfunc,
cfunc)
d = np.array([3, 4, 2, 1])
p = d[cfunc(d, (0, 3))]
assert_argpartitioned(p, (0, 3))
assert_argpartitioned(d[np.argpartition(d, (0, 3))], (0, 3))
self.assertPreciseEqual(p, d[cfunc(d, (-3, -1))])
d = np.arange(17)
self.rnd.shuffle(d)
self.assertPreciseEqual(np.arange(17), d[cfunc(d, list(range(d.size)))])
# test unsorted kth
d = np.arange(17)
self.rnd.shuffle(d)
keys = np.array([1, 3, 8, -2])
self.rnd.shuffle(d)
p = d[cfunc(d, keys)]
assert_argpartitioned(p, keys)
self.rnd.shuffle(keys)
self.assertPreciseEqual(d[cfunc(d, keys)], p)
# equal kth
d = np.arange(20)[::-1]
assert_argpartitioned(d[cfunc(d, [5] * 4)], [5])
assert_argpartitioned(d[cfunc(d, [5] * 4 + [6, 13])], [5] * 4 + [6, 13])
def test_partition_multi_dim(self):
pyfunc = partition
cfunc = jit(nopython=True)(pyfunc)
def check(a, kth):
expected = pyfunc(a, kth)
got = cfunc(a, kth)
self.assertPreciseEqual(expected[:, :, kth], got[:, :, kth])
for s in np.ndindex(expected.shape[:-1]):
self.assertPreciseEqual(np.unique(expected[s][:kth]),
np.unique(got[s][:kth]))
self.assertPreciseEqual(np.unique(expected[s][kth:]),
np.unique(got[s][kth:]))
def a_variations(a):
yield a
yield a.T
yield np.asfortranarray(a)
yield np.full_like(a, fill_value=np.nan)
yield np.full_like(a, fill_value=np.inf)
# multi-dimensional tuple input
yield (((1.0, 3.142, -np.inf, 3),),)
a = np.linspace(1, 10, 48)
a[4:7] = np.nan
a[8] = -np.inf
a[9] = np.inf
a = a.reshape((4, 3, 4))
for arr in a_variations(a):
for k in range(-3, 3):
check(arr, k)
def test_argpartition_multi_dim(self):
pyfunc = argpartition
cfunc = jit(nopython=True)(pyfunc)
def check(a, kth):
expected = pyfunc(a, kth)
got = cfunc(a, kth)
a = np.asarray(a)
idx = np.ndindex(a.shape[:-1])
for s in idx:
self.assertPreciseEqual(a[s][expected[s][kth]],
a[s][got[s][kth]])
for s in np.ndindex(expected.shape[:-1]):
self.assertPreciseEqual(np.unique(a[s][expected[s][:kth]]),
np.unique(a[s][got[s][:kth]]))
self.assertPreciseEqual(np.unique(a[s][expected[s][kth:]]),
np.unique(a[s][got[s][kth:]]))
def a_variations(a):
yield a
yield a.T
yield np.asfortranarray(a)
yield np.full_like(a, fill_value=np.nan)
yield np.full_like(a, fill_value=np.inf)
# multi-dimensional tuple input
yield (((1.0, 3.142, -np.inf, 3),),)
a = np.linspace(1, 10, 48)
a[4:7] = np.nan
a[8] = -np.inf
a[9] = np.inf
a = a.reshape((4, 3, 4))
for arr in a_variations(a):
for k in range(-3, 3):
check(arr, k)
def test_partition_boolean_inputs(self):
pyfunc = partition
cfunc = jit(nopython=True)(pyfunc)
for d in np.linspace(1, 10, 17), np.array((True, False, True)):
for kth in True, False, -1, 0, 1:
self.partition_sanity_check(pyfunc, cfunc, d, kth)
def test_argpartition_boolean_inputs(self):
pyfunc = argpartition
cfunc = jit(nopython=True)(pyfunc)
for d in np.linspace(1, 10, 17), np.array((True, False, True)):
for kth in True, False, -1, 0, 1:
self.argpartition_sanity_check(pyfunc, cfunc, d, kth)
@needs_blas
def test_cov_invalid_ddof(self):
pyfunc = cov
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
m = np.array([[0, 2], [1, 1], [2, 0]]).T
for ddof in np.arange(4), 4j:
with self.assertTypingError() as raises:
cfunc(m, ddof=ddof)
self.assertIn('ddof must be a real numerical scalar type',
str(raises.exception))
for ddof in np.nan, np.inf:
with self.assertRaises(ValueError) as raises:
cfunc(m, ddof=ddof)
self.assertIn('Cannot convert non-finite ddof to integer',
str(raises.exception))
for ddof in 1.1, -0.7:
with self.assertRaises(ValueError) as raises:
cfunc(m, ddof=ddof)
self.assertIn('ddof must be integral value', str(raises.exception))
def corr_corrcoef_basic(self, pyfunc, first_arg_name):
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc, abs_tol=1e-14)
def input_variations():
# array inputs
yield np.array([[0, 2], [1, 1], [2, 0]]).T
yield self.rnd.randn(100).reshape(5, 20)
yield np.asfortranarray(np.array([[0, 2], [1, 1], [2, 0]]).T)
yield self.rnd.randn(100).reshape(5, 20)[:, ::2]
yield np.array([0.3942, 0.5969, 0.7730, 0.9918, 0.7964])
yield np.full((4, 5), fill_value=True)
yield np.array([np.nan, 0.5969, -np.inf, 0.9918, 0.7964])
yield np.linspace(-3, 3, 33).reshape(33, 1)
# non-array inputs
yield ((0.1, 0.2), (0.11, 0.19), (0.09, 0.21)) # UniTuple
yield ((0.1, 0.2), (0.11, 0.19), (0.09j, 0.21j)) # Tuple
yield (-2.1, -1, 4.3)
yield (1, 2, 3)
yield [4, 5, 6]
yield ((0.1, 0.2, 0.3), (0.1, 0.2, 0.3))
yield [(1, 2, 3), (1, 3, 2)]
yield 3.142
yield ((1.1, 2.2, 1.5),)
# empty data structures
yield np.array([])
yield np.array([]).reshape(0, 2)
yield np.array([]).reshape(2, 0)
yield ()
# all inputs other than the first are defaulted
for input_arr in input_variations():
_check({first_arg_name: input_arr})
@needs_blas
def test_corrcoef_basic(self):
pyfunc = corrcoef
self.corr_corrcoef_basic(pyfunc, first_arg_name='x')
@needs_blas
def test_cov_basic(self):
pyfunc = cov
self.corr_corrcoef_basic(pyfunc, first_arg_name='m')
@needs_blas
def test_cov_explicit_arguments(self):
pyfunc = cov
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc, abs_tol=1e-14)
m = self.rnd.randn(105).reshape(15, 7)
y_choices = None, m[::-1]
rowvar_choices = False, True
bias_choices = False, True
ddof_choice = None, -1, 0, 1, 3.0, True
products = itertools.product(y_choices, rowvar_choices,
bias_choices, ddof_choice)
for y, rowvar, bias, ddof in products:
params = {'m': m, 'y': y, 'ddof': ddof,
'bias': bias, 'rowvar': rowvar}
_check(params)
@needs_blas
def test_corrcoef_explicit_arguments(self):
pyfunc = corrcoef
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc, abs_tol=1e-14)
x = self.rnd.randn(105).reshape(15, 7)
y_choices = None, x[::-1]
rowvar_choices = False, True
for y, rowvar in itertools.product(y_choices, rowvar_choices):
params = {'x': x, 'y': y, 'rowvar': rowvar}
_check(params)
def cov_corrcoef_edge_cases(self, pyfunc, first_arg_name):
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc, abs_tol=1e-14)
# some of these examples borrowed from numpy doc string examples:
# https://github.com/numpy/numpy/blob/v1.15.0/numpy/lib/function_base.py#L2199-L2231 # noqa: E501
# some borrowed from TestCov and TestCorrCoef:
# https://github.com/numpy/numpy/blob/80d3a7a/numpy/lib/tests/test_function_base.py # noqa: E501
m = np.array([-2.1, -1, 4.3])
y = np.array([3, 1.1, 0.12])
params = {first_arg_name: m, 'y': y}
_check(params)
m = np.array([1, 2, 3]) # test case modified such that m is 1D
y = np.array([[1j, 2j, 3j]])
params = {first_arg_name: m, 'y': y}
_check(params)
m = np.array([1, 2, 3])
y = (1j, 2j, 3j)
params = {first_arg_name: m, 'y': y}
_check(params)
params = {first_arg_name: y, 'y': m} # flip real and complex inputs
_check(params)
m = np.array([1, 2, 3])
y = (1j, 2j, 3) # note last item is not complex
params = {first_arg_name: m, 'y': y}
_check(params)
params = {first_arg_name: y, 'y': m} # flip real and complex inputs
_check(params)
m = np.array([])
y = np.array([])
params = {first_arg_name: m, 'y': y}
_check(params)
m = 1.1
y = 2.2
params = {first_arg_name: m, 'y': y}
_check(params)
m = self.rnd.randn(10, 3)
y = np.array([-2.1, -1, 4.3]).reshape(1, 3) / 10
params = {first_arg_name: m, 'y': y}
_check(params)
m = np.array([-2.1, -1, 4.3])
y = np.array([[3, 1.1, 0.12], [3, 1.1, 0.12]])
params = {first_arg_name: m, 'y': y}
_check(params)
for rowvar in False, True:
m = np.array([-2.1, -1, 4.3])
y = np.array([[3, 1.1, 0.12], [3, 1.1, 0.12], [4, 1.1, 0.12]])
params = {first_arg_name: m, 'y': y, 'rowvar': rowvar}
_check(params)
# swap m and y
params = {first_arg_name: y, 'y': m, 'rowvar': rowvar}
_check(params)
@needs_blas
def test_corrcoef_edge_cases(self):
pyfunc = corrcoef
self.cov_corrcoef_edge_cases(pyfunc, first_arg_name='x')
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc, abs_tol=1e-14)
for x in (np.nan, -np.inf, 3.142, 0):
params = {'x': x}
_check(params)
@needs_blas
def test_corrcoef_edge_case_extreme_values(self):
pyfunc = corrcoef
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc, abs_tol=1e-14)
# extreme values
x = ((1e-100, 1e100), (1e100, 1e-100))
params = {'x': x}
_check(params)
@needs_blas
def test_cov_edge_cases(self):
pyfunc = cov
self.cov_corrcoef_edge_cases(pyfunc, first_arg_name='m')
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc, abs_tol=1e-14)
# invalid ddof
m = np.array([[0, 2], [1, 1], [2, 0]]).T
params = {'m': m, 'ddof': 5}
_check(params)
@needs_blas
def test_cov_exceptions(self):
pyfunc = cov
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
def _check_m(m):
with self.assertTypingError() as raises:
cfunc(m)
self.assertIn('m has more than 2 dimensions', str(raises.exception))
m = np.ones((5, 6, 7))
_check_m(m)
m = ((((1, 2, 3), (2, 2, 2)),),)
_check_m(m)
m = [[[5, 6, 7]]]
_check_m(m)
def _check_y(m, y):
with self.assertTypingError() as raises:
cfunc(m, y=y)
self.assertIn('y has more than 2 dimensions', str(raises.exception))
m = np.ones((5, 6))
y = np.ones((5, 6, 7))
_check_y(m, y)
m = np.array((1.1, 2.2, 1.1))
y = (((1.2, 2.2, 2.3),),)
_check_y(m, y)
m = np.arange(3)
y = np.arange(4)
with self.assertRaises(ValueError) as raises:
cfunc(m, y=y)
self.assertIn('m and y have incompatible dimensions',
str(raises.exception))
# Numpy raises ValueError: all the input array dimensions except for the
# concatenation axis must match exactly.
m = np.array([-2.1, -1, 4.3]).reshape(1, 3)
with self.assertRaises(RuntimeError) as raises:
cfunc(m)
self.assertIn('2D array containing a single row is unsupported',
str(raises.exception))
def test_ediff1d_basic(self):
pyfunc = ediff1d
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc)
def to_variations(a):
yield None
yield a
yield a.astype(np.int16)
def ary_variations(a):
yield a
yield a.reshape(3, 2, 2)
yield a.astype(np.int32)
for ary in ary_variations(np.linspace(-2, 7, 12)):
params = {'ary': ary}
_check(params)
for a in to_variations(ary):
params = {'ary': ary, 'to_begin': a}
_check(params)
params = {'ary': ary, 'to_end': a}
_check(params)
for b in to_variations(ary):
params = {'ary': ary, 'to_begin': a, 'to_end': b}
_check(params)
def test_ediff1d_exceptions(self):
pyfunc = ediff1d
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
with self.assertTypingError() as e:
cfunc(np.array((True, True, False)))
msg = "Boolean dtype is unsupported (as per NumPy)"
assert msg in str(e.exception)
def test_fliplr_basic(self):
pyfunc = fliplr
cfunc = jit(nopython=True)(pyfunc)
def a_variations():
yield np.arange(10).reshape(5, 2)
yield np.arange(20).reshape(5, 2, 2)
yield ((1, 2),)
yield ([1, 2], [3, 4],)
for a in a_variations():
expected = pyfunc(a)
got = cfunc(a)
self.assertPreciseEqual(expected, got)
with self.assertRaises(TypingError) as raises:
cfunc("abc")
self.assertIn("Cannot np.fliplr on %s type" % types.unicode_type,
str(raises.exception))
def test_fliplr_exception(self):
pyfunc = fliplr
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
with self.assertRaises(TypingError) as raises:
cfunc(np.arange(3))
self.assertIn("cannot index array", str(raises.exception))
self.assertIn("with 2 indices", str(raises.exception))
def test_flipud_basic(self):
pyfunc = flipud
cfunc = jit(nopython=True)(pyfunc)
def a_variations():
yield [1]
yield np.arange(10)
yield np.arange(10).reshape(5, 2)
yield np.arange(20).reshape(5, 2, 2)
yield ((1, 2),)
yield ([1, 2], [3, 4],)
for a in a_variations():
expected = pyfunc(a)
got = cfunc(a)
self.assertPreciseEqual(expected, got)
with self.assertRaises(TypingError) as raises:
cfunc("abc")
self.assertIn("Cannot np.flipud on %s type" % types.unicode_type,
str(raises.exception))
def test_flipud_exception(self):
pyfunc = flipud
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
with self.assertRaises(TypingError) as raises:
cfunc(1)
self.assertIn("cannot index array", str(raises.exception))
self.assertIn("with 1 indices", str(raises.exception))
def test_flip_basic(self):
pyfunc = flip
cfunc = jit(nopython=True)(pyfunc)
def a_variations():
yield np.array(1)
yield np.arange(10)
yield np.arange(10).reshape(5, 2)
yield np.arange(20).reshape(5, 2, 2)
for a in a_variations():
expected = pyfunc(a)
got = cfunc(a)
self.assertPreciseEqual(expected, got)
with self.assertRaises(TypingError) as raises:
cfunc((1, 2, 3))
self.assertIn("Cannot np.flip on UniTuple", str(raises.exception))
def test_logspace2_basic(self):
def inputs():
#start, stop
yield 1, 60
yield -1, 60
yield -60, -1
yield -1, -60
yield 60, -1
yield 1.0, 60.0
yield -60.0, -1.0
yield -1.0, 60.0
yield 0.0, np.e
yield 0.0, np.pi
yield np.complex64(1), np.complex64(2)
yield np.complex64(2j), np.complex64(4j)
yield np.complex64(2), np.complex64(4j)
yield np.complex64(1 + 2j), np.complex64(3 + 4j)
yield np.complex64(1 - 2j), np.complex64(3 - 4j)
yield np.complex64(-1 + 2j), np.complex64(3 + 4j)
pyfunc = logspace2
cfunc = jit(nopython=True)(pyfunc)
for start, stop in inputs():
np.testing.assert_allclose(pyfunc(start, stop), cfunc(start, stop))
def test_logspace2_exception(self):
cfunc = jit(nopython=True)(logspace2)
self.disable_leak_check()
with self.assertRaises(TypingError) as raises:
cfunc("abc", 5)
self.assertIn('The first argument "start" must be a number',
str(raises.exception))
with self.assertRaises(TypingError) as raises:
cfunc(5, "abc")
self.assertIn('The second argument "stop" must be a number',
str(raises.exception))
def test_logspace3_basic(self):
def inputs():
#start, stop
yield 1, 60
yield -1, 60
yield -60, -1
yield -1, -60
yield 60, -1
yield 1.0, 60.0
yield -60.0, -1.0
yield -1.0, 60.0
yield 0.0, np.e
yield 0.0, np.pi
yield np.complex64(1), np.complex64(2)
yield np.complex64(2j), np.complex64(4j)
yield np.complex64(2), np.complex64(4j)
yield np.complex64(1 + 2j), np.complex64(3 + 4j)
yield np.complex64(1 - 2j), np.complex64(3 - 4j)
yield np.complex64(-1 + 2j), np.complex64(3 + 4j)
pyfunc = logspace3
cfunc = jit(nopython=True)(pyfunc)
for start, stop in inputs():
np.testing.assert_allclose(pyfunc(start, stop), cfunc(start, stop))
def test_logspace3_with_num_basic(self):
def inputs():
#start, stop, num
yield 1, 60, 20
yield -1, 60, 30
yield -60, -1, 40
yield -1, -60, 50
yield 60, -1, 60
yield 1.0, 60.0, 70
yield -60.0, -1.0, 80
yield -1.0, 60.0, 90
yield 0.0, np.e, 20
yield 0.0, np.pi, 30
yield np.complex64(1), np.complex64(2), 40
yield np.complex64(2j), np.complex64(4j), 50
yield np.complex64(2), np.complex64(4j), 60
yield np.complex64(1 + 2j), np.complex64(3 + 4j), 70
yield np.complex64(1 - 2j), np.complex64(3 - 4j), 80
yield np.complex64(-1 + 2j), np.complex64(3 + 4j), 90
pyfunc = logspace3
cfunc = jit(nopython=True)(pyfunc)
for start, stop, num in inputs():
np.testing.assert_allclose(pyfunc(start, stop, num),
cfunc(start, stop, num))
def test_logspace3_exception(self):
cfunc = jit(nopython=True)(logspace3)
self.disable_leak_check()
with self.assertRaises(TypingError) as raises:
cfunc("abc", 5)
self.assertIn('The first argument "start" must be a number',
str(raises.exception))
with self.assertRaises(TypingError) as raises:
cfunc(5, "abc")
self.assertIn('The second argument "stop" must be a number',
str(raises.exception))
with self.assertRaises(TypingError) as raises:
cfunc(0, 5, "abc")
self.assertIn('The third argument "num" must be an integer',
str(raises.exception))
def test_geomspace2_basic(self):
def inputs():
#start, stop
yield -1, -60
yield 1.0, 60.0
yield -60.0, -1.0
yield 1, 1000
yield 1000, 1
yield 1, 256
yield -1000, -1
yield -1, np.complex64(2j)
yield np.complex64(2j), -1
yield -1.0, np.complex64(2j)
yield np.complex64(1j), np.complex64(1000j)
yield np.complex64(-1 + 0j), np.complex64(1 + 0j)
yield np.complex64(1), np.complex64(2)
yield np.complex64(2j), np.complex64(4j)
yield np.complex64(2), np.complex64(4j)
yield np.complex64(1 + 2j), np.complex64(3 + 4j)
yield np.complex64(1 - 2j), np.complex64(3 - 4j)
yield np.complex64(-1 + 2j), np.complex64(3 + 4j)
pyfunc = geomspace2
cfunc = jit(nopython=True)(pyfunc)
for start, stop in inputs():
self.assertPreciseEqual(pyfunc(start, stop),
cfunc(start, stop),
abs_tol=1e-12)
def test_geomspace2_exception(self):
cfunc = jit(nopython=True)(geomspace2)
self.disable_leak_check()
with self.assertRaises(TypingError) as raises:
cfunc("abc", 5)
self.assertIn('The argument "start" must be a number',
str(raises.exception))
with self.assertRaises(TypingError) as raises:
cfunc(5, "abc")
self.assertIn('The argument "stop" must be a number',
str(raises.exception))
with self.assertRaises(ValueError) as raises:
cfunc(0, 5)
self.assertIn('Geometric sequence cannot include zero',
str(raises.exception))
with self.assertRaises(ValueError) as raises:
cfunc(5, 0)
self.assertIn('Geometric sequence cannot include zero',
str(raises.exception))
def test_geomspace3_basic(self):
def inputs():
#start, stop, num
yield -1, -60, 50
yield 1.0, 60.0, 70
yield -60.0, -1.0, 80
yield 1, 1000, 4
yield 1, 1000, 3
yield 1000, 1, 4
yield 1, 256, 9
yield -1000, -1, 4
yield -1, np.complex64(2j), 10
yield np.complex64(2j), -1, 20
yield -1.0, np.complex64(2j), 30
yield np.complex64(1j), np.complex64(1000j), 4
yield np.complex64(-1 + 0j), np.complex64(1 + 0j), 5
yield np.complex64(1), np.complex64(2), 40
yield np.complex64(2j), np.complex64(4j), 50
yield np.complex64(2), np.complex64(4j), 60
yield np.complex64(1 + 2j), np.complex64(3 + 4j), 70
yield np.complex64(1 - 2j), np.complex64(3 - 4j), 80
yield np.complex64(-1 + 2j), np.complex64(3 + 4j), 90
pyfunc = geomspace3
cfunc = jit(nopython=True)(pyfunc)
for start, stop, num in inputs():
self.assertPreciseEqual(pyfunc(start, stop, num),
cfunc(start, stop, num),
abs_tol=1e-14)
def test_geomspace3_exception(self):
cfunc = jit(nopython=True)(geomspace3)
self.disable_leak_check()
with self.assertRaises(TypingError) as raises:
cfunc("abc", 5, 10)
self.assertIn('The argument "start" must be a number',
str(raises.exception))
with self.assertRaises(TypingError) as raises:
cfunc(5, "abc", 10)
self.assertIn('The argument "stop" must be a number',
str(raises.exception))
with self.assertRaises(TypingError) as raises:
cfunc(5, 10, "abc")
self.assertIn('The argument "num" must be an integer',
str(raises.exception))
with self.assertRaises(ValueError) as raises:
cfunc(0, 5, 5)
self.assertIn('Geometric sequence cannot include zero',
str(raises.exception))
with self.assertRaises(ValueError) as raises:
cfunc(5, 0, 5)
self.assertIn('Geometric sequence cannot include zero',
str(raises.exception))
def test_geomspace_numpy(self):
cfunc2 = jit(nopython=True)(geomspace2)
cfunc3 = jit(nopython=True)(geomspace3)
pfunc3 = geomspace3
# https://github.com/numpy/numpy/blob/ab2178b47c0ee834180c318db196976623710691/numpy/core/tests/test_function_base.py#L122C3-L142
# test_basic
y = cfunc2(1, 1e6)
self.assertEqual(len(y), 50)
y = cfunc3(1, 1e6, num=100)
self.assertEqual(y[-1], 10 ** 6)
y = cfunc3(1, 1e6, num=7)
self.assertPreciseEqual(y, pfunc3(1,1e6, num=7))
y = cfunc3(8, 2, num=3)
self.assertPreciseEqual(y, pfunc3(8, 2, num=3))
self.assertTrue([x == 0 for x in y.imag])
y = cfunc3(-1, -100, num=3)
self.assertPreciseEqual(y, pfunc3(-1, -100, num=3))
self.assertTrue([x == 0 for x in y.imag])
y = cfunc3(-100, -1, num=3)
self.assertPreciseEqual(y, pfunc3(-100, -1, num=3))
self.assertTrue([x == 0 for x in y.imag])
# test_boundaries_match_start_and_stop_exactly
start = 0.3
stop = 20.3
y = cfunc3(start, stop, num=1)
self.assertPreciseEqual(y[0], start)
y = cfunc3(start, stop, num=3)
self.assertPreciseEqual(y[0], start)
self.assertPreciseEqual(y[-1], stop)
# test_nan_interior
with np.errstate(invalid='ignore'):
y = cfunc3(-3, 3, num=4)
self.assertPreciseEqual(y[0], -3.0)
self.assertTrue(np.isnan(y[1:-1]).all())
self.assertPreciseEqual(y[3], 3.0)
# test_complex
# Purely imaginary
y = cfunc3(1j, 16j, num=5)
self.assertPreciseEqual(y, pfunc3(1j, 16j, num=5), abs_tol=1e-14)
self.assertTrue([x == 0 for x in y.real])
y = cfunc3(-4j, -324j, num=5)
self.assertPreciseEqual(y, pfunc3(-4j, -324j, num=5), abs_tol=1e-13)
self.assertTrue([x == 0 for x in y.real])
y = cfunc3(1 + 1j, 1000 + 1000j, num=4)
self.assertPreciseEqual(y,
pfunc3(1 + 1j, 1000 + 1000j, num=4),
abs_tol=1e-13)
y = cfunc3(-1 + 1j, -1000 + 1000j, num=4)
self.assertPreciseEqual(y,
pfunc3(-1 + 1j, -1000 + 1000j, num=4),
abs_tol=1e-13)
# Logarithmic spirals
y = cfunc3(-1 + 0j, 1 + 0j, num=3)
self.assertPreciseEqual(y, pfunc3(-1 + 0j, 1 + 0j, num=3))
y = cfunc3(0 + 3j, -3 + 0j, 3)
self.assertPreciseEqual(y, pfunc3(0 + 3j, -3 + 0j, 3), abs_tol=1e-15)
y = cfunc3(0 + 3j, 3 + 0j, 3)
self.assertPreciseEqual(y, pfunc3(0 + 3j, 3 + 0j, 3), abs_tol=1e-15)
y = cfunc3(-3 + 0j, 0 - 3j, 3)
self.assertPreciseEqual(y, pfunc3(-3 + 0j, 0 - 3j, 3), abs_tol=1e-15)
y = cfunc3(0 + 3j, -3 + 0j, 3)
self.assertPreciseEqual(y, pfunc3(0 + 3j, -3 + 0j, 3), abs_tol=1e-15)
y = cfunc3(-2 - 3j, 5 + 7j, 7)
self.assertPreciseEqual(y, pfunc3(-2 - 3j, 5 + 7j, 7), abs_tol=1e-14)
y = cfunc3(3j, -5, 2)
self.assertPreciseEqual(y, pfunc3(3j, -5, 2))
y = cfunc3(-5, 3j, 2)
self.assertPreciseEqual(y, pfunc3(-5, 3j, 2))
def test_rot90_basic(self):
pyfunc = rot90
cfunc = jit(nopython=True)(pyfunc)
def a_variations():
yield np.arange(10).reshape(5, 2)
yield np.arange(20).reshape(5, 2, 2)
yield np.arange(64).reshape(2, 2, 2, 2, 2, 2)
for a in a_variations():
expected = pyfunc(a)
got = cfunc(a)
self.assertPreciseEqual(expected, got)
def test_rot90_with_k_basic(self):
pyfunc = rot90_k
cfunc = jit(nopython=True)(pyfunc)
def a_variations():
yield np.arange(10).reshape(5, 2)
yield np.arange(20).reshape(5, 2, 2)
yield np.arange(64).reshape(2, 2, 2, 2, 2, 2)
for a in a_variations():
for k in range(-5, 6):
expected = pyfunc(a, k)
got = cfunc(a, k)
self.assertPreciseEqual(expected, got)
def test_rot90_exception(self):
pyfunc = rot90_k
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
with self.assertRaises(TypingError) as raises:
cfunc("abc")
self.assertIn('The first argument "m" must be an array',
str(raises.exception))
with self.assertRaises(TypingError) as raises:
cfunc(np.arange(4).reshape(2, 2), k="abc")
self.assertIn('The second argument "k" must be an integer',
str(raises.exception))
with self.assertRaises(TypingError) as raises:
cfunc(np.arange(3))
self.assertIn("Input must be >= 2-d.", str(raises.exception))
def _check_split(self, func):
# Since np.split and np.array_split are very similar
pyfunc = func
cfunc = jit(nopython=True)(pyfunc)
def args_variations():
a = np.arange(100)
yield a, 2
yield a, 2, 0
yield a, [1, 4, 72]
yield list(a), [1, 4, 72]
yield tuple(a), [1, 4, 72]
yield a, [1, 4, 72], 0
yield list(a), [1, 4, 72], 0
yield tuple(a), [1, 4, 72], 0
a = np.arange(64).reshape(4, 4, 4)
yield a, 2
yield a, 2, 0
yield a, 2, 1
yield a, [2, 1, 5]
yield a, [2, 1, 5], 1
yield a, [2, 1, 5], 2
yield a, [1, 3]
yield a, [1, 3], 1
yield a, [1, 3], 2
yield a, [1], -1
yield a, [1], -2
yield a, [1], -3
yield a, np.array([], dtype=np.int64), 0
a = np.arange(100).reshape(2, -1)
yield a, 1
yield a, 1, 0
yield a, [1], 0
yield a, 50, 1
yield a, np.arange(10, 50, 10), 1
yield a, (1,)
yield a, (np.int32(4), 10)
a = np.array([])
yield a, 1
yield a, 2
yield a, (2, 3), 0
yield a, 1, 0
a = np.array([[]])
yield a, 1
yield a, (2, 3), 1
yield a, 1, 0
yield a, 1, 1
for args in args_variations():
expected = pyfunc(*args)
got = cfunc(*args)
np.testing.assert_equal(expected, list(got))
def _check_array_split(self, func):
# array_split specific checks, mainly dealing with `int`s
pyfunc = func
cfunc = jit(nopython=True)(pyfunc)
def args_variations():
yield np.arange(8), 3
yield list(np.arange(8)), 3
yield tuple(np.arange(8)), 3
yield np.arange(24).reshape(12, 2), 5
for args in args_variations():
expected = pyfunc(*args)
got = cfunc(*args)
np.testing.assert_equal(expected, list(got))
def test_array_split_basic(self):
self._check_split(array_split)
self._check_array_split(array_split)
def test_split_basic(self):
self._check_split(split)
self.disable_leak_check() # The exception leaks
with self.assertRaises(ValueError) as raises:
njit(split)(np.ones(5), 2)
self.assertIn(
"array split does not result in an equal division",
str(raises.exception)
)
with self.assertRaises(ValueError) as raises:
njit(split)(np.ones(5), [3], axis=-3)
self.assertIn("np.split: Argument axis out of bounds",
str(raises.exception))
def test_vhdsplit_basic(self):
# split and array_split have more comprehensive tests of splitting.
# only do simple tests on vsplit, hsplit and dsplit
# Based on tests from https://github.com/numpy/numpy/blob/f0befec40376fc46fdaceac2c49c7349ad671bde/numpy/lib/tests/test_shape_base.py#L538-L624 # noqa: E501
def inputs1D():
# test_1D_array
yield np.array([1, 2, 3, 4]), 2
yield np.array([1., 2., 3., 4.]), 2
def inputs2D():
# test_2D_array
yield np.array([[1, 2, 3, 4], [1, 2, 3, 4]]), 2
yield np.array([[1., 2., 3., 4.], [1., 2., 3., 4.]]), 2
yield np.arange(16.0).reshape(4, 4), 2
yield np.arange(16.0).reshape(4, 4), np.array([3, 6])
yield np.arange(16.0).reshape(4, 4), [3, 6]
yield np.arange(16.0).reshape(4, 4), (3, 6)
yield np.arange(8.0).reshape(2, 2, 2), 2
def inputs3D():
# test_3D_array
np.array([[[1, 2, 3, 4],
[1, 2, 3, 4]],
[[1, 2, 3, 4],
[1, 2, 3, 4]]]), 2
yield np.arange(16.0).reshape(2, 2, 4), 2
yield np.arange(16.0).reshape(2, 2, 4), np.array([3, 6])
yield np.arange(16.0).reshape(2, 2, 4), [3, 6]
yield np.arange(16.0).reshape(2, 2, 4), (3, 6)
yield np.arange(8.0).reshape(2, 2, 2), 2
inputs = [inputs1D(), inputs2D(), inputs3D()]
for (f, mindim, name) in [(vsplit, 2, "vsplit"),
(hsplit, 1, "hsplit"),
(dsplit, 3, "dsplit")]:
pyfunc = f
cfunc = njit(pyfunc)
for i in range(mindim, 4):
for a, ind_or_sec in inputs[i - 1]:
self.assertPreciseEqual(pyfunc(a, ind_or_sec),
cfunc(a, ind_or_sec))
def test_vhdsplit_exception(self):
# Single test method for vsplit, hsplit and dsplit exceptions
for (f, mindim, name) in [(vsplit, 2, "vsplit"),
(hsplit, 1, "hsplit"),
(dsplit, 3, "dsplit")]:
cfunc = jit(nopython=True)(f)
self.disable_leak_check()
with self.assertRaises(TypingError) as raises:
cfunc(1, 2)
self.assertIn('The argument "ary" must be an array',
str(raises.exception))
with self.assertRaises(TypingError) as raises:
cfunc("abc", 2)
self.assertIn('The argument "ary" must be an array',
str(raises.exception))
with self.assertRaises(TypingError) as raises:
cfunc(np.array([[1, 2, 3, 4], [1, 2, 3, 4]]), "abc")
self.assertIn(('The argument "indices_or_sections" must be int or '
'1d-array'),
str(raises.exception))
with self.assertRaises(ValueError) as raises:
cfunc(np.array(1), 2)
self.assertIn(name + ' only works on arrays of ' + str(mindim) +
' or more dimensions',
str(raises.exception))
def test_roll_basic(self):
pyfunc = roll
cfunc = jit(nopython=True)(pyfunc)
def a_variations():
yield np.arange(7)
yield np.arange(3 * 4 * 5).reshape(3, 4, 5)
yield [1.1, 2.2, 3.3]
yield (True, False, True)
yield False
yield 4
yield (9,)
yield np.asfortranarray(np.array([[1.1, np.nan], [np.inf, 7.8]]))
yield np.array([])
yield ()
def shift_variations():
return itertools.chain.from_iterable(((True, False),
range(-10, 10)))
for a in a_variations():
for shift in shift_variations():
expected = pyfunc(a, shift)
got = cfunc(a, shift)
self.assertPreciseEqual(expected, got)
def test_roll_exceptions(self):
pyfunc = roll
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
for shift in 1.1, (1, 2):
with self.assertTypingError() as e:
cfunc(np.arange(10), shift)
msg = "shift must be an integer"
assert msg in str(e.exception)
def test_extract_basic(self):
pyfunc = extract
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc)
a = np.arange(10)
self.rnd.shuffle(a)
for threshold in range(-3, 13):
cond = a > threshold
_check({'condition': cond, 'arr': a})
a = np.arange(60).reshape(4, 5, 3)
cond = a > 11.2
_check({'condition': cond, 'arr': a})
a = ((1, 2, 3), (3, 4, 5), (4, 5, 6))
cond = np.eye(3).flatten()
_check({'condition': cond, 'arr': a})
a = [1.1, 2.2, 3.3, 4.4]
cond = [1, 1, 0, 1]
_check({'condition': cond, 'arr': a})
a = np.linspace(-2, 10, 6)
element_pool = (True, False, np.nan, -1, -1.0, -1.2, 1, 1.0, 1.5j)
for cond in itertools.combinations_with_replacement(element_pool, 4):
_check({'condition': cond, 'arr': a})
_check({'condition': np.array(cond).reshape(2, 2), 'arr': a})
a = np.array([1, 2, 3])
cond = np.array([])
_check({'condition': cond, 'arr': a})
a = np.array([1, 2, 3])
cond = np.array([1, 0, 1, 0]) # but [1, 0, 1, 0, 1] raises
_check({'condition': cond, 'arr': a})
a = np.array([[1, 2, 3], [4, 5, 6]])
cond = [1, 0, 1, 0, 1, 0] # but [1, 0, 1, 0, 1, 0, 1] raises
_check({'condition': cond, 'arr': a})
a = np.array([[1, 2, 3], [4, 5, 6]])
cond = np.array([1, 0, 1, 0, 1, 0, 0, 0]).reshape(2, 2, 2)
_check({'condition': cond, 'arr': a})
a = np.asfortranarray(np.arange(60).reshape(3, 4, 5))
cond = np.repeat((0, 1), 30)
_check({'condition': cond, 'arr': a})
_check({'condition': cond, 'arr': a[::-1]})
a = np.array(4)
for cond in 0, 1:
_check({'condition': cond, 'arr': a})
a = 1
cond = 1
_check({'condition': cond, 'arr': a})
a = np.array(1)
cond = np.array([True, False])
_check({'condition': cond, 'arr': a})
a = np.arange(4)
cond = np.array([1, 0, 1, 0, 0, 0]).reshape(2, 3) * 1j
_check({'condition': cond, 'arr': a})
def test_extract_exceptions(self):
pyfunc = extract
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
a = np.array([])
cond = np.array([1, 2, 3])
with self.assertRaises(ValueError) as e:
cfunc(cond, a)
self.assertIn('Cannot extract from an empty array', str(e.exception))
def _check(cond, a):
msg = 'condition shape inconsistent with arr shape'
with self.assertRaises(ValueError) as e:
cfunc(cond, a)
self.assertIn(msg, str(e.exception))
a = np.array([[1, 2, 3], [1, 2, 3]])
cond = [1, 0, 1, 0, 1, 0, 1]
_check(cond, a)
a = np.array([1, 2, 3])
cond = np.array([1, 0, 1, 0, 1])
_check(cond, a)
a = np.array(60) # note, this is 0D
cond = 0, 1
_check(cond, a)
a = np.arange(4)
cond = np.array([True, False, False, False, True])
_check(cond, a)
a = np.arange(4)
cond = np.array([True, False, True, False, False, True, False])
_check(cond, a)
def test_np_trapz_basic(self):
pyfunc = np_trapz
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc)
y = [1, 2, 3]
_check({'y': y})
y = (3, 1, 2, 2, 2)
_check({'y': y})
y = np.arange(15).reshape(3, 5)
_check({'y': y})
y = np.linspace(-10, 10, 60).reshape(4, 3, 5)
_check({'y': y}, abs_tol=1e-13)
self.rnd.shuffle(y)
_check({'y': y}, abs_tol=1e-13)
y = np.array([])
_check({'y': y})
y = np.array([3.142, np.nan, np.inf, -np.inf, 5])
_check({'y': y})
y = np.arange(20) + np.linspace(0, 10, 20) * 1j
_check({'y': y})
y = np.array([], dtype=np.complex128)
_check({'y': y})
y = (True, False, True)
_check({'y': y})
def test_np_trapz_x_basic(self):
pyfunc = np_trapz_x
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc)
y = [1, 2, 3]
x = [4, 6, 8]
_check({'y': y, 'x': x})
y = [1, 2, 3, 4, 5]
x = (4, 6)
_check({'y': y, 'x': x})
y = (1, 2, 3, 4, 5)
x = [4, 5, 6, 7, 8]
_check({'y': y, 'x': x})
y = np.array([1, 2, 3, 4, 5])
x = [4, 4]
_check({'y': y, 'x': x})
y = np.array([])
x = np.array([2, 3])
_check({'y': y, 'x': x})
y = (1, 2, 3, 4, 5)
x = None
_check({'y': y, 'x': x})
y = np.arange(20).reshape(5, 4)
x = np.array([4, 5])
_check({'y': y, 'x': x})
y = np.arange(20).reshape(5, 4)
x = np.array([4, 5, 6, 7])
_check({'y': y, 'x': x})
y = np.arange(60).reshape(5, 4, 3)
x = np.array([4, 5])
_check({'y': y, 'x': x})
y = np.arange(60).reshape(5, 4, 3)
x = np.array([4, 5, 7])
_check({'y': y, 'x': x})
y = np.arange(60).reshape(5, 4, 3)
self.rnd.shuffle(y)
x = y + 1.1
self.rnd.shuffle(x)
_check({'y': y, 'x': x})
y = np.arange(20)
x = y + np.linspace(0, 10, 20) * 1j
_check({'y': y, 'x': x})
y = np.array([1, 2, 3])
x = np.array([1 + 1j, 1 + 2j])
_check({'y': y, 'x': x})
@unittest.skip('NumPy behaviour questionable')
def test_trapz_numpy_questionable(self):
# https://github.com/numpy/numpy/issues/12858
pyfunc = np_trapz
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc)
# passes (NumPy and Numba return 2.0)
y = np.array([True, False, True, True]).astype(int)
_check({'y': y})
# fails (NumPy returns 1.5; Numba returns 2.0)
y = np.array([True, False, True, True])
_check({'y': y})
def test_np_trapz_dx_basic(self):
pyfunc = np_trapz_dx
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc)
y = [1, 2, 3]
dx = 2
_check({'y': y, 'dx': dx})
y = [1, 2, 3, 4, 5]
dx = [1, 4, 5, 6]
_check({'y': y, 'dx': dx})
y = [1, 2, 3, 4, 5]
dx = [1, 4, 5, 6]
_check({'y': y, 'dx': dx})
y = np.linspace(-2, 5, 10)
dx = np.nan
_check({'y': y, 'dx': dx})
y = np.linspace(-2, 5, 10)
dx = np.inf
_check({'y': y, 'dx': dx})
y = np.linspace(-2, 5, 10)
dx = np.linspace(-2, 5, 9)
_check({'y': y, 'dx': dx}, abs_tol=1e-13)
y = np.arange(60).reshape(4, 5, 3) * 1j
dx = np.arange(40).reshape(4, 5, 2)
_check({'y': y, 'dx': dx})
x = np.arange(-10, 10, .1)
r = cfunc(np.exp(-.5 * x ** 2) / np.sqrt(2 * np.pi), dx=0.1)
# check integral of normal equals 1
np.testing.assert_almost_equal(r, 1, 7)
y = np.arange(20)
dx = 1j
_check({'y': y, 'dx': dx})
y = np.arange(20)
dx = np.array([5])
_check({'y': y, 'dx': dx})
def test_np_trapz_x_dx_basic(self):
pyfunc = np_trapz_x_dx
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc)
# dx should be ignored
for dx in (None, 2, np.array([1, 2, 3, 4, 5])):
y = [1, 2, 3]
x = [4, 6, 8]
_check({'y': y, 'x': x, 'dx': dx})
y = [1, 2, 3, 4, 5]
x = [4, 6]
_check({'y': y, 'x': x, 'dx': dx})
y = [1, 2, 3, 4, 5]
x = [4, 5, 6, 7, 8]
_check({'y': y, 'x': x, 'dx': dx})
y = np.arange(60).reshape(4, 5, 3)
self.rnd.shuffle(y)
x = y * 1.1
x[2, 2, 2] = np.nan
_check({'y': y, 'x': x, 'dx': dx})
def test_np_trapz_x_dx_exceptions(self):
pyfunc = np_trapz_x_dx
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
def check_not_ok(params):
with self.assertRaises(ValueError) as e:
cfunc(*params)
self.assertIn('unable to broadcast', str(e.exception))
y = [1, 2, 3, 4, 5]
for x in [4, 5, 6, 7, 8, 9], [4, 5, 6]:
check_not_ok((y, x, 1.0))
y = np.arange(60).reshape(3, 4, 5)
x = np.arange(36).reshape(3, 4, 3)
check_not_ok((y, x, 1.0))
y = np.arange(60).reshape(3, 4, 5)
x = np.array([4, 5, 6, 7])
check_not_ok((y, x, 1.0))
y = [1, 2, 3, 4, 5]
dx = np.array([1.0, 2.0])
check_not_ok((y, None, dx))
y = np.arange(60).reshape(3, 4, 5)
dx = np.arange(60).reshape(3, 4, 5)
check_not_ok((y, None, dx))
with self.assertTypingError() as e:
y = np.array(4)
check_not_ok((y, None, 1.0))
self.assertIn('y cannot be 0D', str(e.exception))
for y in 5, False, np.nan:
with self.assertTypingError() as e:
cfunc(y, None, 1.0)
self.assertIn('y cannot be a scalar', str(e.exception))
def test_average(self):
#array of random numbers
N = 100
a = np.random.ranf(N) * 100
w = np.random.ranf(N) * 100
w0 = np.zeros(N)
#boolean array and weights
a_bool = np.random.ranf(N) > 0.5
w_bool = np.random.ranf(N) > 0.5
#array of random ints
a_int = np.random.randint(101, size=N)
w_int = np.random.randint(101, size=N)
#3D array of random numbers
d0 = 100
d1 = 50
d2 = 25
a_3d = np.random.rand(d0,d1,d2) * 100
w_3d = np.random.rand(d0,d1,d2) * 100
pyfunc = np_average
cfunc = jit(nopython=True)(pyfunc)
#test case for average with weights
#(number of elements in array and weight array are equal)
self.assertAlmostEqual( pyfunc(a,weights=w),
cfunc(a,weights=w), places=10)
self.assertAlmostEqual( pyfunc(a_3d,weights=w_3d),
cfunc(a_3d,weights=w_3d), places=10)
#test case for average with array and weights with
#int datatype (number of elements in array and weight array are equal)
self.assertAlmostEqual( pyfunc(a_int,weights=w_int),
cfunc(a_int,weights=w_int), places=10)
#test case for average with boolean weights
self.assertAlmostEqual( pyfunc(a,weights=w_bool),
cfunc(a,weights=w_bool), places=10)
self.assertAlmostEqual( pyfunc(a_bool,weights=w),
cfunc(a_bool,weights=w), places=10)
self.assertAlmostEqual( pyfunc(a_bool, weights=w_bool),
cfunc(a_bool, weights=w_bool), places=10)
#test case for average without weights
self.assertAlmostEqual(pyfunc(a), cfunc(a), places=10)
self.assertAlmostEqual(pyfunc(a_3d), cfunc(a_3d), places=10)
def test_weights_zero_sum(data, weights):
with self.assertRaises(ZeroDivisionError) as e:
cfunc(data, weights=weights)
err = e.exception
self.assertEqual(str(err),
"Weights sum to zero, can't be normalized.")
#test case when sum of weights is zero
test_weights_zero_sum(a, weights=w0)
def test_1D_weights(data, weights):
with self.assertRaises(TypeError) as e:
cfunc(data, weights=weights)
err = e.exception
self.assertEqual(str(err),
"Numba does not support average when shapes of "
"a and weights differ.")
def test_1D_weights_axis(data, axis, weights):
with self.assertRaises(TypeError) as e:
cfunc(data,axis=axis, weights=weights)
err = e.exception
self.assertEqual(str(err),
"Numba does not support average with axis.")
#small case to test exceptions for 2D array and 1D weights
data = np.arange(6).reshape((3,2,1))
w = np.asarray([1. / 4, 3. / 4])
#test without axis argument
test_1D_weights(data, weights=w)
#test with axis argument
test_1D_weights_axis(data, axis=1, weights=w)
def test_allclose(self):
pyfunc = np_allclose
cfunc = jit(nopython=True)(pyfunc)
min_int = np.iinfo(np.int_).min
a = np.array([min_int], dtype=np.int_)
simple_data = [
(np.asarray([1e10, 1e-7]), np.asarray([1.00001e10, 1e-8])),
(np.asarray([1e10, 1e-8]), np.asarray([1.00001e10, 1e-9])),
(np.asarray([1e10, 1e-8]), np.asarray([1.0001e10, 1e-9])),
(np.asarray([1e10]), np.asarray([1.0001e10, 1e-9])),
(1.0, 1.0),
(np.array([np.inf, 1]), np.array([0, np.inf])),
(a, a)
]
for a, b in simple_data:
py_result = pyfunc(a, b)
c_result = cfunc(a, b)
self.assertEqual(py_result, c_result)
a = np.asarray([1.0, np.nan])
b = np.asarray([1.0, np.nan])
self.assertFalse(cfunc(a, b))
self.assertEqual(pyfunc(a, b, equal_nan=True),
cfunc(a, b, equal_nan=True))
b = np.asarray([np.nan, 1.0])
self.assertEqual(pyfunc(a, b), cfunc(a, b))
noise_levels = [1.0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 0.0]
zero_array = np.zeros((25, 4))
a = np.random.ranf((25, 4))
for noise in noise_levels:
for rtol in noise_levels:
for atol in noise_levels:
py_result = pyfunc(zero_array, noise,
atol=atol, rtol=rtol)
c_result = cfunc(zero_array, noise,
atol=atol, rtol=rtol)
self.assertEqual(py_result, c_result)
py_result = pyfunc(noise, zero_array,
atol=atol, rtol=rtol)
c_result = cfunc(noise, zero_array,
atol=atol, rtol=rtol)
self.assertEqual(py_result, c_result)
py_result = pyfunc(np.asarray([noise]), zero_array,
atol=atol, rtol=rtol)
c_result = cfunc(np.asarray([noise]), zero_array,
atol=atol, rtol=rtol)
self.assertEqual(py_result, c_result)
py_result = pyfunc(a, a + noise, atol=atol, rtol=rtol)
c_result = cfunc(a, a + noise, atol=atol, rtol=rtol)
self.assertEqual(py_result, c_result)
py_result = pyfunc(a + noise, a, atol=atol, rtol=rtol)
c_result = cfunc(a + noise, a, atol=atol, rtol=rtol)
self.assertEqual(py_result, c_result)
def test_ip_allclose_numpy(self):
# https://github.com/numpy/numpy/blob/4adc87dff15a247e417d50f10cc4def8e1c17a03/numpy/core/tests/test_numeric.py#L2402-L2420 # noqa: E501
pyfunc = np_allclose
cfunc = jit(nopython=True)(pyfunc)
arr = np.array([100.0, 1000.0])
aran = np.arange(125).astype(dtype=np.float64).reshape((5, 5, 5))
atol = 1e-8
rtol = 1e-5
numpy_data = [
(np.asarray([1, 0]), np.asarray([1, 0])),
(np.asarray([atol]), np.asarray([0.0])),
(np.asarray([1.0]), np.asarray([1 + rtol + atol])),
(arr, arr + arr * rtol),
(arr, arr + arr * rtol + atol * 2),
(aran, aran + aran * rtol),
(np.inf, np.inf),
(np.inf, np.asarray([np.inf]))
]
for (x, y) in numpy_data:
self.assertEqual(pyfunc(x, y), cfunc(x, y))
def test_ip_not_allclose_numpy(self):
# https://github.com/numpy/numpy/blob/4adc87dff15a247e417d50f10cc4def8e1c17a03/numpy/core/tests/test_numeric.py#L2422-L2441 # noqa: E501
pyfunc = np_allclose
cfunc = jit(nopython=True)(pyfunc)
aran = np.arange(125).astype(dtype=np.float64).reshape((5, 5, 5))
atol = 1e-8
rtol = 1e-5
numpy_data = [
(np.asarray([np.inf, 0]), np.asarray([1.0, np.inf])),
(np.asarray([np.inf, 0]), np.asarray([1.0, 0])),
(np.asarray([np.inf, np.inf]), np.asarray([1.0, np.inf])),
(np.asarray([np.inf, np.inf]), np.asarray([1.0, 0.0])),
(np.asarray([-np.inf, 0.0]), np.asarray([np.inf, 0.0])),
(np.asarray([np.nan, 0.0]), np.asarray([np.nan, 0.0])),
(np.asarray([atol * 2]), np.asarray([0.0])),
(np.asarray([1.0]), np.asarray([1 + rtol + atol * 2])),
(aran, aran + aran * atol + atol * 2),
(np.array([np.inf, 1.0]), np.array([0.0, np.inf]))
]
for (x, y) in numpy_data:
self.assertEqual(pyfunc(x, y), cfunc(x, y))
def test_return_class_is_ndarray_numpy(self):
# https://github.com/numpy/numpy/blob/4adc87dff15a247e417d50f10cc4def8e1c17a03/numpy/core/tests/test_numeric.py#L2460-L2468 # noqa: E501
pyfunc = np_allclose
cfunc = jit(nopython=True)(pyfunc)
class Foo(np.ndarray):
def __new__(cls, *args, **kwargs):
return np.array(*args, **kwargs).view(cls)
a = Foo([1])
self.assertTrue(type(cfunc(a, a)) is bool)
def test_equalnan_numpy(self):
# https://github.com/numpy/numpy/blob/4adc87dff15a247e417d50f10cc4def8e1c17a03/numpy/core/tests/test_numeric.py#L2456-L2458 # noqa: E501
pyfunc = np_allclose
cfunc = jit(nopython=True)(pyfunc)
x = np.array([1.0, np.nan])
self.assertEqual(pyfunc(x, x, equal_nan=True),
cfunc(x, x, equal_nan=True))
def test_no_parameter_modification_numpy(self):
# https://github.com/numpy/numpy/blob/4adc87dff15a247e417d50f10cc4def8e1c17a03/numpy/core/tests/test_numeric.py#L2443-L2448 # noqa: E501
pyfunc = np_allclose
cfunc = jit(nopython=True)(pyfunc)
x = np.array([np.inf, 1])
y = np.array([0, np.inf])
cfunc(x, y)
np.testing.assert_array_equal(x, np.array([np.inf, 1]))
np.testing.assert_array_equal(y, np.array([0, np.inf]))
def test_min_int_numpy(self):
# https://github.com/numpy/numpy/blob/4adc87dff15a247e417d50f10cc4def8e1c17a03/numpy/core/tests/test_numeric.py#L2450-L2454 # noqa: E501
pyfunc = np_allclose
cfunc = jit(nopython=True)(pyfunc)
min_int = np.iinfo(np.int_).min
a = np.array([min_int], dtype=np.int_)
self.assertEqual(pyfunc(a, a), cfunc(a, a))
def test_allclose_exception(self):
self.disable_leak_check()
pyfunc = np_allclose
cfunc = jit(nopython=True)(pyfunc)
inps = [
(np.asarray([1e10, 1e-9, np.nan]),
np.asarray([1.0001e10, 1e-9]),
1e-05, 1e-08, False,
"shape mismatch: objects cannot be broadcast to a single shape",
ValueError),
('hello', 3, False, 1e-08, False,
'The first argument "a" must be array-like',
TypingError),
(3, 'hello', False, 1e-08, False,
'The second argument "b" must be array-like',
TypingError),
(2, 3, False, 1e-08, False,
'The third argument "rtol" must be a floating point',
TypingError),
(2, 3, 1e-05, False, False,
'The fourth argument "atol" must be a floating point',
TypingError),
(2, 3, 1e-05, 1e-08, 1,
'The fifth argument "equal_nan" must be a boolean',
TypingError),
]
for a, b, rtol, atol, equal_nan, exc_msg, exc in inps:
with self.assertRaisesRegex(exc, exc_msg):
cfunc(a, b, rtol, atol, equal_nan)
def test_interp_basic(self):
pyfunc = interp
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc, abs_tol=1e-10)
x = np.linspace(-5, 5, 25)
xp = np.arange(-4, 8)
fp = xp + 1.5
_check(params={'x': x, 'xp': xp, 'fp': fp})
self.rnd.shuffle(x)
_check(params={'x': x, 'xp': xp, 'fp': fp})
self.rnd.shuffle(fp)
_check(params={'x': x, 'xp': xp, 'fp': fp})
x[:5] = np.nan
x[-5:] = np.inf
self.rnd.shuffle(x)
_check(params={'x': x, 'xp': xp, 'fp': fp})
fp[:5] = np.nan
fp[-5:] = -np.inf
self.rnd.shuffle(fp)
_check(params={'x': x, 'xp': xp, 'fp': fp})
x = np.arange(-4, 8)
xp = x + 1
fp = x + 2
_check(params={'x': x, 'xp': xp, 'fp': fp})
x = (2.2, 3.3, -5.0)
xp = (2, 3, 4)
fp = (5, 6, 7)
_check(params={'x': x, 'xp': xp, 'fp': fp})
x = ((2.2, 3.3, -5.0), (1.2, 1.3, 4.0))
xp = np.linspace(-4, 4, 10)
fp = np.arange(-5, 5)
_check(params={'x': x, 'xp': xp, 'fp': fp})
x = np.array([1.4, np.nan, np.inf, -np.inf, 0.0, -9.1])
x = x.reshape(3, 2, order='F')
xp = np.linspace(-4, 4, 10)
fp = np.arange(-5, 5)
_check(params={'x': x, 'xp': xp, 'fp': fp})
for x in range(-2, 4):
xp = [0, 1, 2]
fp = (3, 4, 5)
_check(params={'x': x, 'xp': xp, 'fp': fp})
x = np.array([])
xp = [0, 1, 2]
fp = (3, 4, 5)
_check(params={'x': x, 'xp': xp, 'fp': fp})
x = np.linspace(0, 25, 60).reshape(3, 4, 5)
xp = np.arange(20)
fp = xp - 10
_check(params={'x': x, 'xp': xp, 'fp': fp})
x = np.nan
xp = np.arange(5)
fp = np.full(5, np.nan)
_check(params={'x': x, 'xp': xp, 'fp': fp})
x = np.nan
xp = [3]
fp = [4]
_check(params={'x': x, 'xp': xp, 'fp': fp})
x = np.arange(-4, 8)
xp = x
fp = x
_check(params={'x': x, 'xp': xp, 'fp': fp})
x = [True, False]
xp = np.arange(-4, 8)
fp = xp
_check(params={'x': x, 'xp': xp, 'fp': fp})
x = [-np.inf, -1.0, 0.0, 1.0, np.inf]
xp = np.arange(-4, 8)
fp = xp * 2.2
_check(params={'x': x, 'xp': xp, 'fp': fp})
x = np.linspace(-10, 10, 10)
xp = np.array([-np.inf, -1.0, 0.0, 1.0, np.inf])
fp = xp * 2.2
_check(params={'x': x, 'xp': xp, 'fp': fp})
x = self.rnd.randn(100)
xp = np.linspace(-3, 3, 100)
fp = np.full(100, fill_value=3.142)
_check(params={'x': x, 'xp': xp, 'fp': fp})
for factor in 1, -1:
x = np.array([5, 6, 7]) * factor
xp = [1, 2]
fp = [3, 4]
_check(params={'x': x, 'xp': xp, 'fp': fp})
x = 1
xp = [1]
fp = [True]
_check(params={'x': x, 'xp': xp, 'fp': fp})
x = np.linspace(0, 1, 5)
y = np.linspace(0, 1, 5)
x0 = np.linspace(0, 1, 50)
out = cfunc(x0, x, y)
np.testing.assert_almost_equal(out, x0)
x = np.array([1, 2, 3, 4])
xp = np.array([1, 2, 3, 4])
fp = np.array([1, 2, 3.01, 4])
_check(params={'x': x, 'xp': xp, 'fp': fp})
xp = [1]
fp = [np.inf]
_check(params={'x': 1, 'xp': xp, 'fp': fp})
x = np.array([1, 2, 2.5, 3, 4])
xp = np.array([1, 2, 3, 4])
fp = np.array([1, 2, np.nan, 4])
_check({'x': x, 'xp': xp, 'fp': fp})
x = np.array([1, 1.5, 2, 2.5, 3, 4, 4.5, 5, 5.5])
xp = np.array([1, 2, 3, 4, 5])
fp = np.array([np.nan, 2, np.nan, 4, np.nan])
_check({'x': x, 'xp': xp, 'fp': fp})
x = np.array([1, 2, 2.5, 3, 4])
xp = np.array([1, 2, 3, 4])
fp = np.array([1, 2, np.inf, 4])
_check({'x': x, 'xp': xp, 'fp': fp})
x = np.array([1, 1.5, np.nan, 2.5, -np.inf, 4, 4.5, 5, np.inf, 0, 7])
xp = np.array([1, 2, 3, 4, 5, 6])
fp = np.array([1, 2, np.nan, 4, 3, np.inf])
_check({'x': x, 'xp': xp, 'fp': fp})
x = np.array([3.10034867, 3.0999066, 3.10001529])
xp = np.linspace(0, 10, 1 + 20000)
fp = np.sin(xp / 2.0)
_check({'x': x, 'xp': xp, 'fp': fp})
x = self.rnd.uniform(0, 2 * np.pi, (100,))
xp = np.linspace(0, 2 * np.pi, 1000)
fp = np.cos(xp)
exact = np.cos(x)
got = cfunc(x, xp, fp)
np.testing.assert_allclose(exact, got, atol=1e-5)
# very dense calibration
x = self.rnd.randn(10)
xp = np.linspace(-10, 10, 1000)
fp = np.ones_like(xp)
_check({'x': x, 'xp': xp, 'fp': fp})
# very sparse calibration
x = self.rnd.randn(1000)
xp = np.linspace(-10, 10, 10)
fp = np.ones_like(xp)
_check({'x': x, 'xp': xp, 'fp': fp})
def _make_some_values_non_finite(self, a):
p = a.size // 100
np.put(a, self.rnd.choice(range(a.size), p, replace=False), np.nan)
np.put(a, self.rnd.choice(range(a.size), p, replace=False), -np.inf)
np.put(a, self.rnd.choice(range(a.size), p, replace=False), np.inf)
def arrays(self, ndata):
# much_finer_grid
yield np.linspace(2.0, 7.0, 1 + ndata * 5)
# finer_grid
yield np.linspace(2.0, 7.0, 1 + ndata)
# similar_grid
yield np.linspace(2.1, 6.8, 1 + ndata // 2)
# coarser_grid
yield np.linspace(2.1, 7.5, 1 + ndata // 2)
# much_coarser_grid
yield np.linspace(1.1, 9.5, 1 + ndata // 5)
# finer_stretched_grid
yield np.linspace(3.1, 5.3, 1 + ndata) * 1.09
# similar_stretched_grid
yield np.linspace(3.1, 8.3, 1 + ndata // 2) * 1.09
# finer_compressed_grid
yield np.linspace(3.1, 5.3, 1 + ndata) * 0.91
# similar_compressed_grid
yield np.linspace(3.1, 8.3, 1 + ndata // 2) * 0.91
# warped_grid
yield np.linspace(3.1, 5.3, 1 + ndata // 2) + 0.3 * np.sin(
np.arange(1 + ndata / 2) * np.pi / (1 + ndata / 2))
# very_low_noise_grid
yield np.linspace(3.1, 5.3, 1 + ndata) + self.rnd.normal(
size=1 + ndata, scale=0.5 / ndata)
# low_noise_grid
yield np.linspace(3.1, 5.3, 1 + ndata) + self.rnd.normal(
size=1 + ndata, scale=2.0 / ndata)
# med_noise_grid
yield np.linspace(3.1, 5.3, 1 + ndata) + self.rnd.normal(
size=1 + ndata, scale=5.0 / ndata)
# high_noise_grid
yield np.linspace(3.1, 5.3, 1 + ndata) + self.rnd.normal(
size=1 + ndata, scale=20.0 / ndata)
# very_high_noise_grid
yield np.linspace(3.1, 5.3, 1 + ndata) + self.rnd.normal(
size=1 + ndata, scale=50.0 / ndata)
# extreme_noise_grid
yield np.linspace(3.1, 5.3, 1 + ndata) + self.rnd.normal(
size=1 + ndata, scale=200.0 / ndata)
# random_fine_grid
yield self.rnd.rand(1 + ndata) * 9.0 + 0.6
# random_grid
yield self.rnd.rand(1 + ndata * 2) * 4.0 + 1.3
def test_interp_stress_tests(self):
pyfunc = interp
cfunc = jit(nopython=True)(pyfunc)
ndata = 20000
xp = np.linspace(0, 10, 1 + ndata)
fp = np.sin(xp / 2.0)
for x in self.arrays(ndata):
atol = 1e-14 # using abs_tol as otherwise fails on 32bit builds
expected = pyfunc(x, xp, fp)
got = cfunc(x, xp, fp)
self.assertPreciseEqual(expected, got, abs_tol=atol)
# no longer require xp to be monotonically increasing
# (in keeping with numpy) even if the output might not
# be meaningful; shuffle all inputs
self.rnd.shuffle(x)
expected = pyfunc(x, xp, fp)
got = cfunc(x, xp, fp)
self.assertPreciseEqual(expected, got, abs_tol=atol)
self.rnd.shuffle(xp)
expected = pyfunc(x, xp, fp)
got = cfunc(x, xp, fp)
self.assertPreciseEqual(expected, got, abs_tol=atol)
self.rnd.shuffle(fp)
expected = pyfunc(x, xp, fp)
got = cfunc(x, xp, fp)
self.assertPreciseEqual(expected, got, abs_tol=atol)
# add some values non finite
self._make_some_values_non_finite(x)
expected = pyfunc(x, xp, fp)
got = cfunc(x, xp, fp)
self.assertPreciseEqual(expected, got, abs_tol=atol)
self._make_some_values_non_finite(xp)
expected = pyfunc(x, xp, fp)
got = cfunc(x, xp, fp)
self.assertPreciseEqual(expected, got, abs_tol=atol)
self._make_some_values_non_finite(fp)
expected = pyfunc(x, xp, fp)
got = cfunc(x, xp, fp)
self.assertPreciseEqual(expected, got, abs_tol=atol)
def test_interp_complex_stress_tests(self):
pyfunc = interp
cfunc = jit(nopython=True)(pyfunc)
ndata = 2000
xp = np.linspace(0, 10, 1 + ndata)
real = np.sin(xp / 2.0)
real[:200] = self.rnd.choice([np.inf, -np.inf, np.nan], 200)
self.rnd.shuffle(real)
imag = np.cos(xp / 2.0)
imag[:200] = self.rnd.choice([np.inf, -np.inf, np.nan], 200)
self.rnd.shuffle(imag)
fp = real + 1j * imag
for x in self.arrays(ndata):
expected = pyfunc(x, xp, fp)
got = cfunc(x, xp, fp)
np.testing.assert_allclose(expected, got, equal_nan=True)
self.rnd.shuffle(x)
self.rnd.shuffle(xp)
self.rnd.shuffle(fp)
np.testing.assert_allclose(expected, got, equal_nan=True)
def test_interp_exceptions(self):
pyfunc = interp
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
x = np.array([1, 2, 3])
xp = np.array([])
fp = np.array([])
with self.assertRaises(ValueError) as e:
cfunc(x, xp, fp)
msg = "array of sample points is empty"
self.assertIn(msg, str(e.exception))
x = 1
xp = np.array([1, 2, 3])
fp = np.array([1, 2])
with self.assertRaises(ValueError) as e:
cfunc(x, xp, fp)
msg = "fp and xp are not of the same size."
self.assertIn(msg, str(e.exception))
x = 1
xp = np.arange(6).reshape(3, 2)
fp = np.arange(6)
with self.assertTypingError() as e:
cfunc(x, xp, fp)
msg = "xp must be 1D"
self.assertIn(msg, str(e.exception))
x = 1
xp = np.arange(6)
fp = np.arange(6).reshape(3, 2)
with self.assertTypingError() as e:
cfunc(x, xp, fp)
msg = "fp must be 1D"
self.assertIn(msg, str(e.exception))
x = 1 + 1j
xp = np.arange(6)
fp = np.arange(6)
with self.assertTypingError() as e:
cfunc(x, xp, fp)
complex_dtype_msg = (
"Cannot cast array data from complex dtype "
"to float64 dtype"
)
self.assertIn(complex_dtype_msg, str(e.exception))
x = 1
xp = (np.arange(6) + 1j).astype(np.complex64)
fp = np.arange(6)
with self.assertTypingError() as e:
cfunc(x, xp, fp)
self.assertIn(complex_dtype_msg, str(e.exception))
def test_interp_non_finite_calibration(self):
# examples from
# https://github.com/numpy/numpy/issues/12951
pyfunc = interp
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc)
xp = np.array([0, 1, 9, 10])
fp = np.array([-np.inf, 0.1, 0.9, np.inf])
x = np.array([0.2, 9.5])
params = {'x': x, 'xp': xp, 'fp': fp}
_check(params)
xp = np.array([-np.inf, 1, 9, np.inf])
fp = np.array([0, 0.1, 0.9, 1])
x = np.array([0.2, 9.5])
params = {'x': x, 'xp': xp, 'fp': fp}
_check(params)
def test_interp_supplemental_tests(self):
# inspired by class TestInterp
# https://github.com/numpy/numpy/blob/f5b6850f231/numpy/lib/tests/test_function_base.py # noqa: E501
pyfunc = interp
cfunc = jit(nopython=True)(pyfunc)
for size in range(1, 10):
xp = np.arange(size, dtype=np.double)
yp = np.ones(size, dtype=np.double)
incpts = np.array([-1, 0, size - 1, size], dtype=np.double)
decpts = incpts[::-1]
incres = cfunc(incpts, xp, yp)
decres = cfunc(decpts, xp, yp)
inctgt = np.array([1, 1, 1, 1], dtype=float)
dectgt = inctgt[::-1]
np.testing.assert_almost_equal(incres, inctgt)
np.testing.assert_almost_equal(decres, dectgt)
x = np.linspace(0, 1, 5)
y = np.linspace(0, 1, 5)
x0 = 0
np.testing.assert_almost_equal(cfunc(x0, x, y), x0)
x0 = 0.3
np.testing.assert_almost_equal(cfunc(x0, x, y), x0)
x0 = np.float32(0.3)
np.testing.assert_almost_equal(cfunc(x0, x, y), x0)
x0 = np.float64(0.3)
np.testing.assert_almost_equal(cfunc(x0, x, y), x0)
x0 = np.nan
np.testing.assert_almost_equal(cfunc(x0, x, y), x0)
x = np.linspace(0, 1, 5)
y = np.linspace(0, 1, 5)
x0 = np.array(0.3)
np.testing.assert_almost_equal(cfunc(x0, x, y), x0)
xp = np.arange(0, 10, 0.0001)
fp = np.sin(xp)
np.testing.assert_almost_equal(cfunc(np.pi, xp, fp), 0.0)
def test_interp_supplemental_complex_tests(self):
# inspired by class TestInterp
# https://github.com/numpy/numpy/blob/f5b6850f231/numpy/lib/tests/test_function_base.py # noqa: E501
pyfunc = interp
cfunc = jit(nopython=True)(pyfunc)
x = np.linspace(0, 1, 5)
y = np.linspace(0, 1, 5) + (1 + np.linspace(0, 1, 5)) * 1.0j
x0 = 0.3
y0 = x0 + (1 + x0) * 1.0j
np.testing.assert_almost_equal(cfunc(x0, x, y), y0)
def test_interp_float_precision_handled_per_numpy(self):
# test cases from https://github.com/numba/numba/issues/4890
pyfunc = interp
cfunc = jit(nopython=True)(pyfunc)
dtypes = [np.float32, np.float64, np.int32, np.int64]
for combo in itertools.combinations_with_replacement(dtypes, 3):
xp_dtype, fp_dtype, x_dtype = combo
xp = np.arange(10, dtype=xp_dtype)
fp = (xp ** 2).astype(fp_dtype)
x = np.linspace(2, 3, 10, dtype=x_dtype)
expected = pyfunc(x, xp, fp)
got = cfunc(x, xp, fp)
self.assertPreciseEqual(expected, got)
def test_isnat(self):
def values():
yield np.datetime64("2016-01-01")
yield np.datetime64("NaT")
yield np.datetime64('NaT', 'ms')
yield np.datetime64('NaT', 'ns')
yield np.datetime64('2038-01-19T03:14:07')
yield np.timedelta64('NaT', "ms")
yield np.timedelta64(34, "ms")
for unit in ['Y', 'M', 'W', 'D',
'h', 'm', 's', 'ms', 'us',
'ns', 'ps', 'fs', 'as']:
yield np.array([123, -321, "NaT"],
dtype='<datetime64[%s]' % unit)
yield np.array([123, -321, "NaT"],
dtype='<timedelta64[%s]' % unit)
pyfunc = isnat
cfunc = jit(nopython=True)(pyfunc)
for x in values():
expected = pyfunc(x)
got = cfunc(x)
if isinstance(x, np.ndarray):
self.assertPreciseEqual(expected, got, (x,))
else:
self.assertEqual(expected, got, x)
def test_asarray(self):
def input_variations():
"""
To quote from: https://docs.scipy.org/doc/numpy/reference/generated/numpy.asarray.html # noqa: E501
Input data, in any form that can be converted to an array.
This includes:
* lists
* lists of tuples
* tuples
* tuples of tuples
* tuples of lists
* ndarrays
"""
yield 1j
yield 1.2
yield False
yield 1
yield [1, 2, 3]
yield [(1, 2, 3), (1, 2, 3)]
yield (1, 2, 3)
yield ((1, 2, 3), (1, 2, 3))
yield ([1, 2, 3], [1, 2, 3])
yield np.array([])
yield np.arange(4)
yield np.arange(12).reshape(3, 4)
yield np.arange(12).reshape(3, 4).T
# Test cases for `numba.typed.List`
def make_list(values):
a = List()
for i in values:
a.append(i)
return a
yield make_list((1, 2, 3))
yield make_list((1.0, 2.0, 3.0))
yield make_list((1j, 2j, 3j))
yield make_list((True, False, True))
# used to check that if the input is already an array and the dtype is
# the same as that of the input/omitted then the array itself is
# returned.
def check_pass_through(jitted, expect_same, params):
returned = jitted(**params)
if expect_same:
self.assertTrue(returned is params['a'])
else:
self.assertTrue(returned is not params['a'])
# should be numerically the same, just different dtype
np.testing.assert_allclose(returned, params['a'])
self.assertTrue(returned.dtype == params['dtype'])
for pyfunc in [asarray, asarray_kws]:
cfunc = jit(nopython=True)(pyfunc)
_check = partial(self._check_output, pyfunc, cfunc)
for x in input_variations():
params = {'a': x}
if 'kws' in pyfunc.__name__:
for dt in [None, np.complex128]:
params['dtype'] = dt
_check(params)
else:
_check(params)
# check the behaviour over a dtype change (or not!)
x = np.arange(10, dtype=np.float32)
params = {'a': x}
if 'kws' in pyfunc.__name__:
params['dtype'] = None
check_pass_through(cfunc, True, params)
params['dtype'] = np.complex128
check_pass_through(cfunc, False, params)
params['dtype'] = np.float32
check_pass_through(cfunc, True, params)
else:
check_pass_through(cfunc, True, params)
def test_asarray_literal(self):
def case1():
return np.asarray("hello world")
def case2(): # kind1
s = "hello world"
return np.asarray(s)
def case3(): # kind2
s = '大处 着眼,小处着手。大大大处'
return np.asarray(s)
def case4():
s = ''
return np.asarray(s)
funcs = [case1, case2, case3, case4]
for pyfunc in funcs:
cfunc = jit(nopython=True)(pyfunc)
expected = pyfunc()
got = cfunc()
self.assertPreciseEqual(expected, got)
def test_asarray_rejects_List_with_illegal_dtype(self):
self.disable_leak_check()
cfunc = jit(nopython=True)(asarray)
def test_reject(alist):
with self.assertRaises(TypingError) as e:
cfunc(alist)
self.assertIn(
"asarray support for List is limited "
"to Boolean and Number types",
str(e.exception))
def make_none_typed_list():
l = List()
l.append(None)
return l
def make_nested_list():
l = List()
m = List()
m.append(1)
l.append(m)
return l
def make_nested_list_with_dict():
l = List()
d = Dict()
d[1] = "a"
l.append(d)
return l
def make_unicode_list():
l = List()
for i in ("a", "bc", "def"):
l.append(i)
return l
test_reject(make_none_typed_list())
test_reject(make_nested_list())
test_reject(make_nested_list_with_dict())
test_reject(make_unicode_list())
def test_asfarray(self):
def inputs():
yield np.array([1, 2, 3]), None
yield np.array([2, 3], dtype=np.float32), np.float32
yield np.array([2, 3], dtype=np.int8), np.int8
yield np.array([2, 3], dtype=np.int8), np.complex64
yield np.array([2, 3], dtype=np.int8), np.complex128
pyfunc = asfarray
cfunc = jit(nopython=True)(pyfunc)
for arr, dt in inputs():
if dt is None:
expected = pyfunc(arr)
got = cfunc(arr)
else:
expected = pyfunc(arr, dtype=dt)
got = cfunc(arr, dtype=dt)
self.assertPreciseEqual(expected, got)
self.assertTrue(np.issubdtype(got.dtype, np.inexact), got.dtype)
# test default kwarg variant
pyfunc = asfarray_default_kwarg
cfunc = jit(nopython=True)(pyfunc)
arr = np.array([1, 2, 3])
expected = pyfunc(arr)
got = cfunc(arr)
self.assertPreciseEqual(expected, got)
self.assertTrue(np.issubdtype(got.dtype, np.inexact), got.dtype)
def test_repeat(self):
# np.repeat(a, repeats)
np_pyfunc = np_repeat
np_nbfunc = njit(np_pyfunc)
# a.repeat(repeats)
array_pyfunc = array_repeat
array_nbfunc = njit(array_pyfunc)
for pyfunc, nbfunc in ((np_pyfunc, np_nbfunc),
(array_pyfunc, array_nbfunc)):
def check(a, repeats):
self.assertPreciseEqual(pyfunc(a, repeats), nbfunc(a, repeats))
# test array arguments
target_numpy_values = [
np.ones(1),
np.arange(1000),
np.array([[0, 1], [2, 3]]),
np.array([]),
np.array([[], []]),
]
target_numpy_types = [
np.uint32,
np.int32,
np.uint64,
np.int64,
np.float32,
np.float64,
np.complex64,
np.complex128,
]
target_numpy_inputs = (np.array(a,dtype=t) for a,t in
itertools.product(target_numpy_values,
target_numpy_types))
target_non_numpy_inputs = [
1,
1.0,
True,
1j,
[0, 1, 2],
(0, 1, 2),
]
for i in itertools.chain(target_numpy_inputs,
target_non_numpy_inputs):
check(i, repeats=0)
check(i, repeats=1)
check(i, repeats=2)
check(i, repeats=3)
check(i, repeats=100)
# check broadcasting when repeats is an array/list
one = np.arange(1)
for i in ([0], [1], [2]):
check(one, repeats=i)
check(one, repeats=np.array(i))
two = np.arange(2)
for i in ([0, 0], [0, 1], [1, 0], [0, 1], [1, 2], [2, 1], [2, 2]):
check(two, repeats=i)
check(two, repeats=np.array(i))
check(two, repeats=np.array([2, 2], dtype=np.int32))
check(np.arange(10), repeats=np.arange(10))
def test_repeat_exception(self):
# np.repeat(a, repeats)
np_pyfunc = np_repeat
np_nbfunc = njit(np_pyfunc)
# a.repeat(repeats)
array_pyfunc = array_repeat
array_nbfunc = njit(array_pyfunc)
self.disable_leak_check()
for pyfunc, nbfunc in ((np_pyfunc, np_nbfunc),
(array_pyfunc, array_nbfunc)):
# negative repeat argument
with self.assertRaises(ValueError) as e:
nbfunc(np.ones(1), -1)
self.assertIn("negative dimensions are not allowed",
str(e.exception))
# float repeat argument has custom error message
with self.assertRaises(TypingError) as e:
nbfunc(np.ones(1), 1.0)
self.assertIn(
"The repeats argument must be an integer "
"or an array-like of integer dtype",
str(e.exception))
# negative repeat argument as array
with self.assertRaises(ValueError) as e:
nbfunc(np.ones(2), np.array([1, -1]))
self.assertIn("negative dimensions are not allowed",
str(e.exception))
# broadcasting error, repeats too large
with self.assertRaises(ValueError) as e:
nbfunc(np.ones(2), np.array([1, 1, 1]))
self.assertIn("operands could not be broadcast together",
str(e.exception))
# broadcasting error, repeats too small
with self.assertRaises(ValueError) as e:
nbfunc(np.ones(5), np.array([1, 1, 1, 1]))
self.assertIn("operands could not be broadcast together",
str(e.exception))
# float repeat argument has custom error message
with self.assertRaises(TypingError) as e:
nbfunc(np.ones(2), [1.0, 1.0])
self.assertIn(
"The repeats argument must be an integer "
"or an array-like of integer dtype",
str(e.exception))
for rep in [True, "a", "1"]:
with self.assertRaises(TypingError):
nbfunc(np.ones(1), rep)
def test_select(self):
np_pyfunc = np_select
np_nbfunc = njit(np_select)
test_cases = [
# Each test case below is one tuple.
# Each tuple is separated by a description of what's being tested
# test with arrays of length 3 instead of 2 and a different default
([np.array([False, False, False]),
np.array([False, True, False]),
np.array([False, False, True])],
[np.array([1, 2, 3]),
np.array([4, 5, 6]),
np.array([7, 8, 9])], 15.3),
# test with arrays of length 1 instead of 2
([np.array([True]),
np.array([False])], [np.array([1]), np.array([2])], 0),
# test with lists of length 100 of arrays of length 1
([np.array([False])] * 100, [np.array([1])] * 100, 0),
# passing arrays with NaNs
([np.isnan(np.array([1, 2, 3, np.nan, 5, 7]))] * 2,
[np.array([1, 2, 3, np.nan, 5, 7])] * 2, 0),
# passing lists with 2d arrays
([np.isnan(np.array([[1, 2, 3, np.nan, 5, 7]]))] * 2,
[np.array([[1, 2, 3, np.nan, 5, 7]])] * 2, 0),
# passing arrays with complex numbers
([np.isnan(np.array([1, 2, 3 + 2j, np.nan, 5, 7]))] * 2,
[np.array([1, 2, 3 + 2j, np.nan, 5, 7])] * 2, 0)
]
for x in (np.arange(10), np.arange(10).reshape((5, 2))):
# test with two lists
test_cases.append(([x < 3, x > 5], [x, x ** 2], 0))
# test with two tuples
test_cases.append(((x < 3, x > 5), (x, x ** 2), 0))
# test with one list and one tuple
test_cases.append(([x < 3, x > 5], (x, x ** 2), 0))
# test with one tuple and one list
test_cases.append(((x < 3, x > 5), [x, x ** 2], 0))
for condlist, choicelist, default in test_cases:
self.assertPreciseEqual(np_pyfunc(condlist, choicelist, default),
np_nbfunc(condlist, choicelist, default))
np_pyfunc_defaults = np_select_defaults
np_nbfunc_defaults = njit(np_select_defaults)
# check the defaults work, using whatever the last input was
self.assertPreciseEqual(np_pyfunc_defaults(condlist, choicelist),
np_nbfunc_defaults(condlist, choicelist))
def test_select_exception(self):
np_nbfunc = njit(np_select)
x = np.arange(10)
self.disable_leak_check()
for condlist, choicelist, default, expected_error, expected_text in [
# Each test case below is one tuple.
# Each tuple is separated by the description of the intended error
# passing condlist of dim zero
([np.array(True), np.array([False, True, False])],
[np.array(1), np.arange(12).reshape(4, 3)], 0,
TypingError, "condlist arrays must be of at least dimension 1"),
# condlist and choicelist with different dimensions
([np.array(True), np.array(False)], [np.array([1]), np.array([2])],
0, TypingError, "condlist and choicelist elements must have the "
"same number of dimensions"),
# condlist and choicelist with different dimensions
([np.array([True]), np.array([False])],
[np.array([[1]]), np.array([[2]])], 0, TypingError,
"condlist and choicelist elements must have the "
"same number of dimensions"),
# passing choicelist of dim zero
([np.array(True), np.array(False)], [np.array(1), np.array(2)], 0,
TypingError, "condlist arrays must be of at least dimension 1"),
# passing an array as condlist instead of a list or tuple
(np.isnan(np.array([1, 2, 3, np.nan, 5, 7])),
np.array([1, 2, 3, np.nan, 5, 7]), 0, TypingError,
"condlist must be a List or a Tuple"),
# default is a list
([True], [0], [0], TypingError,
"default must be a scalar"),
# condlist with ints instead of booleans
([(x < 3).astype(int), (x > 5).astype(int)], [x, x ** 2], 0,
TypingError, "condlist arrays must contain booleans"),
# condlist and choicelist of different length
([x > 9, x > 8, x > 7, x > 6], [x, x**2, x], 0, ValueError,
"list of cases must be same length as list of conditions"),
# condlist contains tuples instead of arrays
# if in the future numba's np.where accepts tuples, the
# implementation of np.select should also accept them and
# the following two test cases should be normal tests
# instead of negative tests
# test with lists of length 100 of tuples of length 1 for condlist
([(False,)] * 100, [np.array([1])] * 100, 0, TypingError,
'items of condlist must be arrays'),
# test with lists of length 100 of tuples of length 1 for choicelist
([np.array([False])] * 100, [(1,)] * 100, 0, TypingError,
'items of choicelist must be arrays'),
]:
with self.assertRaises(expected_error) as e:
np_nbfunc(condlist, choicelist, default)
self.assertIn(expected_text, str(e.exception))
def test_windowing(self):
def check_window(func):
np_pyfunc = func
np_nbfunc = njit(func)
for M in [0, 1, 5, 12]:
expected = np_pyfunc(M)
got = np_nbfunc(M)
self.assertPreciseEqual(expected, got, prec='double')
for M in ['a', 1.1, 1j]:
with self.assertRaises(TypingError) as raises:
np_nbfunc(1.1)
self.assertIn("M must be an integer", str(raises.exception))
check_window(np_bartlett)
check_window(np_blackman)
check_window(np_hamming)
check_window(np_hanning)
# Test np.kaiser separately
np_pyfunc = np_kaiser
np_nbfunc = njit(np_kaiser)
for M in [0, 1, 5, 12]:
for beta in [0.0, 5.0, 14.0]:
expected = np_pyfunc(M, beta)
got = np_nbfunc(M, beta)
if IS_32BITS or platform.machine() in ['ppc64le', 'aarch64']:
self.assertPreciseEqual(expected,
got, prec='double', ulps=2)
else:
self.assertPreciseEqual(expected, got, prec='double',
ulps=2)
for M in ['a', 1.1, 1j]:
with self.assertRaises(TypingError) as raises:
np_nbfunc(M, 1.0)
self.assertIn("M must be an integer", str(raises.exception))
for beta in ['a', 1j]:
with self.assertRaises(TypingError) as raises:
np_nbfunc(5, beta)
self.assertIn("beta must be an integer or float",
str(raises.exception))
def test_cross(self):
pyfunc = np_cross
cfunc = jit(nopython=True)(pyfunc)
pairs = [
# 3x3 (n-dims)
(
np.array([[1, 2, 3], [4, 5, 6]]),
np.array([[4, 5, 6], [1, 2, 3]])
),
# 2x3 array-like (n-dims)
(
np.array([[1, 2, 3], [4, 5, 6]]),
((4, 5), (1, 2))
),
# 3x3 (1-dim) with type promotion
(
np.array([1, 2, 3], dtype=np.int64),
np.array([4, 5, 6], dtype=np.float64)
),
# 3x3 array-like (1-dim)
(
(1, 2, 3),
(4, 5, 6)
),
# 2x3 (1-dim)
(
np.array([1, 2]),
np.array([4, 5, 6])
),
# 3x3 (with broadcasting 1d x 2d)
(
np.array([1, 2, 3]),
np.array([[4, 5, 6], [1, 2, 3]])
),
# 3x3 (with broadcasting 2d x 1d)
(
np.array([[1, 2, 3], [4, 5, 6]]),
np.array([1, 2, 3])
),
# 3x2 (with higher order broadcasting)
(
np.arange(36).reshape(6, 2, 3),
np.arange(4).reshape(2, 2)
)
]
for x, y in pairs:
expected = pyfunc(x, y)
got = cfunc(x, y)
self.assertPreciseEqual(expected, got)
def test_cross_exceptions(self):
pyfunc = np_cross
cfunc = jit(nopython=True)(pyfunc)
self.disable_leak_check()
# test incompatible dimensions for ndim == 1
with self.assertRaises(ValueError) as raises:
cfunc(
np.arange(4),
np.arange(3)
)
self.assertIn(
'Incompatible dimensions for cross product',
str(raises.exception)
)
# test 2d cross product error for ndim == 1
with self.assertRaises(ValueError) as raises:
cfunc(
np.array((1, 2)),
np.array((3, 4))
)
self.assertIn(
'Dimensions for both inputs is 2.',
str(raises.exception)
)
self.assertIn(
'`cross2d(a, b)` from `numba.np.extensions`.',
str(raises.exception)
)
# test incompatible dimensions for ndim > 1
with self.assertRaises(ValueError) as raises:
cfunc(
np.arange(8).reshape((2, 4)),
np.arange(6)[::-1].reshape((2, 3))
)
self.assertIn(
'Incompatible dimensions for cross product',
str(raises.exception)
)
# test 2d cross product error for ndim == 1
with self.assertRaises(ValueError) as raises:
cfunc(
np.arange(8).reshape((4, 2)),
np.arange(8)[::-1].reshape((4, 2))
)
self.assertIn(
'Dimensions for both inputs is 2',
str(raises.exception)
)
# test non-array-like input
with self.assertRaises(TypingError) as raises:
cfunc(
set([1, 2, 3]),
set([4, 5, 6])
)
self.assertIn(
'Inputs must be array-like.',
str(raises.exception)
)
def test_cross2d(self):
pyfunc = np_cross
cfunc = njit(nb_cross2d)
pairs = [
# 2x2 (n-dims)
(
np.array([[1, 2], [4, 5]]),
np.array([[4, 5], [1, 2]])
),
# 2x2 array-like (n-dims)
(
np.array([[1, 2], [4, 5]]),
((4, 5), (1, 2))
),
# 2x2 (1-dim) with type promotion
(
np.array([1, 2], dtype=np.int64),
np.array([4, 5], dtype=np.float64)
),
# 2x2 array-like (1-dim)
(
(1, 2),
(4, 5)
),
# 2x2 (with broadcasting 1d x 2d)
(
np.array([1, 2]),
np.array([[4, 5], [1, 2]])
),
# 2x2 (with broadcasting 2d x 1d)
(
np.array([[1, 2], [4, 5]]),
np.array([1, 2])
),
# 2x2 (with higher order broadcasting)
(
np.arange(36).reshape(6, 3, 2),
np.arange(6).reshape(3, 2)
)
]
for x, y in pairs:
expected = pyfunc(x, y)
got = cfunc(x, y)
self.assertPreciseEqual(expected, got)
def test_cross2d_exceptions(self):
cfunc = njit(nb_cross2d)
self.disable_leak_check()
# test incompatible dimensions for ndim == 1
with self.assertRaises(ValueError) as raises:
cfunc(
np.array((1, 2, 3)),
np.array((4, 5, 6))
)
self.assertIn(
'Incompatible dimensions for 2D cross product',
str(raises.exception)
)
# test incompatible dimensions for ndim > 1
with self.assertRaises(ValueError) as raises:
cfunc(
np.arange(6).reshape((2, 3)),
np.arange(6)[::-1].reshape((2, 3))
)
self.assertIn(
'Incompatible dimensions for 2D cross product',
str(raises.exception)
)
# test non-array-like input
with self.assertRaises(TypingError) as raises:
cfunc(
set([1, 2]),
set([4, 5])
)
self.assertIn(
'Inputs must be array-like.',
str(raises.exception)
)
def test_trim_zeros(self):
def arrays():
yield np.array([])
yield np.zeros(5)
yield np.zeros(1)
yield np.array([1, 2, 3])
yield np.array([0, 1, 2, 3])
yield np.array([0., 1., 2., np.nan, 0.])
yield np.array(['0', 'Hello', 'world'])
def explicit_trim():
yield np.array([0, 1, 2, 0, 0]), 'FB'
yield np.array([0, 1, 2]), 'B'
yield np.array([np.nan, 0., 1.2, 2.3, 0.]), 'b'
yield np.array([0, 0, 1, 2, 5]), 'f'
yield np.array([0, 1, 2, 0]), 'abf'
yield np.array([0, 4, 0]), 'd'
yield np.array(['\0', '1', '2']), 'f'
pyfunc = np_trim_zeros
cfunc = jit(nopython=True)(pyfunc)
for arr in arrays():
expected = pyfunc(arr)
got = cfunc(arr)
self.assertPreciseEqual(expected, got)
for arr, trim in explicit_trim():
expected = pyfunc(arr, trim)
got = cfunc(arr, trim)
self.assertPreciseEqual(expected, got)
def test_trim_zeros_numpy(self):
# https://github.com/numpy/numpy/blob/9d8d46ad615a7e13256b930146ac369f651016c0/numpy/lib/tests/test_function_base.py#L1251-L1313
a = np.array([0, 0, 1, 0, 2, 3, 4, 0])
b = a.astype(float)
c = a.astype(complex)
# d = a.astype(object)
values = [a, b, c]
# test_basic
slc = np.s_[2:-1]
for arr in values:
res = np_trim_zeros(arr)
self.assertPreciseEqual(res, arr[slc])
# test_leading_skip
slc = np.s_[:-1]
for arr in values:
res = np_trim_zeros(arr, trim='b')
self.assertPreciseEqual(res, arr[slc])
# test_trailing_skip
slc = np.s_[2:]
for arr in values:
res = np_trim_zeros(arr, trim='F')
self.assertPreciseEqual(res, arr[slc])
# test_all_zero
for _arr in values:
arr = np.zeros_like(_arr, dtype=_arr.dtype)
res1 = np_trim_zeros(arr, trim='B')
assert len(res1) == 0
res2 = np_trim_zeros(arr, trim='f')
assert len(res2) == 0
# test_size_zero
arr = np.zeros(0)
res = np_trim_zeros(arr)
self.assertPreciseEqual(arr, res)
# test_overflow
for arr in [np.array([0, 2**62, 0]), np.array([0, 2**63, 0]),
np.array([0, 2**64, 0])]:
slc = np.s_[1:2]
res = np_trim_zeros(arr)
self.assertPreciseEqual(res, arr[slc])
# test_no_trim
arr = np.array([None, 1, None])
res = np_trim_zeros(arr)
self.assertPreciseEqual(arr, res)
# test_list_to_list
res = np_trim_zeros(a.tolist())
assert isinstance(res, list)
def test_trim_zeros_exceptions(self):
self.disable_leak_check()
cfunc = jit(nopython=True)(np_trim_zeros)
with self.assertRaises(TypingError) as raises:
cfunc(np.array([[1, 2, 3], [4, 5, 6]]))
self.assertIn(
'array must be 1D',
str(raises.exception)
)
with self.assertRaises(TypingError) as raises:
cfunc(3)
self.assertIn(
'The first argument must be an array',
str(raises.exception)
)
with self.assertRaises(TypingError) as raises:
cfunc({0, 1, 2})
self.assertIn(
'The first argument must be an array',
str(raises.exception)
)
with self.assertRaises(TypingError) as raises:
cfunc(np.array([0, 1, 2]), 1)
self.assertIn(
'The second argument must be a string',
str(raises.exception)
)
def test_union1d(self):
pyfunc = np_union1d
cfunc = jit(nopython=True)(pyfunc)
arrays = [
# Test 1d arrays
(
np.array([1, 2, 3]),
np.array([2, 3, 4])
),
# Test 2d with 1d array
(
np.array([[1, 2, 3], [2, 3, 4]]),
np.array([2, 5, 6])
),
# Test 3d with 1d array
(
np.arange(0, 20).reshape(2,2,5),
np.array([1, 20, 21])
),
# Test 2d with 3d array
(
np.arange(0, 10).reshape(2,5),
np.arange(0, 20).reshape(2,5,2)
),
# Test other array-like
(
np.array([False, True, 7]),
np.array([1, 2, 3])
)
]
for a, b in arrays:
expected = pyfunc(a,b)
got = cfunc(a,b)
self.assertPreciseEqual(expected, got)
def test_union1d_exceptions(self):
cfunc = jit(nopython=True)(np_union1d)
self.disable_leak_check()
# Test inputs not array-like
with self.assertRaises(TypingError) as raises:
cfunc("Hello", np.array([1,2]))
self.assertIn(
"The arguments to np.union1d must be array-like",
str(raises.exception)
)
with self.assertRaises(TypingError) as raises:
cfunc(np.array([1,2]), "Hello")
self.assertIn(
"The arguments to np.union1d must be array-like",
str(raises.exception)
)
with self.assertRaises(TypingError) as raises:
cfunc("Hello", "World")
self.assertIn(
"The arguments to np.union1d must be array-like",
str(raises.exception)
)
# Test Unicode array exceptions
with self.assertRaises(TypingError) as raises:
cfunc(np.array(['hello', 'world']), np.array(['a', 'b']))
self.assertIn(
"For Unicode arrays, arrays must have same dtype",
str(raises.exception)
)
with self.assertRaises(TypingError) as raises:
cfunc(np.array(['c', 'd']), np.array(['foo', 'bar']))
self.assertIn(
"For Unicode arrays, arrays must have same dtype",
str(raises.exception)
)
with self.assertRaises(TypingError) as raises:
cfunc(np.array(['c', 'd']), np.array([1, 2]))
self.assertIn(
"For Unicode arrays, arrays must have same dtype",
str(raises.exception)
)
with self.assertRaises(TypingError) as raises:
cfunc(np.array(['c', 'd']), np.array([1.1, 2.5]))
self.assertIn(
"For Unicode arrays, arrays must have same dtype",
str(raises.exception)
)
def test_asarray_chkfinite(self):
pyfunc = np_asarray_chkfinite
cfunc = jit(nopython=True)(pyfunc)
self.disable_leak_check()
pairs = [
#1D array with all args
(
np.array([1, 2, 3]),
np.float32,
),
#1D array
(
np.array([1, 2, 3]),
),
#1D array-like
(
[1, 2, 3, 4],
),
# 2x2 (n-dims)
(
np.array([[1, 2], [3, 4]]),
np.float32,
),
# 2x2 array-like (n-dims)
(
((1, 2), (3, 4)),
np.int64
),
# 2x2 (1-dim) with type promotion
(
np.array([1, 2], dtype=np.int64),
),
# 3x2 (with higher order broadcasting)
(
np.arange(36).reshape(6, 2, 3),
),
]
for pair in pairs:
expected = pyfunc(*pair)
got = cfunc(*pair)
self.assertPreciseEqual(expected, got)
def test_asarray_chkfinite_exceptions(self):
cfunc = jit(nopython=True)(np_asarray_chkfinite)
self.disable_leak_check()
#test for single value
with self.assertRaises(TypingError) as e:
cfunc(2)
msg = "The argument to np.asarray_chkfinite must be array-like"
self.assertIn(msg, str(e.exception))
#test for NaNs
with self.assertRaises(ValueError) as e:
cfunc(np.array([2, 4, np.nan, 5]))
self.assertIn("array must not contain infs or NaNs", str(e.exception))
#test for infs
with self.assertRaises(ValueError) as e:
cfunc(np.array([1, 2, np.inf, 4]))
self.assertIn("array must not contain infs or NaNs", str(e.exception))
#test for dtype
with self.assertRaises(TypingError) as e:
cfunc(np.array([1, 2, 3, 4]), 'float32')
self.assertIn("dtype must be a valid Numpy dtype", str(e.exception))
def test_unwrap_basic(self):
pyfunc = unwrap
cfunc = njit(pyfunc)
pyfunc1 = unwrap1
cfunc1 = njit(pyfunc1)
pyfunc13 = unwrap13
cfunc13 = njit(pyfunc13)
pyfunc123 = unwrap123
cfunc123 = njit(pyfunc123)
# Based on tests from https://github.com/numpy/numpy/blob/3032e84ff34f20def2ef4ebf9f8695947af3fd24/numpy/lib/tests/test_function_base.py#L1979-L2003 # noqa: E501
# Additional tests are included to ensure proper support for
# higher dimensional arrays
# p only
def inputs1():
yield np.array([1, 1 + 2 * np.pi])
phase = np.linspace(0, np.pi, num=5)
phase[3:] += np.pi
yield phase
yield np.arange(16).reshape((4,4))
yield np.arange(160, step=10).reshape((4,4))
yield np.arange(240, step=10).reshape((2,3,4))
for p in inputs1():
self.assertPreciseEqual(pyfunc1(p), cfunc1(p))
uneven_seq = np.array([0, 75, 150, 225, 300, 430])
wrap_uneven = np.mod(uneven_seq, 250)
# p and period only
def inputs13():
yield np.array([1, 1 + 256]), 255
yield np.array([0, 75, 150, 225, 300]), 255
yield np.array([0, 1, 2, -1, 0]), 4
yield np.array([2, 3, 4, 5, 2, 3, 4, 5]), 4
yield wrap_uneven, 250
# check that you can set axis=-1 without errors
self.assertPreciseEqual(pyfunc(wrap_uneven, axis=-1, period=250),
cfunc(wrap_uneven, axis=-1, period=250))
for p, period in inputs13():
self.assertPreciseEqual(pyfunc13(p, period=period),
cfunc13(p, period=period))
# p, period and discont
def inputs123():
yield wrap_uneven, 250, 140
for p, period, discont in inputs123():
self.assertPreciseEqual(pyfunc123(p, period=period,
discont=discont),
cfunc123(p, period=period,
discont=discont))
def test_unwrap_exception(self):
cfunc = njit(unwrap)
self.disable_leak_check()
with self.assertRaises(TypingError) as e:
cfunc('abc')
self.assertIn('The argument "p" must be array-like',
str(e.exception))
with self.assertRaises(TypingError) as e:
cfunc(np.array([1, 2]), 'abc')
self.assertIn('The argument "discont" must be a scalar',
str(e.exception))
with self.assertRaises(TypingError) as e:
cfunc(np.array([1, 2]), 3, period='abc')
self.assertIn('The argument "period" must be a scalar',
str(e.exception))
with self.assertRaises(TypingError) as e:
cfunc(np.array([1, 2]), 3, axis='abc')
self.assertIn('The argument "axis" must be an integer',
str(e.exception))
with self.assertRaises(ValueError) as e:
cfunc(np.array([1, 2]), 3, axis=2)
self.assertIn('Value for argument "axis" is not supported',
str(e.exception))
def test_swapaxes_basic(self):
pyfunc = swapaxes
cfunc = jit(nopython=True)(pyfunc)
def a_variations():
yield np.arange(10)
yield np.arange(10).reshape(2, 5)
yield np.arange(60).reshape(5, 4, 3)
for a in a_variations():
for a1 in range(-a.ndim, a.ndim):
for a2 in range(-a.ndim, a.ndim):
expected = pyfunc(a, a1, a2)
got = cfunc(a, a1, a2)
self.assertPreciseEqual(expected, got)
def test_swapaxes_exception(self):
pyfunc = swapaxes
cfunc = jit(nopython=True)(pyfunc)
# Exceptions leak references
self.disable_leak_check()
with self.assertRaises(TypingError) as raises:
cfunc('abc', 0, 0)
self.assertIn('The first argument "a" must be an array',
str(raises.exception))
with self.assertRaises(TypingError) as raises:
cfunc(np.arange(4), 'abc', 0)
self.assertIn('The second argument "axis1" must be an integer',
str(raises.exception))
with self.assertRaises(TypingError) as raises:
cfunc(np.arange(4), 0, 'abc')
self.assertIn('The third argument "axis2" must be an integer',
str(raises.exception))
with self.assertRaises(ValueError) as raises:
cfunc(np.arange(4), 1, 0)
self.assertIn('np.swapaxes: Argument axis1 out of bounds',
str(raises.exception))
with self.assertRaises(ValueError) as raises:
cfunc(np.arange(8).reshape(2, 4), 0, -3)
self.assertIn('np.swapaxes: Argument axis2 out of bounds',
str(raises.exception))
def test_take_along_axis(self):
a = np.arange(24).reshape((3, 1, 4, 2))
# For now axis must be literal, test explicitly defined implementations
@njit
def axis_none(a, i):
return np.take_along_axis(a, i, axis=None)
indices = np.array([1, 2], dtype=np.uint64)
self.assertPreciseEqual(axis_none(a, indices),
axis_none.py_func(a, indices))
def gen(axis):
@njit
def impl(a, i):
return np.take_along_axis(a, i, axis)
return impl
for i in range(-1, a.ndim):
jfunc = gen(i)
ai = np.argsort(a, axis=i)
self.assertPreciseEqual(jfunc(a, ai), jfunc.py_func(a, ai))
def test_take_along_axis_broadcasting(self):
# Based on
# https://github.com/numpy/numpy/blob/v1.21.0/numpy/lib/tests/test_shape_base.py#L74-L79
# This demonstrates that arrays are broadcast before the algorithm is
# applied.
arr = np.ones((3, 4, 1))
ai = np.ones((1, 2, 5), dtype=np.intp)
def gen(axis):
@njit
def impl(a, i):
return np.take_along_axis(a, i, axis)
return impl
# Check same axis but expressed as positive/negative value
for i in (1, -2):
check = gen(i)
expected = check.py_func(arr, ai)
actual = check(arr, ai)
self.assertPreciseEqual(expected, actual)
self.assertEqual(actual.shape, (3, 2, 5))
def test_take_along_axis_exceptions(self):
arr2d = np.arange(8).reshape(2, 4)
# Valid indices when axis=None is passed to take_along_axis:
indices_none = np.array([0, 1], dtype=np.uint64)
indices = np.ones((2, 4), dtype=np.uint64)
# For now axis must be literal, so we need to construct functions with
# explicit axis:
def gen(axis):
@njit
def impl(a, i):
return np.take_along_axis(a, i, axis)
return impl
with self.assertRaises(TypingError) as raises:
gen("a")(arr2d, indices)
self.assertIn("axis must be an integer", str(raises.exception))
with self.assertRaises(TypingError) as raises:
gen(-3)(arr2d, indices)
self.assertIn("axis is out of bounds", str(raises.exception))
with self.assertRaises(TypingError) as raises:
gen(2)(arr2d, indices)
self.assertIn("axis is out of bounds", str(raises.exception))
with self.assertRaises(TypingError) as raises:
gen(None)(12, indices_none)
self.assertIn('"arr" must be an array', str(raises.exception))
with self.assertRaises(TypingError) as raises:
gen(None)(arr2d, 5)
self.assertIn('"indices" must be an array', str(raises.exception))
with self.assertRaises(TypingError) as raises:
gen(None)(arr2d, np.array([0.0, 1.0]))
self.assertIn(
'indices array must contain integers',
str(raises.exception)
)
@njit
def not_literal_axis(a, i, axis):
return np.take_along_axis(a, i, axis)
with self.assertRaises(TypingError) as raises:
not_literal_axis(arr2d, indices, 0)
self.assertIn("axis must be a literal value", str(raises.exception))
with self.assertRaises(TypingError) as raises:
gen(0)(arr2d, np.array([0, 1], dtype=np.uint64))
self.assertIn("must have the same number of dimensions",
str(raises.exception))
# With axis None, array's ndim is implicitly 1.
with self.assertRaises(TypingError) as raises:
gen(None)(arr2d, arr2d)
self.assertIn("must have the same number of dimensions",
str(raises.exception))
with self.assertRaises(ValueError) as raises:
gen(0)(arr2d, np.ones((2, 3), dtype=np.uint64))
self.assertIn("dimensions don't match", str(raises.exception))
# Exceptions leak references
self.disable_leak_check()
def test_nan_to_num(self):
# Test cases are from
# https://github.com/numpy/numpy/blob/8ff45c5bb520db04af8720bf1d34a392a8d2561a/numpy/lib/tests/test_type_check.py#L350-L452
values = [
np.nan,
1,
1.1,
1 + 1j,
complex(-np.inf, np.nan),
complex(np.nan, np.nan),
np.array([1], dtype=int),
np.array([complex(-np.inf, np.inf), complex(1, np.nan),
complex(np.nan, 1), complex(np.inf, -np.inf)]),
np.array([0.1, 1.0, 0.4]),
np.array([1, 2, 3]),
np.array([[0.1, 1.0, 0.4], [0.4, 1.2, 4.0]]),
np.array([0.1, np.nan, 0.4]),
np.array([[0.1, np.nan, 0.4], [np.nan, 1.2, 4.0]]),
np.array([-np.inf, np.nan, np.inf]),
np.array([-np.inf, np.nan, np.inf], dtype=np.float32)
]
nans = [0.0, 10]
pyfunc = nan_to_num
cfunc = njit(nan_to_num)
for value, nan in product(values, nans):
expected = pyfunc(value, nan=nan)
got = cfunc(value, nan=nan)
self.assertPreciseEqual(expected, got)
def test_nan_to_num_copy_false(self):
# Check that copy=False operates in-place.
cfunc = njit(nan_to_num)
x = np.array([0.1, 0.4, np.nan])
expected = 1.0
cfunc(x, copy=False, nan=expected)
self.assertPreciseEqual(x[-1], expected)
x_complex = np.array([0.1, 0.4, complex(np.nan, np.nan)])
cfunc(x_complex, copy=False, nan=expected)
self.assertPreciseEqual(x_complex[-1], 1. + 1.j)
def test_nan_to_num_invalid_argument(self):
cfunc = njit(nan_to_num)
with self.assertTypingError() as raises:
cfunc("invalid_input")
self.assertIn("The first argument must be a scalar or an array-like",
str(raises.exception))
def test_diagflat_basic(self):
pyfunc1 = diagflat1
cfunc1 = njit(pyfunc1)
pyfunc2 = diagflat2
cfunc2 = njit(pyfunc2)
def inputs():
yield np.array([1,2]), 1
yield np.array([[1,2],[3,4]]), -2
yield np.arange(8).reshape((2,2,2)), 2
yield [1, 2], 1
yield np.array([]), 1
for v, k in inputs():
self.assertPreciseEqual(pyfunc1(v), cfunc1(v))
self.assertPreciseEqual(pyfunc2(v, k), cfunc2(v, k))
def test_diagflat1_exception(self):
pyfunc = diagflat1
cfunc = njit(pyfunc)
self.disable_leak_check()
with self.assertRaises(TypingError) as raises:
cfunc("abc")
self.assertIn('The argument "v" must be array-like',
str(raises.exception))
def test_diagflat2_exception(self):
pyfunc = diagflat2
cfunc = njit(pyfunc)
self.disable_leak_check()
with self.assertRaises(TypingError) as raises:
cfunc("abc", 2)
self.assertIn('The argument "v" must be array-like',
str(raises.exception))
with self.assertRaises(TypingError) as raises:
cfunc([1, 2], "abc")
self.assertIn('The argument "k" must be an integer',
str(raises.exception))
with self.assertRaises(TypingError) as raises:
cfunc([1, 2], 3.0)
self.assertIn('The argument "k" must be an integer',
str(raises.exception))
class TestNPMachineParameters(TestCase):
# tests np.finfo, np.iinfo, np.MachAr
template = '''
def foo():
ty = np.%s
return np.%s(ty)
'''
def check(self, func, attrs, *args):
pyfunc = func
cfunc = jit(nopython=True)(pyfunc)
expected = pyfunc(*args)
got = cfunc(*args)
# check result
for attr in attrs:
self.assertPreciseEqual(getattr(expected, attr),
getattr(got, attr))
def create_harcoded_variant(self, basefunc, ty):
#create an instance of using the function with a hardcoded type
#and eval it into existence, return the function for use
tystr = ty.__name__
basestr = basefunc.__name__
funcstr = self.template % (tystr, basestr)
eval(compile(funcstr, '<string>', 'exec'))
return locals()['foo']
@unittest.skipIf(numpy_version >= (1, 24), "NumPy < 1.24 required")
def test_MachAr(self):
attrs = ('ibeta', 'it', 'machep', 'eps', 'negep', 'epsneg', 'iexp',
'minexp', 'xmin', 'maxexp', 'xmax', 'irnd', 'ngrd',
'epsilon', 'tiny', 'huge', 'precision', 'resolution',)
self.check(machar, attrs)
def test_finfo(self):
types = [np.float32, np.float64, np.complex64, np.complex128]
attrs = ('eps', 'epsneg', 'iexp', 'machep', 'max', 'maxexp', 'negep',
'nexp', 'nmant', 'precision', 'resolution', 'tiny', 'bits',)
for ty in types:
self.check(finfo, attrs, ty(1))
hc_func = self.create_harcoded_variant(np.finfo, ty)
self.check(hc_func, attrs)
# check unsupported attr raises
with self.assertRaises(TypingError) as raises:
cfunc = jit(nopython=True)(finfo_machar)
cfunc(7.)
msg = "Unknown attribute 'machar' of type finfo"
self.assertIn(msg, str(raises.exception))
# check invalid type raises
with self.assertTypingError():
cfunc = jit(nopython=True)(finfo)
cfunc(np.int32(7))
def test_iinfo(self):
# check types and instances of types
types = [np.int8, np.int16, np.int32, np.int64, np.uint8, np.uint16,
np.uint32, np.uint64]
attrs = ('min', 'max', 'bits',)
for ty in types:
self.check(iinfo, attrs, ty(1))
hc_func = self.create_harcoded_variant(np.iinfo, ty)
self.check(hc_func, attrs)
# check invalid type raises
with self.assertTypingError():
cfunc = jit(nopython=True)(iinfo)
cfunc(np.float64(7))
@unittest.skipUnless(numpy_version < (1, 24), "Needs NumPy < 1.24")
@TestCase.run_test_in_subprocess
def test_np_MachAr_deprecation_np122(self):
# Tests that Numba is replaying the NumPy 1.22 deprecation warning
# raised on the getattr of 'MachAr' on the NumPy module.
# Needs to be run in a subprocess as the warning is generated from the
# typing part of the `np.MachAr` overload, which may already have been
# executed for the given types and so an empty in memory cache is
# needed.
msg = r'.*`np.MachAr` is deprecated \(NumPy 1.22\)'
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('ignore') # override warning behavior
warnings.filterwarnings("always", message=msg,
category=NumbaDeprecationWarning,)
f = njit(lambda : np.MachAr().eps)
f()
self.assertEqual(len(w), 1)
self.assertIn('`np.MachAr` is deprecated', str(w[0]))
class TestRegistryImports(TestCase):
def test_unsafe_import_in_registry(self):
# See 8940
# This should not fail
code = dedent("""
import numba
import numpy as np
@numba.njit
def foo():
np.array([1 for _ in range(1)])
foo()
print("OK")
""")
result, error = run_in_subprocess(code)
# Assert that the bytestring "OK" was printed to stdout
self.assertEqual(b"OK", result.strip())
self.assertEqual(b"", error.strip())
if __name__ == '__main__':
unittest.main()