Skip to content

Conversation

@skirpichev
Copy link
Owner

@skirpichev skirpichev commented May 25, 2024

"Generally, mixed-mode arithmetic combining real and complex variables should be performed directly, not by first coercing the real to complex, lest the sign of zero be rendered uninformative; the same goes for combinations of pure imaginary quantities with complex variables." (c) Kahan, W: Branch cuts for complex elementary functions.

That's why C standards since C99 introduce imaginary types. This patch implements similar extension to the Python language.

Lets consider (actually interrelated) problems, which will be solved on this way.

  1. Now complex arithmetic could be used for implementation of mathematical functions without special "corner cases", with textbooks formulae. Take the inverse tangent as an example:

    >>> z = complex(-0.0, 2)
    >>> cmath.atan(z)
    (-1.5707963267948966+0.5493061443340549j)
    >>> atan = lambda z: 1j*(cmath.log(1 - 1j*z) - cmath.log(1 + 1j*z))/2
    >>> atan(z)  # real part had wrong sign before
    (-1.5707963267948966+0.5493061443340549j)
    
  2. Previously, we have unsigned imaginary literals with the following semantics:

    a±bj = complex(a ± 0.0, ±b)
    complex(a, ±b)*cj = complex(a*0.0 ∓ b*c, a*c ± b*0.0)
    

    While this behaviour was well documented, most users would expect instead here:

    a±bj = complex(a, ±b)
    complex(a, ±b)*cj = complex(∓b*c, a*c)
    

    i.e. that it follows to the rectangular notation for complex numbers.

    For example:

    >>> -0.0+1j  # was 1j
    (-0.0+1j)
    >>> float('inf')*1j  # was (nan+infj)
    infj
    >>> -0.0+1j  # was 1j
    (-0.0+1j)
    >>> complex(-0.0, 1)  # was (-0+1j), note funny signed integer zero
    (-0.0+1j)
    
  3. The eval(repr(x)) == x invariant now holds for the complex type.

What's changed:

  • Added a new subtype (imaginary) of the complex type with few overloaded methods (conjugate() and __getnewargs__()).
  • Complex and imaginary types implement IEC 60559-compatible complex arithmetic (as specified by C11 Annex G).
  • Imaginary literals now produce instances of imaginary type.
  • cmath.infj/nanj were changed to be of imaginary type.
  • Modules ast, code, copy, marshal got support for imaginary type.
  • Few tests adapted to use complex, instead of imaginary literals
  • Print dot for signed zeros in the real part of repr(complex)
  • repr(complex) now prints real part even if it's zero.

3.14-imaginary.diff.gz

@skirpichev skirpichev force-pushed the imaginary-class-109218 branch 2 times, most recently from 7323971 to 99d1b8c Compare May 25, 2024 13:45
@skirpichev skirpichev marked this pull request as ready for review June 4, 2024 05:57
@skirpichev skirpichev changed the title gh-109218: Imaginary type and IEC 60559-compatible complex arithmetic Imaginary type and IEC 60559-compatible complex arithmetic Jun 9, 2024
@skirpichev skirpichev force-pushed the imaginary-class-109218 branch 2 times, most recently from 4db428d to 6f13b24 Compare June 14, 2024 12:19
@skirpichev skirpichev force-pushed the imaginary-class-109218 branch 3 times, most recently from 4ca3e9a to c114f16 Compare June 29, 2024 09:16
skirpichev pushed a commit that referenced this pull request Jul 21, 2024
…ython#119498) (#1… (python#119905)

Revert "[3.12] pythongh-69214: Fix fcntl.ioctl() request type (python#119498) (python#119505)"

This reverts commit 078da88.

The change modified how negative values, like termios.TIOCSWINSZ, was
treated and is actually backward incompatible.
@skirpichev skirpichev force-pushed the imaginary-class-109218 branch from 36c6bf5 to 7e68e91 Compare July 25, 2024 07:51
@skirpichev skirpichev force-pushed the imaginary-class-109218 branch from 6a44153 to d605b8e Compare August 3, 2024 07:19
@skirpichev skirpichev force-pushed the imaginary-class-109218 branch from 2c3d2b4 to db12274 Compare October 1, 2024 04:15
@skirpichev skirpichev force-pushed the imaginary-class-109218 branch 2 times, most recently from 45dfe36 to f9edb38 Compare November 27, 2024 01:14
@skirpichev skirpichev marked this pull request as draft November 27, 2024 01:14
@skirpichev skirpichev force-pushed the imaginary-class-109218 branch 3 times, most recently from d56a55c to d062169 Compare November 28, 2024 02:24
@skirpichev skirpichev marked this pull request as ready for review February 11, 2025 06:37
@skirpichev skirpichev force-pushed the imaginary-class-109218 branch from b9c4ad2 to 1f62ac6 Compare April 15, 2025 10:03
@skirpichev skirpichev force-pushed the imaginary-class-109218 branch from 70419ab to 413dc1d Compare August 7, 2025 05:29
@skirpichev skirpichev force-pushed the imaginary-class-109218 branch from 413dc1d to c1e8c55 Compare August 7, 2025 05:39
"Generally, mixed-mode arithmetic combining real and complex variables
should be performed directly, not by first coercing the real to complex,
lest the sign of zero be rendered uninformative; the same goes for
combinations of pure imaginary quantities with complex variables." (c)
Kahan, W: Branch cuts for complex elementary functions.

