Repository: scipy/scipy
File: scipy/sparse/linalg/tests/test_interface.py (Python)

Code before:


INT_DTYPES = (np.int8, np.int16, np.int32, np.int64)
REAL_DTYPES = (np.float32, np.float64, np.longdouble)
COMPLEX_DTYPES = (np.complex64, np.complex128, np.clongdouble)
INEXACTDTYPES = REAL_DTYPES + COMPLEX_DTYPES
ALLDTYPES = INT_DTYPES + INEXACTDTYPES


@pytest.mark.parametrize("test_dtype", ALLDTYPES)
def test_determine_lo_dtype_from_matvec(test_dtype, xp):
    if "longdouble" in test_dtype.__name__ and not is_numpy(xp):
        pytest.skip("longdoubles are only tested for `np`")
    # gh-19209
    scalar = xp.asarray(np.array(1, dtype=test_dtype))
    def mv(v):
        return xp.stack([scalar * v[0], v[1]])

    lo = interface.LinearOperator((2, 2), matvec=mv, xp=xp)
    # expected dtype depends on if mixed exact-inexact promotion is defined
    # since dtype determination follows the following procedure:
    # - take the dtype from calling `matvec` on an `int8`
    # - unless that fails (e.g. via overflow or no mixed exact-inexact promotion),
    #   in which case use the default integral dtype
    expected = scalar.dtype
    if test_dtype in globals()["INEXACTDTYPES"]:
        try:
            xp.asarray(2) + xp.asarray(2.0)
        except TypeError:
            expected = xpx.default_dtype(xp, kind="integral")
    assert lo.dtype == expected


def test_determine_lo_dtype_for_int(xp):
    # gh-19209
    # test Python int larger than int8 max cast to some int
    def mv(v):
        return xp.asarray([128 * v[0], v[1]])

    lo = interface.LinearOperator((2, 2), matvec=mv, xp=xp)
    assert xp.isdtype(lo.dtype, "integral")


def test_adjoint_conjugate(xp):
    X = xp.asarray([[1j]], dtype=xp.complex128)
    A = interface.aslinearoperator(X)

    B = 1j * A
    Y = 1j * X

    v = xp.asarray([1], dtype=xp.complex128)

Review comment (suggestion):
oops we can just use https://data-apis.org/array-api/draft/API_specification/generated/array_api.isdtype.html#isdtype

Code after:
    # operator dtype)
    interface.LinearOperator((2, 2), matvec=matvec, xp=xp)
    assert_equal(call_count[0], 1)


INT_DTYPES = (np.int8, np.int16, np.int32, np.int64)
REAL_DTYPES = (np.float32, np.float64, np.longdouble)
COMPLEX_DTYPES = (np.complex64, np.complex128, np.clongdouble)
INEXACTDTYPES = REAL_DTYPES + COMPLEX_DTYPES
ALLDTYPES = INT_DTYPES + INEXACTDTYPES


@pytest.mark.parametrize("test_dtype", ALLDTYPES)
def test_determine_lo_dtype_from_matvec(test_dtype, xp):
    if "longdouble" in test_dtype.__name__ and not is_numpy(xp):
        pytest.skip("longdoubles are only tested for `np`")
    # gh-19209
    scalar = xp.asarray(np.array(1, dtype=test_dtype))
    def mv(v):
        return xp.stack([scalar * v[0], v[1]])

    lo = interface.LinearOperator((2, 2), matvec=mv, xp=xp)
    # expected dtype depends on if mixed exact-inexact promotion is defined
    # since dtype determination follows the following procedure:
    # - take the dtype from calling `matvec` on an `int8`
    # - unless that fails (e.g. via overflow or no mixed exact-inexact promotion),
    #   in which case use the default integral dtype
    expected = scalar.dtype
    if xp.isdtype(expected, ("real floating", "complex floating")):
        try:
            xp.asarray(2) + xp.asarray(2.0)
        except TypeError:
            expected = xpx.default_dtype(xp, kind="integral")
    assert lo.dtype == expected


def test_determine_lo_dtype_for_int(xp):
    # gh-19209
    # test Python int larger than int8 max cast to some int
    def mv(v):
        return xp.asarray([128 * v[0], v[1]])

    lo = interface.LinearOperator((2, 2), matvec=mv, xp=xp)
    assert xp.isdtype(lo.dtype, "integral")


def test_adjoint_conjugate(xp):
    X = xp.asarray([[1j]], dtype=xp.complex128)
    A = interface.aslinearoperator(X)

    B = 1j * A