Blame external/pybind11/tests/test_eigen.py

Packit 534379
import pytest
Packit 534379
from pybind11_tests import ConstructorStats
Packit 534379
Packit 534379
pytestmark = pytest.requires_eigen_and_numpy
Packit 534379
Packit 534379
with pytest.suppress(ImportError):
Packit 534379
    from pybind11_tests import eigen as m
Packit 534379
    import numpy as np
Packit 534379
Packit 534379
    ref = np.array([[ 0.,  3,  0,  0,  0, 11],
Packit 534379
                    [22,  0,  0,  0, 17, 11],
Packit 534379
                    [ 7,  5,  0,  1,  0, 11],
Packit 534379
                    [ 0,  0,  0,  0,  0, 11],
Packit 534379
                    [ 0,  0, 14,  0,  8, 11]])
Packit 534379
Packit 534379
Packit 534379
def assert_equal_ref(mat):
Packit 534379
    np.testing.assert_array_equal(mat, ref)
Packit 534379
Packit 534379
Packit 534379
def assert_sparse_equal_ref(sparse_mat):
Packit 534379
    assert_equal_ref(sparse_mat.toarray())
Packit 534379
Packit 534379
Packit 534379
def test_fixed():
Packit 534379
    assert_equal_ref(m.fixed_c())
Packit 534379
    assert_equal_ref(m.fixed_r())
Packit 534379
    assert_equal_ref(m.fixed_copy_r(m.fixed_r()))
Packit 534379
    assert_equal_ref(m.fixed_copy_c(m.fixed_c()))
Packit 534379
    assert_equal_ref(m.fixed_copy_r(m.fixed_c()))
Packit 534379
    assert_equal_ref(m.fixed_copy_c(m.fixed_r()))
Packit 534379
Packit 534379
Packit 534379
def test_dense():
Packit 534379
    assert_equal_ref(m.dense_r())
Packit 534379
    assert_equal_ref(m.dense_c())
Packit 534379
    assert_equal_ref(m.dense_copy_r(m.dense_r()))
Packit 534379
    assert_equal_ref(m.dense_copy_c(m.dense_c()))
Packit 534379
    assert_equal_ref(m.dense_copy_r(m.dense_c()))
Packit 534379
    assert_equal_ref(m.dense_copy_c(m.dense_r()))
Packit 534379
Packit 534379
Packit 534379
def test_partially_fixed():
Packit 534379
    ref2 = np.array([[0., 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]])
Packit 534379
    np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2), ref2)
Packit 534379
    np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2), ref2)
Packit 534379
    np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2[:, 1]), ref2[:, [1]])
Packit 534379
    np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2[0, :]), ref2[[0], :])
Packit 534379
    np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)])
Packit 534379
    np.testing.assert_array_equal(
Packit 534379
        m.partial_copy_four_rm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :])
Packit 534379
Packit 534379
    np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2), ref2)
Packit 534379
    np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2), ref2)
Packit 534379
    np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2[:, 1]), ref2[:, [1]])
Packit 534379
    np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2[0, :]), ref2[[0], :])
Packit 534379
    np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)])
Packit 534379
    np.testing.assert_array_equal(
Packit 534379
        m.partial_copy_four_cm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :])
Packit 534379
Packit 534379
    # TypeError should be raise for a shape mismatch
Packit 534379
    functions = [m.partial_copy_four_rm_r, m.partial_copy_four_rm_c,
Packit 534379
                 m.partial_copy_four_cm_r, m.partial_copy_four_cm_c]
Packit 534379
    matrix_with_wrong_shape = [[1, 2],
Packit 534379
                               [3, 4]]
Packit 534379
    for f in functions:
Packit 534379
        with pytest.raises(TypeError) as excinfo:
Packit 534379
            f(matrix_with_wrong_shape)
Packit 534379
        assert "incompatible function arguments" in str(excinfo.value)
Packit 534379
Packit 534379
Packit 534379
def test_mutator_descriptors():
Packit 534379
    zr = np.arange(30, dtype='float32').reshape(5, 6)  # row-major
Packit 534379
    zc = zr.reshape(6, 5).transpose()  # column-major
Packit 534379
Packit 534379
    m.fixed_mutator_r(zr)
Packit 534379
    m.fixed_mutator_c(zc)
Packit 534379
    m.fixed_mutator_a(zr)
Packit 534379
    m.fixed_mutator_a(zc)
Packit 534379
    with pytest.raises(TypeError) as excinfo:
Packit 534379
        m.fixed_mutator_r(zc)
Packit 534379
    assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable, flags.c_contiguous]) -> None'
Packit 534379
            in str(excinfo.value))
Packit 534379
    with pytest.raises(TypeError) as excinfo:
Packit 534379
        m.fixed_mutator_c(zr)
Packit 534379
    assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable, flags.f_contiguous]) -> None'
Packit 534379
            in str(excinfo.value))
Packit 534379
    with pytest.raises(TypeError) as excinfo:
Packit 534379
        m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype='float32'))
Packit 534379
    assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable]) -> None'
Packit 534379
            in str(excinfo.value))
Packit 534379
    zr.flags.writeable = False
Packit 534379
    with pytest.raises(TypeError):
Packit 534379
        m.fixed_mutator_r(zr)
Packit 534379
    with pytest.raises(TypeError):