That's why C standards since C99 introduce imaginary types.  This patch
implements similar extension to the Python language.

Lets consider (actually interrelated) problems, which will be solved on
this way.

1) Now complex arithmetic could be used for implementation of
   mathematical functions without special "corner cases", with textbooks
   formulae.  Take the inverse tangent as an example:

       >>> z = complex(-0.0, 2)
       >>> cmath.atan(z)
       (-1.5707963267948966+0.5493061443340549j)
       >>> atan = lambda z: 1j*(cmath.log(1 - 1j*z) - cmath.log(1 + 1j*z))/2
       >>> atan(z)  # real part had wrong sign before
       (-1.5707963267948966+0.5493061443340549j)

2) Previously, we have unsigned imaginary literals with the following
   semantics:

       a±bj = complex(a ± 0.0, ±b)
       complex(a, ±b)*cj = complex(a*0.0 ∓ b*c, a*c ± b*0.0)

   While this behaviour was well documented, most users would expect
   instead here:

       a±bj = complex(a, ±b)
       complex(a, ±b)*cj = complex(∓b*c, a*c)

   i.e. that it follows to the rectangular notation for complex numbers.

   For example:

       >>> -0.0+1j  # was 1j
       (-0.0+1j)
       >>> float('inf')*1j  # was (nan+infj)
       infj
       >>> -0.0+1j  # was 1j
       (-0.0+1j)
       >>> complex(-0.0, 1)  # was (-0+1j), not funny signed integer zero
       (-0.0+1j)

3) The ``eval(repr(x)) == x`` invariant now holds for the complex type.

What's changed:

    * Added a new subtype (imaginary) of the complex type with
      few overloaded methods (conjugate() and __getnewargs__()).
    * Complex and imaginary types implement IEC 60559-compatible complex
      arithmetic (as specified by C11 Annex G).
    * Imaginary literals now produce instances of imaginary type.
    * cmath.infj/nanj were changed to be of imaginary type.
    * Modules ast, code, copy, marshal got support for imaginary type.
    * Few tests adapted to use complex, instead of imaginary literals
    * Print dot for signed zeros in the real part of repr(complex)
    * repr(complex) now prints real part even if it's zero.
@skirpichev skirpichev force-pushed the imaginary-class-109218 branch from 6befc8c to 7110869 Compare October 19, 2025 04:18
@skirpichev skirpichev closed this Oct 19, 2025
@skirpichev skirpichev deleted the imaginary-class-109218 branch October 19, 2025 05:40
@skirpichev skirpichev restored the imaginary-class-109218 branch October 20, 2025 04:08
@skirpichev skirpichev reopened this Oct 20, 2025
@skirpichev skirpichev marked this pull request as draft October 29, 2025 00:22
@skirpichev
Copy link
Owner Author

skirpichev commented Oct 30, 2025

Failures for mpmath's test suite on top of this:

pip install -v -e .[tests]
pytest
platform linux -- Python 3.14.0, pytest-8.4.2, pluggy-1.6.0
mpmath backend: python
mpmath mp class: <mpmath.ctx_mp.MPContext object at 0x7fe8052ff620>
mpmath version: 1.4.0b2
Python version: 3.14.0 (tags/v3.14.0-dirty:ebf955df7a8, Oct 26 2025, 03:42:06) [GCC 12.2.0]
rootdir: /home/sk/src/mpmath
configfile: pyproject.toml
testpaths: mpmath, docs
plugins: timeout-2.4.0, hypothesis-6.142.4
timeout: 600.0s
timeout method: signal
timeout func_only: False
collected 2437 items                                                                                                                                          

[...]

========================================================================== FAILURES ===========================================================================
_____________________________________________________________________ test_mpc_complexes ______________________________________________________________________

    @settings(max_examples=20000)
>   @given(fmt_str(types=list('gGfFeE') + [''], for_complex=True),
                   ^^^
           st.complex_numbers(allow_nan=True,
                              allow_infinity=True,
                              allow_subnormal=True))

mpmath/tests/test_format.py:521:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

fmt = 'g', z = (0.0+0j)

    @settings(max_examples=20000)
    @given(fmt_str(types=list('gGfFeE') + [''], for_complex=True),
           st.complex_numbers(allow_nan=True,
                              allow_infinity=True,
                              allow_subnormal=True))
    def test_mpc_complexes(fmt, z):
        mp.pretty_dps = "repr"
        if ((not z.real and math.copysign(1, z.real) == -1)
                or (not z.imag and math.copysign(1, z.imag) == -1)):
            mp.pretty_dps = "str"
            return  # skip negative zero
        spec = read_format_spec(fmt)
        if spec['frac_separators'] and vinfo < (3, 14):
            return  # see also python/cpython#130860
        if spec['precision'] < 0 and any(math.isfinite(_) for _ in [z.real, z.imag]):
            # The mpmath could choose a different decimal
            # representative (wrt CPython) for same binary
            # floating-point number.
            if cmath.isnan(complex(format(z))):
                assert cmath.isnan(complex(format(mp.mpc(z))))
            else:
                assert complex(format(z)) == complex(format(mp.mpc(z)))
        else:
