codekingpro/portable-devtools
114k
1import contextlib
2import itertools
3import operator
4import platform
5import sys
6import warnings
7
8import pytest
9from hypothesis import given, settings
10from hypothesis.extra import numpy as hynp
11from hypothesis.strategies import sampled_from
12
13import numpy as np
14from numpy._core._rational_tests import rational
15from numpy._utils import _pep440
16from numpy.exceptions import ComplexWarning
17from numpy.testing import (
18 IS_PYPY,
19 _gen_alignment_data,
20 assert_,
21 assert_almost_equal,
22 assert_array_equal,
23 assert_equal,
24 assert_raises,
25 check_support_sve,
26)
27
28types = [np.bool, np.byte, np.ubyte, np.short, np.ushort, np.intc, np.uintc,
29 np.int_, np.uint, np.longlong, np.ulonglong,
30 np.single, np.double, np.longdouble, np.csingle,
31 np.cdouble, np.clongdouble]
32
33floating_types = np.floating.__subclasses__()
34complex_floating_types = np.complexfloating.__subclasses__()
35
36objecty_things = [object(), None, np.array(None, dtype=object)]
37
38binary_operators_for_scalars = [
39 operator.lt, operator.le, operator.eq, operator.ne, operator.ge,
40 operator.gt, operator.add, operator.floordiv, operator.mod,
41 operator.mul, operator.pow, operator.sub, operator.truediv
42]
43binary_operators_for_scalar_ints = binary_operators_for_scalars + [
44 operator.xor, operator.or_, operator.and_
45]
46
47
48# This compares scalarmath against ufuncs.
49
50class TestTypes:
51 def test_types(self):
52 for atype in types:
53 a = atype(1)
54 assert_(a == 1, f"error with {atype!r}: got {a!r}")
55
56 def test_type_add(self):
57 # list of types
58 for k, atype in enumerate(types):
59 a_scalar = atype(3)
60 a_array = np.array([3], dtype=atype)
61 for l, btype in enumerate(types):
62 b_scalar = btype(1)
63 b_array = np.array([1], dtype=btype)
64 c_scalar = a_scalar + b_scalar
65 c_array = a_array + b_array
66 # It was comparing the type numbers, but the new ufunc
67 # function-finding mechanism finds the lowest function
68 # to which both inputs can be cast - which produces 'l'
69 # when you do 'q' + 'b'. The old function finding mechanism
70 # skipped ahead based on the first argument, but that
71 # does not produce properly symmetric results...
72 assert_equal(c_scalar.dtype, c_array.dtype,
73 "error with types (%d/'%c' + %d/'%c')" %
74 (k, np.dtype(atype).char, l, np.dtype(btype).char))
75
76 def test_type_create(self):
77 for atype in types:
78 a = np.array([1, 2, 3], atype)
79 b = atype([1, 2, 3])
80 assert_equal(a, b)
81
82 def test_leak(self):
83 # test leak of scalar objects
84 # a leak would show up in valgrind as still-reachable of ~2.6MB
85 for i in range(200000):
86 np.add(1, 1)
87
88
89def check_ufunc_scalar_equivalence(op, arr1, arr2):
90 scalar1 = arr1[()]
91 scalar2 = arr2[()]
92 assert isinstance(scalar1, np.generic)
93 assert isinstance(scalar2, np.generic)
94
95 if arr1.dtype.kind == "c" or arr2.dtype.kind == "c":
96 comp_ops = {operator.ge, operator.gt, operator.le, operator.lt}
97 if op in comp_ops and (np.isnan(scalar1) or np.isnan(scalar2)):
98 pytest.xfail("complex comp ufuncs use sort-order, scalars do not.")
99 if op == operator.pow and arr2.item() in [-1, 0, 0.5, 1, 2]:
100 # array**scalar special case can have different result dtype
101 # (Other powers may have issues also, but are not hit here.)
102 # TODO: It would be nice to resolve this issue.
103 pytest.skip("array**2 can have incorrect/weird result dtype")
104
105 # ignore fpe's since they may just mismatch for integers anyway.
106 with warnings.catch_warnings(), np.errstate(all="ignore"):
107 # Comparisons DeprecationWarnings replacing errors (2022-03):
108 warnings.simplefilter("error", DeprecationWarning)
109 try:
110 res = op(arr1, arr2)
111 except Exception as e:
112 with pytest.raises(type(e)):
113 op(scalar1, scalar2)
114 else:
115 scalar_res = op(scalar1, scalar2)
116 assert_array_equal(scalar_res, res, strict=True)
117
118
119@pytest.mark.slow
120@settings(max_examples=10000, deadline=2000)
121@given(sampled_from(binary_operators_for_scalars),
122 hynp.arrays(dtype=hynp.scalar_dtypes(), shape=()),
123 hynp.arrays(dtype=hynp.scalar_dtypes(), shape=()))
124def test_array_scalar_ufunc_equivalence(op, arr1, arr2):
125 """
126 This is a thorough test attempting to cover important promotion paths
127 and ensuring that arrays and scalars stay as aligned as possible.
128 However, if it creates troubles, it should maybe just be removed.
129 """
130 check_ufunc_scalar_equivalence(op, arr1, arr2)
131
132
133@pytest.mark.slow
134@given(sampled_from(binary_operators_for_scalars),
135 hynp.scalar_dtypes(), hynp.scalar_dtypes())
136def test_array_scalar_ufunc_dtypes(op, dt1, dt2):
137 # Same as above, but don't worry about sampling weird values so that we
138 # do not have to sample as much
139 arr1 = np.array(2, dtype=dt1)
140 arr2 = np.array(3, dtype=dt2) # some power do weird things.
141
142 check_ufunc_scalar_equivalence(op, arr1, arr2)
143
144
145@pytest.mark.parametrize("fscalar", [np.float16, np.float32])
146def test_int_float_promotion_truediv(fscalar):
147 # Promotion for mixed int and float32/float16 must not go to float64
148 i = np.int8(1)
149 f = fscalar(1)
150 expected = np.result_type(i, f)
151 assert (i / f).dtype == expected
152 assert (f / i).dtype == expected
153 # But normal int / int true division goes to float64:
154 assert (i / i).dtype == np.dtype("float64")
155 # For int16, result has to be ast least float32 (takes ufunc path):
156 assert (np.int16(1) / f).dtype == np.dtype("float32")
157
158
159class TestBaseMath:
160 @pytest.mark.xfail(check_support_sve(), reason="gh-22982")
161 def test_blocked(self):
162 # test alignments offsets for simd instructions
163 # alignments for vz + 2 * (vs - 1) + 1
164 for dt, sz in [(np.float32, 11), (np.float64, 7), (np.int32, 11)]:
165 for out, inp1, inp2, msg in _gen_alignment_data(dtype=dt,
166 type='binary',
167 max_size=sz):
168 exp1 = np.ones_like(inp1)
169 inp1[...] = np.ones_like(inp1)
170 inp2[...] = np.zeros_like(inp2)
171 assert_almost_equal(np.add(inp1, inp2), exp1, err_msg=msg)
172 assert_almost_equal(np.add(inp1, 2), exp1 + 2, err_msg=msg)
173 assert_almost_equal(np.add(1, inp2), exp1, err_msg=msg)
174
175 np.add(inp1, inp2, out=out)
176 assert_almost_equal(out, exp1, err_msg=msg)
177
178 inp2[...] += np.arange(inp2.size, dtype=dt) + 1
179 assert_almost_equal(np.square(inp2),
180 np.multiply(inp2, inp2), err_msg=msg)
181 # skip true divide for ints
182 if dt != np.int32:
183 assert_almost_equal(np.reciprocal(inp2),
184 np.divide(1, inp2), err_msg=msg)
185
186 inp1[...] = np.ones_like(inp1)
187 np.add(inp1, 2, out=out)
188 assert_almost_equal(out, exp1 + 2, err_msg=msg)
189 inp2[...] = np.ones_like(inp2)
190 np.add(2, inp2, out=out)
191 assert_almost_equal(out, exp1 + 2, err_msg=msg)
192
193 def test_lower_align(self):
194 # check data that is not aligned to element size
195 # i.e doubles are aligned to 4 bytes on i386
196 d = np.zeros(23 * 8, dtype=np.int8)[4:-4].view(np.float64)
197 o = np.zeros(23 * 8, dtype=np.int8)[4:-4].view(np.float64)
198 assert_almost_equal(d + d, d * 2)
199 np.add(d, d, out=o)
200 np.add(np.ones_like(d), d, out=o)
201 np.add(d, np.ones_like(d), out=o)
202 np.add(np.ones_like(d), d)
203 np.add(d, np.ones_like(d))
204
205
206class TestPower:
207 def test_small_types(self):
208 for t in [np.int8, np.int16, np.float16]:
209 a = t(3)
210 b = a ** 4
211 assert_(b == 81, f"error with {t!r}: got {b!r}")
212
213 def test_large_types(self):
214 for t in [np.int32, np.int64, np.float32, np.float64, np.longdouble]:
215 a = t(51)
216 b = a ** 4
217 msg = f"error with {t!r}: got {b!r}"
218 if np.issubdtype(t, np.integer):
219 assert_(b == 6765201, msg)
220 else:
221 assert_almost_equal(b, 6765201, err_msg=msg)
222
223 def test_integers_to_negative_integer_power(self):
224 # Note that the combination of uint64 with a signed integer
225 # has common type np.float64. The other combinations should all
226 # raise a ValueError for integer ** negative integer.
227 exp = [np.array(-1, dt)[()] for dt in 'bhilq']
228
229 # 1 ** -1 possible special case
230 base = [np.array(1, dt)[()] for dt in 'bhilqBHILQ']
231 for i1, i2 in itertools.product(base, exp):
232 if i1.dtype != np.uint64:
233 assert_raises(ValueError, operator.pow, i1, i2)
234 else:
235 res = operator.pow(i1, i2)
236 assert_(res.dtype.type is np.float64)
237 assert_almost_equal(res, 1.)
238
239 # -1 ** -1 possible special case
240 base = [np.array(-1, dt)[()] for dt in 'bhilq']
241 for i1, i2 in itertools.product(base, exp):
242 if i1.dtype != np.uint64:
243 assert_raises(ValueError, operator.pow, i1, i2)
244 else:
245 res = operator.pow(i1, i2)
246 assert_(res.dtype.type is np.float64)
247 assert_almost_equal(res, -1.)
248
249 # 2 ** -1 perhaps generic
250 base = [np.array(2, dt)[()] for dt in 'bhilqBHILQ']
251 for i1, i2 in itertools.product(base, exp):
252 if i1.dtype != np.uint64:
253 assert_raises(ValueError, operator.pow, i1, i2)
254 else:
255 res = operator.pow(i1, i2)
256 assert_(res.dtype.type is np.float64)
257 assert_almost_equal(res, .5)
258
259 def test_mixed_types(self):
260 typelist = [np.int8, np.int16, np.float16,
261 np.float32, np.float64, np.int8,
262 np.int16, np.int32, np.int64]
263 for t1 in typelist:
264 for t2 in typelist:
265 a = t1(3)
266 b = t2(2)
267 result = a**b
268 msg = f"error with {t1!r} and {t2!r}:got {result!r}, expected {9!r}"
269 if np.issubdtype(np.dtype(result), np.integer):
270 assert_(result == 9, msg)
271 else:
272 assert_almost_equal(result, 9, err_msg=msg)
273
274 def test_modular_power(self):
275 # modular power is not implemented, so ensure it errors
276 a = 5
277 b = 4
278 c = 10
279 expected = pow(a, b, c) # noqa: F841
280 for t in (np.int32, np.float32, np.complex64):
281 # note that 3-operand power only dispatches on the first argument
282 assert_raises(TypeError, operator.pow, t(a), b, c)
283 assert_raises(TypeError, operator.pow, np.array(t(a)), b, c)
284
285
286def floordiv_and_mod(x, y):
287 return (x // y, x % y)
288
289
290def _signs(dt):
291 if dt in np.typecodes['UnsignedInteger']:
292 return (+1,)
293 else:
294 return (+1, -1)
295
296
297class TestModulus:
298
299 def test_modulus_basic(self):
300 dt = np.typecodes['AllInteger'] + np.typecodes['Float']
301 for op in [floordiv_and_mod, divmod]:
302 for dt1, dt2 in itertools.product(dt, dt):
303 for sg1, sg2 in itertools.product(_signs(dt1), _signs(dt2)):
304 fmt = 'op: %s, dt1: %s, dt2: %s, sg1: %s, sg2: %s'
305 msg = fmt % (op.__name__, dt1, dt2, sg1, sg2)
306 a = np.array(sg1 * 71, dtype=dt1)[()]
307 b = np.array(sg2 * 19, dtype=dt2)[()]
308 div, rem = op(a, b)
309 assert_equal(div * b + rem, a, err_msg=msg)
310 if sg2 == -1:
311 assert_(b < rem <= 0, msg)
312 else:
313 assert_(b > rem >= 0, msg)
314
315 def test_float_modulus_exact(self):
316 # test that float results are exact for small integers. This also
317 # holds for the same integers scaled by powers of two.
318 nlst = list(range(-127, 0))
319 plst = list(range(1, 128))
320 dividend = nlst + [0] + plst
321 divisor = nlst + plst
322 arg = list(itertools.product(dividend, divisor))
323 tgt = [divmod(*t) for t in arg]
324
325 a, b = np.array(arg, dtype=int).T
326 # convert exact integer results from Python to float so that
327 # signed zero can be used, it is checked.
328 tgtdiv, tgtrem = np.array(tgt, dtype=float).T
329 tgtdiv = np.where((tgtdiv == 0.0) & ((b < 0) ^ (a < 0)), -0.0, tgtdiv)
330 tgtrem = np.where((tgtrem == 0.0) & (b < 0), -0.0, tgtrem)
331
332 for op in [floordiv_and_mod, divmod]:
333 for dt in np.typecodes['Float']:
334 msg = f'op: {op.__name__}, dtype: {dt}'
335 fa = a.astype(dt)
336 fb = b.astype(dt)
337 # use list comprehension so a_ and b_ are scalars
338 div, rem = zip(*[op(a_, b_) for a_, b_ in zip(fa, fb)])
339 assert_equal(div, tgtdiv, err_msg=msg)
340 assert_equal(rem, tgtrem, err_msg=msg)
341
342 def test_float_modulus_roundoff(self):
343 # gh-6127
344 dt = np.typecodes['Float']
345 for op in [floordiv_and_mod, divmod]:
346 for dt1, dt2 in itertools.product(dt, dt):
347 for sg1, sg2 in itertools.product((+1, -1), (+1, -1)):
348 fmt = 'op: %s, dt1: %s, dt2: %s, sg1: %s, sg2: %s'
349 msg = fmt % (op.__name__, dt1, dt2, sg1, sg2)
350 a = np.array(sg1 * 78 * 6e-8, dtype=dt1)[()]
351 b = np.array(sg2 * 6e-8, dtype=dt2)[()]
352 div, rem = op(a, b)
353 # Equal assertion should hold when fmod is used
354 assert_equal(div * b + rem, a, err_msg=msg)
355 if sg2 == -1:
356 assert_(b < rem <= 0, msg)
357 else:
358 assert_(b > rem >= 0, msg)
359
360 def test_float_modulus_corner_cases(self):
361 # Check remainder magnitude.
362 for dt in np.typecodes['Float']:
363 b = np.array(1.0, dtype=dt)
364 a = np.nextafter(np.array(0.0, dtype=dt), -b)
365 rem = operator.mod(a, b)
366 assert_(rem <= b, f'dt: {dt}')
367 rem = operator.mod(-a, -b)
368 assert_(rem >= -b, f'dt: {dt}')
369
370 # Check nans, inf
371 with warnings.catch_warnings(), np.errstate(all='ignore'):
372 for dt in np.typecodes['Float']:
373 fone = np.array(1.0, dtype=dt)
374 fzer = np.array(0.0, dtype=dt)
375 finf = np.array(np.inf, dtype=dt)
376 fnan = np.array(np.nan, dtype=dt)
377 rem = operator.mod(fone, fzer)
378 assert_(np.isnan(rem), f'dt: {dt}')
379 # MSVC 2008 returns NaN here, so disable the check.
380 #rem = operator.mod(fone, finf)
381 #assert_(rem == fone, 'dt: %s' % dt)
382 rem = operator.mod(fone, fnan)
383 assert_(np.isnan(rem), f'dt: {dt}')
384 rem = operator.mod(finf, fone)
385 assert_(np.isnan(rem), f'dt: {dt}')
386 for op in [floordiv_and_mod, divmod]:
387 div, mod = op(fone, fzer)
388 assert_(np.isinf(div)) and assert_(np.isnan(mod))
389
390 def test_inplace_floordiv_handling(self):
391 # issue gh-12927
392 # this only applies to in-place floordiv //=, because the output type
393 # promotes to float which does not fit
394 a = np.array([1, 2], np.int64)
395 b = np.array([1, 2], np.uint64)
396 with pytest.raises(TypeError,
397 match=r"Cannot cast ufunc 'floor_divide' output from"):
398 a //= b
399
400class TestComparison:
401 def test_comparision_different_types(self):
402 x = np.array(1)
403 y = np.array('s')
404 eq = x == y
405 neq = x != y
406 assert eq is np.bool_(False)
407 assert neq is np.bool_(True)
408
409
410class TestComplexDivision:
411 def test_zero_division(self):
412 with np.errstate(all="ignore"):
413 for t in [np.complex64, np.complex128]:
414 a = t(0.0)
415 b = t(1.0)
416 assert_(np.isinf(b / a))
417 b = t(complex(np.inf, np.inf))
418 assert_(np.isinf(b / a))
419 b = t(complex(np.inf, np.nan))
420 assert_(np.isinf(b / a))
421 b = t(complex(np.nan, np.inf))
422 assert_(np.isinf(b / a))
423 b = t(complex(np.nan, np.nan))
424 assert_(np.isnan(b / a))
425 b = t(0.)
426 assert_(np.isnan(b / a))
427
428 def test_signed_zeros(self):
429 with np.errstate(all="ignore"):
430 for t in [np.complex64, np.complex128]:
431 # tupled (numerator, denominator, expected)
432 # for testing as expected == numerator/denominator
433 data = (
434 (( 0.0, -1.0), ( 0.0, 1.0), (-1.0, -0.0)),
435 (( 0.0, -1.0), ( 0.0, -1.0), ( 1.0, -0.0)),
436 (( 0.0, -1.0), (-0.0, -1.0), ( 1.0, 0.0)),
437 (( 0.0, -1.0), (-0.0, 1.0), (-1.0, 0.0)),
438 (( 0.0, 1.0), ( 0.0, -1.0), (-1.0, 0.0)),
439 (( 0.0, -1.0), ( 0.0, -1.0), ( 1.0, -0.0)),
440 ((-0.0, -1.0), ( 0.0, -1.0), ( 1.0, -0.0)),
441 ((-0.0, 1.0), ( 0.0, -1.0), (-1.0, -0.0))
442 )
443 for cases in data:
444 n = cases[0]
445 d = cases[1]
446 ex = cases[2]
447 result = t(complex(n[0], n[1])) / t(complex(d[0], d[1]))
448 # check real and imag parts separately to avoid comparison
449 # in array context, which does not account for signed zeros
450 assert_equal(result.real, ex[0])
451 assert_equal(result.imag, ex[1])
452
453 def test_branches(self):
454 with np.errstate(all="ignore"):
455 for t in [np.complex64, np.complex128]:
456 # tupled (numerator, denominator, expected)
457 # for testing as expected == numerator/denominator
458 data = []
459
460 # trigger branch: real(fabs(denom)) > imag(fabs(denom))
461 # followed by else condition as neither are == 0
462 data.append((( 2.0, 1.0), ( 2.0, 1.0), (1.0, 0.0)))
463
464 # trigger branch: real(fabs(denom)) > imag(fabs(denom))
465 # followed by if condition as both are == 0
466 # is performed in test_zero_division(), so this is skipped
467
468 # trigger else if branch: real(fabs(denom)) < imag(fabs(denom))
469 data.append(((1.0, 2.0), (1.0, 2.0), (1.0, 0.0)))
470
471 for cases in data:
472 n = cases[0]
473 d = cases[1]
474 ex = cases[2]
475 result = t(complex(n[0], n[1])) / t(complex(d[0], d[1]))
476 # check real and imag parts separately to avoid comparison
477 # in array context, which does not account for signed zeros
478 assert_equal(result.real, ex[0])
479 assert_equal(result.imag, ex[1])
480
481
482class TestConversion:
483 def test_int_from_long(self):
484 l = [1e6, 1e12, 1e18, -1e6, -1e12, -1e18]
485 li = [10**6, 10**12, 10**18, -10**6, -10**12, -10**18]
486 for T in [None, np.float64, np.int64]:
487 a = np.array(l, dtype=T)
488 assert_equal([int(_m) for _m in a], li)
489
490 a = np.array(l[:3], dtype=np.uint64)
491 assert_equal([int(_m) for _m in a], li[:3])
492
493 def test_iinfo_long_values(self):
494 for code in 'bBhH':
495 with pytest.raises(OverflowError):
496 np.array(np.iinfo(code).max + 1, dtype=code)
497
498 for code in np.typecodes['AllInteger']:
499 res = np.array(np.iinfo(code).max, dtype=code)
500 tgt = np.iinfo(code).max
501 assert_(res == tgt)
502
503 for code in np.typecodes['AllInteger']:
504 res = np.dtype(code).type(np.iinfo(code).max)
505 tgt = np.iinfo(code).max
506 assert_(res == tgt)
507
508 def test_int_raise_behaviour(self):
509 def overflow_error_func(dtype):
510 dtype(np.iinfo(dtype).max + 1)
511
512 for code in [np.int_, np.uint, np.longlong, np.ulonglong]:
513 assert_raises(OverflowError, overflow_error_func, code)
514
515 def test_int_from_infinite_longdouble(self):
516 # gh-627
517 x = np.longdouble(np.inf)
518 assert_raises(OverflowError, int, x)
519 with pytest.warns(ComplexWarning):
520 x = np.clongdouble(np.inf)
521 assert_raises(OverflowError, int, x)
522
523 @pytest.mark.skipif(not IS_PYPY, reason="Test is PyPy only (gh-9972)")
524 def test_int_from_infinite_longdouble___int__(self):
525 x = np.longdouble(np.inf)
526 assert_raises(OverflowError, x.__int__)
527 with pytest.warns(ComplexWarning):
528 x = np.clongdouble(np.inf)
529 assert_raises(OverflowError, x.__int__)
530
531 @pytest.mark.skipif(np.finfo(np.double) == np.finfo(np.longdouble),
532 reason="long double is same as double")
533 @pytest.mark.skipif(platform.machine().startswith("ppc"),
534 reason="IBM double double")
535 def test_int_from_huge_longdouble(self):
536 # Produce a longdouble that would overflow a double,
537 # use exponent that avoids bug in Darwin pow function.
538 exp = np.finfo(np.double).maxexp - 1
539 huge_ld = 2 * 1234 * np.longdouble(2) ** exp
540 huge_i = 2 * 1234 * 2 ** exp
541 assert_(huge_ld != np.inf)
542 assert_equal(int(huge_ld), huge_i)
543
544 def test_int_from_longdouble(self):
545 x = np.longdouble(1.5)
546 assert_equal(int(x), 1)
547 x = np.longdouble(-10.5)
548 assert_equal(int(x), -10)
549
550 def test_numpy_scalar_relational_operators(self):
551 # All integer
552 for dt1 in np.typecodes['AllInteger']:
553 assert_(1 > np.array(0, dtype=dt1)[()], f"type {dt1} failed")
554 assert_(not 1 < np.array(0, dtype=dt1)[()], f"type {dt1} failed")
555
556 for dt2 in np.typecodes['AllInteger']:
557 assert_(np.array(1, dtype=dt1)[()] > np.array(0, dtype=dt2)[()],
558 f"type {dt1} and {dt2} failed")
559 assert_(not np.array(1, dtype=dt1)[()] < np.array(0, dtype=dt2)[()],
560 f"type {dt1} and {dt2} failed")
561
562 # Unsigned integers
563 for dt1 in 'BHILQP':
564 assert_(-1 < np.array(1, dtype=dt1)[()], f"type {dt1} failed")
565 assert_(not -1 > np.array(1, dtype=dt1)[()], f"type {dt1} failed")
566 assert_(-1 != np.array(1, dtype=dt1)[()], f"type {dt1} failed")
567
568 # unsigned vs signed
569 for dt2 in 'bhilqp':
570 assert_(np.array(1, dtype=dt1)[()] > np.array(-1, dtype=dt2)[()],
571 f"type {dt1} and {dt2} failed")
572 assert_(not np.array(1, dtype=dt1)[()] < np.array(-1, dtype=dt2)[()],
573 f"type {dt1} and {dt2} failed")
574 assert_(np.array(1, dtype=dt1)[()] != np.array(-1, dtype=dt2)[()],
575 f"type {dt1} and {dt2} failed")
576
577 # Signed integers and floats
578 for dt1 in 'bhlqp' + np.typecodes['Float']:
579 assert_(1 > np.array(-1, dtype=dt1)[()], f"type {dt1} failed")
580 assert_(not 1 < np.array(-1, dtype=dt1)[()], f"type {dt1} failed")
581 assert_(-1 == np.array(-1, dtype=dt1)[()], f"type {dt1} failed")
582
583 for dt2 in 'bhlqp' + np.typecodes['Float']:
584 assert_(np.array(1, dtype=dt1)[()] > np.array(-1, dtype=dt2)[()],
585 f"type {dt1} and {dt2} failed")
586 assert_(not np.array(1, dtype=dt1)[()] < np.array(-1, dtype=dt2)[()],
587 f"type {dt1} and {dt2} failed")
588 assert_(np.array(-1, dtype=dt1)[()] == np.array(-1, dtype=dt2)[()],
589 f"type {dt1} and {dt2} failed")
590
591 def test_scalar_comparison_to_none(self):
592 # Scalars should just return False and not give a warnings.
593 # The comparisons are flagged by pep8, ignore that.
594 with warnings.catch_warnings(record=True) as w:
595 warnings.filterwarnings('always', '', FutureWarning)
596 assert_(not np.float32(1) == None) # noqa: E711
597 assert_(not np.str_('test') == None) # noqa: E711
598 # This is dubious (see below):
599 assert_(not np.datetime64('NaT') == None) # noqa: E711
600
601 assert_(np.float32(1) != None) # noqa: E711
602 assert_(np.str_('test') != None) # noqa: E711
603 # This is dubious (see below):
604 assert_(np.datetime64('NaT') != None) # noqa: E711
605 assert_(len(w) == 0)
606
607 # For documentation purposes, this is why the datetime is dubious.
608 # At the time of deprecation this was no behaviour change, but
609 # it has to be considered when the deprecations are done.
610 assert_(np.equal(np.datetime64('NaT'), None))
611
612
613#class TestRepr:
614# def test_repr(self):
615# for t in types:
616# val = t(1197346475.0137341)
617# val_repr = repr(val)
618# val2 = eval(val_repr)
619# assert_equal( val, val2 )
620
621
622class TestRepr:
623 def _test_type_repr(self, t):
624 finfo = np.finfo(t)
625 last_fraction_bit_idx = finfo.nexp + finfo.nmant
626 last_exponent_bit_idx = finfo.nexp
627 storage_bytes = np.dtype(t).itemsize * 8
628 # could add some more types to the list below
629 for which in ['small denorm', 'small norm']:
630 # Values from https://en.wikipedia.org/wiki/IEEE_754
631 constr = np.array([0x00] * storage_bytes, dtype=np.uint8)
632 if which == 'small denorm':
633 byte = last_fraction_bit_idx // 8
634 bytebit = 7 - (last_fraction_bit_idx % 8)
635 constr[byte] = 1 << bytebit
636 elif which == 'small norm':
637 byte = last_exponent_bit_idx // 8
638 bytebit = 7 - (last_exponent_bit_idx % 8)
639 constr[byte] = 1 << bytebit
640 else:
641 raise ValueError('hmm')
642 val = constr.view(t)[0]
643 val_repr = repr(val)
644 val2 = t(eval(val_repr))
645 if not (val2 == 0 and val < 1e-100):
646 assert_equal(val, val2)
647
648 def test_float_repr(self):
649 # long double test cannot work, because eval goes through a python
650 # float
651 for t in [np.float32, np.float64]:
652 self._test_type_repr(t)
653
654
655if not IS_PYPY:
656 # sys.getsizeof() is not valid on PyPy
657 class TestSizeOf:
658
659 def test_equal_nbytes(self):
660 for type in types:
661 x = type(0)
662 assert_(sys.getsizeof(x) > x.nbytes)
663
664 def test_error(self):
665 d = np.float32()
666 assert_raises(TypeError, d.__sizeof__, "a")
667
668
669class TestMultiply:
670 def test_seq_repeat(self):
671 # Test that basic sequences get repeated when multiplied with
672 # numpy integers. And errors are raised when multiplied with others.
673 # Some of this behaviour may be controversial and could be open for
674 # change.
675 accepted_types = set(np.typecodes["AllInteger"])
676 deprecated_types = {'?'}
677 forbidden_types = (
678 set(np.typecodes["All"]) - accepted_types - deprecated_types)
679 forbidden_types -= {'V'} # can't default-construct void scalars
680
681 for seq_type in (list, tuple):
682 seq = seq_type([1, 2, 3])
683 for numpy_type in accepted_types:
684 i = np.dtype(numpy_type).type(2)
685 assert_equal(seq * i, seq * int(i))
686 assert_equal(i * seq, int(i) * seq)
687
688 for numpy_type in deprecated_types:
689 i = np.dtype(numpy_type).type()
690 with assert_raises(TypeError):
691 operator.mul(seq, i)
692
693 for numpy_type in forbidden_types:
694 i = np.dtype(numpy_type).type()
695 assert_raises(TypeError, operator.mul, seq, i)
696 assert_raises(TypeError, operator.mul, i, seq)
697
698 def test_no_seq_repeat_basic_array_like(self):
699 # Test that an array-like which does not know how to be multiplied
700 # does not attempt sequence repeat (raise TypeError).
701 # See also gh-7428.
702 class ArrayLike:
703 def __init__(self, arr):
704 self.arr = arr
705
706 def __array__(self, dtype=None, copy=None):
707 return self.arr
708
709 # Test for simple ArrayLike above and memoryviews (original report)
710 for arr_like in (ArrayLike(np.ones(3)), memoryview(np.ones(3))):
711 assert_array_equal(arr_like * np.float32(3.), np.full(3, 3.))
712 assert_array_equal(np.float32(3.) * arr_like, np.full(3, 3.))
713 assert_array_equal(arr_like * np.int_(3), np.full(3, 3))
714 assert_array_equal(np.int_(3) * arr_like, np.full(3, 3))
715
716
717class TestNegative:
718 def test_exceptions(self):
719 a = np.ones((), dtype=np.bool)[()]
720 assert_raises(TypeError, operator.neg, a)
721
722 def test_result(self):
723 types = np.typecodes['AllInteger'] + np.typecodes['AllFloat']
724 with warnings.catch_warnings():
725 warnings.simplefilter('ignore', RuntimeWarning)
726 for dt in types:
727 a = np.ones((), dtype=dt)[()]
728 if dt in np.typecodes['UnsignedInteger']:
729 st = np.dtype(dt).type
730 max = st(np.iinfo(dt).max)
731 assert_equal(operator.neg(a), max)
732 else:
733 assert_equal(operator.neg(a) + a, 0)
734
735class TestSubtract:
736 def test_exceptions(self):
737 a = np.ones((), dtype=np.bool)[()]
738 assert_raises(TypeError, operator.sub, a, a)
739
740 def test_result(self):
741 types = np.typecodes['AllInteger'] + np.typecodes['AllFloat']
742 with warnings.catch_warnings():
743 warnings.simplefilter('ignore', RuntimeWarning)
744 for dt in types:
745 a = np.ones((), dtype=dt)[()]
746 assert_equal(operator.sub(a, a), 0)
747
748
749class TestAbs:
750 def _test_abs_func(self, absfunc, test_dtype):
751 x = test_dtype(-1.5)
752 assert_equal(absfunc(x), 1.5)
753 x = test_dtype(0.0)
754 res = absfunc(x)
755 # assert_equal() checks zero signedness
756 assert_equal(res, 0.0)
757 x = test_dtype(-0.0)
758 res = absfunc(x)
759 assert_equal(res, 0.0)
760
761 x = test_dtype(np.finfo(test_dtype).max)
762 assert_equal(absfunc(x), x.real)
763
764 with warnings.catch_warnings():
765 warnings.simplefilter('ignore', UserWarning)
766 x = test_dtype(np.finfo(test_dtype).tiny)
767 assert_equal(absfunc(x), x.real)
768
769 x = test_dtype(np.finfo(test_dtype).min)
770 assert_equal(absfunc(x), -x.real)
771
772 @pytest.mark.parametrize("dtype", floating_types + complex_floating_types)
773 def test_builtin_abs(self, dtype):
774 if (
775 sys.platform == "cygwin" and dtype == np.clongdouble and
776 (
777 _pep440.parse(platform.release().split("-")[0])
778 < _pep440.Version("3.3.0")
779 )
780 ):
781 pytest.xfail(
782 reason="absl is computed in double precision on cygwin < 3.3"
783 )
784 self._test_abs_func(abs, dtype)
785
786 @pytest.mark.parametrize("dtype", floating_types + complex_floating_types)
787 def test_numpy_abs(self, dtype):
788 if (
789 sys.platform == "cygwin" and dtype == np.clongdouble and
790 (
791 _pep440.parse(platform.release().split("-")[0])
792 < _pep440.Version("3.3.0")
793 )
794 ):
795 pytest.xfail(
796 reason="absl is computed in double precision on cygwin < 3.3"
797 )
798 self._test_abs_func(np.abs, dtype)
799
800class TestBitShifts:
801
802 @pytest.mark.parametrize('type_code', np.typecodes['AllInteger'])
803 @pytest.mark.parametrize('op',
804 [operator.rshift, operator.lshift], ids=['>>', '<<'])
805 def test_shift_all_bits(self, type_code, op):
806 """Shifts where the shift amount is the width of the type or wider """
807 # gh-2449
808 dt = np.dtype(type_code)
809 nbits = dt.itemsize * 8
810 for val in [5, -5]:
811 for shift in [nbits, nbits + 4]:
812 val_scl = np.array(val).astype(dt)[()]
813 shift_scl = dt.type(shift)
814 res_scl = op(val_scl, shift_scl)
815 if val_scl < 0 and op is operator.rshift:
816 # sign bit is preserved
817 assert_equal(res_scl, -1)
818 else:
819 assert_equal(res_scl, 0)
820
821 # Result on scalars should be the same as on arrays
822 val_arr = np.array([val_scl] * 32, dtype=dt)
823 shift_arr = np.array([shift] * 32, dtype=dt)
824 res_arr = op(val_arr, shift_arr)
825 assert_equal(res_arr, res_scl)
826
827
828class TestHash:
829 @pytest.mark.parametrize("type_code", np.typecodes['AllInteger'])
830 def test_integer_hashes(self, type_code):
831 scalar = np.dtype(type_code).type
832 for i in range(128):
833 assert hash(i) == hash(scalar(i))
834
835 @pytest.mark.parametrize("type_code", np.typecodes['AllFloat'])
836 def test_float_and_complex_hashes(self, type_code):
837 scalar = np.dtype(type_code).type
838 for val in [np.pi, np.inf, 3, 6.]:
839 numpy_val = scalar(val)
840 # Cast back to Python, in case the NumPy scalar has less precision
841 if numpy_val.dtype.kind == 'c':
842 val = complex(numpy_val)
843 else:
844 val = float(numpy_val)
845 assert val == numpy_val
846 assert hash(val) == hash(numpy_val)
847
848 if hash(float(np.nan)) != hash(float(np.nan)):
849 # If Python distinguishes different NaNs we do so too (gh-18833)
850 assert hash(scalar(np.nan)) != hash(scalar(np.nan))
851
852 @pytest.mark.parametrize("type_code", np.typecodes['Complex'])
853 def test_complex_hashes(self, type_code):
854 # Test some complex valued hashes specifically:
855 scalar = np.dtype(type_code).type
856 for val in [np.pi + 1j, np.inf - 3j, 3j, 6. + 1j]:
857 numpy_val = scalar(val)
858 assert hash(complex(numpy_val)) == hash(numpy_val)
859
860
861@contextlib.contextmanager
862def recursionlimit(n):
863 o = sys.getrecursionlimit()
864 try:
865 sys.setrecursionlimit(n)
866 yield
867 finally:
868 sys.setrecursionlimit(o)
869
870
871@given(sampled_from(objecty_things),
872 sampled_from(binary_operators_for_scalar_ints),
873 sampled_from(types + [rational]))
874@pytest.mark.thread_unsafe(reason="sets recursion limit globally")
875def test_operator_object_left(o, op, type_):
876 try:
877 with recursionlimit(200):
878 op(o, type_(1))
879 except TypeError:
880 pass
881
882
883@given(sampled_from(objecty_things),
884 sampled_from(binary_operators_for_scalar_ints),
885 sampled_from(types + [rational]))
886@pytest.mark.thread_unsafe(reason="sets recursion limit globally")
887def test_operator_object_right(o, op, type_):
888 try:
889 with recursionlimit(200):
890 op(type_(1), o)
891 except TypeError:
892 pass
893
894
895@given(sampled_from(binary_operators_for_scalars),
896 sampled_from(types),
897 sampled_from(types))
898def test_operator_scalars(op, type1, type2):
899 try:
900 op(type1(1), type2(1))
901 except TypeError:
902 pass
903
904
905@pytest.mark.parametrize("op", binary_operators_for_scalars)
906@pytest.mark.parametrize("sctype", [np.longdouble, np.clongdouble])
907def test_longdouble_operators_with_obj(sctype, op):
908 # This is/used to be tricky, because NumPy generally falls back to
909 # using the ufunc via `np.asarray()`, this effectively might do:
910 # longdouble + None
911 # -> asarray(longdouble) + np.array(None, dtype=object)
912 # -> asarray(longdouble).astype(object) + np.array(None, dtype=object)
913 # And after getting the scalars in the inner loop:
914 # -> longdouble + None
915 #
916 # That would recurse infinitely. Other scalars return the python object
917 # on cast, so this type of things works OK.
918 #
919 # As of NumPy 2.1, this has been consolidated into the np.generic binops
920 # and now checks `.item()`. That also allows the below path to work now.
921 try:
922 op(sctype(3), None)
923 except TypeError:
924 pass
925 try:
926 op(None, sctype(3))
927 except TypeError:
928 pass
929
930
931@pytest.mark.parametrize("op", [operator.add, operator.pow, operator.sub])
932@pytest.mark.parametrize("sctype", [np.longdouble, np.clongdouble])
933def test_longdouble_with_arrlike(sctype, op):
934 # As of NumPy 2.1, longdouble behaves like other types and can coerce
935 # e.g. lists. (Not necessarily better, but consistent.)
936 assert_array_equal(op(sctype(3), [1, 2]), op(3, np.array([1, 2])))
937 assert_array_equal(op([1, 2], sctype(3)), op(np.array([1, 2]), 3))
938
939
940@pytest.mark.parametrize("op", binary_operators_for_scalars)
941@pytest.mark.parametrize("sctype", [np.longdouble, np.clongdouble])
942@np.errstate(all="ignore")
943def test_longdouble_operators_with_large_int(sctype, op):
944 # (See `test_longdouble_operators_with_obj` for why longdouble is special)
945 # NEP 50 means that the result is clearly a (c)longdouble here:
946 if sctype == np.clongdouble and op in [operator.mod, operator.floordiv]:
947 # The above operators are not support for complex though...
948 with pytest.raises(TypeError):
949 op(sctype(3), 2**64)
950 with pytest.raises(TypeError):
951 op(sctype(3), 2**64)
952 else:
953 assert op(sctype(3), -2**64) == op(sctype(3), sctype(-2**64))
954 assert op(2**64, sctype(3)) == op(sctype(2**64), sctype(3))
955
956
957@pytest.mark.parametrize("dtype", np.typecodes["AllInteger"])
958@pytest.mark.parametrize("operation", [
959 lambda min, max: max + max,
960 lambda min, max: min - max,
961 lambda min, max: max * max], ids=["+", "-", "*"])
962def test_scalar_integer_operation_overflow(dtype, operation):
963 st = np.dtype(dtype).type
964 min = st(np.iinfo(dtype).min)
965 max = st(np.iinfo(dtype).max)
966
967 with pytest.warns(RuntimeWarning, match="overflow encountered"):
968 operation(min, max)
969
970
971@pytest.mark.parametrize("dtype", np.typecodes["Integer"])
972@pytest.mark.parametrize("operation", [
973 lambda min, neg_1: -min,
974 lambda min, neg_1: abs(min),
975 lambda min, neg_1: min * neg_1,
976 pytest.param(lambda min, neg_1: min // neg_1,
977 marks=pytest.mark.skip(reason="broken on some platforms"))],
978 ids=["neg", "abs", "*", "//"])
979def test_scalar_signed_integer_overflow(dtype, operation):
980 # The minimum signed integer can "overflow" for some additional operations
981 st = np.dtype(dtype).type
982 min = st(np.iinfo(dtype).min)
983 neg_1 = st(-1)
984
985 with pytest.warns(RuntimeWarning, match="overflow encountered"):
986 operation(min, neg_1)
987
988
989@pytest.mark.parametrize("dtype", np.typecodes["UnsignedInteger"])
990def test_scalar_unsigned_integer_overflow(dtype):
991 val = np.dtype(dtype).type(8)
992 with pytest.warns(RuntimeWarning, match="overflow encountered"):
993 -val
994
995 zero = np.dtype(dtype).type(0)
996 -zero # does not warn
997
998@pytest.mark.parametrize("dtype", np.typecodes["AllInteger"])
999@pytest.mark.parametrize("operation", [
1000 lambda val, zero: val // zero,
1001 lambda val, zero: val % zero, ], ids=["//", "%"])
1002def test_scalar_integer_operation_divbyzero(dtype, operation):
1003 st = np.dtype(dtype).type
1004 val = st(100)
1005 zero = st(0)
1006
1007 with pytest.warns(RuntimeWarning, match="divide by zero"):
1008 operation(val, zero)
1009
1010
1011ops_with_names = [
1012 ("__lt__", "__gt__", operator.lt, True),
1013 ("__le__", "__ge__", operator.le, True),
1014 ("__eq__", "__eq__", operator.eq, True),
1015 # Note __op__ and __rop__ may be identical here:
1016 ("__ne__", "__ne__", operator.ne, True),
1017 ("__gt__", "__lt__", operator.gt, True),
1018 ("__ge__", "__le__", operator.ge, True),
1019 ("__floordiv__", "__rfloordiv__", operator.floordiv, False),
1020 ("__truediv__", "__rtruediv__", operator.truediv, False),
1021 ("__add__", "__radd__", operator.add, False),
1022 ("__mod__", "__rmod__", operator.mod, False),
1023 ("__mul__", "__rmul__", operator.mul, False),
1024 ("__pow__", "__rpow__", operator.pow, False),
1025 ("__sub__", "__rsub__", operator.sub, False),
1026]
1027
1028
1029@pytest.mark.parametrize(["__op__", "__rop__", "op", "cmp"], ops_with_names)
1030@pytest.mark.parametrize("sctype", [np.float32, np.float64, np.longdouble])
1031def test_subclass_deferral(sctype, __op__, __rop__, op, cmp):
1032 """
1033 This test covers scalar subclass deferral. Note that this is exceedingly
1034 complicated, especially since it tends to fall back to the array paths and
1035 these additionally add the "array priority" mechanism.
1036
1037 The behaviour was modified subtly in 1.22 (to make it closer to how Python
1038 scalars work). Due to its complexity and the fact that subclassing NumPy
1039 scalars is probably a bad idea to begin with. There is probably room
1040 for adjustments here.
1041 """
1042 class myf_simple1(sctype):
1043 pass
1044
1045 class myf_simple2(sctype):
1046 pass
1047
1048 def op_func(self, other):
1049 return __op__
1050
1051 def rop_func(self, other):
1052 return __rop__
1053
1054 myf_op = type("myf_op", (sctype,), {__op__: op_func, __rop__: rop_func})
1055
1056 # inheritance has to override, or this is correctly lost:
1057 res = op(myf_simple1(1), myf_simple2(2))
1058 assert type(res) == sctype or type(res) == np.bool
1059 assert op(myf_simple1(1), myf_simple2(2)) == op(1, 2) # inherited
1060
1061 # Two independent subclasses do not really define an order. This could
1062 # be attempted, but we do not since Python's `int` does neither:
1063 assert op(myf_op(1), myf_simple1(2)) == __op__
1064 assert op(myf_simple1(1), myf_op(2)) == op(1, 2) # inherited
1065
1066
1067def test_longdouble_complex():
1068 # Simple test to check longdouble and complex combinations, since these
1069 # need to go through promotion, which longdouble needs to be careful about.
1070 x = np.longdouble(1)
1071 assert x + 1j == 1 + 1j
1072 assert 1j + x == 1 + 1j
1073
1074
1075@pytest.mark.parametrize(["__op__", "__rop__", "op", "cmp"], ops_with_names)
1076@pytest.mark.parametrize("subtype", [float, int, complex, np.float16])
1077def test_pyscalar_subclasses(subtype, __op__, __rop__, op, cmp):
1078 # This tests that python scalar subclasses behave like a float64 (if they
1079 # don't override it).
1080 # In an earlier version of NEP 50, they behaved like the Python buildins.
1081 def op_func(self, other):
1082 return __op__
1083
1084 def rop_func(self, other):
1085 return __rop__
1086
1087 # Check that deferring is indicated using `__array_ufunc__`:
1088 myt = type("myt", (subtype,),
1089 {__op__: op_func, __rop__: rop_func, "__array_ufunc__": None})
1090
1091 # Just like normally, we should never presume we can modify the float.
1092 assert op(myt(1), np.float64(2)) == __op__
1093 assert op(np.float64(1), myt(2)) == __rop__
1094
1095 if op in {operator.mod, operator.floordiv} and subtype == complex:
1096 return # module is not support for complex. Do not test.
1097
1098 if __rop__ == __op__:
1099 return
1100
1101 # When no deferring is indicated, subclasses are handled normally.
1102 myt = type("myt", (subtype,), {__rop__: rop_func})
1103 behaves_like = lambda x: np.array(subtype(x))[()]
1104
1105 # Check for float32, as a float subclass float64 may behave differently
1106 res = op(myt(1), np.float16(2))
1107 expected = op(behaves_like(1), np.float16(2))
1108 assert res == expected
1109 assert type(res) == type(expected)
1110 res = op(np.float32(2), myt(1))
1111 expected = op(np.float32(2), behaves_like(1))
1112 assert res == expected
1113 assert type(res) == type(expected)
1114
1115 # Same check for longdouble (compare via dtype to accept float64 when
1116 # longdouble has the identical size), which is currently not perfectly
1117 # consistent.
1118 res = op(myt(1), np.longdouble(2))
1119 expected = op(behaves_like(1), np.longdouble(2))
1120 assert res == expected
1121 assert np.dtype(type(res)) == np.dtype(type(expected))
1122 res = op(np.float32(2), myt(1))
1123 expected = op(np.float32(2), behaves_like(1))
1124 assert res == expected
1125 assert np.dtype(type(res)) == np.dtype(type(expected))
1126
1127
1128def test_truediv_int():
1129 # This should work, as the result is float:
1130 assert np.uint8(3) / 123454 == np.float64(3) / 123454
1131
1132
1133@pytest.mark.slow
1134@pytest.mark.parametrize("op",
1135 # TODO: Power is a bit special, but here mostly bools seem to behave oddly
1136 [op for op in binary_operators_for_scalars if op is not operator.pow])
1137@pytest.mark.parametrize("sctype", types)
1138@pytest.mark.parametrize("other_type", [float, int, complex])
1139@pytest.mark.parametrize("rop", [True, False])
1140def test_scalar_matches_array_op_with_pyscalar(op, sctype, other_type, rop):
1141 # Check that the ufunc path matches by coercing to an array explicitly
1142 val1 = sctype(2)
1143 val2 = other_type(2)
1144
1145 if rop:
1146 _op = op
1147 op = lambda x, y: _op(y, x)
1148
1149 try:
1150 res = op(val1, val2)
1151 except TypeError:
1152 try:
1153 expected = op(np.asarray(val1), val2)
1154 raise AssertionError("ufunc didn't raise.")
1155 except TypeError:
1156 return
1157 else:
1158 expected = op(np.asarray(val1), val2)
1159
1160 # Note that we only check dtype equivalency, as ufuncs may pick the lower
1161 # dtype if they are equivalent.
1162 assert res == expected
1163 if isinstance(val1, float) and other_type is complex and rop:
1164 # Python complex accepts float subclasses, so we don't get a chance
1165 # and the result may be a Python complex (thus, the `np.array()``)
1166 assert np.array(res).dtype == expected.dtype
1167 else:
1168 assert res.dtype == expected.dtype
1169 