Packit 534379
        m.fixed_mutator_a(zr)
Packit 534379
Packit 534379
Packit 534379
def test_cpp_casting():
Packit 534379
    assert m.cpp_copy(m.fixed_r()) == 22.
Packit 534379
    assert m.cpp_copy(m.fixed_c()) == 22.
Packit 534379
    z = np.array([[5., 6], [7, 8]])
Packit 534379
    assert m.cpp_copy(z) == 7.
Packit 534379
    assert m.cpp_copy(m.get_cm_ref()) == 21.
Packit 534379
    assert m.cpp_copy(m.get_rm_ref()) == 21.
Packit 534379
    assert m.cpp_ref_c(m.get_cm_ref()) == 21.
Packit 534379
    assert m.cpp_ref_r(m.get_rm_ref()) == 21.
Packit 534379
    with pytest.raises(RuntimeError) as excinfo:
Packit 534379
        # Can't reference m.fixed_c: it contains floats, m.cpp_ref_any wants doubles
Packit 534379
        m.cpp_ref_any(m.fixed_c())
Packit 534379
    assert 'Unable to cast Python instance' in str(excinfo.value)
Packit 534379
    with pytest.raises(RuntimeError) as excinfo:
Packit 534379
        # Can't reference m.fixed_r: it contains floats, m.cpp_ref_any wants doubles
Packit 534379
        m.cpp_ref_any(m.fixed_r())
Packit 534379
    assert 'Unable to cast Python instance' in str(excinfo.value)
Packit 534379
    assert m.cpp_ref_any(m.ReturnTester.create()) == 1.
Packit 534379
Packit 534379
    assert m.cpp_ref_any(m.get_cm_ref()) == 21.
Packit 534379
    assert m.cpp_ref_any(m.get_cm_ref()) == 21.
Packit 534379
Packit 534379
Packit 534379
def test_pass_readonly_array():
Packit 534379
    z = np.full((5, 6), 42.0)
Packit 534379
    z.flags.writeable = False
Packit 534379
    np.testing.assert_array_equal(z, m.fixed_copy_r(z))
Packit 534379
    np.testing.assert_array_equal(m.fixed_r_const(), m.fixed_r())
Packit 534379
    assert not m.fixed_r_const().flags.writeable
Packit 534379
    np.testing.assert_array_equal(m.fixed_copy_r(m.fixed_r_const()), m.fixed_r_const())
Packit 534379
Packit 534379
Packit 534379
def test_nonunit_stride_from_python():
Packit 534379
    counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3))
Packit 534379
    second_row = counting_mat[1, :]
Packit 534379
    second_col = counting_mat[:, 1]
Packit 534379
    np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row)
Packit 534379
    np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row)
Packit 534379
    np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row)
Packit 534379
    np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col)
Packit 534379
    np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col)
Packit 534379
    np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col)
Packit 534379
Packit 534379
    counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))
Packit 534379
    slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]]
Packit 534379
    for slice_idx, ref_mat in enumerate(slices):
Packit 534379
        np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat)
Packit 534379
        np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat)
Packit 534379
Packit 534379
    # Mutator:
Packit 534379
    m.double_threer(second_row)
Packit 534379
    m.double_threec(second_col)
Packit 534379
    np.testing.assert_array_equal(counting_mat, [[0., 2, 2], [6, 16, 10], [6, 14, 8]])
Packit 534379
Packit 534379
Packit 534379
def test_negative_stride_from_python(msg):
Packit 534379
    """Eigen doesn't support (as of yet) negative strides. When a function takes an Eigen matrix by
Packit 534379
    copy or const reference, we can pass a numpy array that has negative strides.  Otherwise, an
Packit 534379
    exception will be thrown as Eigen will not be able to map the numpy array."""
Packit 534379
Packit 534379
    counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3))
Packit 534379
    counting_mat = counting_mat[::-1, ::-1]
Packit 534379
    second_row = counting_mat[1, :]
Packit 534379
    second_col = counting_mat[:, 1]
Packit 534379
    np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row)
Packit 534379
    np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row)
Packit 534379
    np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row)
Packit 534379
    np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col)
Packit 534379
    np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col)
Packit 534379
    np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col)
Packit 534379
Packit 534379
    counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))
Packit 534379
    counting_3d = counting_3d[::-1, ::-1, ::-1]
Packit 534379
    slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]]
Packit 534379
    for slice_idx, ref_mat in enumerate(slices):
Packit 534379
        np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat)
Packit 534379
        np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat)
Packit 534379
Packit 534379
    # Mutator:
Packit 534379
    with pytest.raises(TypeError) as excinfo:
Packit 534379
        m.double_threer(second_row)
Packit 534379
    assert msg(excinfo.value) == """
Packit 534379
        double_threer(): incompatible function arguments. The following argument types are supported:
Packit 534379
            1. (arg0: numpy.ndarray[float32[1, 3], flags.writeable]) -> None
Packit 534379
Packit 534379
        Invoked with: """ + repr(np.array([ 5.,  4.,  3.], dtype='float32'))  # noqa: E501 line too long
Packit 534379
Packit 534379
    with pytest.raises(TypeError) as excinfo:
Packit 534379
        m.double_threec(second_col)