>           assert format(z, fmt) == format(mp.mpc(z), fmt)
E           AssertionError: assert '0.0+0j' == '0+0j'
E             
E             - 0+0j
E             + 0.0+0j
E             ? ++
E           Falsifying example: test_mpc_complexes(
E               fmt='g',
E               z=complex(0.0, 0.0),
E           )

/home/sk/src/mpmath/docs/basics.rst:230: DocTestFailure
___________________________________________________________________ [doctest] contexts.rst ____________________________________________________________________
303     >>> type(_[0,0])
304     <class 'float'>
305     >>> print(fp.quad(fp.sin, [0, fp.pi]))    # numerical integration
306     2.0
307
308 The ``fp`` context wraps Python's ``math`` and ``cmath`` modules for elementary functions. It supports both real and complex numbers and automatically generates complex results for real inputs (``math`` raises an exception)::
309
310     >>> fp.sqrt(5)
311     2.23606797749979
312     >>> fp.sqrt(-5)
Expected:
    2.23606797749979j
Got:
    (0.0+2.23606797749979j)

@skirpichev
Copy link
Owner Author

Tests on numpy-2.3.4:

python -m pip install -r requirements/all_requirements.txt
# skip stuff with huge memory usage
spin test -v -- --color=yes -k "not TestMonsterType and not recursion and not test_to_bool_scalar_not_convertible and not test_object_array_self_reference and not test_object_array_circular_reference"
=================================== FAILURES ===================================
_____________ TestScalarDiscovery.test_pyscalar_subclasses[10.14j] _____________

self = <test_array_coercion.TestScalarDiscovery object at 0x14ecbe373d40>
pyscalar = 10.14j

    @pytest.mark.parametrize("pyscalar", [10, 10.32, 10.14j, 10**100])
    def test_pyscalar_subclasses(self, pyscalar):
        """NumPy arrays are read/write which means that anything but invariant
        behaviour is on thin ice.  However, we currently are happy to discover
        subclasses of Python float, int, complex the same as the base classes.
        This should potentially be deprecated.
        """
        class MyScalar(type(pyscalar)):
            pass
    
>       res = np.array(MyScalar(pyscalar))
E       TypeError: imaginary() first argument must be a real number, not 'imaginary'

MyScalar   = <class 'test_array_coercion.TestScalarDiscovery.test_pyscalar_subclasses.<locals>.MyScalar'>
pyscalar   = 10.14j
self       = <test_array_coercion.TestScalarDiscovery object at 0x14ecbe373d40>

numpy/_core/tests/test_array_coercion.py:359: TypeError
_______ TestPromotion.test_complex_scalar_value_based[float16-complex64] _______

self = <test_dtype.TestPromotion object at 0x14ecbd9ae270>
other = <class 'numpy.float16'>, expected = <class 'numpy.complex64'>

    @pytest.mark.parametrize(["other", "expected"],
                 [(np.bool, np.complex128),
                  (np.int64, np.complex128),
                  (np.float16, np.complex64),
                  (np.float32, np.complex64),
                  (np.float64, np.complex128),
                  (np.longdouble, np.clongdouble),
                  (np.complex64, np.complex64),
                  (np.complex128, np.complex128),
                  (np.clongdouble, np.clongdouble),
                  ])
    def test_complex_scalar_value_based(self, other, expected):
        # This would change if we modify the value based promotion
        complex_scalar = 1j
    
        res = np.result_type(other, complex_scalar)
>       assert res == expected
E       AssertionError: assert dtype('complex128') == <class 'numpy.complex64'>

complex_scalar = 1j
expected   = <class 'numpy.complex64'>
other      = <class 'numpy.float16'>
res        = dtype('complex128')
self       = <test_dtype.TestPromotion object at 0x14ecbd9ae270>

numpy/_core/tests/test_dtype.py:1492: AssertionError
_______ TestPromotion.test_complex_scalar_value_based[float32-complex64] _______

self = <test_dtype.TestPromotion object at 0x14ecbda93710>
other = <class 'numpy.float32'>, expected = <class 'numpy.complex64'>

    @pytest.mark.parametrize(["other", "expected"],
                 [(np.bool, np.complex128),
                  (np.int64, np.complex128),
                  (np.float16, np.complex64),
                  (np.float32, np.complex64),
                  (np.float64, np.complex128),
                  (np.longdouble, np.clongdouble),
                  (np.complex64, np.complex64),
                  (np.complex128, np.complex128),
                  (np.clongdouble, np.clongdouble),
                  ])
    def test_complex_scalar_value_based(self, other, expected):
        # This would change if we modify the value based promotion
        complex_scalar = 1j
    
        res = np.result_type(other, complex_scalar)
>       assert res == expected
E       AssertionError: assert dtype('complex128') == <class 'numpy.complex64'>

complex_scalar = 1j
expected   = <class 'numpy.complex64'>
other      = <class 'numpy.float32'>
res        = dtype('complex128')
self       = <test_dtype.TestPromotion object at 0x14ecbda93710>

numpy/_core/tests/test_dtype.py:1492: AssertionError
______ TestPromotion.test_complex_scalar_value_based[complex64-complex64] ______

