Spaces:
Running
Running
File size: 5,247 Bytes
6a86ad5 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
from sympy import ZZ, Matrix
from sympy.polys.matrices import DM, DomainMatrix
from sympy.polys.matrices.dense import ddm_iinv
from sympy.polys.matrices.exceptions import DMNonInvertibleMatrixError
from sympy.matrices.exceptions import NonInvertibleMatrixError
import pytest
from sympy.testing.pytest import raises
from sympy.core.numbers import all_close
from sympy.abc import x
# Examples are given as adjugate matrix and determinant adj_det should match
# these exactly but inv_den only matches after cancel_denom.
INVERSE_EXAMPLES = [
(
'zz_1',
DomainMatrix([], (0, 0), ZZ),
DomainMatrix([], (0, 0), ZZ),
ZZ(1),
),
(
'zz_2',
DM([[2]], ZZ),
DM([[1]], ZZ),
ZZ(2),
),
(
'zz_3',
DM([[2, 0],
[0, 2]], ZZ),
DM([[2, 0],
[0, 2]], ZZ),
ZZ(4),
),
(
'zz_4',
DM([[1, 2],
[3, 4]], ZZ),
DM([[ 4, -2],
[-3, 1]], ZZ),
ZZ(-2),
),
(
'zz_5',
DM([[2, 2, 0],
[0, 2, 2],
[0, 0, 2]], ZZ),
DM([[4, -4, 4],
[0, 4, -4],
[0, 0, 4]], ZZ),
ZZ(8),
),
(
'zz_6',
DM([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]], ZZ),
DM([[-3, 6, -3],
[ 6, -12, 6],
[-3, 6, -3]], ZZ),
ZZ(0),
),
]
@pytest.mark.parametrize('name, A, A_inv, den', INVERSE_EXAMPLES)
def test_Matrix_inv(name, A, A_inv, den):
def _check(**kwargs):
if den != 0:
assert A.inv(**kwargs) == A_inv
else:
raises(NonInvertibleMatrixError, lambda: A.inv(**kwargs))
K = A.domain
A = A.to_Matrix()
A_inv = A_inv.to_Matrix() / K.to_sympy(den)
_check()
for method in ['GE', 'LU', 'ADJ', 'CH', 'LDL', 'QR']:
_check(method=method)
@pytest.mark.parametrize('name, A, A_inv, den', INVERSE_EXAMPLES)
def test_dm_inv_den(name, A, A_inv, den):
if den != 0:
A_inv_f, den_f = A.inv_den()
assert A_inv_f.cancel_denom(den_f) == A_inv.cancel_denom(den)
else:
raises(DMNonInvertibleMatrixError, lambda: A.inv_den())
@pytest.mark.parametrize('name, A, A_inv, den', INVERSE_EXAMPLES)
def test_dm_inv(name, A, A_inv, den):
A = A.to_field()
if den != 0:
A_inv = A_inv.to_field() / den
assert A.inv() == A_inv
else:
raises(DMNonInvertibleMatrixError, lambda: A.inv())
@pytest.mark.parametrize('name, A, A_inv, den', INVERSE_EXAMPLES)
def test_ddm_inv(name, A, A_inv, den):
A = A.to_field().to_ddm()
if den != 0:
A_inv = (A_inv.to_field() / den).to_ddm()
assert A.inv() == A_inv
else:
raises(DMNonInvertibleMatrixError, lambda: A.inv())
@pytest.mark.parametrize('name, A, A_inv, den', INVERSE_EXAMPLES)
def test_sdm_inv(name, A, A_inv, den):
A = A.to_field().to_sdm()
if den != 0:
A_inv = (A_inv.to_field() / den).to_sdm()
assert A.inv() == A_inv
else:
raises(DMNonInvertibleMatrixError, lambda: A.inv())
@pytest.mark.parametrize('name, A, A_inv, den', INVERSE_EXAMPLES)
def test_dense_ddm_iinv(name, A, A_inv, den):
A = A.to_field().to_ddm().copy()
K = A.domain
A_result = A.copy()
if den != 0:
A_inv = (A_inv.to_field() / den).to_ddm()
ddm_iinv(A_result, A, K)
assert A_result == A_inv
else:
raises(DMNonInvertibleMatrixError, lambda: ddm_iinv(A_result, A, K))
@pytest.mark.parametrize('name, A, A_inv, den', INVERSE_EXAMPLES)
def test_Matrix_adjugate(name, A, A_inv, den):
A = A.to_Matrix()
A_inv = A_inv.to_Matrix()
assert A.adjugate() == A_inv
for method in ["bareiss", "berkowitz", "bird", "laplace", "lu"]:
assert A.adjugate(method=method) == A_inv
@pytest.mark.parametrize('name, A, A_inv, den', INVERSE_EXAMPLES)
def test_dm_adj_det(name, A, A_inv, den):
assert A.adj_det() == (A_inv, den)
def test_inverse_inexact():
M = Matrix([[x-0.3, -0.06, -0.22],
[-0.46, x-0.48, -0.41],
[-0.14, -0.39, x-0.64]])
Mn = Matrix([[1.0*x**2 - 1.12*x + 0.1473, 0.06*x + 0.0474, 0.22*x - 0.081],
[0.46*x - 0.237, 1.0*x**2 - 0.94*x + 0.1612, 0.41*x - 0.0218],
[0.14*x + 0.1122, 0.39*x - 0.1086, 1.0*x**2 - 0.78*x + 0.1164]])
d = 1.0*x**3 - 1.42*x**2 + 0.4249*x - 0.0546540000000002
Mi = Mn / d
M_dm = M.to_DM()
M_dmd = M_dm.to_dense()
M_dm_num, M_dm_den = M_dm.inv_den()
M_dmd_num, M_dmd_den = M_dmd.inv_den()
# XXX: We don't check M_dm().to_field().inv() which currently uses division
# and produces a more complicate result from gcd cancellation failing.
# DomainMatrix.inv() over RR(x) should be changed to clear denominators and
# use DomainMatrix.inv_den().
Minvs = [
M.inv(),
(M_dm_num.to_field() / M_dm_den).to_Matrix(),
(M_dmd_num.to_field() / M_dmd_den).to_Matrix(),
M_dm_num.to_Matrix() / M_dm_den.as_expr(),
M_dmd_num.to_Matrix() / M_dmd_den.as_expr(),
]
for Minv in Minvs:
for Mi1, Mi2 in zip(Minv.flat(), Mi.flat()):
assert all_close(Mi2, Mi1)
|