Packit 534379
    assert msg(excinfo.value) == """
Packit 534379
        double_threec(): incompatible function arguments. The following argument types are supported:
Packit 534379
            1. (arg0: numpy.ndarray[float32[3, 1], flags.writeable]) -> None
Packit 534379
Packit 534379
        Invoked with: """ + repr(np.array([ 7.,  4.,  1.], dtype='float32'))  # noqa: E501 line too long
Packit 534379
Packit 534379
Packit 534379
def test_nonunit_stride_to_python():
Packit 534379
    assert np.all(m.diagonal(ref) == ref.diagonal())
Packit 534379
    assert np.all(m.diagonal_1(ref) == ref.diagonal(1))
Packit 534379
    for i in range(-5, 7):
Packit 534379
        assert np.all(m.diagonal_n(ref, i) == ref.diagonal(i)), "m.diagonal_n({})".format(i)
Packit 534379
Packit 534379
    assert np.all(m.block(ref, 2, 1, 3, 3) == ref[2:5, 1:4])
Packit 534379
    assert np.all(m.block(ref, 1, 4, 4, 2) == ref[1:, 4:])
Packit 534379
    assert np.all(m.block(ref, 1, 4, 3, 2) == ref[1:4, 4:])
Packit 534379
Packit 534379
Packit 534379
def test_eigen_ref_to_python():
Packit 534379
    chols = [m.cholesky1, m.cholesky2, m.cholesky3, m.cholesky4]
Packit 534379
    for i, chol in enumerate(chols, start=1):
Packit 534379
        mymat = chol(np.array([[1., 2, 4], [2, 13, 23], [4, 23, 77]]))
Packit 534379
        assert np.all(mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]])), "cholesky{}".format(i)
Packit 534379
Packit 534379
Packit 534379
def assign_both(a1, a2, r, c, v):
Packit 534379
    a1[r, c] = v
Packit 534379
    a2[r, c] = v
Packit 534379
Packit 534379
Packit 534379
def array_copy_but_one(a, r, c, v):
Packit 534379
    z = np.array(a, copy=True)
Packit 534379
    z[r, c] = v
Packit 534379
    return z
Packit 534379
Packit 534379
Packit 534379
def test_eigen_return_references():
Packit 534379
    """Tests various ways of returning references and non-referencing copies"""
Packit 534379
Packit 534379
    master = np.ones((10, 10))
Packit 534379
    a = m.ReturnTester()
Packit 534379
    a_get1 = a.get()
Packit 534379
    assert not a_get1.flags.owndata and a_get1.flags.writeable
Packit 534379
    assign_both(a_get1, master, 3, 3, 5)
Packit 534379
    a_get2 = a.get_ptr()
Packit 534379
    assert not a_get2.flags.owndata and a_get2.flags.writeable
Packit 534379
    assign_both(a_get1, master, 2, 3, 6)
Packit 534379
Packit 534379
    a_view1 = a.view()
Packit 534379
    assert not a_view1.flags.owndata and not a_view1.flags.writeable
Packit 534379
    with pytest.raises(ValueError):
Packit 534379
        a_view1[2, 3] = 4
Packit 534379
    a_view2 = a.view_ptr()
Packit 534379
    assert not a_view2.flags.owndata and not a_view2.flags.writeable
Packit 534379
    with pytest.raises(ValueError):
Packit 534379
        a_view2[2, 3] = 4
Packit 534379
Packit 534379
    a_copy1 = a.copy_get()
Packit 534379
    assert a_copy1.flags.owndata and a_copy1.flags.writeable
Packit 534379
    np.testing.assert_array_equal(a_copy1, master)
Packit 534379
    a_copy1[7, 7] = -44  # Shouldn't affect anything else
Packit 534379
    c1want = array_copy_but_one(master, 7, 7, -44)
Packit 534379
    a_copy2 = a.copy_view()
Packit 534379
    assert a_copy2.flags.owndata and a_copy2.flags.writeable
Packit 534379
    np.testing.assert_array_equal(a_copy2, master)
Packit 534379
    a_copy2[4, 4] = -22  # Shouldn't affect anything else
Packit 534379
    c2want = array_copy_but_one(master, 4, 4, -22)
Packit 534379
Packit 534379
    a_ref1 = a.ref()
Packit 534379
    assert not a_ref1.flags.owndata and a_ref1.flags.writeable
Packit 534379
    assign_both(a_ref1, master, 1, 1, 15)
Packit 534379
    a_ref2 = a.ref_const()
Packit 534379
    assert not a_ref2.flags.owndata and not a_ref2.flags.writeable
Packit 534379
    with pytest.raises(ValueError):
Packit 534379
        a_ref2[5, 5] = 33
Packit 534379
    a_ref3 = a.ref_safe()
Packit 534379
    assert not a_ref3.flags.owndata and a_ref3.flags.writeable
Packit 534379
    assign_both(a_ref3, master, 0, 7, 99)
Packit 534379
    a_ref4 = a.ref_const_safe()
Packit 534379
    assert not a_ref4.flags.owndata and not a_ref4.flags.writeable
Packit 534379
    with pytest.raises(ValueError):
Packit 534379
        a_ref4[7, 0] = 987654321
Packit 534379
Packit 534379
    a_copy3 = a.copy_ref()
Packit 534379
    assert a_copy3.flags.owndata and a_copy3.flags.writeable
Packit 534379
    np.testing.assert_array_equal(a_copy3, master)
Packit 534379
    a_copy3[8, 1] = 11