self = <test_dtype.TestPromotion object at 0x14ecbd99c890>
other = <class 'numpy.complex64'>, expected = <class 'numpy.complex64'>

    @pytest.mark.parametrize(["other", "expected"],
                 [(np.bool, np.complex128),
                  (np.int64, np.complex128),
                  (np.float16, np.complex64),
                  (np.float32, np.complex64),
                  (np.float64, np.complex128),
                  (np.longdouble, np.clongdouble),
                  (np.complex64, np.complex64),
                  (np.complex128, np.complex128),
                  (np.clongdouble, np.clongdouble),
                  ])
    def test_complex_scalar_value_based(self, other, expected):
        # This would change if we modify the value based promotion
        complex_scalar = 1j
    
        res = np.result_type(other, complex_scalar)
>       assert res == expected
E       AssertionError: assert dtype('complex128') == <class 'numpy.complex64'>

complex_scalar = 1j
expected   = <class 'numpy.complex64'>
other      = <class 'numpy.complex64'>
res        = dtype('complex128')
self       = <test_dtype.TestPromotion object at 0x14ecbd99c890>

numpy/_core/tests/test_dtype.py:1492: AssertionError
_________ test_expected_promotion[complex64-dtypes1-optional_dtypes1] __________

expected = <class 'numpy.complex64'>, dtypes = [<class 'numpy.float32'>, 0j]
optional_dtypes = [<class 'numpy.float16'>, 0.0, <class 'numpy.uint16'>, <class 'numpy.int16'>, <class 'numpy.int8'>, 0]

    @pytest.mark.parametrize("expected,dtypes,optional_dtypes", [
>           (np.float32, [np.float32],
                [np.float16, 0.0, np.uint16, np.int16, np.int8, 0]),
            (np.complex64, [np.float32, 0j],
                [np.float16, 0.0, np.uint16, np.int16, np.int8, 0]),
            (np.float32, [np.int16, np.uint16, np.float16],
                [np.int8, np.uint8, np.float32, 0., 0]),
            (np.int32, [np.int16, np.uint16],
                [np.int8, np.uint8, 0, np.bool]),
            ])

dtypes     = [<class 'numpy.float32'>, 0j]
expected   = <class 'numpy.complex64'>
f          = <function given.<locals>.run_test_as_given.<locals>.wrapped_test at 0x14ecba7b83b0>
optional_dtypes = [<class 'numpy.float16'>, 0.0, <class 'numpy.uint16'>, <class 'numpy.int16'>, <class 'numpy.int8'>, 0]

numpy/_core/tests/test_nep50_promotions.py:190: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

expected = <class 'numpy.complex64'>, dtypes = [<class 'numpy.float32'>, 0j]
optional_dtypes = [<class 'numpy.float16'>, 0.0, <class 'numpy.uint16'>, <class 'numpy.int16'>, <class 'numpy.int8'>, 0]
data = data(...)

    @pytest.mark.parametrize("expected,dtypes,optional_dtypes", [
            (np.float32, [np.float32],
                [np.float16, 0.0, np.uint16, np.int16, np.int8, 0]),
            (np.complex64, [np.float32, 0j],
                [np.float16, 0.0, np.uint16, np.int16, np.int8, 0]),
            (np.float32, [np.int16, np.uint16, np.float16],
                [np.int8, np.uint8, np.float32, 0., 0]),
            (np.int32, [np.int16, np.uint16],
                [np.int8, np.uint8, 0, np.bool]),
            ])
    @hypothesis.given(data=strategies.data())
    def test_expected_promotion(expected, dtypes, optional_dtypes, data):
        # Sample randomly while ensuring "dtypes" is always present:
        optional = data.draw(strategies.lists(
                strategies.sampled_from(dtypes + optional_dtypes)))
        all_dtypes = dtypes + optional
        dtypes_sample = data.draw(strategies.permutations(all_dtypes))
    
        res = np.result_type(*dtypes_sample)
>       assert res == expected
E       AssertionError: assert dtype('complex128') == <class 'numpy.complex64'>
E       Falsifying example: test_expected_promotion(
E           expected=numpy.complex64,
E           dtypes=[numpy.float32, 0j],
E           optional_dtypes=[numpy.float16,
E            0.0,
E            numpy.uint16,
E            numpy.int16,
E            numpy.int8,
E            0],
E           data=data(...),
E       )
E       Draw 1: []
E       Draw 2: [numpy.float32, 0j]
E       
E       You can reproduce this example by temporarily adding @reproduce_failure('6.104.1', b'AAAA') as a decorator on your test case

all_dtypes = [<class 'numpy.float32'>, 0j]
data       = data(...)
dtypes     = [<class 'numpy.float32'>, 0j]
dtypes_sample = [<class 'numpy.float32'>, 0j]
expected   = <class 'numpy.complex64'>
optional   = []
optional_dtypes = [<class 'numpy.float16'>, 0.0, <class 'numpy.uint16'>, <class 'numpy.int16'>, <class 'numpy.int8'>, 0]
res        = dtype('complex128')

numpy/_core/tests/test_nep50_promotions.py:208: AssertionError
________________________ test_complex_types[complex64] _________________________

tp = <class 'numpy.complex64'>

    @pytest.mark.parametrize('tp', [np.complex64, np.cdouble, np.clongdouble])
    def test_complex_types(tp):
        """Check formatting of complex types.
    
            This is only for the str function, and only for simple types.
            The precision of np.float32 and np.longdouble aren't the same as the
            python float precision.
    
        """
        for x in [0, 1, -1, 1e20]:
>           assert_equal(str(tp(x)), str(complex(x)),
                         err_msg=f'Failed str formatting for type {tp}')
