Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
test_scalarmath.py1169 linesDownload Raw Back to tests
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 
codekingpro/portable-devtools · Team Ai