Packit 534379
    c3want = array_copy_but_one(master, 8, 1, 11)
Packit 534379
    a_copy4 = a.copy_ref_const()
Packit 534379
    assert a_copy4.flags.owndata and a_copy4.flags.writeable
Packit 534379
    np.testing.assert_array_equal(a_copy4, master)
Packit 534379
    a_copy4[8, 4] = 88
Packit 534379
    c4want = array_copy_but_one(master, 8, 4, 88)
Packit 534379
Packit 534379
    a_block1 = a.block(3, 3, 2, 2)
Packit 534379
    assert not a_block1.flags.owndata and a_block1.flags.writeable
Packit 534379
    a_block1[0, 0] = 55
Packit 534379
    master[3, 3] = 55
Packit 534379
    a_block2 = a.block_safe(2, 2, 3, 2)
Packit 534379
    assert not a_block2.flags.owndata and a_block2.flags.writeable
Packit 534379
    a_block2[2, 1] = -123
Packit 534379
    master[4, 3] = -123
Packit 534379
    a_block3 = a.block_const(6, 7, 4, 3)
Packit 534379
    assert not a_block3.flags.owndata and not a_block3.flags.writeable
Packit 534379
    with pytest.raises(ValueError):
Packit 534379
        a_block3[2, 2] = -44444
Packit 534379
Packit 534379
    a_copy5 = a.copy_block(2, 2, 2, 3)
Packit 534379
    assert a_copy5.flags.owndata and a_copy5.flags.writeable
Packit 534379
    np.testing.assert_array_equal(a_copy5, master[2:4, 2:5])
Packit 534379
    a_copy5[1, 1] = 777
Packit 534379
    c5want = array_copy_but_one(master[2:4, 2:5], 1, 1, 777)
Packit 534379
Packit 534379
    a_corn1 = a.corners()
Packit 534379
    assert not a_corn1.flags.owndata and a_corn1.flags.writeable
Packit 534379
    a_corn1 *= 50
Packit 534379
    a_corn1[1, 1] = 999
Packit 534379
    master[0, 0] = 50
Packit 534379
    master[0, 9] = 50
Packit 534379
    master[9, 0] = 50
Packit 534379
    master[9, 9] = 999
Packit 534379
    a_corn2 = a.corners_const()
Packit 534379
    assert not a_corn2.flags.owndata and not a_corn2.flags.writeable
Packit 534379
    with pytest.raises(ValueError):
Packit 534379
        a_corn2[1, 0] = 51
Packit 534379
Packit 534379
    # All of the changes made all the way along should be visible everywhere
Packit 534379
    # now (except for the copies, of course)
Packit 534379
    np.testing.assert_array_equal(a_get1, master)
Packit 534379
    np.testing.assert_array_equal(a_get2, master)
Packit 534379
    np.testing.assert_array_equal(a_view1, master)
Packit 534379
    np.testing.assert_array_equal(a_view2, master)
Packit 534379
    np.testing.assert_array_equal(a_ref1, master)
Packit 534379
    np.testing.assert_array_equal(a_ref2, master)
Packit 534379
    np.testing.assert_array_equal(a_ref3, master)
Packit 534379
    np.testing.assert_array_equal(a_ref4, master)
Packit 534379
    np.testing.assert_array_equal(a_block1, master[3:5, 3:5])
Packit 534379
    np.testing.assert_array_equal(a_block2, master[2:5, 2:4])
Packit 534379
    np.testing.assert_array_equal(a_block3, master[6:10, 7:10])
Packit 534379
    np.testing.assert_array_equal(a_corn1, master[0::master.shape[0] - 1, 0::master.shape[1] - 1])
Packit 534379
    np.testing.assert_array_equal(a_corn2, master[0::master.shape[0] - 1, 0::master.shape[1] - 1])
Packit 534379
Packit 534379
    np.testing.assert_array_equal(a_copy1, c1want)
Packit 534379
    np.testing.assert_array_equal(a_copy2, c2want)
Packit 534379
    np.testing.assert_array_equal(a_copy3, c3want)
Packit 534379
    np.testing.assert_array_equal(a_copy4, c4want)
Packit 534379
    np.testing.assert_array_equal(a_copy5, c5want)
Packit 534379
Packit 534379
Packit 534379
def assert_keeps_alive(cl, method, *args):
Packit 534379
    cstats = ConstructorStats.get(cl)
Packit 534379
    start_with = cstats.alive()
Packit 534379
    a = cl()
Packit 534379
    assert cstats.alive() == start_with + 1
Packit 534379
    z = method(a, *args)
Packit 534379
    assert cstats.alive() == start_with + 1
Packit 534379
    del a
Packit 534379
    # Here's the keep alive in action:
Packit 534379
    assert cstats.alive() == start_with + 1
Packit 534379
    del z
Packit 534379
    # Keep alive should have expired:
Packit 534379
    assert cstats.alive() == start_with
Packit 534379
Packit 534379
Packit 534379
def test_eigen_keepalive():
Packit 534379
    a = m.ReturnTester()
Packit 534379
    cstats = ConstructorStats.get(m.ReturnTester)
Packit 534379
    assert cstats.alive() == 1
Packit 534379
    unsafe = [a.ref(), a.ref_const(), a.block(1, 2, 3, 4)]