E           AssertionError: 
E           Items are not equal: Failed str formatting for type <class 'numpy.complex64'>
E            ACTUAL: '0j'
E            DESIRED: '(0.0+0j)'

tp         = <class 'numpy.complex64'>
x          = 0

numpy/_core/tests/test_print.py:59: AssertionError
________________________ test_complex_types[complex128] ________________________

tp = <class 'numpy.complex128'>

    @pytest.mark.parametrize('tp', [np.complex64, np.cdouble, np.clongdouble])
    def test_complex_types(tp):
        """Check formatting of complex types.
    
            This is only for the str function, and only for simple types.
            The precision of np.float32 and np.longdouble aren't the same as the
            python float precision.
    
        """
        for x in [0, 1, -1, 1e20]:
>           assert_equal(str(tp(x)), str(complex(x)),
                         err_msg=f'Failed str formatting for type {tp}')
E           AssertionError: 
E           Items are not equal: Failed str formatting for type <class 'numpy.complex128'>
E            ACTUAL: '0j'
E            DESIRED: '(0.0+0j)'

tp         = <class 'numpy.complex128'>
x          = 0

numpy/_core/tests/test_print.py:59: AssertionError
_______________________ test_complex_types[clongdouble] ________________________

tp = <class 'numpy.clongdouble'>

    @pytest.mark.parametrize('tp', [np.complex64, np.cdouble, np.clongdouble])
    def test_complex_types(tp):
        """Check formatting of complex types.
    
            This is only for the str function, and only for simple types.
            The precision of np.float32 and np.longdouble aren't the same as the
            python float precision.
    
        """
        for x in [0, 1, -1, 1e20]:
>           assert_equal(str(tp(x)), str(complex(x)),
                         err_msg=f'Failed str formatting for type {tp}')
E           AssertionError: 
E           Items are not equal: Failed str formatting for type <class 'numpy.clongdouble'>
E            ACTUAL: '0j'
E            DESIRED: '(0.0+0j)'

tp         = <class 'numpy.clongdouble'>
x          = 0

numpy/_core/tests/test_print.py:59: AssertionError
______________________ test_complex_type_print[complex64] ______________________

tp = <class 'numpy.complex64'>

    @pytest.mark.parametrize('tp', [np.complex64, np.cdouble, np.clongdouble])
    def test_complex_type_print(tp):
        """Check formatting when using print """
        # We do not create complex with inf/nan directly because the feature is
        # missing in python < 2.6
        for x in [0, 1, -1, 1e20]:
>           _test_redirected_print(complex(x), tp)

tp         = <class 'numpy.complex64'>
x          = 0

numpy/_core/tests/test_print.py:142: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

x = (0.0+0j), tp = <class 'numpy.complex64'>, ref = None

    def _test_redirected_print(x, tp, ref=None):
        file = StringIO()
        file_tp = StringIO()
        stdout = sys.stdout
        try:
            sys.stdout = file_tp
            print(tp(x))
            sys.stdout = file
            if ref:
                print(ref)
            else:
                print(x)
        finally:
            sys.stdout = stdout
    
>       assert_equal(file.getvalue(), file_tp.getvalue(),
                     err_msg=f'print failed for type{tp}')
E       AssertionError: 
E       Items are not equal: print failed for type<class 'numpy.complex64'>
E        ACTUAL: '(0.0+0j)\n'
E        DESIRED: '0j\n'

file       = <_io.StringIO object at 0x14eca3e9fbe0>
file_tp    = <_io.StringIO object at 0x14eca0407d90>
ref        = None
stdout     = <EncodedFile name="<_io.FileIO name=6 mode='rb+' closefd=True>" mode='r+' encoding='utf-8'>
tp         = <class 'numpy.complex64'>
x          = (0.0+0j)

numpy/_core/tests/test_print.py:116: AssertionError
_____________________ test_complex_type_print[complex128] ______________________

tp = <class 'numpy.complex128'>

    @pytest.mark.parametrize('tp', [np.complex64, np.cdouble, np.clongdouble])
    def test_complex_type_print(tp):
        """Check formatting when using print """
        # We do not create complex with inf/nan directly because the feature is
        # missing in python < 2.6
        for x in [0, 1, -1, 1e20]:
>           _test_redirected_print(complex(x), tp)

tp         = <class 'numpy.complex128'>
x          = 0

numpy/_core/tests/test_print.py:142: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

x = (0.0+0j), tp = <class 'numpy.complex128'>, ref = None

    def _test_redirected_print(x, tp, ref=None):
        file = StringIO()
        file_tp = StringIO()
        stdout = sys.stdout
        try:
            sys.stdout = file_tp
            print(tp(x))
            sys.stdout = file
            if ref:
                print(ref)
            else:
                print(x)
        finally:
            sys.stdout = stdout
    
>       assert_equal(file.getvalue(), file_tp.getvalue(),
                     err_msg=f'print failed for type{tp}')
E       AssertionError: 
E       Items are not equal: print failed for type<class 'numpy.complex128'>
E        ACTUAL: '(0.0+0j)\n'
E        DESIRED: '0j\n'

file       = <_io.StringIO object at 0x14eca0407be0>
file_tp    = <_io.StringIO object at 0x14eca0407880>
ref        = None
stdout     = <EncodedFile name="<_io.FileIO name=6 mode='rb+' closefd=True>" mode='r+' encoding='utf-8'>
tp         = <class 'numpy.complex128'>
x          = (0.0+0j)

