summaryrefslogtreecommitdiff
path: root/numpy/core/tests/test_umath.py
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/core/tests/test_umath.py')
-rw-r--r--numpy/core/tests/test_umath.py509
1 files changed, 474 insertions, 35 deletions
diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py
index e2e95ec69..9e3fe387b 100644
--- a/numpy/core/tests/test_umath.py
+++ b/numpy/core/tests/test_umath.py
@@ -17,10 +17,26 @@ from numpy.testing import (
assert_, assert_equal, assert_raises, assert_raises_regex,
assert_array_equal, assert_almost_equal, assert_array_almost_equal,
assert_array_max_ulp, assert_allclose, assert_no_warnings, suppress_warnings,
- _gen_alignment_data, assert_array_almost_equal_nulp
+ _gen_alignment_data, assert_array_almost_equal_nulp, IS_WASM, IS_MUSL
)
from numpy.testing._private.utils import _glibc_older_than
+UFUNCS = [obj for obj in np.core.umath.__dict__.values()
+ if isinstance(obj, np.ufunc)]
+
+UFUNCS_UNARY = [
+ uf for uf in UFUNCS if uf.nin == 1
+]
+UFUNCS_UNARY_FP = [
+ uf for uf in UFUNCS_UNARY if 'f->f' in uf.types
+]
+
+UFUNCS_BINARY = [
+ uf for uf in UFUNCS if uf.nin == 2
+]
+UFUNCS_BINARY_ACC = [
+ uf for uf in UFUNCS_BINARY if hasattr(uf, "accumulate") and uf.nout == 1
+]
def interesting_binop_operands(val1, val2, dtype):
"""
@@ -275,16 +291,16 @@ class TestComparisons:
b_lst = b.tolist()
# (Binary) Comparison (x1=array, x2=array)
- comp_b = np_comp(a, b)
- comp_b_list = [py_comp(x, y) for x, y in zip(a_lst, b_lst)]
+ comp_b = np_comp(a, b).view(np.uint8)
+ comp_b_list = [int(py_comp(x, y)) for x, y in zip(a_lst, b_lst)]
# (Scalar1) Comparison (x1=scalar, x2=array)
- comp_s1 = np_comp(np_scalar, b)
- comp_s1_list = [py_comp(scalar, x) for x in b_lst]
+ comp_s1 = np_comp(np_scalar, b).view(np.uint8)
+ comp_s1_list = [int(py_comp(scalar, x)) for x in b_lst]
# (Scalar2) Comparison (x1=array, x2=scalar)
- comp_s2 = np_comp(a, np_scalar)
- comp_s2_list = [py_comp(x, scalar) for x in a_lst]
+ comp_s2 = np_comp(a, np_scalar).view(np.uint8)
+ comp_s2_list = [int(py_comp(x, scalar)) for x in a_lst]
# Sequence: Binary, Scalar1 and Scalar2
assert_(comp_b.tolist() == comp_b_list,
@@ -338,6 +354,79 @@ class TestComparisons:
assert_equal(np.equal.reduce(a, dtype=bool), True)
assert_raises(TypeError, np.equal.reduce, a)
+ def test_object_dtype(self):
+ assert np.equal(1, [1], dtype=object).dtype == object
+ assert np.equal(1, [1], signature=(None, None, "O")).dtype == object
+
+ def test_object_nonbool_dtype_error(self):
+ # bool output dtype is fine of course:
+ assert np.equal(1, [1], dtype=bool).dtype == bool
+
+ # but the following are examples do not have a loop:
+ with pytest.raises(TypeError, match="No loop matching"):
+ np.equal(1, 1, dtype=np.int64)
+
+ with pytest.raises(TypeError, match="No loop matching"):
+ np.equal(1, 1, sig=(None, None, "l"))
+
+ @pytest.mark.parametrize("dtypes", ["qQ", "Qq"])
+ @pytest.mark.parametrize('py_comp, np_comp', [
+ (operator.lt, np.less),
+ (operator.le, np.less_equal),
+ (operator.gt, np.greater),
+ (operator.ge, np.greater_equal),
+ (operator.eq, np.equal),
+ (operator.ne, np.not_equal)
+ ])
+ @pytest.mark.parametrize("vals", [(2**60, 2**60+1), (2**60+1, 2**60)])
+ def test_large_integer_direct_comparison(
+ self, dtypes, py_comp, np_comp, vals):
+ # Note that float(2**60) + 1 == float(2**60).
+ a1 = np.array([2**60], dtype=dtypes[0])
+ a2 = np.array([2**60 + 1], dtype=dtypes[1])
+ expected = py_comp(2**60, 2**60+1)
+
+ assert py_comp(a1, a2) == expected
+ assert np_comp(a1, a2) == expected
+ # Also check the scalars:
+ s1 = a1[0]
+ s2 = a2[0]
+ assert isinstance(s1, np.integer)
+ assert isinstance(s2, np.integer)
+ # The Python operator here is mainly interesting:
+ assert py_comp(s1, s2) == expected
+ assert np_comp(s1, s2) == expected
+
+ @pytest.mark.parametrize("dtype", np.typecodes['UnsignedInteger'])
+ @pytest.mark.parametrize('py_comp_func, np_comp_func', [
+ (operator.lt, np.less),
+ (operator.le, np.less_equal),
+ (operator.gt, np.greater),
+ (operator.ge, np.greater_equal),
+ (operator.eq, np.equal),
+ (operator.ne, np.not_equal)
+ ])
+ @pytest.mark.parametrize("flip", [True, False])
+ def test_unsigned_signed_direct_comparison(
+ self, dtype, py_comp_func, np_comp_func, flip):
+ if flip:
+ py_comp = lambda x, y: py_comp_func(y, x)
+ np_comp = lambda x, y: np_comp_func(y, x)
+ else:
+ py_comp = py_comp_func
+ np_comp = np_comp_func
+
+ arr = np.array([np.iinfo(dtype).max], dtype=dtype)
+ expected = py_comp(int(arr[0]), -1)
+
+ assert py_comp(arr, -1) == expected
+ assert np_comp(arr, -1) == expected
+ scalar = arr[0]
+ assert isinstance(scalar, np.integer)
+ # The Python operator here is mainly interesting:
+ assert py_comp(scalar, -1) == expected
+ assert np_comp(scalar, -1) == expected
+
class TestAdd:
def test_reduce_alignment(self):
@@ -362,6 +451,7 @@ class TestDivision:
assert_equal(x // 100, [0, 0, 0, 1, -1, -1, -1, -1, -2])
assert_equal(x % 100, [5, 10, 90, 0, 95, 90, 10, 0, 80])
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
@pytest.mark.parametrize("dtype,ex_val", itertools.product(
np.sctypes['int'] + np.sctypes['uint'], (
(
@@ -392,7 +482,7 @@ class TestDivision:
def test_division_int_boundary(self, dtype, ex_val):
fo = np.iinfo(dtype)
neg = -1 if fo.min < 0 else 1
- # Large enough to test SIMD loops and remaind elements
+ # Large enough to test SIMD loops and remainder elements
lsize = 512 + 7
a, b, divisors = eval(ex_val)
a_lst, b_lst = a.tolist(), b.tolist()
@@ -447,6 +537,7 @@ class TestDivision:
np.array([], dtype=dtype) // 0
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
@pytest.mark.parametrize("dtype,ex_val", itertools.product(
np.sctypes['int'] + np.sctypes['uint'], (
"np.array([fo.max, 1, 2, 1, 1, 2, 3], dtype=dtype)",
@@ -508,6 +599,8 @@ class TestDivision:
quotient_array = np.array([quotient]*5)
assert all(dividend_array // divisor == quotient_array), msg
else:
+ if IS_WASM:
+ pytest.skip("fp errors don't work in wasm")
with np.errstate(divide='raise', invalid='raise'):
with pytest.raises(FloatingPointError):
dividend // divisor
@@ -554,6 +647,9 @@ class TestDivision:
assert_equal(np.signbit(x//1), 0)
assert_equal(np.signbit((-x)//1), 1)
+ @pytest.mark.skipif(hasattr(np.__config__, "blas_ssl2_info"),
+ reason="gh-22982")
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
@pytest.mark.parametrize('dtype', np.typecodes['Float'])
def test_floor_division_errors(self, dtype):
fnan = np.array(np.nan, dtype=dtype)
@@ -668,6 +764,7 @@ class TestRemainder:
else:
assert_(b > rem >= 0, msg)
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
@pytest.mark.xfail(sys.platform.startswith("darwin"),
reason="MacOS seems to not give the correct 'invalid' warning for "
"`fmod`. Hopefully, others always do.")
@@ -694,6 +791,9 @@ class TestRemainder:
# inf / 0 does not set any flags, only the modulo creates a NaN
np.divmod(finf, fzero)
+ @pytest.mark.skipif(hasattr(np.__config__, "blas_ssl2_info"),
+ reason="gh-22982")
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
@pytest.mark.xfail(sys.platform.startswith("darwin"),
reason="MacOS seems to not give the correct 'invalid' warning for "
"`fmod`. Hopefully, others always do.")
@@ -715,6 +815,7 @@ class TestRemainder:
fn(fone, fnan)
fn(fnan, fone)
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
def test_float_remainder_overflow(self):
a = np.finfo(np.float64).tiny
with np.errstate(over='ignore', invalid='ignore'):
@@ -836,6 +937,7 @@ class TestDivisionIntegerOverflowsAndDivideByZero:
helper_lambdas['min-zero'], helper_lambdas['neg_min-zero'])
}
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
@pytest.mark.parametrize("dtype", np.typecodes["Integer"])
def test_signed_division_overflow(self, dtype):
to_check = interesting_binop_operands(np.iinfo(dtype).min, -1, dtype)
@@ -862,6 +964,7 @@ class TestDivisionIntegerOverflowsAndDivideByZero:
assert extractor(res1) == np.iinfo(op1.dtype).min
assert extractor(res2) == 0
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
@pytest.mark.parametrize("dtype", np.typecodes["AllInteger"])
def test_divide_by_zero(self, dtype):
# Note that the return value cannot be well defined here, but NumPy
@@ -881,6 +984,7 @@ class TestDivisionIntegerOverflowsAndDivideByZero:
assert extractor(res1) == 0
assert extractor(res2) == 0
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
@pytest.mark.parametrize("dividend_dtype",
np.sctypes['int'])
@pytest.mark.parametrize("divisor_dtype",
@@ -1043,6 +1147,33 @@ class TestPower:
assert_complex_equal(np.power(zero, -p), cnan)
assert_complex_equal(np.power(zero, -1+0.2j), cnan)
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
+ def test_zero_power_nonzero(self):
+ # Testing 0^{Non-zero} issue 18378
+ zero = np.array([0.0+0.0j])
+ cnan = np.array([complex(np.nan, np.nan)])
+
+ def assert_complex_equal(x, y):
+ assert_array_equal(x.real, y.real)
+ assert_array_equal(x.imag, y.imag)
+
+ #Complex powers with positive real part will not generate a warning
+ assert_complex_equal(np.power(zero, 1+4j), zero)
+ assert_complex_equal(np.power(zero, 2-3j), zero)
+ #Testing zero values when real part is greater than zero
+ assert_complex_equal(np.power(zero, 1+1j), zero)
+ assert_complex_equal(np.power(zero, 1+0j), zero)
+ assert_complex_equal(np.power(zero, 1-1j), zero)
+ #Complex powers will negative real part or 0 (provided imaginary
+ # part is not zero) will generate a NAN and hence a RUNTIME warning
+ with pytest.warns(expected_warning=RuntimeWarning) as r:
+ assert_complex_equal(np.power(zero, -1+1j), cnan)
+ assert_complex_equal(np.power(zero, -2-3j), cnan)
+ assert_complex_equal(np.power(zero, -7+0j), cnan)
+ assert_complex_equal(np.power(zero, 0+1j), cnan)
+ assert_complex_equal(np.power(zero, 0-1j), cnan)
+ assert len(r) == 5
+
def test_fast_power(self):
x = np.array([1, 2, 3], np.int16)
res = x**2.0
@@ -1095,7 +1226,7 @@ class TestPower:
assert_raises(ValueError, np.power, a, minusone)
assert_raises(ValueError, np.power, one, b)
assert_raises(ValueError, np.power, one, minusone)
-
+
def test_float_to_inf_power(self):
for dt in [np.float32, np.float64]:
a = np.array([1, 1, 2, 2, -2, -2, np.inf, -np.inf], dt)
@@ -1132,6 +1263,7 @@ class TestLog2:
v = np.log2(2.**i)
assert_equal(v, float(i), err_msg='at exponent %d' % i)
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
def test_log2_special(self):
assert_equal(np.log2(1.), 0.)
assert_equal(np.log2(np.inf), np.inf)
@@ -1222,9 +1354,20 @@ class TestLog:
# test log() of max for dtype does not raise
for dt in ['f', 'd', 'g']:
- with np.errstate(all='raise'):
- x = np.finfo(dt).max
- np.log(x)
+ try:
+ with np.errstate(all='raise'):
+ x = np.finfo(dt).max
+ np.log(x)
+ except FloatingPointError as exc:
+ if dt == 'g' and IS_MUSL:
+ # FloatingPointError is known to occur on longdouble
+ # for musllinux_x86_64 x is very large
+ pytest.skip(
+ "Overflow has occurred for"
+ " np.log(np.finfo(np.longdouble).max)"
+ )
+ else:
+ raise exc
def test_log_strides(self):
np.random.seed(42)
@@ -1290,6 +1433,7 @@ class TestSpecialFloats:
assert_raises(FloatingPointError, np.exp, np.float64(-1000.))
assert_raises(FloatingPointError, np.exp, np.float64(-1E19))
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
def test_log_values(self):
with np.errstate(all='ignore'):
x = [np.nan, np.nan, np.inf, np.nan, -np.inf, np.nan]
@@ -1339,23 +1483,51 @@ class TestSpecialFloats:
a = np.array(1e9, dtype='float32')
np.log(a)
- def test_sincos_values(self):
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
+ @pytest.mark.parametrize('dtype', ['e', 'f', 'd', 'g'])
+ def test_sincos_values(self, dtype):
with np.errstate(all='ignore'):
x = [np.nan, np.nan, np.nan, np.nan]
y = [np.nan, -np.nan, np.inf, -np.inf]
- for dt in ['e', 'f', 'd', 'g']:
- xf = np.array(x, dtype=dt)
- yf = np.array(y, dtype=dt)
- assert_equal(np.sin(yf), xf)
- assert_equal(np.cos(yf), xf)
-
+ xf = np.array(x, dtype=dtype)
+ yf = np.array(y, dtype=dtype)
+ assert_equal(np.sin(yf), xf)
+ assert_equal(np.cos(yf), xf)
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
+ @pytest.mark.xfail(
+ sys.platform.startswith("darwin"),
+ reason="underflow is triggered for scalar 'sin'"
+ )
+ def test_sincos_underflow(self):
+ with np.errstate(under='raise'):
+ underflow_trigger = np.array(
+ float.fromhex("0x1.f37f47a03f82ap-511"),
+ dtype=np.float64
+ )
+ np.sin(underflow_trigger)
+ np.cos(underflow_trigger)
+
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
+ @pytest.mark.parametrize('callable', [np.sin, np.cos])
+ @pytest.mark.parametrize('dtype', ['e', 'f', 'd'])
+ @pytest.mark.parametrize('value', [np.inf, -np.inf])
+ def test_sincos_errors(self, callable, dtype, value):
with np.errstate(invalid='raise'):
- for callable in [np.sin, np.cos]:
- for value in [np.inf, -np.inf]:
- for dt in ['e', 'f', 'd']:
- assert_raises(FloatingPointError, callable,
- np.array([value], dtype=dt))
+ assert_raises(FloatingPointError, callable,
+ np.array([value], dtype=dtype))
+
+ @pytest.mark.parametrize('callable', [np.sin, np.cos])
+ @pytest.mark.parametrize('dtype', ['f', 'd'])
+ @pytest.mark.parametrize('stride', [-1, 1, 2, 4, 5])
+ def test_sincos_overlaps(self, callable, dtype, stride):
+ N = 100
+ M = N // abs(stride)
+ rng = np.random.default_rng(42)
+ x = rng.standard_normal(N, dtype)
+ y = callable(x[::stride])
+ callable(x[::stride], out=x[:M])
+ assert_equal(x[:M], y)
@pytest.mark.parametrize('dt', ['e', 'f', 'd', 'g'])
def test_sqrt_values(self, dt):
@@ -1379,6 +1551,7 @@ class TestSpecialFloats:
yf = np.array(y, dtype=dt)
assert_equal(np.abs(yf), xf)
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
def test_square_values(self):
x = [np.nan, np.nan, np.inf, np.inf]
y = [np.nan, -np.nan, np.inf, -np.inf]
@@ -1396,6 +1569,7 @@ class TestSpecialFloats:
assert_raises(FloatingPointError, np.square,
np.array(1E200, dtype='d'))
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
def test_reciprocal_values(self):
with np.errstate(all='ignore'):
x = [np.nan, np.nan, 0.0, -0.0, np.inf, -np.inf]
@@ -1410,6 +1584,7 @@ class TestSpecialFloats:
assert_raises(FloatingPointError, np.reciprocal,
np.array(-0.0, dtype=dt))
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
def test_tan(self):
with np.errstate(all='ignore'):
in_ = [np.nan, -np.nan, 0.0, -0.0, np.inf, -np.inf]
@@ -1426,6 +1601,7 @@ class TestSpecialFloats:
assert_raises(FloatingPointError, np.tan,
np.array(-np.inf, dtype=dt))
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
def test_arcsincos(self):
with np.errstate(all='ignore'):
in_ = [np.nan, -np.nan, np.inf, -np.inf]
@@ -1452,6 +1628,7 @@ class TestSpecialFloats:
out_arr = np.array(out, dtype=dt)
assert_equal(np.arctan(in_arr), out_arr)
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
def test_sinh(self):
in_ = [np.nan, -np.nan, np.inf, -np.inf]
out = [np.nan, np.nan, np.inf, -np.inf]
@@ -1468,6 +1645,7 @@ class TestSpecialFloats:
assert_raises(FloatingPointError, np.sinh,
np.array(1200.0, dtype='d'))
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
def test_cosh(self):
in_ = [np.nan, -np.nan, np.inf, -np.inf]
out = [np.nan, np.nan, np.inf, np.inf]
@@ -1500,6 +1678,7 @@ class TestSpecialFloats:
out_arr = np.array(out, dtype=dt)
assert_equal(np.arcsinh(in_arr), out_arr)
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
def test_arccosh(self):
with np.errstate(all='ignore'):
in_ = [np.nan, -np.nan, np.inf, -np.inf, 1.0, 0.0]
@@ -1515,6 +1694,7 @@ class TestSpecialFloats:
assert_raises(FloatingPointError, np.arccosh,
np.array(value, dtype=dt))
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
def test_arctanh(self):
with np.errstate(all='ignore'):
in_ = [np.nan, -np.nan, np.inf, -np.inf, 1.0, -1.0, 2.0]
@@ -1550,6 +1730,7 @@ class TestSpecialFloats:
assert_raises(FloatingPointError, np.exp2,
np.array(value, dtype=dt))
+ @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
def test_expm1(self):
with np.errstate(all='ignore'):
in_ = [np.nan, -np.nan, np.inf, -np.inf]
@@ -1566,18 +1747,78 @@ class TestSpecialFloats:
np.array(value, dtype=dt))
# test to ensure no spurious FP exceptions are raised due to SIMD
- def test_spurious_fpexception(self):
- for dt in ['e', 'f', 'd']:
- arr = np.array([1.0, 2.0], dtype=dt)
- with assert_no_warnings():
- np.log(arr)
- np.log2(arr)
- np.log10(arr)
- np.arccosh(arr)
-
+ INF_INVALID_ERR = [
+ np.cos, np.sin, np.tan, np.arccos, np.arcsin, np.spacing, np.arctanh
+ ]
+ NEG_INVALID_ERR = [
+ np.log, np.log2, np.log10, np.log1p, np.sqrt, np.arccosh,
+ np.arctanh
+ ]
+ ONE_INVALID_ERR = [
+ np.arctanh,
+ ]
+ LTONE_INVALID_ERR = [
+ np.arccosh,
+ ]
+ BYZERO_ERR = [
+ np.log, np.log2, np.log10, np.reciprocal, np.arccosh
+ ]
+
+ @pytest.mark.parametrize("ufunc", UFUNCS_UNARY_FP)
+ @pytest.mark.parametrize("dtype", ('e', 'f', 'd'))
+ @pytest.mark.parametrize("data, escape", (
+ ([0.03], LTONE_INVALID_ERR),
+ ([0.03]*32, LTONE_INVALID_ERR),
+ # neg
+ ([-1.0], NEG_INVALID_ERR),
+ ([-1.0]*32, NEG_INVALID_ERR),
+ # flat
+ ([1.0], ONE_INVALID_ERR),
+ ([1.0]*32, ONE_INVALID_ERR),
+ # zero
+ ([0.0], BYZERO_ERR),
+ ([0.0]*32, BYZERO_ERR),
+ ([-0.0], BYZERO_ERR),
+ ([-0.0]*32, BYZERO_ERR),
+ # nan
+ ([0.5, 0.5, 0.5, np.nan], LTONE_INVALID_ERR),
+ ([0.5, 0.5, 0.5, np.nan]*32, LTONE_INVALID_ERR),
+ ([np.nan, 1.0, 1.0, 1.0], ONE_INVALID_ERR),
+ ([np.nan, 1.0, 1.0, 1.0]*32, ONE_INVALID_ERR),
+ ([np.nan], []),
+ ([np.nan]*32, []),
+ # inf
+ ([0.5, 0.5, 0.5, np.inf], INF_INVALID_ERR + LTONE_INVALID_ERR),
+ ([0.5, 0.5, 0.5, np.inf]*32, INF_INVALID_ERR + LTONE_INVALID_ERR),
+ ([np.inf, 1.0, 1.0, 1.0], INF_INVALID_ERR),
+ ([np.inf, 1.0, 1.0, 1.0]*32, INF_INVALID_ERR),
+ ([np.inf], INF_INVALID_ERR),
+ ([np.inf]*32, INF_INVALID_ERR),
+ # ninf
+ ([0.5, 0.5, 0.5, -np.inf],
+ NEG_INVALID_ERR + INF_INVALID_ERR + LTONE_INVALID_ERR),
+ ([0.5, 0.5, 0.5, -np.inf]*32,
+ NEG_INVALID_ERR + INF_INVALID_ERR + LTONE_INVALID_ERR),
+ ([-np.inf, 1.0, 1.0, 1.0], NEG_INVALID_ERR + INF_INVALID_ERR),
+ ([-np.inf, 1.0, 1.0, 1.0]*32, NEG_INVALID_ERR + INF_INVALID_ERR),
+ ([-np.inf], NEG_INVALID_ERR + INF_INVALID_ERR),
+ ([-np.inf]*32, NEG_INVALID_ERR + INF_INVALID_ERR),
+ ))
+ def test_unary_spurious_fpexception(self, ufunc, dtype, data, escape):
+ if escape and ufunc in escape:
+ return
+ # FIXME: NAN raises FP invalid exception:
+ # - ceil/float16 on MSVC:32-bit
+ # - spacing/float16 on almost all platforms
+ if ufunc in (np.spacing, np.ceil) and dtype == 'e':
+ return
+ array = np.array(data, dtype=dtype)
+ with assert_no_warnings():
+ ufunc(array)
class TestFPClass:
- @pytest.mark.parametrize("stride", [-4,-2,-1,1,2,4])
+ @pytest.mark.parametrize("stride", [-5, -4, -3, -2, -1, 1,
+ 2, 4, 5, 6, 7, 8, 9, 10])
def test_fpclass(self, stride):
arr_f64 = np.array([np.nan, -np.nan, np.inf, -np.inf, -1.0, 1.0, -0.0, 0.0, 2.2251e-308, -2.2251e-308], dtype='d')
arr_f32 = np.array([np.nan, -np.nan, np.inf, -np.inf, -1.0, 1.0, -0.0, 0.0, 1.4013e-045, -1.4013e-045], dtype='f')
@@ -1594,6 +1835,52 @@ class TestFPClass:
assert_equal(np.isfinite(arr_f32[::stride]), finite[::stride])
assert_equal(np.isfinite(arr_f64[::stride]), finite[::stride])
+ @pytest.mark.parametrize("dtype", ['d', 'f'])
+ def test_fp_noncontiguous(self, dtype):
+ data = np.array([np.nan, -np.nan, np.inf, -np.inf, -1.0,
+ 1.0, -0.0, 0.0, 2.2251e-308,
+ -2.2251e-308], dtype=dtype)
+ nan = np.array([True, True, False, False, False, False,
+ False, False, False, False])
+ inf = np.array([False, False, True, True, False, False,
+ False, False, False, False])
+ sign = np.array([False, True, False, True, True, False,
+ True, False, False, True])
+ finite = np.array([False, False, False, False, True, True,
+ True, True, True, True])
+ out = np.ndarray(data.shape, dtype='bool')
+ ncontig_in = data[1::3]
+ ncontig_out = out[1::3]
+ contig_in = np.array(ncontig_in)
+ assert_equal(ncontig_in.flags.c_contiguous, False)
+ assert_equal(ncontig_out.flags.c_contiguous, False)
+ assert_equal(contig_in.flags.c_contiguous, True)
+ # ncontig in, ncontig out
+ assert_equal(np.isnan(ncontig_in, out=ncontig_out), nan[1::3])
+ assert_equal(np.isinf(ncontig_in, out=ncontig_out), inf[1::3])
+ assert_equal(np.signbit(ncontig_in, out=ncontig_out), sign[1::3])
+ assert_equal(np.isfinite(ncontig_in, out=ncontig_out), finite[1::3])
+ # contig in, ncontig out
+ assert_equal(np.isnan(contig_in, out=ncontig_out), nan[1::3])
+ assert_equal(np.isinf(contig_in, out=ncontig_out), inf[1::3])
+ assert_equal(np.signbit(contig_in, out=ncontig_out), sign[1::3])
+ assert_equal(np.isfinite(contig_in, out=ncontig_out), finite[1::3])
+ # ncontig in, contig out
+ assert_equal(np.isnan(ncontig_in), nan[1::3])
+ assert_equal(np.isinf(ncontig_in), inf[1::3])
+ assert_equal(np.signbit(ncontig_in), sign[1::3])
+ assert_equal(np.isfinite(ncontig_in), finite[1::3])
+ # contig in, contig out, nd stride
+ data_split = np.array(np.array_split(data, 2))
+ nan_split = np.array(np.array_split(nan, 2))
+ inf_split = np.array(np.array_split(inf, 2))
+ sign_split = np.array(np.array_split(sign, 2))
+ finite_split = np.array(np.array_split(finite, 2))
+ assert_equal(np.isnan(data_split), nan_split)
+ assert_equal(np.isinf(data_split), inf_split)
+ assert_equal(np.signbit(data_split), sign_split)
+ assert_equal(np.isfinite(data_split), finite_split)
+
class TestLDExp:
@pytest.mark.parametrize("stride", [-4,-2,-1,1,2,4])
@pytest.mark.parametrize("dtype", ['f', 'd'])
@@ -1607,6 +1894,7 @@ class TestLDExp:
class TestFRExp:
@pytest.mark.parametrize("stride", [-4,-2,-1,1,2,4])
@pytest.mark.parametrize("dtype", ['f', 'd'])
+ @pytest.mark.xfail(IS_MUSL, reason="gh23048")
@pytest.mark.skipif(not sys.platform.startswith('linux'),
reason="np.frexp gives different answers for NAN/INF on windows and linux")
def test_frexp(self, dtype, stride):
@@ -2570,6 +2858,35 @@ class TestAbsoluteNegative:
np.abs(d, out=d)
np.abs(np.ones_like(d), out=d)
+ @pytest.mark.parametrize("dtype", ['d', 'f', 'int32', 'int64'])
+ @pytest.mark.parametrize("big", [True, False])
+ def test_noncontiguous(self, dtype, big):
+ data = np.array([-1.0, 1.0, -0.0, 0.0, 2.2251e-308, -2.5, 2.5, -6,
+ 6, -2.2251e-308, -8, 10], dtype=dtype)
+ expect = np.array([1.0, -1.0, 0.0, -0.0, -2.2251e-308, 2.5, -2.5, 6,
+ -6, 2.2251e-308, 8, -10], dtype=dtype)
+ if big:
+ data = np.repeat(data, 10)
+ expect = np.repeat(expect, 10)
+ out = np.ndarray(data.shape, dtype=dtype)
+ ncontig_in = data[1::2]
+ ncontig_out = out[1::2]
+ contig_in = np.array(ncontig_in)
+ # contig in, contig out
+ assert_array_equal(np.negative(contig_in), expect[1::2])
+ # contig in, ncontig out
+ assert_array_equal(np.negative(contig_in, out=ncontig_out),
+ expect[1::2])
+ # ncontig in, contig out
+ assert_array_equal(np.negative(ncontig_in), expect[1::2])
+ # ncontig in, ncontig out
+ assert_array_equal(np.negative(ncontig_in, out=ncontig_out),
+ expect[1::2])
+ # contig in, contig out, nd stride
+ data_split = np.array(np.array_split(data, 2))
+ expect_split = np.array(np.array_split(expect, 2))
+ assert_equal(np.negative(data_split), expect_split)
+
class TestPositive:
def test_valid(self):
@@ -3265,6 +3582,79 @@ class TestSpecialMethods:
assert_raises(ValueError, np.modf, a, out=('one', 'two', 'three'))
assert_raises(ValueError, np.modf, a, out=('one',))
+ def test_ufunc_override_where(self):
+
+ class OverriddenArrayOld(np.ndarray):
+
+ def _unwrap(self, objs):
+ cls = type(self)
+ result = []
+ for obj in objs:
+ if isinstance(obj, cls):
+ obj = np.array(obj)
+ elif type(obj) != np.ndarray:
+ return NotImplemented
+ result.append(obj)
+ return result
+
+ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
+
+ inputs = self._unwrap(inputs)
+ if inputs is NotImplemented:
+ return NotImplemented
+
+ kwargs = kwargs.copy()
+ if "out" in kwargs:
+ kwargs["out"] = self._unwrap(kwargs["out"])
+ if kwargs["out"] is NotImplemented:
+ return NotImplemented
+
+ r = super().__array_ufunc__(ufunc, method, *inputs, **kwargs)
+ if r is not NotImplemented:
+ r = r.view(type(self))
+
+ return r
+
+ class OverriddenArrayNew(OverriddenArrayOld):
+ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
+
+ kwargs = kwargs.copy()
+ if "where" in kwargs:
+ kwargs["where"] = self._unwrap((kwargs["where"], ))
+ if kwargs["where"] is NotImplemented:
+ return NotImplemented
+ else:
+ kwargs["where"] = kwargs["where"][0]
+
+ r = super().__array_ufunc__(ufunc, method, *inputs, **kwargs)
+ if r is not NotImplemented:
+ r = r.view(type(self))
+
+ return r
+
+ ufunc = np.negative
+
+ array = np.array([1, 2, 3])
+ where = np.array([True, False, True])
+ expected = ufunc(array, where=where)
+
+ with pytest.raises(TypeError):
+ ufunc(array, where=where.view(OverriddenArrayOld))
+
+ result_1 = ufunc(
+ array,
+ where=where.view(OverriddenArrayNew)
+ )
+ assert isinstance(result_1, OverriddenArrayNew)
+ assert np.all(np.array(result_1) == expected, where=where)
+
+ result_2 = ufunc(
+ array.view(OverriddenArrayNew),
+ where=where.view(OverriddenArrayNew)
+ )
+ assert isinstance(result_2, OverriddenArrayNew)
+ assert np.all(np.array(result_2) == expected, where=where)
+
def test_ufunc_override_exception(self):
class A:
@@ -3686,6 +4076,8 @@ class TestComplexFunctions:
assert_almost_equal(fz.real, fr, err_msg='real part %s' % f)
assert_almost_equal(fz.imag, 0., err_msg='imag part %s' % f)
+ @pytest.mark.xfail(IS_MUSL, reason="gh23049")
+ @pytest.mark.xfail(IS_WASM, reason="doesn't work")
def test_precisions_consistent(self):
z = 1 + 1j
for f in self.funcs:
@@ -3695,6 +4087,8 @@ class TestComplexFunctions:
assert_almost_equal(fcf, fcd, decimal=6, err_msg='fch-fcd %s' % f)
assert_almost_equal(fcl, fcd, decimal=15, err_msg='fch-fcl %s' % f)
+ @pytest.mark.xfail(IS_MUSL, reason="gh23049")
+ @pytest.mark.xfail(IS_WASM, reason="doesn't work")
def test_branch_cuts(self):
# check branch cuts and continuity on them
_check_branch_cut(np.log, -0.5, 1j, 1, -1, True)
@@ -3720,6 +4114,8 @@ class TestComplexFunctions:
_check_branch_cut(np.arccosh, [0-2j, 2j, 2], [1, 1, 1j], 1, 1)
_check_branch_cut(np.arctanh, [0-2j, 2j, 0], [1, 1, 1j], 1, 1)
+ @pytest.mark.xfail(IS_MUSL, reason="gh23049")
+ @pytest.mark.xfail(IS_WASM, reason="doesn't work")
def test_branch_cuts_complex64(self):
# check branch cuts and continuity on them
_check_branch_cut(np.log, -0.5, 1j, 1, -1, True, np.complex64)
@@ -3764,6 +4160,8 @@ class TestComplexFunctions:
b = cfunc(p)
assert_(abs(a - b) < atol, "%s %s: %s; cmath: %s" % (fname, p, a, b))
+ @pytest.mark.xfail(IS_MUSL, reason="gh23049")
+ @pytest.mark.xfail(IS_WASM, reason="doesn't work")
@pytest.mark.parametrize('dtype', [np.complex64, np.complex_, np.longcomplex])
def test_loss_of_precision(self, dtype):
"""Check loss of precision in complex arc* functions"""
@@ -3854,6 +4252,14 @@ class TestComplexFunctions:
check(func, pts, 1j)
check(func, pts, 1+1j)
+ @np.errstate(all="ignore")
+ def test_promotion_corner_cases(self):
+ for func in self.funcs:
+ assert func(np.float16(1)).dtype == np.float16
+ # Integer to low precision float promotion is a dubious choice:
+ assert func(np.uint8(1)).dtype == np.float16
+ assert func(np.int16(1)).dtype == np.float32
+
class TestAttributes:
def test_attributes(self):
@@ -4027,7 +4433,7 @@ def _test_spacing(t):
nan = t(np.nan)
inf = t(np.inf)
with np.errstate(invalid='ignore'):
- assert_(np.spacing(one) == eps)
+ assert_equal(np.spacing(one), eps)
assert_(np.isnan(np.spacing(nan)))
assert_(np.isnan(np.spacing(inf)))
assert_(np.isnan(np.spacing(-inf)))
@@ -4163,6 +4569,7 @@ def test_rint_big_int():
# Rint should not change the value
assert_equal(val, np.rint(val))
+
@pytest.mark.parametrize('ftype', [np.float32, np.float64])
def test_memoverlap_accumulate(ftype):
# Reproduces bug https://github.com/numpy/numpy/issues/15597
@@ -4172,6 +4579,38 @@ def test_memoverlap_accumulate(ftype):
assert_equal(np.maximum.accumulate(arr), out_max)
assert_equal(np.minimum.accumulate(arr), out_min)
+@pytest.mark.parametrize("ufunc, dtype", [
+ (ufunc, t[0])
+ for ufunc in UFUNCS_BINARY_ACC
+ for t in ufunc.types
+ if t[-1] == '?' and t[0] not in 'DFGMmO'
+])
+def test_memoverlap_accumulate_cmp(ufunc, dtype):
+ if ufunc.signature:
+ pytest.skip('For generic signatures only')
+ for size in (2, 8, 32, 64, 128, 256):
+ arr = np.array([0, 1, 1]*size, dtype=dtype)
+ acc = ufunc.accumulate(arr, dtype='?')
+ acc_u8 = acc.view(np.uint8)
+ exp = np.array(list(itertools.accumulate(arr, ufunc)), dtype=np.uint8)
+ assert_equal(exp, acc_u8)
+
+@pytest.mark.parametrize("ufunc, dtype", [
+ (ufunc, t[0])
+ for ufunc in UFUNCS_BINARY_ACC
+ for t in ufunc.types
+ if t[0] == t[1] and t[0] == t[-1] and t[0] not in 'DFGMmO?'
+])
+def test_memoverlap_accumulate_symmetric(ufunc, dtype):
+ if ufunc.signature:
+ pytest.skip('For generic signatures only')
+ with np.errstate(all='ignore'):
+ for size in (2, 8, 32, 64, 128, 256):
+ arr = np.array([0, 1, 2]*size).astype(dtype)
+ acc = ufunc.accumulate(arr, dtype=dtype)
+ exp = np.array(list(itertools.accumulate(arr, ufunc)), dtype=dtype)
+ assert_equal(exp, acc)
+
def test_signaling_nan_exceptions():
with assert_no_warnings():
a = np.ndarray(shape=(), dtype='float32', buffer=b'\x00\xe0\xbf\xff')