Packit 534379
    copies = [a.copy_get(), a.copy_view(), a.copy_ref(), a.copy_ref_const(),
Packit 534379
              a.copy_block(4, 3, 2, 1)]
Packit 534379
    del a
Packit 534379
    assert cstats.alive() == 0
Packit 534379
    del unsafe
Packit 534379
    del copies
Packit 534379
Packit 534379
    for meth in [m.ReturnTester.get, m.ReturnTester.get_ptr, m.ReturnTester.view,
Packit 534379
                 m.ReturnTester.view_ptr, m.ReturnTester.ref_safe, m.ReturnTester.ref_const_safe,
Packit 534379
                 m.ReturnTester.corners, m.ReturnTester.corners_const]:
Packit 534379
        assert_keeps_alive(m.ReturnTester, meth)
Packit 534379
Packit 534379
    for meth in [m.ReturnTester.block_safe, m.ReturnTester.block_const]:
Packit 534379
        assert_keeps_alive(m.ReturnTester, meth, 4, 3, 2, 1)
Packit 534379
Packit 534379
Packit 534379
def test_eigen_ref_mutators():
Packit 534379
    """Tests Eigen's ability to mutate numpy values"""
Packit 534379
Packit 534379
    orig = np.array([[1., 2, 3], [4, 5, 6], [7, 8, 9]])
Packit 534379
    zr = np.array(orig)
Packit 534379
    zc = np.array(orig, order='F')
Packit 534379
    m.add_rm(zr, 1, 0, 100)
Packit 534379
    assert np.all(zr == np.array([[1., 2, 3], [104, 5, 6], [7, 8, 9]]))
Packit 534379
    m.add_cm(zc, 1, 0, 200)
Packit 534379
    assert np.all(zc == np.array([[1., 2, 3], [204, 5, 6], [7, 8, 9]]))
Packit 534379
Packit 534379
    m.add_any(zr, 1, 0, 20)
Packit 534379
    assert np.all(zr == np.array([[1., 2, 3], [124, 5, 6], [7, 8, 9]]))
Packit 534379
    m.add_any(zc, 1, 0, 10)
Packit 534379
    assert np.all(zc == np.array([[1., 2, 3], [214, 5, 6], [7, 8, 9]]))
Packit 534379
Packit 534379
    # Can't reference a col-major array with a row-major Ref, and vice versa:
Packit 534379
    with pytest.raises(TypeError):
Packit 534379
        m.add_rm(zc, 1, 0, 1)
Packit 534379
    with pytest.raises(TypeError):
Packit 534379
        m.add_cm(zr, 1, 0, 1)
Packit 534379
Packit 534379
    # Overloads:
Packit 534379
    m.add1(zr, 1, 0, -100)
Packit 534379
    m.add2(zr, 1, 0, -20)
Packit 534379
    assert np.all(zr == orig)
Packit 534379
    m.add1(zc, 1, 0, -200)
Packit 534379
    m.add2(zc, 1, 0, -10)
Packit 534379
    assert np.all(zc == orig)
Packit 534379
Packit 534379
    # a non-contiguous slice (this won't work on either the row- or
Packit 534379
    # column-contiguous refs, but should work for the any)
Packit 534379
    cornersr = zr[0::2, 0::2]
Packit 534379
    cornersc = zc[0::2, 0::2]
Packit 534379
Packit 534379
    assert np.all(cornersr == np.array([[1., 3], [7, 9]]))
Packit 534379
    assert np.all(cornersc == np.array([[1., 3], [7, 9]]))
Packit 534379
Packit 534379
    with pytest.raises(TypeError):
Packit 534379
        m.add_rm(cornersr, 0, 1, 25)
Packit 534379
    with pytest.raises(TypeError):
Packit 534379
        m.add_cm(cornersr, 0, 1, 25)
Packit 534379
    with pytest.raises(TypeError):
Packit 534379
        m.add_rm(cornersc, 0, 1, 25)
Packit 534379
    with pytest.raises(TypeError):
Packit 534379
        m.add_cm(cornersc, 0, 1, 25)
Packit 534379
    m.add_any(cornersr, 0, 1, 25)
Packit 534379
    m.add_any(cornersc, 0, 1, 44)
Packit 534379
    assert np.all(zr == np.array([[1., 2, 28], [4, 5, 6], [7, 8, 9]]))
Packit 534379
    assert np.all(zc == np.array([[1., 2, 47], [4, 5, 6], [7, 8, 9]]))
Packit 534379
Packit 534379
    # You shouldn't be allowed to pass a non-writeable array to a mutating Eigen method:
Packit 534379
    zro = zr[0:4, 0:4]
Packit 534379
    zro.flags.writeable = False
Packit 534379
    with pytest.raises(TypeError):
Packit 534379
        m.add_rm(zro, 0, 0, 0)
Packit 534379
    with pytest.raises(TypeError):
Packit 534379
        m.add_any(zro, 0, 0, 0)
Packit 534379
    with pytest.raises(TypeError):
Packit 534379
        m.add1(zro, 0, 0, 0)
Packit 534379
    with pytest.raises(TypeError):
Packit 534379
        m.add2(zro, 0, 0, 0)
Packit 534379
Packit 534379
    # integer array shouldn't be passable to a double-matrix-accepting mutating func:
Packit 534379
    zi = np.array([[1, 2], [3, 4]])
Packit 534379
    with pytest.raises(TypeError):
Packit 534379
        m.add_rm(zi)
Packit 534379
Packit 534379
Packit 534379
def test_numpy_ref_mutators():
Packit 534379
    """Tests numpy mutating Eigen matrices (for returned Eigen::Ref<...>s)"""
Packit 534379
Packit 534379
    m.reset_refs()  # In case another test already changed it
Packit 534379
Packit 534379
    zc = m.get_cm_ref()
Packit 534379
    zcro = m.get_cm_const_ref()
Packit 534379
    zr = m.get_rm_ref()
Packit 534379
    zrro = m.get_rm_const_ref()
Packit 534379
Packit 534379
    assert [zc[1, 2], zcro[1, 2], zr[1, 2], zrro[1, 2]] == [23] * 4
Packit 534379
Packit 534379
    assert not zc.flags.owndata and zc.flags.writeable
Packit 534379
    assert not zr.flags.owndata and zr.flags.writeable
Packit 534379
    assert not zcro.flags.owndata and not zcro.flags.writeable
Packit 534379
    assert not zrro.flags.owndata and not zrro.flags.writeable
Packit 534379
Packit 534379
    zc[1, 2] = 99
Packit 534379
    expect = np.array([[11., 12, 13], [21, 22, 99], [31, 32, 33]])
Packit 534379
    # We should have just changed zc, of course, but also zcro and the original eigen matrix
Packit 534379
    assert np.all(zc == expect)
Packit 534379
    assert np.all(zcro == expect)
Packit 534379
    assert np.all(m.get_cm_ref() == expect)
Packit 534379
Packit 534379
    zr[1, 2] = 99
Packit 534379
    assert np.all(zr == expect)
Packit 534379
    assert np.all(zrro == expect)
Packit 534379
    assert np.all(m.get_rm_ref() == expect)
Packit 534379
Packit 534379
    # Make sure the readonly ones are numpy-readonly:
Packit 534379
    with pytest.raises(ValueError):
Packit 534379
        zcro[1, 2] = 6
Packit 534379
    with pytest.raises(ValueError):
Packit 534379
        zrro[1, 2] = 6
Packit 534379
Packit 534379
    # We should be able to explicitly copy like this (and since we're copying,
Packit 534379
    # the const should drop away)
Packit 534379
    y1 = np.array(m.get_cm_const_ref())
Packit 534379
Packit 534379
    assert y1.flags.owndata and y1.flags.writeable
Packit 534379
    # We should get copies of the eigen data, which was modified above:
Packit 534379
    assert y1[1, 2] == 99
Packit 534379
    y1[1, 2] += 12
Packit 534379
    assert y1[1, 2] == 111
Packit 534379
    assert zc[1, 2] == 99  # Make sure we aren't referencing the original
Packit 534379
Packit 534379
Packit 534379
def test_both_ref_mutators():
Packit 534379
    """Tests a complex chain of nested eigen/numpy references"""
Packit 534379
Packit 534379
    m.reset_refs()  # In case another test already changed it
Packit 534379
Packit 534379
    z = m.get_cm_ref()  # numpy -> eigen
Packit 534379
    z[0, 2] -= 3
Packit 534379
    z2 = m.incr_matrix(z, 1)  # numpy -> eigen -> numpy -> eigen
Packit 534379
    z2[1, 1] += 6
Packit 534379
    z3 = m.incr_matrix(z, 2)  # (numpy -> eigen)^3
Packit 534379
    z3[2, 2] += -5
Packit 534379
    z4 = m.incr_matrix(z, 3)  # (numpy -> eigen)^4
Packit 534379
    z4[1, 1] -= 1
Packit 534379
    z5 = m.incr_matrix(z, 4)  # (numpy -> eigen)^5
Packit 534379
    z5[0, 0] = 0
Packit 534379
    assert np.all(z == z2)
Packit 534379
    assert np.all(z == z3)
Packit 534379
    assert np.all(z == z4)
Packit 534379
    assert np.all(z == z5)
Packit 534379
    expect = np.array([[0., 22, 20], [31, 37, 33], [41, 42, 38]])
Packit 534379
    assert np.all(z == expect)
Packit 534379
Packit 534379
    y = np.array(range(100), dtype='float64').reshape(10, 10)
Packit 534379
    y2 = m.incr_matrix_any(y, 10)  # np -> eigen -> np
Packit 534379
    y3 = m.incr_matrix_any(y2[0::2, 0::2], -33)  # np -> eigen -> np slice -> np -> eigen -> np
Packit 534379
    y4 = m.even_rows(y3)  # numpy -> eigen slice -> (... y3)
Packit 534379
    y5 = m.even_cols(y4)  # numpy -> eigen slice -> (... y4)
Packit 534379
    y6 = m.incr_matrix_any(y5, 1000)  # numpy -> eigen -> (... y5)
Packit 534379
Packit 534379
    # Apply same mutations using just numpy:
Packit 534379
    yexpect = np.array(range(100), dtype='float64').reshape(10, 10)
Packit 534379
    yexpect += 10
Packit 534379
    yexpect[0::2, 0::2] -= 33
Packit 534379
    yexpect[0::4, 0::4] += 1000
Packit 534379
    assert np.all(y6 == yexpect[0::4, 0::4])
Packit 534379
    assert np.all(y5 == yexpect[0::4, 0::4])
Packit 534379
    assert np.all(y4 == yexpect[0::4, 0::2])
Packit 534379
    assert np.all(y3 == yexpect[0::2, 0::2])
Packit 534379
    assert np.all(y2 == yexpect)
Packit 534379
    assert np.all(y == yexpect)
Packit 534379
Packit 534379
Packit 534379
def test_nocopy_wrapper():
Packit 534379
    # get_elem requires a column-contiguous matrix reference, but should be
Packit 534379
    # callable with other types of matrix (via copying):
Packit 534379
    int_matrix_colmajor = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], order='F')
Packit 534379
    dbl_matrix_colmajor = np.array(int_matrix_colmajor, dtype='double', order='F', copy=True)
Packit 534379
    int_matrix_rowmajor = np.array(int_matrix_colmajor, order='C', copy=True)
Packit 534379
    dbl_matrix_rowmajor = np.array(int_matrix_rowmajor, dtype='double', order='C', copy=True)
Packit 534379
Packit 534379
    # All should be callable via get_elem:
Packit 534379
    assert m.get_elem(int_matrix_colmajor) == 8
Packit 534379
    assert m.get_elem(dbl_matrix_colmajor) == 8
Packit 534379
    assert m.get_elem(int_matrix_rowmajor) == 8
Packit 534379
    assert m.get_elem(dbl_matrix_rowmajor) == 8
Packit 534379
Packit 534379
    # All but the second should fail with m.get_elem_nocopy:
Packit 534379
    with pytest.raises(TypeError) as excinfo:
Packit 534379
        m.get_elem_nocopy(int_matrix_colmajor)
Packit 534379
    assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and
Packit 534379
            ', flags.f_contiguous' in str(excinfo.value))
Packit 534379
    assert m.get_elem_nocopy(dbl_matrix_colmajor) == 8
Packit 534379
    with pytest.raises(TypeError) as excinfo:
Packit 534379
        m.get_elem_nocopy(int_matrix_rowmajor)
Packit 534379
    assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and
Packit 534379
            ', flags.f_contiguous' in str(excinfo.value))
Packit 534379
    with pytest.raises(TypeError) as excinfo:
Packit 534379
        m.get_elem_nocopy(dbl_matrix_rowmajor)
Packit 534379
    assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and
Packit 534379
            ', flags.f_contiguous' in str(excinfo.value))
Packit 534379
Packit 534379
    # For the row-major test, we take a long matrix in row-major, so only the third is allowed:
Packit 534379
    with pytest.raises(TypeError) as excinfo:
Packit 534379
        m.get_elem_rm_nocopy(int_matrix_colmajor)
Packit 534379
    assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and
Packit 534379
            ', flags.c_contiguous' in str(excinfo.value))
Packit 534379
    with pytest.raises(TypeError) as excinfo:
Packit 534379
        m.get_elem_rm_nocopy(dbl_matrix_colmajor)
Packit 534379
    assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and
Packit 534379
            ', flags.c_contiguous' in str(excinfo.value))
Packit 534379
    assert m.get_elem_rm_nocopy(int_matrix_rowmajor) == 8
Packit 534379
    with pytest.raises(TypeError) as excinfo:
Packit 534379
        m.get_elem_rm_nocopy(dbl_matrix_rowmajor)
Packit 534379
    assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and
Packit 534379
            ', flags.c_contiguous' in str(excinfo.value))
Packit 534379
Packit 534379
Packit 534379
def test_eigen_ref_life_support():
Packit 534379
    """Ensure the lifetime of temporary arrays created by the `Ref` caster
Packit 534379
Packit 534379
    The `Ref` caster sometimes creates a copy which needs to stay alive. This needs to
Packit 534379
    happen both for directs casts (just the array) or indirectly (e.g. list of arrays).
Packit 534379
    """
Packit 534379
Packit 534379
    a = np.full(shape=10, fill_value=8, dtype=np.int8)
Packit 534379
    assert m.get_elem_direct(a) == 8
Packit 534379
Packit 534379
    list_of_a = [a]
Packit 534379
    assert m.get_elem_indirect(list_of_a) == 8
Packit 534379
Packit 534379
Packit 534379
def test_special_matrix_objects():
Packit 534379
    assert np.all(m.incr_diag(7) == np.diag([1., 2, 3, 4, 5, 6, 7]))
Packit 534379
Packit 534379
    asymm = np.array([[ 1.,  2,  3,  4],
Packit 534379
                      [ 5,  6,  7,  8],
Packit 534379
                      [ 9, 10, 11, 12],
Packit 534379
                      [13, 14, 15, 16]])
Packit 534379
    symm_lower = np.array(asymm)
Packit 534379
    symm_upper = np.array(asymm)
Packit 534379
    for i in range(4):
Packit 534379
        for j in range(i + 1, 4):
Packit 534379
            symm_lower[i, j] = symm_lower[j, i]
Packit 534379
            symm_upper[j, i] = symm_upper[i, j]
Packit 534379
Packit 534379
    assert np.all(m.symmetric_lower(asymm) == symm_lower)
Packit 534379
    assert np.all(m.symmetric_upper(asymm) == symm_upper)
Packit 534379
Packit 534379
Packit 534379
def test_dense_signature(doc):
Packit 534379
    assert doc(m.double_col) == """
Packit 534379
        double_col(arg0: numpy.ndarray[float32[m, 1]]) -> numpy.ndarray[float32[m, 1]]
Packit 534379
    """