numpy/_core/tests/test_print.py:116: AssertionError
_____________________ test_complex_type_print[clongdouble] _____________________

tp = <class 'numpy.clongdouble'>

    @pytest.mark.parametrize('tp', [np.complex64, np.cdouble, np.clongdouble])
    def test_complex_type_print(tp):
        """Check formatting when using print """
        # We do not create complex with inf/nan directly because the feature is
        # missing in python < 2.6
        for x in [0, 1, -1, 1e20]:
>           _test_redirected_print(complex(x), tp)

tp         = <class 'numpy.clongdouble'>
x          = 0

numpy/_core/tests/test_print.py:142: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

x = (0.0+0j), tp = <class 'numpy.clongdouble'>, ref = None

    def _test_redirected_print(x, tp, ref=None):
        file = StringIO()
        file_tp = StringIO()
        stdout = sys.stdout
        try:
            sys.stdout = file_tp
            print(tp(x))
            sys.stdout = file
            if ref:
                print(ref)
            else:
                print(x)
        finally:
            sys.stdout = stdout
    
>       assert_equal(file.getvalue(), file_tp.getvalue(),
                     err_msg=f'print failed for type{tp}')
E       AssertionError: 
E       Items are not equal: print failed for type<class 'numpy.clongdouble'>
E        ACTUAL: '(0.0+0j)\n'
E        DESIRED: '0j\n'

file       = <_io.StringIO object at 0x14eca0406170>
file_tp    = <_io.StringIO object at 0x14eca0407ac0>
ref        = None
stdout     = <EncodedFile name="<_io.FileIO name=6 mode='rb+' closefd=True>" mode='r+' encoding='utf-8'>
tp         = <class 'numpy.clongdouble'>
x          = (0.0+0j)

numpy/_core/tests/test_print.py:116: AssertionError
________________________ TestSpecialFloats.test_arctanh ________________________

self = <test_umath.TestSpecialFloats object at 0x14ecb6c24cd0>

    @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]
            out = [np.nan, np.nan, np.nan, np.nan, np.inf, -np.inf, np.nan]
            for dt in ['e', 'f', 'd']:
                in_arr = np.array(in_, dtype=dt)
                out_arr = np.array(out, dtype=dt)
                assert_equal(np.arctanh(in_arr), out_arr)
    
        for value in [1.01, np.inf, -np.inf, 1.0, -1.0]:
            with np.errstate(invalid='raise', divide='raise'):
                for dt in ['e', 'f', 'd']:
                    assert_raises(FloatingPointError, np.arctanh,
                                  np.array(value, dtype=dt))
    
        # Make sure glibc < 2.18 atanh is not used, issue 25087
>       assert np.signbit(np.arctanh(-1j).real)
E       AssertionError: assert np.False_
E        +  where np.False_ = <ufunc 'signbit'>(np.float64(0.0))
E        +    where <ufunc 'signbit'> = np.signbit
E        +    and   np.float64(0.0) = np.complex128(-0.7853981633974483j).real
E        +      where np.complex128(-0.7853981633974483j) = <ufunc 'arctanh'>(-1j)
E        +        where <ufunc 'arctanh'> = np.arctanh

dt         = 'd'
in_        = [nan, nan, inf, -inf, 1.0, -1.0, ...]
in_arr     = array([ nan,  nan,  inf, -inf,   1.,  -1.,   2.])
out        = [nan, nan, nan, nan, inf, -inf, ...]
out_arr    = array([ nan,  nan,  nan,  nan,  inf, -inf,  nan])
self       = <test_umath.TestSpecialFloats object at 0x14ecb6c24cd0>
value      = -1.0

numpy/_core/tests/test_umath.py:1780: AssertionError
_________________________ TestClog.test_special_values _________________________

E   AssertionError: 
    Arrays are not almost equal to 7 decimals
    
    nan location mismatch:
     ACTUAL: array([inf])
     DESIRED: array(nan)
All traceback entries are hidden. Pass `--full-trace` to see hidden and internal frames.

During handling of the above exception, another exception occurred:

self = <test_umath_complex.TestClog object at 0x14ecb6184550>

    @platform_skip
    @pytest.mark.skipif(platform.machine() == "armv5tel", reason="See gh-413.")
    def test_special_values(self):
        xl = []
        yl = []
    
        # From C99 std (Sec 6.3.2)
        # XXX: check exceptions raised
        # --- raise for invalid fails.
    
        # clog(-0 + i0) returns -inf + i pi and raises the 'divide-by-zero'
        # floating-point exception.
        with np.errstate(divide='raise'):
            x = np.array([ncu.NZERO], dtype=complex)
            y = complex(-np.inf, np.pi)
            assert_raises(FloatingPointError, np.log, x)
        with np.errstate(divide='ignore'):
            assert_almost_equal(np.log(x), y)
    
        xl.append(x)
        yl.append(y)
    
        # clog(+0 + i0) returns -inf + i0 and raises the 'divide-by-zero'
        # floating-point exception.
        with np.errstate(divide='raise'):
            x = np.array([0], dtype=complex)
            y = complex(-np.inf, 0)
            assert_raises(FloatingPointError, np.log, x)
        with np.errstate(divide='ignore'):
            assert_almost_equal(np.log(x), y)
    
        xl.append(x)
        yl.append(y)
    
        # clog(x + i inf returns +inf + i pi /2, for finite x.
        x = np.array([complex(1, np.inf)], dtype=complex)
        y = complex(np.inf, 0.5 * np.pi)
        assert_almost_equal(np.log(x), y)
        xl.append(x)
        yl.append(y)
    
        x = np.array([complex(-1, np.inf)], dtype=complex)
        assert_almost_equal(np.log(x), y)
        xl.append(x)
        yl.append(y)
    
        # clog(x + iNaN) returns NaN + iNaN and optionally raises the
        # 'invalid' floating- point exception, for finite x.
        with np.errstate(invalid='raise'):
            x = np.array([complex(1., np.nan)], dtype=complex)
            y = complex(np.nan, np.nan)
            #assert_raises(FloatingPointError, np.log, x)
        with np.errstate(invalid='ignore'):
            assert_almost_equal(np.log(x), y)
    
        xl.append(x)
        yl.append(y)
    
        with np.errstate(invalid='raise'):
            x = np.array([np.inf + 1j * np.nan], dtype=complex)
            #assert_raises(FloatingPointError, np.log, x)
        with np.errstate(invalid='ignore'):
>           assert_almost_equal(np.log(x), y)
E           AssertionError: 
E           Arrays are not almost equal to 7 decimals
E            ACTUAL: array([inf+nanj])
E            DESIRED: (nan+nanj)

self       = <test_umath_complex.TestClog object at 0x14ecb6184550>
x          = array([inf+nanj])
xl         = [array([-0.+0.j]), array([0.+0.j]), array([1.+infj]), array([-1.+infj]), array([1.+nanj])]
y          = (nan+nanj)
yl         = [(-inf+3.141592653589793j), (-inf+0j), (inf+1.5707963267948966j), (inf+1.5707963267948966j), (nan+nanj)]

numpy/_core/tests/test_umath_complex.py:205: AssertionError
_________________ TestFFT1D.test_identity_long_short[float32] __________________

self = <numpy.fft.tests.test_pocketfft.TestFFT1D object at 0x14ecb5568690>
dtype = <class 'numpy.float32'>

    @pytest.mark.parametrize("dtype", [np.single, np.double, np.longdouble])
    def test_identity_long_short(self, dtype):
        # Test with explicitly given number of points, both for n
        # smaller and for n larger than the input size.
        maxlen = 16
        atol = 5 * np.spacing(np.array(1., dtype=dtype))
        x = random(maxlen).astype(dtype) + 1j * random(maxlen).astype(dtype)
        xx = np.concatenate([x, np.zeros_like(x)])
        xr = random(maxlen).astype(dtype)
        xxr = np.concatenate([xr, np.zeros_like(xr)])
        for i in range(1, maxlen * 2):
            check_c = np.fft.ifft(np.fft.fft(x, n=i), n=i)
>           assert check_c.real.dtype == dtype
E           AssertionError: assert dtype('float64') == <class 'numpy.float32'>
E            +  where dtype('float64') = array([0.10322467]).dtype
E            +    where array([0.10322467]) = array([0.10322467+0.09446973j]).real

atol       = np.float32(5.9604645e-07)
check_c    = array([0.10322467+0.09446973j])
dtype      = <class 'numpy.float32'>
i          = 1
maxlen     = 16
self       = <numpy.fft.tests.test_pocketfft.TestFFT1D object at 0x14ecb5568690>
x          = array([0.10322467+0.09446973j, 0.40137205+0.71078795j,
       0.25308073+0.89583135j, 0.0065759 +0.45593634j,
       0...578626j,
       0.05623784+0.92287761j, 0.72729743+0.20907432j,
       0.23731565+0.44196665j, 0.47920024+0.7298789j ])
xr         = array([0.6769731 , 0.9564662 , 0.9660296 , 0.5706945 , 0.75230396,
       0.38604528, 0.4292501 , 0.10437143, 0.67341954, 0.2706087 ,
       0.07986131, 0.0982309 , 0.72237694, 0.22892717, 0.7699853 ,
       0.90592   ], dtype=float32)
xx         = array([0.10322467+0.09446973j, 0.40137205+0.71078795j,
       0.25308073+0.89583135j, 0.0065759 +0.45593634j,
       0...       ,
       0.        +0.j        , 0.        +0.j        ,
       0.        +0.j        , 0.        +0.j        ])
xxr        = array([0.6769731 , 0.9564662 , 0.9660296 , 0.5706945 , 0.75230396,
       0.38604528, 0.4292501 , 0.10437143, 0.673419...    ,
       0.        , 0.        , 0.        , 0.        , 0.        ,
       0.        , 0.        ], dtype=float32)

numpy/fft/tests/test_pocketfft.py:48: AssertionError
__________________________ test_complex_coefficients ___________________________

    def test_complex_coefficients():
        """Test both numpy and built-in complex."""
        coefs = [0 + 1j, 1 + 1j, -2 + 2j, 3 + 0j]
        # numpy complex
        p1 = poly.Polynomial(coefs)
        # Python complex
        p2 = poly.Polynomial(array(coefs, dtype=object))
        poly.set_default_printstyle('unicode')
        assert_equal(str(p1), "1j + (1+1j)·x - (2-2j)·x² + (3+0j)·x³")