Packit 534379
    assert doc(m.double_row) == """
Packit 534379
        double_row(arg0: numpy.ndarray[float32[1, n]]) -> numpy.ndarray[float32[1, n]]
Packit 534379
    """
Packit 534379
    assert doc(m.double_complex) == """
Packit 534379
        double_complex(arg0: numpy.ndarray[complex64[m, 1]]) -> numpy.ndarray[complex64[m, 1]]
Packit 534379
    """
Packit 534379
    assert doc(m.double_mat_rm) == """
Packit 534379
        double_mat_rm(arg0: numpy.ndarray[float32[m, n]]) -> numpy.ndarray[float32[m, n]]
Packit 534379
    """
Packit 534379
Packit 534379
Packit 534379
def test_named_arguments():
Packit 534379
    a = np.array([[1.0, 2], [3, 4], [5, 6]])
Packit 534379
    b = np.ones((2, 1))
Packit 534379
Packit 534379
    assert np.all(m.matrix_multiply(a, b) == np.array([[3.], [7], [11]]))
Packit 534379
    assert np.all(m.matrix_multiply(A=a, B=b) == np.array([[3.], [7], [11]]))
Packit 534379
    assert np.all(m.matrix_multiply(B=b, A=a) == np.array([[3.], [7], [11]]))
Packit 534379
Packit 534379
    with pytest.raises(ValueError) as excinfo:
Packit 534379
        m.matrix_multiply(b, a)
Packit 534379
    assert str(excinfo.value) == 'Nonconformable matrices!'
Packit 534379
Packit 534379
    with pytest.raises(ValueError) as excinfo:
Packit 534379
        m.matrix_multiply(A=b, B=a)
Packit 534379
    assert str(excinfo.value) == 'Nonconformable matrices!'
Packit 534379
Packit 534379
    with pytest.raises(ValueError) as excinfo:
Packit 534379
        m.matrix_multiply(B=a, A=b)
Packit 534379
    assert str(excinfo.value) == 'Nonconformable matrices!'
Packit 534379
Packit 534379
Packit 534379
@pytest.requires_eigen_and_scipy
Packit 534379
def test_sparse():
Packit 534379
    assert_sparse_equal_ref(m.sparse_r())
Packit 534379
    assert_sparse_equal_ref(m.sparse_c())
Packit 534379
    assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_r()))
Packit 534379
    assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_c()))
Packit 534379
    assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_c()))
Packit 534379
    assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_r()))
Packit 534379
Packit 534379
Packit 534379
@pytest.requires_eigen_and_scipy
Packit 534379
def test_sparse_signature(doc):
Packit 534379
    assert doc(m.sparse_copy_r) == """
Packit 534379
        sparse_copy_r(arg0: scipy.sparse.csr_matrix[float32]) -> scipy.sparse.csr_matrix[float32]
Packit 534379
    """  # noqa: E501 line too long
Packit 534379
    assert doc(m.sparse_copy_c) == """
Packit 534379
        sparse_copy_c(arg0: scipy.sparse.csc_matrix[float32]) -> scipy.sparse.csc_matrix[float32]
Packit 534379
    """  # noqa: E501 line too long
Packit 534379
Packit 534379
Packit 534379
def test_issue738():
Packit 534379
    """Ignore strides on a length-1 dimension (even if they would be incompatible length > 1)"""
Packit 534379
    assert np.all(m.iss738_f1(np.array([[1., 2, 3]])) == np.array([[1., 102, 203]]))
Packit 534379
    assert np.all(m.iss738_f1(np.array([[1.], [2], [3]])) == np.array([[1.], [12], [23]]))
Packit 534379
Packit 534379
    assert np.all(m.iss738_f2(np.array([[1., 2, 3]])) == np.array([[1., 102, 203]]))
Packit 534379
    assert np.all(m.iss738_f2(np.array([[1.], [2], [3]])) == np.array([[1.], [12], [23]]))
Packit 534379
Packit 534379
Packit 534379
def test_issue1105():
Packit 534379
    """Issue 1105: 1xN or Nx1 input arrays weren't accepted for eigen
Packit 534379
    compile-time row vectors or column vector"""
Packit 534379
    assert m.iss1105_row(np.ones((1, 7)))
Packit 534379
    assert m.iss1105_col(np.ones((7, 1)))
Packit 534379
Packit 534379
    # These should still fail (incompatible dimensions):
Packit 534379
    with pytest.raises(TypeError) as excinfo:
Packit 534379
        m.iss1105_row(np.ones((7, 1)))
Packit 534379
    assert "incompatible function arguments" in str(excinfo.value)
Packit 534379
    with pytest.raises(TypeError) as excinfo:
Packit 534379
        m.iss1105_col(np.ones((1, 7)))
Packit 534379
    assert "incompatible function arguments" in str(excinfo.value)
Packit 534379
Packit 534379
Packit 534379
def test_custom_operator_new():
Packit 534379
    """Using Eigen types as member variables requires a class-specific
Packit 534379
    operator new with proper alignment"""
Packit 534379
Packit 534379
    o = m.CustomOperatorNew()
Packit 534379
    np.testing.assert_allclose(o.a, 0.0)
Packit 534379
    np.testing.assert_allclose(o.b.diagonal(), 1.0)