>       assert_equal(str(p2), "1j + (1+1j)·x + (-2+2j)·x² + (3+0j)·x³")
E       AssertionError: 
E       Items are not equal:
E        ACTUAL: '(0.0+1j) + (1+1j)·x + (-2+2j)·x² + (3+0j)·x³'
E        DESIRED: '1j + (1+1j)·x + (-2+2j)·x² + (3+0j)·x³'

coefs      = [(0.0+1j), (1+1j), (-2+2j), (3+0j)]
p1         = Polynomial([ 0.+1.j,  1.+1.j, -2.+2.j,  3.+0.j], domain=[-1.,  1.], window=[-1.,  1.], symbol='x')
p2         = Polynomial([(0.0+1j), (1+1j), (-2+2j), (3+0j)], dtype=object, domain=[-1.,  1.], window=[-1.,  1.], symbol='x')

numpy/polynomial/tests/test_printing.py:271: AssertionError
_________________ TestArrayAlmostEqualNulp.test_complex64_pass _________________

self = <numpy.testing.tests.test_utils.TestArrayAlmostEqualNulp object at 0x14eca5cb4130>

    def test_complex64_pass(self):
        nulp = 5
        x = np.linspace(-20, 20, 50, dtype=np.float32)
        x = 10**x
        x = np.r_[-x, x]
        xi = x + x * 1j
    
        eps = np.finfo(x.dtype).eps
        y = x + x * eps * nulp / 2.
>       assert_array_almost_equal_nulp(xi, x + y * 1j, nulp)
E       AssertionError: Arrays are not equal to 5 ULP

eps        = np.float32(1.1920929e-07)
nulp       = 5
self       = <numpy.testing.tests.test_utils.TestArrayAlmostEqualNulp object at 0x14eca5cb4130>
x          = array([-9.99999968e-21, -6.55127950e-20, -4.29192665e-19, -2.81177343e-18,
       -1.84207150e-17, -1.20679259e-16, -7...e+15,  5.42867116e+16,
        3.55647413e+17,  2.32995612e+18,  1.52641934e+19,  1.00000002e+20],
      dtype=float32)
xi         = array([-9.99999968e-21-9.99999968e-21j, -6.55127950e-20-6.55127950e-20j,
       -4.29192665e-19-4.29192665e-19j, -2.81...647413e+17j,  2.32995612e+18+2.32995612e+18j,
        1.52641934e+19+1.52641934e+19j,  1.00000002e+20+1.00000002e+20j])
y          = array([-1.0000003e-20, -6.5512814e-20, -4.2919279e-19, -2.8117743e-18,
       -1.8420720e-17, -1.2067930e-16, -7.90603...64313e+15,  5.4286729e+16,
        3.5564752e+17,  2.3299569e+18,  1.5264198e+19,  1.0000003e+20],
      dtype=float32)

numpy/testing/tests/test_utils.py:1413: AssertionError
=========================== short test summary info ============================
FAILED numpy/_core/tests/test_array_coercion.py::TestScalarDiscovery::test_pyscalar_subclasses[10.14j] - TypeError: imaginary() first argument must be a real number, not 'imaginary'
FAILED numpy/_core/tests/test_dtype.py::TestPromotion::test_complex_scalar_value_based[float16-complex64] - AssertionError: assert dtype('complex128') == <class 'numpy.complex64'>
FAILED numpy/_core/tests/test_dtype.py::TestPromotion::test_complex_scalar_value_based[float32-complex64] - AssertionError: assert dtype('complex128') == <class 'numpy.complex64'>
FAILED numpy/_core/tests/test_dtype.py::TestPromotion::test_complex_scalar_value_based[complex64-complex64] - AssertionError: assert dtype('complex128') == <class 'numpy.complex64'>
FAILED numpy/_core/tests/test_nep50_promotions.py::test_expected_promotion[complex64-dtypes1-optional_dtypes1] - AssertionError: assert dtype('complex128') == <class 'numpy.complex64'>
FAILED numpy/_core/tests/test_print.py::test_complex_types[complex64] - AssertionError: 
FAILED numpy/_core/tests/test_print.py::test_complex_types[complex128] - AssertionError: 
FAILED numpy/_core/tests/test_print.py::test_complex_types[clongdouble] - AssertionError: 
FAILED numpy/_core/tests/test_print.py::test_complex_type_print[complex64] - AssertionError: 
FAILED numpy/_core/tests/test_print.py::test_complex_type_print[complex128] - AssertionError: 
FAILED numpy/_core/tests/test_print.py::test_complex_type_print[clongdouble] - AssertionError: 
FAILED numpy/_core/tests/test_umath.py::TestSpecialFloats::test_arctanh - AssertionError: assert np.False_
FAILED numpy/_core/tests/test_umath_complex.py::TestClog::test_special_values - AssertionError: 
FAILED numpy/fft/tests/test_pocketfft.py::TestFFT1D::test_identity_long_short[float32] - AssertionError: assert dtype('float64') == <class 'numpy.float32'>
FAILED numpy/polynomial/tests/test_printing.py::test_complex_coefficients - AssertionError: 
FAILED numpy/testing/tests/test_utils.py::TestArrayAlmostEqualNulp::test_complex64_pass - AssertionError: Arrays are not equal to 5 ULP
= 16 failed, 45067 passed, 3854 skipped, 2831 deselected, 33 xfailed, 5 xpassed in 1750.64s (0:29:10) =

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants