switching to high quality piper tts and added label translations
This commit is contained in:
@@ -0,0 +1,558 @@
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.external.gmpy import GROUND_TYPES
|
||||
|
||||
from sympy.polys import ZZ, QQ
|
||||
|
||||
from sympy.polys.matrices.ddm import DDM
|
||||
from sympy.polys.matrices.exceptions import (
|
||||
DMShapeError, DMNonInvertibleMatrixError, DMDomainError,
|
||||
DMBadInputError)
|
||||
|
||||
|
||||
def test_DDM_init():
|
||||
items = [[ZZ(0), ZZ(1), ZZ(2)], [ZZ(3), ZZ(4), ZZ(5)]]
|
||||
shape = (2, 3)
|
||||
ddm = DDM(items, shape, ZZ)
|
||||
assert ddm.shape == shape
|
||||
assert ddm.rows == 2
|
||||
assert ddm.cols == 3
|
||||
assert ddm.domain == ZZ
|
||||
|
||||
raises(DMBadInputError, lambda: DDM([[ZZ(2), ZZ(3)]], (2, 2), ZZ))
|
||||
raises(DMBadInputError, lambda: DDM([[ZZ(1)], [ZZ(2), ZZ(3)]], (2, 2), ZZ))
|
||||
|
||||
|
||||
def test_DDM_getsetitem():
|
||||
ddm = DDM([[ZZ(2), ZZ(3)], [ZZ(4), ZZ(5)]], (2, 2), ZZ)
|
||||
|
||||
assert ddm[0][0] == ZZ(2)
|
||||
assert ddm[0][1] == ZZ(3)
|
||||
assert ddm[1][0] == ZZ(4)
|
||||
assert ddm[1][1] == ZZ(5)
|
||||
|
||||
raises(IndexError, lambda: ddm[2][0])
|
||||
raises(IndexError, lambda: ddm[0][2])
|
||||
|
||||
ddm[0][0] = ZZ(-1)
|
||||
assert ddm[0][0] == ZZ(-1)
|
||||
|
||||
|
||||
def test_DDM_str():
|
||||
ddm = DDM([[ZZ(0), ZZ(1)], [ZZ(2), ZZ(3)]], (2, 2), ZZ)
|
||||
if GROUND_TYPES == 'gmpy': # pragma: no cover
|
||||
assert str(ddm) == '[[0, 1], [2, 3]]'
|
||||
assert repr(ddm) == 'DDM([[mpz(0), mpz(1)], [mpz(2), mpz(3)]], (2, 2), ZZ)'
|
||||
else: # pragma: no cover
|
||||
assert repr(ddm) == 'DDM([[0, 1], [2, 3]], (2, 2), ZZ)'
|
||||
assert str(ddm) == '[[0, 1], [2, 3]]'
|
||||
|
||||
|
||||
def test_DDM_eq():
|
||||
items = [[ZZ(0), ZZ(1)], [ZZ(2), ZZ(3)]]
|
||||
ddm1 = DDM(items, (2, 2), ZZ)
|
||||
ddm2 = DDM(items, (2, 2), ZZ)
|
||||
|
||||
assert (ddm1 == ddm1) is True
|
||||
assert (ddm1 == items) is False
|
||||
assert (items == ddm1) is False
|
||||
assert (ddm1 == ddm2) is True
|
||||
assert (ddm2 == ddm1) is True
|
||||
|
||||
assert (ddm1 != ddm1) is False
|
||||
assert (ddm1 != items) is True
|
||||
assert (items != ddm1) is True
|
||||
assert (ddm1 != ddm2) is False
|
||||
assert (ddm2 != ddm1) is False
|
||||
|
||||
ddm3 = DDM([[ZZ(0), ZZ(1)], [ZZ(3), ZZ(3)]], (2, 2), ZZ)
|
||||
ddm3 = DDM(items, (2, 2), QQ)
|
||||
|
||||
assert (ddm1 == ddm3) is False
|
||||
assert (ddm3 == ddm1) is False
|
||||
assert (ddm1 != ddm3) is True
|
||||
assert (ddm3 != ddm1) is True
|
||||
|
||||
|
||||
def test_DDM_convert_to():
|
||||
ddm = DDM([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
|
||||
assert ddm.convert_to(ZZ) == ddm
|
||||
ddmq = ddm.convert_to(QQ)
|
||||
assert ddmq.domain == QQ
|
||||
|
||||
|
||||
def test_DDM_zeros():
|
||||
ddmz = DDM.zeros((3, 4), QQ)
|
||||
assert list(ddmz) == [[QQ(0)] * 4] * 3
|
||||
assert ddmz.shape == (3, 4)
|
||||
assert ddmz.domain == QQ
|
||||
|
||||
def test_DDM_ones():
|
||||
ddmone = DDM.ones((2, 3), QQ)
|
||||
assert list(ddmone) == [[QQ(1)] * 3] * 2
|
||||
assert ddmone.shape == (2, 3)
|
||||
assert ddmone.domain == QQ
|
||||
|
||||
def test_DDM_eye():
|
||||
ddmz = DDM.eye(3, QQ)
|
||||
f = lambda i, j: QQ(1) if i == j else QQ(0)
|
||||
assert list(ddmz) == [[f(i, j) for i in range(3)] for j in range(3)]
|
||||
assert ddmz.shape == (3, 3)
|
||||
assert ddmz.domain == QQ
|
||||
|
||||
|
||||
def test_DDM_copy():
|
||||
ddm1 = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ)
|
||||
ddm2 = ddm1.copy()
|
||||
assert (ddm1 == ddm2) is True
|
||||
ddm1[0][0] = QQ(-1)
|
||||
assert (ddm1 == ddm2) is False
|
||||
ddm2[0][0] = QQ(-1)
|
||||
assert (ddm1 == ddm2) is True
|
||||
|
||||
|
||||
def test_DDM_transpose():
|
||||
ddm = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ)
|
||||
ddmT = DDM([[QQ(1), QQ(2)]], (1, 2), QQ)
|
||||
assert ddm.transpose() == ddmT
|
||||
ddm02 = DDM([], (0, 2), QQ)
|
||||
ddm02T = DDM([[], []], (2, 0), QQ)
|
||||
assert ddm02.transpose() == ddm02T
|
||||
assert ddm02T.transpose() == ddm02
|
||||
ddm0 = DDM([], (0, 0), QQ)
|
||||
assert ddm0.transpose() == ddm0
|
||||
|
||||
|
||||
def test_DDM_add():
|
||||
A = DDM([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ)
|
||||
B = DDM([[ZZ(3)], [ZZ(4)]], (2, 1), ZZ)
|
||||
C = DDM([[ZZ(4)], [ZZ(6)]], (2, 1), ZZ)
|
||||
AQ = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ)
|
||||
assert A + B == A.add(B) == C
|
||||
|
||||
raises(DMShapeError, lambda: A + DDM([[ZZ(5)]], (1, 1), ZZ))
|
||||
raises(TypeError, lambda: A + ZZ(1))
|
||||
raises(TypeError, lambda: ZZ(1) + A)
|
||||
raises(DMDomainError, lambda: A + AQ)
|
||||
raises(DMDomainError, lambda: AQ + A)
|
||||
|
||||
|
||||
def test_DDM_sub():
|
||||
A = DDM([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ)
|
||||
B = DDM([[ZZ(3)], [ZZ(4)]], (2, 1), ZZ)
|
||||
C = DDM([[ZZ(-2)], [ZZ(-2)]], (2, 1), ZZ)
|
||||
AQ = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ)
|
||||
D = DDM([[ZZ(5)]], (1, 1), ZZ)
|
||||
assert A - B == A.sub(B) == C
|
||||
|
||||
raises(TypeError, lambda: A - ZZ(1))
|
||||
raises(TypeError, lambda: ZZ(1) - A)
|
||||
raises(DMShapeError, lambda: A - D)
|
||||
raises(DMShapeError, lambda: D - A)
|
||||
raises(DMShapeError, lambda: A.sub(D))
|
||||
raises(DMShapeError, lambda: D.sub(A))
|
||||
raises(DMDomainError, lambda: A - AQ)
|
||||
raises(DMDomainError, lambda: AQ - A)
|
||||
raises(DMDomainError, lambda: A.sub(AQ))
|
||||
raises(DMDomainError, lambda: AQ.sub(A))
|
||||
|
||||
|
||||
def test_DDM_neg():
|
||||
A = DDM([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ)
|
||||
An = DDM([[ZZ(-1)], [ZZ(-2)]], (2, 1), ZZ)
|
||||
assert -A == A.neg() == An
|
||||
assert -An == An.neg() == A
|
||||
|
||||
|
||||
def test_DDM_mul():
|
||||
A = DDM([[ZZ(1)]], (1, 1), ZZ)
|
||||
A2 = DDM([[ZZ(2)]], (1, 1), ZZ)
|
||||
assert A * ZZ(2) == A2
|
||||
assert ZZ(2) * A == A2
|
||||
raises(TypeError, lambda: [[1]] * A)
|
||||
raises(TypeError, lambda: A * [[1]])
|
||||
|
||||
|
||||
def test_DDM_matmul():
|
||||
A = DDM([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ)
|
||||
B = DDM([[ZZ(3), ZZ(4)]], (1, 2), ZZ)
|
||||
AB = DDM([[ZZ(3), ZZ(4)], [ZZ(6), ZZ(8)]], (2, 2), ZZ)
|
||||
BA = DDM([[ZZ(11)]], (1, 1), ZZ)
|
||||
|
||||
assert A @ B == A.matmul(B) == AB
|
||||
assert B @ A == B.matmul(A) == BA
|
||||
|
||||
raises(TypeError, lambda: A @ 1)
|
||||
raises(TypeError, lambda: A @ [[3, 4]])
|
||||
|
||||
Bq = DDM([[QQ(3), QQ(4)]], (1, 2), QQ)
|
||||
|
||||
raises(DMDomainError, lambda: A @ Bq)
|
||||
raises(DMDomainError, lambda: Bq @ A)
|
||||
|
||||
C = DDM([[ZZ(1)]], (1, 1), ZZ)
|
||||
|
||||
assert A @ C == A.matmul(C) == A
|
||||
|
||||
raises(DMShapeError, lambda: C @ A)
|
||||
raises(DMShapeError, lambda: C.matmul(A))
|
||||
|
||||
Z04 = DDM([], (0, 4), ZZ)
|
||||
Z40 = DDM([[]]*4, (4, 0), ZZ)
|
||||
Z50 = DDM([[]]*5, (5, 0), ZZ)
|
||||
Z05 = DDM([], (0, 5), ZZ)
|
||||
Z45 = DDM([[0] * 5] * 4, (4, 5), ZZ)
|
||||
Z54 = DDM([[0] * 4] * 5, (5, 4), ZZ)
|
||||
Z00 = DDM([], (0, 0), ZZ)
|
||||
|
||||
assert Z04 @ Z45 == Z04.matmul(Z45) == Z05
|
||||
assert Z45 @ Z50 == Z45.matmul(Z50) == Z40
|
||||
assert Z00 @ Z04 == Z00.matmul(Z04) == Z04
|
||||
assert Z50 @ Z00 == Z50.matmul(Z00) == Z50
|
||||
assert Z00 @ Z00 == Z00.matmul(Z00) == Z00
|
||||
assert Z50 @ Z04 == Z50.matmul(Z04) == Z54
|
||||
|
||||
raises(DMShapeError, lambda: Z05 @ Z40)
|
||||
raises(DMShapeError, lambda: Z05.matmul(Z40))
|
||||
|
||||
|
||||
def test_DDM_hstack():
|
||||
A = DDM([[ZZ(1), ZZ(2), ZZ(3)]], (1, 3), ZZ)
|
||||
B = DDM([[ZZ(4), ZZ(5)]], (1, 2), ZZ)
|
||||
C = DDM([[ZZ(6)]], (1, 1), ZZ)
|
||||
|
||||
Ah = A.hstack(B)
|
||||
assert Ah.shape == (1, 5)
|
||||
assert Ah.domain == ZZ
|
||||
assert Ah == DDM([[ZZ(1), ZZ(2), ZZ(3), ZZ(4), ZZ(5)]], (1, 5), ZZ)
|
||||
|
||||
Ah = A.hstack(B, C)
|
||||
assert Ah.shape == (1, 6)
|
||||
assert Ah.domain == ZZ
|
||||
assert Ah == DDM([[ZZ(1), ZZ(2), ZZ(3), ZZ(4), ZZ(5), ZZ(6)]], (1, 6), ZZ)
|
||||
|
||||
|
||||
def test_DDM_vstack():
|
||||
A = DDM([[ZZ(1)], [ZZ(2)], [ZZ(3)]], (3, 1), ZZ)
|
||||
B = DDM([[ZZ(4)], [ZZ(5)]], (2, 1), ZZ)
|
||||
C = DDM([[ZZ(6)]], (1, 1), ZZ)
|
||||
|
||||
Ah = A.vstack(B)
|
||||
assert Ah.shape == (5, 1)
|
||||
assert Ah.domain == ZZ
|
||||
assert Ah == DDM([[ZZ(1)], [ZZ(2)], [ZZ(3)], [ZZ(4)], [ZZ(5)]], (5, 1), ZZ)
|
||||
|
||||
Ah = A.vstack(B, C)
|
||||
assert Ah.shape == (6, 1)
|
||||
assert Ah.domain == ZZ
|
||||
assert Ah == DDM([[ZZ(1)], [ZZ(2)], [ZZ(3)], [ZZ(4)], [ZZ(5)], [ZZ(6)]], (6, 1), ZZ)
|
||||
|
||||
|
||||
def test_DDM_applyfunc():
|
||||
A = DDM([[ZZ(1), ZZ(2), ZZ(3)]], (1, 3), ZZ)
|
||||
B = DDM([[ZZ(2), ZZ(4), ZZ(6)]], (1, 3), ZZ)
|
||||
assert A.applyfunc(lambda x: 2*x, ZZ) == B
|
||||
|
||||
def test_DDM_rref():
|
||||
|
||||
A = DDM([], (0, 4), QQ)
|
||||
assert A.rref() == (A, [])
|
||||
|
||||
A = DDM([[QQ(0), QQ(1)], [QQ(1), QQ(1)]], (2, 2), QQ)
|
||||
Ar = DDM([[QQ(1), QQ(0)], [QQ(0), QQ(1)]], (2, 2), QQ)
|
||||
pivots = [0, 1]
|
||||
assert A.rref() == (Ar, pivots)
|
||||
|
||||
A = DDM([[QQ(1), QQ(2), QQ(1)], [QQ(3), QQ(4), QQ(1)]], (2, 3), QQ)
|
||||
Ar = DDM([[QQ(1), QQ(0), QQ(-1)], [QQ(0), QQ(1), QQ(1)]], (2, 3), QQ)
|
||||
pivots = [0, 1]
|
||||
assert A.rref() == (Ar, pivots)
|
||||
|
||||
A = DDM([[QQ(3), QQ(4), QQ(1)], [QQ(1), QQ(2), QQ(1)]], (2, 3), QQ)
|
||||
Ar = DDM([[QQ(1), QQ(0), QQ(-1)], [QQ(0), QQ(1), QQ(1)]], (2, 3), QQ)
|
||||
pivots = [0, 1]
|
||||
assert A.rref() == (Ar, pivots)
|
||||
|
||||
A = DDM([[QQ(1), QQ(0)], [QQ(1), QQ(3)], [QQ(0), QQ(1)]], (3, 2), QQ)
|
||||
Ar = DDM([[QQ(1), QQ(0)], [QQ(0), QQ(1)], [QQ(0), QQ(0)]], (3, 2), QQ)
|
||||
pivots = [0, 1]
|
||||
assert A.rref() == (Ar, pivots)
|
||||
|
||||
A = DDM([[QQ(1), QQ(0), QQ(1)], [QQ(3), QQ(0), QQ(1)]], (2, 3), QQ)
|
||||
Ar = DDM([[QQ(1), QQ(0), QQ(0)], [QQ(0), QQ(0), QQ(1)]], (2, 3), QQ)
|
||||
pivots = [0, 2]
|
||||
assert A.rref() == (Ar, pivots)
|
||||
|
||||
|
||||
def test_DDM_nullspace():
|
||||
# more tests are in test_nullspace.py
|
||||
A = DDM([[QQ(1), QQ(1)], [QQ(1), QQ(1)]], (2, 2), QQ)
|
||||
Anull = DDM([[QQ(-1), QQ(1)]], (1, 2), QQ)
|
||||
nonpivots = [1]
|
||||
assert A.nullspace() == (Anull, nonpivots)
|
||||
|
||||
|
||||
def test_DDM_particular():
|
||||
A = DDM([[QQ(1), QQ(0)]], (1, 2), QQ)
|
||||
assert A.particular() == DDM.zeros((1, 1), QQ)
|
||||
|
||||
|
||||
def test_DDM_det():
|
||||
# 0x0 case
|
||||
A = DDM([], (0, 0), ZZ)
|
||||
assert A.det() == ZZ(1)
|
||||
|
||||
# 1x1 case
|
||||
A = DDM([[ZZ(2)]], (1, 1), ZZ)
|
||||
assert A.det() == ZZ(2)
|
||||
|
||||
# 2x2 case
|
||||
A = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
|
||||
assert A.det() == ZZ(-2)
|
||||
|
||||
# 3x3 with swap
|
||||
A = DDM([[ZZ(1), ZZ(2), ZZ(3)], [ZZ(1), ZZ(2), ZZ(4)], [ZZ(1), ZZ(2), ZZ(5)]], (3, 3), ZZ)
|
||||
assert A.det() == ZZ(0)
|
||||
|
||||
# 2x2 QQ case
|
||||
A = DDM([[QQ(1, 2), QQ(1, 2)], [QQ(1, 3), QQ(1, 4)]], (2, 2), QQ)
|
||||
assert A.det() == QQ(-1, 24)
|
||||
|
||||
# Nonsquare error
|
||||
A = DDM([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ)
|
||||
raises(DMShapeError, lambda: A.det())
|
||||
|
||||
# Nonsquare error with empty matrix
|
||||
A = DDM([], (0, 1), ZZ)
|
||||
raises(DMShapeError, lambda: A.det())
|
||||
|
||||
|
||||
def test_DDM_inv():
|
||||
A = DDM([[QQ(1, 1), QQ(2, 1)], [QQ(3, 1), QQ(4, 1)]], (2, 2), QQ)
|
||||
Ainv = DDM([[QQ(-2, 1), QQ(1, 1)], [QQ(3, 2), QQ(-1, 2)]], (2, 2), QQ)
|
||||
assert A.inv() == Ainv
|
||||
|
||||
A = DDM([[QQ(1), QQ(2)]], (1, 2), QQ)
|
||||
raises(DMShapeError, lambda: A.inv())
|
||||
|
||||
A = DDM([[ZZ(2)]], (1, 1), ZZ)
|
||||
raises(DMDomainError, lambda: A.inv())
|
||||
|
||||
A = DDM([], (0, 0), QQ)
|
||||
assert A.inv() == A
|
||||
|
||||
A = DDM([[QQ(1), QQ(2)], [QQ(2), QQ(4)]], (2, 2), QQ)
|
||||
raises(DMNonInvertibleMatrixError, lambda: A.inv())
|
||||
|
||||
|
||||
def test_DDM_lu():
|
||||
A = DDM([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
|
||||
L, U, swaps = A.lu()
|
||||
assert L == DDM([[QQ(1), QQ(0)], [QQ(3), QQ(1)]], (2, 2), QQ)
|
||||
assert U == DDM([[QQ(1), QQ(2)], [QQ(0), QQ(-2)]], (2, 2), QQ)
|
||||
assert swaps == []
|
||||
|
||||
A = [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 2]]
|
||||
Lexp = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 1, 1]]
|
||||
Uexp = [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]
|
||||
to_dom = lambda rows, dom: [[dom(e) for e in row] for row in rows]
|
||||
A = DDM(to_dom(A, QQ), (4, 4), QQ)
|
||||
Lexp = DDM(to_dom(Lexp, QQ), (4, 4), QQ)
|
||||
Uexp = DDM(to_dom(Uexp, QQ), (4, 4), QQ)
|
||||
L, U, swaps = A.lu()
|
||||
assert L == Lexp
|
||||
assert U == Uexp
|
||||
assert swaps == []
|
||||
|
||||
|
||||
def test_DDM_lu_solve():
|
||||
# Basic example
|
||||
A = DDM([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
|
||||
b = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ)
|
||||
x = DDM([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ)
|
||||
assert A.lu_solve(b) == x
|
||||
|
||||
# Example with swaps
|
||||
A = DDM([[QQ(0), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
|
||||
assert A.lu_solve(b) == x
|
||||
|
||||
# Overdetermined, consistent
|
||||
A = DDM([[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]], (3, 2), QQ)
|
||||
b = DDM([[QQ(1)], [QQ(2)], [QQ(3)]], (3, 1), QQ)
|
||||
assert A.lu_solve(b) == x
|
||||
|
||||
# Overdetermined, inconsistent
|
||||
b = DDM([[QQ(1)], [QQ(2)], [QQ(4)]], (3, 1), QQ)
|
||||
raises(DMNonInvertibleMatrixError, lambda: A.lu_solve(b))
|
||||
|
||||
# Square, noninvertible
|
||||
A = DDM([[QQ(1), QQ(2)], [QQ(1), QQ(2)]], (2, 2), QQ)
|
||||
b = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ)
|
||||
raises(DMNonInvertibleMatrixError, lambda: A.lu_solve(b))
|
||||
|
||||
# Underdetermined
|
||||
A = DDM([[QQ(1), QQ(2)]], (1, 2), QQ)
|
||||
b = DDM([[QQ(3)]], (1, 1), QQ)
|
||||
raises(NotImplementedError, lambda: A.lu_solve(b))
|
||||
|
||||
# Domain mismatch
|
||||
bz = DDM([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ)
|
||||
raises(DMDomainError, lambda: A.lu_solve(bz))
|
||||
|
||||
# Shape mismatch
|
||||
b3 = DDM([[QQ(1)], [QQ(2)], [QQ(3)]], (3, 1), QQ)
|
||||
raises(DMShapeError, lambda: A.lu_solve(b3))
|
||||
|
||||
|
||||
def test_DDM_charpoly():
|
||||
A = DDM([], (0, 0), ZZ)
|
||||
assert A.charpoly() == [ZZ(1)]
|
||||
|
||||
A = DDM([
|
||||
[ZZ(1), ZZ(2), ZZ(3)],
|
||||
[ZZ(4), ZZ(5), ZZ(6)],
|
||||
[ZZ(7), ZZ(8), ZZ(9)]], (3, 3), ZZ)
|
||||
Avec = [ZZ(1), ZZ(-15), ZZ(-18), ZZ(0)]
|
||||
assert A.charpoly() == Avec
|
||||
|
||||
A = DDM([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
|
||||
raises(DMShapeError, lambda: A.charpoly())
|
||||
|
||||
|
||||
def test_DDM_getitem():
|
||||
dm = DDM([
|
||||
[ZZ(1), ZZ(2), ZZ(3)],
|
||||
[ZZ(4), ZZ(5), ZZ(6)],
|
||||
[ZZ(7), ZZ(8), ZZ(9)]], (3, 3), ZZ)
|
||||
|
||||
assert dm.getitem(1, 1) == ZZ(5)
|
||||
assert dm.getitem(1, -2) == ZZ(5)
|
||||
assert dm.getitem(-1, -3) == ZZ(7)
|
||||
|
||||
raises(IndexError, lambda: dm.getitem(3, 3))
|
||||
|
||||
|
||||
def test_DDM_setitem():
|
||||
dm = DDM.zeros((3, 3), ZZ)
|
||||
dm.setitem(0, 0, 1)
|
||||
dm.setitem(1, -2, 1)
|
||||
dm.setitem(-1, -1, 1)
|
||||
assert dm == DDM.eye(3, ZZ)
|
||||
|
||||
raises(IndexError, lambda: dm.setitem(3, 3, 0))
|
||||
|
||||
|
||||
def test_DDM_extract_slice():
|
||||
dm = DDM([
|
||||
[ZZ(1), ZZ(2), ZZ(3)],
|
||||
[ZZ(4), ZZ(5), ZZ(6)],
|
||||
[ZZ(7), ZZ(8), ZZ(9)]], (3, 3), ZZ)
|
||||
|
||||
assert dm.extract_slice(slice(0, 3), slice(0, 3)) == dm
|
||||
assert dm.extract_slice(slice(1, 3), slice(-2)) == DDM([[4], [7]], (2, 1), ZZ)
|
||||
assert dm.extract_slice(slice(1, 3), slice(-2)) == DDM([[4], [7]], (2, 1), ZZ)
|
||||
assert dm.extract_slice(slice(2, 3), slice(-2)) == DDM([[ZZ(7)]], (1, 1), ZZ)
|
||||
assert dm.extract_slice(slice(0, 2), slice(-2)) == DDM([[1], [4]], (2, 1), ZZ)
|
||||
assert dm.extract_slice(slice(-1), slice(-1)) == DDM([[1, 2], [4, 5]], (2, 2), ZZ)
|
||||
|
||||
assert dm.extract_slice(slice(2), slice(3, 4)) == DDM([[], []], (2, 0), ZZ)
|
||||
assert dm.extract_slice(slice(3, 4), slice(2)) == DDM([], (0, 2), ZZ)
|
||||
assert dm.extract_slice(slice(3, 4), slice(3, 4)) == DDM([], (0, 0), ZZ)
|
||||
|
||||
|
||||
def test_DDM_extract():
|
||||
dm1 = DDM([
|
||||
[ZZ(1), ZZ(2), ZZ(3)],
|
||||
[ZZ(4), ZZ(5), ZZ(6)],
|
||||
[ZZ(7), ZZ(8), ZZ(9)]], (3, 3), ZZ)
|
||||
dm2 = DDM([
|
||||
[ZZ(6), ZZ(4)],
|
||||
[ZZ(3), ZZ(1)]], (2, 2), ZZ)
|
||||
assert dm1.extract([1, 0], [2, 0]) == dm2
|
||||
assert dm1.extract([-2, 0], [-1, 0]) == dm2
|
||||
|
||||
assert dm1.extract([], []) == DDM.zeros((0, 0), ZZ)
|
||||
assert dm1.extract([1], []) == DDM.zeros((1, 0), ZZ)
|
||||
assert dm1.extract([], [1]) == DDM.zeros((0, 1), ZZ)
|
||||
|
||||
raises(IndexError, lambda: dm2.extract([2], [0]))
|
||||
raises(IndexError, lambda: dm2.extract([0], [2]))
|
||||
raises(IndexError, lambda: dm2.extract([-3], [0]))
|
||||
raises(IndexError, lambda: dm2.extract([0], [-3]))
|
||||
|
||||
|
||||
def test_DDM_flat():
|
||||
dm = DDM([
|
||||
[ZZ(6), ZZ(4)],
|
||||
[ZZ(3), ZZ(1)]], (2, 2), ZZ)
|
||||
assert dm.flat() == [ZZ(6), ZZ(4), ZZ(3), ZZ(1)]
|
||||
|
||||
|
||||
def test_DDM_is_zero_matrix():
|
||||
A = DDM([[QQ(1), QQ(0)], [QQ(0), QQ(0)]], (2, 2), QQ)
|
||||
Azero = DDM.zeros((1, 2), QQ)
|
||||
assert A.is_zero_matrix() is False
|
||||
assert Azero.is_zero_matrix() is True
|
||||
|
||||
|
||||
def test_DDM_is_upper():
|
||||
# Wide matrices:
|
||||
A = DDM([
|
||||
[QQ(1), QQ(2), QQ(3), QQ(4)],
|
||||
[QQ(0), QQ(5), QQ(6), QQ(7)],
|
||||
[QQ(0), QQ(0), QQ(8), QQ(9)]
|
||||
], (3, 4), QQ)
|
||||
B = DDM([
|
||||
[QQ(1), QQ(2), QQ(3), QQ(4)],
|
||||
[QQ(0), QQ(5), QQ(6), QQ(7)],
|
||||
[QQ(0), QQ(7), QQ(8), QQ(9)]
|
||||
], (3, 4), QQ)
|
||||
assert A.is_upper() is True
|
||||
assert B.is_upper() is False
|
||||
|
||||
# Tall matrices:
|
||||
A = DDM([
|
||||
[QQ(1), QQ(2), QQ(3)],
|
||||
[QQ(0), QQ(5), QQ(6)],
|
||||
[QQ(0), QQ(0), QQ(8)],
|
||||
[QQ(0), QQ(0), QQ(0)]
|
||||
], (4, 3), QQ)
|
||||
B = DDM([
|
||||
[QQ(1), QQ(2), QQ(3)],
|
||||
[QQ(0), QQ(5), QQ(6)],
|
||||
[QQ(0), QQ(0), QQ(8)],
|
||||
[QQ(0), QQ(0), QQ(10)]
|
||||
], (4, 3), QQ)
|
||||
assert A.is_upper() is True
|
||||
assert B.is_upper() is False
|
||||
|
||||
|
||||
def test_DDM_is_lower():
|
||||
# Tall matrices:
|
||||
A = DDM([
|
||||
[QQ(1), QQ(2), QQ(3), QQ(4)],
|
||||
[QQ(0), QQ(5), QQ(6), QQ(7)],
|
||||
[QQ(0), QQ(0), QQ(8), QQ(9)]
|
||||
], (3, 4), QQ).transpose()
|
||||
B = DDM([
|
||||
[QQ(1), QQ(2), QQ(3), QQ(4)],
|
||||
[QQ(0), QQ(5), QQ(6), QQ(7)],
|
||||
[QQ(0), QQ(7), QQ(8), QQ(9)]
|
||||
], (3, 4), QQ).transpose()
|
||||
assert A.is_lower() is True
|
||||
assert B.is_lower() is False
|
||||
|
||||
# Wide matrices:
|
||||
A = DDM([
|
||||
[QQ(1), QQ(2), QQ(3)],
|
||||
[QQ(0), QQ(5), QQ(6)],
|
||||
[QQ(0), QQ(0), QQ(8)],
|
||||
[QQ(0), QQ(0), QQ(0)]
|
||||
], (4, 3), QQ).transpose()
|
||||
B = DDM([
|
||||
[QQ(1), QQ(2), QQ(3)],
|
||||
[QQ(0), QQ(5), QQ(6)],
|
||||
[QQ(0), QQ(0), QQ(8)],
|
||||
[QQ(0), QQ(0), QQ(10)]
|
||||
], (4, 3), QQ).transpose()
|
||||
assert A.is_lower() is True
|
||||
assert B.is_lower() is False
|
||||
@@ -0,0 +1,350 @@
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
from sympy.polys import ZZ, QQ
|
||||
|
||||
from sympy.polys.matrices.ddm import DDM
|
||||
from sympy.polys.matrices.dense import (
|
||||
ddm_transpose,
|
||||
ddm_iadd, ddm_isub, ddm_ineg, ddm_imatmul, ddm_imul, ddm_irref,
|
||||
ddm_idet, ddm_iinv, ddm_ilu, ddm_ilu_split, ddm_ilu_solve, ddm_berk)
|
||||
|
||||
from sympy.polys.matrices.exceptions import (
|
||||
DMDomainError,
|
||||
DMNonInvertibleMatrixError,
|
||||
DMNonSquareMatrixError,
|
||||
DMShapeError,
|
||||
)
|
||||
|
||||
|
||||
def test_ddm_transpose():
|
||||
a = [[1, 2], [3, 4]]
|
||||
assert ddm_transpose(a) == [[1, 3], [2, 4]]
|
||||
|
||||
|
||||
def test_ddm_iadd():
|
||||
a = [[1, 2], [3, 4]]
|
||||
b = [[5, 6], [7, 8]]
|
||||
ddm_iadd(a, b)
|
||||
assert a == [[6, 8], [10, 12]]
|
||||
|
||||
|
||||
def test_ddm_isub():
|
||||
a = [[1, 2], [3, 4]]
|
||||
b = [[5, 6], [7, 8]]
|
||||
ddm_isub(a, b)
|
||||
assert a == [[-4, -4], [-4, -4]]
|
||||
|
||||
|
||||
def test_ddm_ineg():
|
||||
a = [[1, 2], [3, 4]]
|
||||
ddm_ineg(a)
|
||||
assert a == [[-1, -2], [-3, -4]]
|
||||
|
||||
|
||||
def test_ddm_matmul():
|
||||
a = [[1, 2], [3, 4]]
|
||||
ddm_imul(a, 2)
|
||||
assert a == [[2, 4], [6, 8]]
|
||||
|
||||
a = [[1, 2], [3, 4]]
|
||||
ddm_imul(a, 0)
|
||||
assert a == [[0, 0], [0, 0]]
|
||||
|
||||
|
||||
def test_ddm_imatmul():
|
||||
a = [[1, 2, 3], [4, 5, 6]]
|
||||
b = [[1, 2], [3, 4], [5, 6]]
|
||||
|
||||
c1 = [[0, 0], [0, 0]]
|
||||
ddm_imatmul(c1, a, b)
|
||||
assert c1 == [[22, 28], [49, 64]]
|
||||
|
||||
c2 = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
|
||||
ddm_imatmul(c2, b, a)
|
||||
assert c2 == [[9, 12, 15], [19, 26, 33], [29, 40, 51]]
|
||||
|
||||
b3 = [[1], [2], [3]]
|
||||
c3 = [[0], [0]]
|
||||
ddm_imatmul(c3, a, b3)
|
||||
assert c3 == [[14], [32]]
|
||||
|
||||
|
||||
def test_ddm_irref():
|
||||
# Empty matrix
|
||||
A = []
|
||||
Ar = []
|
||||
pivots = []
|
||||
assert ddm_irref(A) == pivots
|
||||
assert A == Ar
|
||||
|
||||
# Standard square case
|
||||
A = [[QQ(0), QQ(1)], [QQ(1), QQ(1)]]
|
||||
Ar = [[QQ(1), QQ(0)], [QQ(0), QQ(1)]]
|
||||
pivots = [0, 1]
|
||||
assert ddm_irref(A) == pivots
|
||||
assert A == Ar
|
||||
|
||||
# m < n case
|
||||
A = [[QQ(1), QQ(2), QQ(1)], [QQ(3), QQ(4), QQ(1)]]
|
||||
Ar = [[QQ(1), QQ(0), QQ(-1)], [QQ(0), QQ(1), QQ(1)]]
|
||||
pivots = [0, 1]
|
||||
assert ddm_irref(A) == pivots
|
||||
assert A == Ar
|
||||
|
||||
# same m < n but reversed
|
||||
A = [[QQ(3), QQ(4), QQ(1)], [QQ(1), QQ(2), QQ(1)]]
|
||||
Ar = [[QQ(1), QQ(0), QQ(-1)], [QQ(0), QQ(1), QQ(1)]]
|
||||
pivots = [0, 1]
|
||||
assert ddm_irref(A) == pivots
|
||||
assert A == Ar
|
||||
|
||||
# m > n case
|
||||
A = [[QQ(1), QQ(0)], [QQ(1), QQ(3)], [QQ(0), QQ(1)]]
|
||||
Ar = [[QQ(1), QQ(0)], [QQ(0), QQ(1)], [QQ(0), QQ(0)]]
|
||||
pivots = [0, 1]
|
||||
assert ddm_irref(A) == pivots
|
||||
assert A == Ar
|
||||
|
||||
# Example with missing pivot
|
||||
A = [[QQ(1), QQ(0), QQ(1)], [QQ(3), QQ(0), QQ(1)]]
|
||||
Ar = [[QQ(1), QQ(0), QQ(0)], [QQ(0), QQ(0), QQ(1)]]
|
||||
pivots = [0, 2]
|
||||
assert ddm_irref(A) == pivots
|
||||
assert A == Ar
|
||||
|
||||
# Example with missing pivot and no replacement
|
||||
A = [[QQ(0), QQ(1)], [QQ(0), QQ(2)], [QQ(1), QQ(0)]]
|
||||
Ar = [[QQ(1), QQ(0)], [QQ(0), QQ(1)], [QQ(0), QQ(0)]]
|
||||
pivots = [0, 1]
|
||||
assert ddm_irref(A) == pivots
|
||||
assert A == Ar
|
||||
|
||||
|
||||
def test_ddm_idet():
|
||||
A = []
|
||||
assert ddm_idet(A, ZZ) == ZZ(1)
|
||||
|
||||
A = [[ZZ(2)]]
|
||||
assert ddm_idet(A, ZZ) == ZZ(2)
|
||||
|
||||
A = [[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]]
|
||||
assert ddm_idet(A, ZZ) == ZZ(-2)
|
||||
|
||||
A = [[ZZ(1), ZZ(2), ZZ(3)], [ZZ(1), ZZ(2), ZZ(4)], [ZZ(1), ZZ(3), ZZ(5)]]
|
||||
assert ddm_idet(A, ZZ) == ZZ(-1)
|
||||
|
||||
A = [[ZZ(1), ZZ(2), ZZ(3)], [ZZ(1), ZZ(2), ZZ(4)], [ZZ(1), ZZ(2), ZZ(5)]]
|
||||
assert ddm_idet(A, ZZ) == ZZ(0)
|
||||
|
||||
A = [[QQ(1, 2), QQ(1, 2)], [QQ(1, 3), QQ(1, 4)]]
|
||||
assert ddm_idet(A, QQ) == QQ(-1, 24)
|
||||
|
||||
|
||||
def test_ddm_inv():
|
||||
A = []
|
||||
Ainv = []
|
||||
ddm_iinv(Ainv, A, QQ)
|
||||
assert Ainv == A
|
||||
|
||||
A = []
|
||||
Ainv = []
|
||||
raises(DMDomainError, lambda: ddm_iinv(Ainv, A, ZZ))
|
||||
|
||||
A = [[QQ(1), QQ(2)]]
|
||||
Ainv = [[QQ(0), QQ(0)]]
|
||||
raises(DMNonSquareMatrixError, lambda: ddm_iinv(Ainv, A, QQ))
|
||||
|
||||
A = [[QQ(1, 1), QQ(2, 1)], [QQ(3, 1), QQ(4, 1)]]
|
||||
Ainv = [[QQ(0), QQ(0)], [QQ(0), QQ(0)]]
|
||||
Ainv_expected = [[QQ(-2, 1), QQ(1, 1)], [QQ(3, 2), QQ(-1, 2)]]
|
||||
ddm_iinv(Ainv, A, QQ)
|
||||
assert Ainv == Ainv_expected
|
||||
|
||||
A = [[QQ(1, 1), QQ(2, 1)], [QQ(2, 1), QQ(4, 1)]]
|
||||
Ainv = [[QQ(0), QQ(0)], [QQ(0), QQ(0)]]
|
||||
raises(DMNonInvertibleMatrixError, lambda: ddm_iinv(Ainv, A, QQ))
|
||||
|
||||
|
||||
def test_ddm_ilu():
|
||||
A = []
|
||||
Alu = []
|
||||
swaps = ddm_ilu(A)
|
||||
assert A == Alu
|
||||
assert swaps == []
|
||||
|
||||
A = [[]]
|
||||
Alu = [[]]
|
||||
swaps = ddm_ilu(A)
|
||||
assert A == Alu
|
||||
assert swaps == []
|
||||
|
||||
A = [[QQ(1), QQ(2)], [QQ(3), QQ(4)]]
|
||||
Alu = [[QQ(1), QQ(2)], [QQ(3), QQ(-2)]]
|
||||
swaps = ddm_ilu(A)
|
||||
assert A == Alu
|
||||
assert swaps == []
|
||||
|
||||
A = [[QQ(0), QQ(2)], [QQ(3), QQ(4)]]
|
||||
Alu = [[QQ(3), QQ(4)], [QQ(0), QQ(2)]]
|
||||
swaps = ddm_ilu(A)
|
||||
assert A == Alu
|
||||
assert swaps == [(0, 1)]
|
||||
|
||||
A = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(5), QQ(6)], [QQ(7), QQ(8), QQ(9)]]
|
||||
Alu = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(-3), QQ(-6)], [QQ(7), QQ(2), QQ(0)]]
|
||||
swaps = ddm_ilu(A)
|
||||
assert A == Alu
|
||||
assert swaps == []
|
||||
|
||||
A = [[QQ(0), QQ(1), QQ(2)], [QQ(0), QQ(1), QQ(3)], [QQ(1), QQ(1), QQ(2)]]
|
||||
Alu = [[QQ(1), QQ(1), QQ(2)], [QQ(0), QQ(1), QQ(3)], [QQ(0), QQ(1), QQ(-1)]]
|
||||
swaps = ddm_ilu(A)
|
||||
assert A == Alu
|
||||
assert swaps == [(0, 2)]
|
||||
|
||||
A = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(5), QQ(6)]]
|
||||
Alu = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(-3), QQ(-6)]]
|
||||
swaps = ddm_ilu(A)
|
||||
assert A == Alu
|
||||
assert swaps == []
|
||||
|
||||
A = [[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]]
|
||||
Alu = [[QQ(1), QQ(2)], [QQ(3), QQ(-2)], [QQ(5), QQ(2)]]
|
||||
swaps = ddm_ilu(A)
|
||||
assert A == Alu
|
||||
assert swaps == []
|
||||
|
||||
|
||||
def test_ddm_ilu_split():
|
||||
U = []
|
||||
L = []
|
||||
Uexp = []
|
||||
Lexp = []
|
||||
swaps = ddm_ilu_split(L, U, QQ)
|
||||
assert U == Uexp
|
||||
assert L == Lexp
|
||||
assert swaps == []
|
||||
|
||||
U = [[]]
|
||||
L = [[QQ(1)]]
|
||||
Uexp = [[]]
|
||||
Lexp = [[QQ(1)]]
|
||||
swaps = ddm_ilu_split(L, U, QQ)
|
||||
assert U == Uexp
|
||||
assert L == Lexp
|
||||
assert swaps == []
|
||||
|
||||
U = [[QQ(1), QQ(2)], [QQ(3), QQ(4)]]
|
||||
L = [[QQ(1), QQ(0)], [QQ(0), QQ(1)]]
|
||||
Uexp = [[QQ(1), QQ(2)], [QQ(0), QQ(-2)]]
|
||||
Lexp = [[QQ(1), QQ(0)], [QQ(3), QQ(1)]]
|
||||
swaps = ddm_ilu_split(L, U, QQ)
|
||||
assert U == Uexp
|
||||
assert L == Lexp
|
||||
assert swaps == []
|
||||
|
||||
U = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(5), QQ(6)]]
|
||||
L = [[QQ(1), QQ(0)], [QQ(0), QQ(1)]]
|
||||
Uexp = [[QQ(1), QQ(2), QQ(3)], [QQ(0), QQ(-3), QQ(-6)]]
|
||||
Lexp = [[QQ(1), QQ(0)], [QQ(4), QQ(1)]]
|
||||
swaps = ddm_ilu_split(L, U, QQ)
|
||||
assert U == Uexp
|
||||
assert L == Lexp
|
||||
assert swaps == []
|
||||
|
||||
U = [[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]]
|
||||
L = [[QQ(1), QQ(0), QQ(0)], [QQ(0), QQ(1), QQ(0)], [QQ(0), QQ(0), QQ(1)]]
|
||||
Uexp = [[QQ(1), QQ(2)], [QQ(0), QQ(-2)], [QQ(0), QQ(0)]]
|
||||
Lexp = [[QQ(1), QQ(0), QQ(0)], [QQ(3), QQ(1), QQ(0)], [QQ(5), QQ(2), QQ(1)]]
|
||||
swaps = ddm_ilu_split(L, U, QQ)
|
||||
assert U == Uexp
|
||||
assert L == Lexp
|
||||
assert swaps == []
|
||||
|
||||
|
||||
def test_ddm_ilu_solve():
|
||||
# Basic example
|
||||
# A = [[QQ(1), QQ(2)], [QQ(3), QQ(4)]]
|
||||
U = [[QQ(1), QQ(2)], [QQ(0), QQ(-2)]]
|
||||
L = [[QQ(1), QQ(0)], [QQ(3), QQ(1)]]
|
||||
swaps = []
|
||||
b = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ)
|
||||
x = DDM([[QQ(0)], [QQ(0)]], (2, 1), QQ)
|
||||
xexp = DDM([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ)
|
||||
ddm_ilu_solve(x, L, U, swaps, b)
|
||||
assert x == xexp
|
||||
|
||||
# Example with swaps
|
||||
# A = [[QQ(0), QQ(2)], [QQ(3), QQ(4)]]
|
||||
U = [[QQ(3), QQ(4)], [QQ(0), QQ(2)]]
|
||||
L = [[QQ(1), QQ(0)], [QQ(0), QQ(1)]]
|
||||
swaps = [(0, 1)]
|
||||
b = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ)
|
||||
x = DDM([[QQ(0)], [QQ(0)]], (2, 1), QQ)
|
||||
xexp = DDM([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ)
|
||||
ddm_ilu_solve(x, L, U, swaps, b)
|
||||
assert x == xexp
|
||||
|
||||
# Overdetermined, consistent
|
||||
# A = DDM([[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]], (3, 2), QQ)
|
||||
U = [[QQ(1), QQ(2)], [QQ(0), QQ(-2)], [QQ(0), QQ(0)]]
|
||||
L = [[QQ(1), QQ(0), QQ(0)], [QQ(3), QQ(1), QQ(0)], [QQ(5), QQ(2), QQ(1)]]
|
||||
swaps = []
|
||||
b = DDM([[QQ(1)], [QQ(2)], [QQ(3)]], (3, 1), QQ)
|
||||
x = DDM([[QQ(0)], [QQ(0)]], (2, 1), QQ)
|
||||
xexp = DDM([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ)
|
||||
ddm_ilu_solve(x, L, U, swaps, b)
|
||||
assert x == xexp
|
||||
|
||||
# Overdetermined, inconsistent
|
||||
b = DDM([[QQ(1)], [QQ(2)], [QQ(4)]], (3, 1), QQ)
|
||||
raises(DMNonInvertibleMatrixError, lambda: ddm_ilu_solve(x, L, U, swaps, b))
|
||||
|
||||
# Square, noninvertible
|
||||
# A = DDM([[QQ(1), QQ(2)], [QQ(1), QQ(2)]], (2, 2), QQ)
|
||||
U = [[QQ(1), QQ(2)], [QQ(0), QQ(0)]]
|
||||
L = [[QQ(1), QQ(0)], [QQ(1), QQ(1)]]
|
||||
swaps = []
|
||||
b = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ)
|
||||
raises(DMNonInvertibleMatrixError, lambda: ddm_ilu_solve(x, L, U, swaps, b))
|
||||
|
||||
# Underdetermined
|
||||
# A = DDM([[QQ(1), QQ(2)]], (1, 2), QQ)
|
||||
U = [[QQ(1), QQ(2)]]
|
||||
L = [[QQ(1)]]
|
||||
swaps = []
|
||||
b = DDM([[QQ(3)]], (1, 1), QQ)
|
||||
raises(NotImplementedError, lambda: ddm_ilu_solve(x, L, U, swaps, b))
|
||||
|
||||
# Shape mismatch
|
||||
b3 = DDM([[QQ(1)], [QQ(2)], [QQ(3)]], (3, 1), QQ)
|
||||
raises(DMShapeError, lambda: ddm_ilu_solve(x, L, U, swaps, b3))
|
||||
|
||||
# Empty shape mismatch
|
||||
U = [[QQ(1)]]
|
||||
L = [[QQ(1)]]
|
||||
swaps = []
|
||||
x = [[QQ(1)]]
|
||||
b = []
|
||||
raises(DMShapeError, lambda: ddm_ilu_solve(x, L, U, swaps, b))
|
||||
|
||||
# Empty system
|
||||
U = []
|
||||
L = []
|
||||
swaps = []
|
||||
b = []
|
||||
x = []
|
||||
ddm_ilu_solve(x, L, U, swaps, b)
|
||||
assert x == []
|
||||
|
||||
|
||||
def test_ddm_charpoly():
|
||||
A = []
|
||||
assert ddm_berk(A, ZZ) == [[ZZ(1)]]
|
||||
|
||||
A = [[ZZ(1), ZZ(2), ZZ(3)], [ZZ(4), ZZ(5), ZZ(6)], [ZZ(7), ZZ(8), ZZ(9)]]
|
||||
Avec = [[ZZ(1)], [ZZ(-15)], [ZZ(-18)], [ZZ(0)]]
|
||||
assert ddm_berk(A, ZZ) == Avec
|
||||
|
||||
A = DDM([[ZZ(1), ZZ(2)]], (1, 2), ZZ)
|
||||
raises(DMShapeError, lambda: ddm_berk(A, ZZ))
|
||||
+1383
File diff suppressed because it is too large
Load Diff
+153
@@ -0,0 +1,153 @@
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
from sympy.core.symbol import S
|
||||
from sympy.polys import ZZ, QQ
|
||||
from sympy.polys.matrices.domainscalar import DomainScalar
|
||||
from sympy.polys.matrices.domainmatrix import DomainMatrix
|
||||
|
||||
|
||||
def test_DomainScalar___new__():
|
||||
raises(TypeError, lambda: DomainScalar(ZZ(1), QQ))
|
||||
raises(TypeError, lambda: DomainScalar(ZZ(1), 1))
|
||||
|
||||
|
||||
def test_DomainScalar_new():
|
||||
A = DomainScalar(ZZ(1), ZZ)
|
||||
B = A.new(ZZ(4), ZZ)
|
||||
assert B == DomainScalar(ZZ(4), ZZ)
|
||||
|
||||
|
||||
def test_DomainScalar_repr():
|
||||
A = DomainScalar(ZZ(1), ZZ)
|
||||
assert repr(A) in {'1', 'mpz(1)'}
|
||||
|
||||
|
||||
def test_DomainScalar_from_sympy():
|
||||
expr = S(1)
|
||||
B = DomainScalar.from_sympy(expr)
|
||||
assert B == DomainScalar(ZZ(1), ZZ)
|
||||
|
||||
|
||||
def test_DomainScalar_to_sympy():
|
||||
B = DomainScalar(ZZ(1), ZZ)
|
||||
expr = B.to_sympy()
|
||||
assert expr.is_Integer and expr == 1
|
||||
|
||||
|
||||
def test_DomainScalar_to_domain():
|
||||
A = DomainScalar(ZZ(1), ZZ)
|
||||
B = A.to_domain(QQ)
|
||||
assert B == DomainScalar(QQ(1), QQ)
|
||||
|
||||
|
||||
def test_DomainScalar_convert_to():
|
||||
A = DomainScalar(ZZ(1), ZZ)
|
||||
B = A.convert_to(QQ)
|
||||
assert B == DomainScalar(QQ(1), QQ)
|
||||
|
||||
|
||||
def test_DomainScalar_unify():
|
||||
A = DomainScalar(ZZ(1), ZZ)
|
||||
B = DomainScalar(QQ(2), QQ)
|
||||
A, B = A.unify(B)
|
||||
assert A.domain == B.domain == QQ
|
||||
|
||||
|
||||
def test_DomainScalar_add():
|
||||
A = DomainScalar(ZZ(1), ZZ)
|
||||
B = DomainScalar(QQ(2), QQ)
|
||||
assert A + B == DomainScalar(QQ(3), QQ)
|
||||
|
||||
raises(TypeError, lambda: A + 1.5)
|
||||
|
||||
def test_DomainScalar_sub():
|
||||
A = DomainScalar(ZZ(1), ZZ)
|
||||
B = DomainScalar(QQ(2), QQ)
|
||||
assert A - B == DomainScalar(QQ(-1), QQ)
|
||||
|
||||
raises(TypeError, lambda: A - 1.5)
|
||||
|
||||
def test_DomainScalar_mul():
|
||||
A = DomainScalar(ZZ(1), ZZ)
|
||||
B = DomainScalar(QQ(2), QQ)
|
||||
dm = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
|
||||
assert A * B == DomainScalar(QQ(2), QQ)
|
||||
assert A * dm == dm
|
||||
assert B * 2 == DomainScalar(QQ(4), QQ)
|
||||
|
||||
raises(TypeError, lambda: A * 1.5)
|
||||
|
||||
|
||||
def test_DomainScalar_floordiv():
|
||||
A = DomainScalar(ZZ(-5), ZZ)
|
||||
B = DomainScalar(QQ(2), QQ)
|
||||
assert A // B == DomainScalar(QQ(-5, 2), QQ)
|
||||
C = DomainScalar(ZZ(2), ZZ)
|
||||
assert A // C == DomainScalar(ZZ(-3), ZZ)
|
||||
|
||||
raises(TypeError, lambda: A // 1.5)
|
||||
|
||||
|
||||
def test_DomainScalar_mod():
|
||||
A = DomainScalar(ZZ(5), ZZ)
|
||||
B = DomainScalar(QQ(2), QQ)
|
||||
assert A % B == DomainScalar(QQ(0), QQ)
|
||||
C = DomainScalar(ZZ(2), ZZ)
|
||||
assert A % C == DomainScalar(ZZ(1), ZZ)
|
||||
|
||||
raises(TypeError, lambda: A % 1.5)
|
||||
|
||||
|
||||
def test_DomainScalar_divmod():
|
||||
A = DomainScalar(ZZ(5), ZZ)
|
||||
B = DomainScalar(QQ(2), QQ)
|
||||
assert divmod(A, B) == (DomainScalar(QQ(5, 2), QQ), DomainScalar(QQ(0), QQ))
|
||||
C = DomainScalar(ZZ(2), ZZ)
|
||||
assert divmod(A, C) == (DomainScalar(ZZ(2), ZZ), DomainScalar(ZZ(1), ZZ))
|
||||
|
||||
raises(TypeError, lambda: divmod(A, 1.5))
|
||||
|
||||
|
||||
def test_DomainScalar_pow():
|
||||
A = DomainScalar(ZZ(-5), ZZ)
|
||||
B = A**(2)
|
||||
assert B == DomainScalar(ZZ(25), ZZ)
|
||||
|
||||
raises(TypeError, lambda: A**(1.5))
|
||||
|
||||
|
||||
def test_DomainScalar_pos():
|
||||
A = DomainScalar(QQ(2), QQ)
|
||||
B = DomainScalar(QQ(2), QQ)
|
||||
assert +A == B
|
||||
|
||||
|
||||
def test_DomainScalar_neg():
|
||||
A = DomainScalar(QQ(2), QQ)
|
||||
B = DomainScalar(QQ(-2), QQ)
|
||||
assert -A == B
|
||||
|
||||
|
||||
def test_DomainScalar_eq():
|
||||
A = DomainScalar(QQ(2), QQ)
|
||||
assert A == A
|
||||
B = DomainScalar(ZZ(-5), ZZ)
|
||||
assert A != B
|
||||
C = DomainScalar(ZZ(2), ZZ)
|
||||
assert A != C
|
||||
D = [1]
|
||||
assert A != D
|
||||
|
||||
|
||||
def test_DomainScalar_isZero():
|
||||
A = DomainScalar(ZZ(0), ZZ)
|
||||
assert A.is_zero() == True
|
||||
B = DomainScalar(ZZ(1), ZZ)
|
||||
assert B.is_zero() == False
|
||||
|
||||
|
||||
def test_DomainScalar_isOne():
|
||||
A = DomainScalar(ZZ(1), ZZ)
|
||||
assert A.is_one() == True
|
||||
B = DomainScalar(ZZ(0), ZZ)
|
||||
assert B.is_one() == False
|
||||
@@ -0,0 +1,90 @@
|
||||
"""
|
||||
Tests for the sympy.polys.matrices.eigen module
|
||||
"""
|
||||
|
||||
from sympy.core.singleton import S
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.matrices.dense import Matrix
|
||||
|
||||
from sympy.polys.agca.extensions import FiniteExtension
|
||||
from sympy.polys.domains import QQ
|
||||
from sympy.polys.polytools import Poly
|
||||
from sympy.polys.rootoftools import CRootOf
|
||||
from sympy.polys.matrices.domainmatrix import DomainMatrix
|
||||
|
||||
from sympy.polys.matrices.eigen import dom_eigenvects, dom_eigenvects_to_sympy
|
||||
|
||||
|
||||
def test_dom_eigenvects_rational():
|
||||
# Rational eigenvalues
|
||||
A = DomainMatrix([[QQ(1), QQ(2)], [QQ(1), QQ(2)]], (2, 2), QQ)
|
||||
rational_eigenvects = [
|
||||
(QQ, QQ(3), 1, DomainMatrix([[QQ(1), QQ(1)]], (1, 2), QQ)),
|
||||
(QQ, QQ(0), 1, DomainMatrix([[QQ(-2), QQ(1)]], (1, 2), QQ)),
|
||||
]
|
||||
assert dom_eigenvects(A) == (rational_eigenvects, [])
|
||||
|
||||
# Test converting to Expr:
|
||||
sympy_eigenvects = [
|
||||
(S(3), 1, [Matrix([1, 1])]),
|
||||
(S(0), 1, [Matrix([-2, 1])]),
|
||||
]
|
||||
assert dom_eigenvects_to_sympy(rational_eigenvects, [], Matrix) == sympy_eigenvects
|
||||
|
||||
|
||||
def test_dom_eigenvects_algebraic():
|
||||
# Algebraic eigenvalues
|
||||
A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ)
|
||||
Avects = dom_eigenvects(A)
|
||||
|
||||
# Extract the dummy to build the expected result:
|
||||
lamda = Avects[1][0][1].gens[0]
|
||||
irreducible = Poly(lamda**2 - 5*lamda - 2, lamda, domain=QQ)
|
||||
K = FiniteExtension(irreducible)
|
||||
KK = K.from_sympy
|
||||
algebraic_eigenvects = [
|
||||
(K, irreducible, 1, DomainMatrix([[KK((lamda-4)/3), KK(1)]], (1, 2), K)),
|
||||
]
|
||||
assert Avects == ([], algebraic_eigenvects)
|
||||
|
||||
# Test converting to Expr:
|
||||
sympy_eigenvects = [
|
||||
(S(5)/2 - sqrt(33)/2, 1, [Matrix([[-sqrt(33)/6 - S(1)/2], [1]])]),
|
||||
(S(5)/2 + sqrt(33)/2, 1, [Matrix([[-S(1)/2 + sqrt(33)/6], [1]])]),
|
||||
]
|
||||
assert dom_eigenvects_to_sympy([], algebraic_eigenvects, Matrix) == sympy_eigenvects
|
||||
|
||||
|
||||
def test_dom_eigenvects_rootof():
|
||||
# Algebraic eigenvalues
|
||||
A = DomainMatrix([
|
||||
[0, 0, 0, 0, -1],
|
||||
[1, 0, 0, 0, 1],
|
||||
[0, 1, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 1, 0]], (5, 5), QQ)
|
||||
Avects = dom_eigenvects(A)
|
||||
|
||||
# Extract the dummy to build the expected result:
|
||||
lamda = Avects[1][0][1].gens[0]
|
||||
irreducible = Poly(lamda**5 - lamda + 1, lamda, domain=QQ)
|
||||
K = FiniteExtension(irreducible)
|
||||
KK = K.from_sympy
|
||||
algebraic_eigenvects = [
|
||||
(K, irreducible, 1,
|
||||
DomainMatrix([
|
||||
[KK(lamda**4-1), KK(lamda**3), KK(lamda**2), KK(lamda), KK(1)]
|
||||
], (1, 5), K)),
|
||||
]
|
||||
assert Avects == ([], algebraic_eigenvects)
|
||||
|
||||
# Test converting to Expr (slow):
|
||||
l0, l1, l2, l3, l4 = [CRootOf(lamda**5 - lamda + 1, i) for i in range(5)]
|
||||
sympy_eigenvects = [
|
||||
(l0, 1, [Matrix([-1 + l0**4, l0**3, l0**2, l0, 1])]),
|
||||
(l1, 1, [Matrix([-1 + l1**4, l1**3, l1**2, l1, 1])]),
|
||||
(l2, 1, [Matrix([-1 + l2**4, l2**3, l2**2, l2, 1])]),
|
||||
(l3, 1, [Matrix([-1 + l3**4, l3**3, l3**2, l3, 1])]),
|
||||
(l4, 1, [Matrix([-1 + l4**4, l4**3, l4**2, l4, 1])]),
|
||||
]
|
||||
assert dom_eigenvects_to_sympy([], algebraic_eigenvects, Matrix) == sympy_eigenvects
|
||||
@@ -0,0 +1,301 @@
|
||||
from sympy.polys.matrices import DomainMatrix, DM
|
||||
from sympy.polys.domains import ZZ, QQ
|
||||
from sympy import Matrix
|
||||
import pytest
|
||||
|
||||
|
||||
FFLU_EXAMPLES = [
|
||||
(
|
||||
'zz_2x3',
|
||||
DM([[1, 2, 3], [4, 5, 6]], ZZ),
|
||||
DM([[1, 0], [0, 1]], ZZ),
|
||||
DM([[1, 0], [4, -3]], ZZ),
|
||||
DM([[1, 0], [0, -3]], ZZ),
|
||||
DM([[1, 2, 3], [0, -3, -6]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_2x2',
|
||||
DM([[4, 3], [6, 3]], ZZ),
|
||||
DM([[1, 0], [0, 1]], ZZ),
|
||||
DM([[1, 0], [6, -6]], ZZ),
|
||||
DM([[4, 0], [0, -3]], ZZ),
|
||||
DM([[4, 3], [0, -3]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_3x2',
|
||||
DM([[1, 2], [3, 4], [5, 6]], ZZ),
|
||||
DM([[1, 0, 0], [0, 1, 0], [0, 0, 1]], ZZ),
|
||||
DM([[1, 0, 0], [3, 1, 0], [5, 2, 1]], ZZ),
|
||||
DM([[1, 0], [0, -2]], ZZ),
|
||||
DM([[1, 2], [0, -2], [0, 0]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_3x3',
|
||||
DM([[1, 2, 3], [4, 5, 6], [7, 8, 9]], ZZ),
|
||||
DM([[1, 0, 0], [0, 1, 0], [0, 0, 1]], ZZ),
|
||||
DM([[1, 0, 0], [4, 1, 0], [7, 2, 1]], ZZ),
|
||||
DM([[1, 0, 0], [0, -3, 0], [0, 0, 0]], ZZ),
|
||||
DM([[1, 2, 3], [0, -3, -6], [0, 0, 0]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_zero',
|
||||
DM([[0, 0, 0], [0, 0, 0], [0, 0, 0]], ZZ),
|
||||
DM([[1, 0, 0], [0, 1, 0], [0, 0, 1]], ZZ),
|
||||
DM([[1, 0, 0], [0, 1, 0], [0, 0, 1]], ZZ),
|
||||
DM([[0, 0, 0], [0, 0, 0], [0, 0, 0]], ZZ),
|
||||
DM([[0, 0, 0], [0, 0, 0], [0, 0, 0]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_empty',
|
||||
DM([], ZZ),
|
||||
DM([], ZZ),
|
||||
DM([], ZZ),
|
||||
DM([], ZZ),
|
||||
DM([], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_empty_0x2',
|
||||
DomainMatrix([], (0, 2), ZZ),
|
||||
DomainMatrix([], (0, 0), ZZ),
|
||||
DomainMatrix([], (0, 0), ZZ),
|
||||
DomainMatrix([], (0, 0), ZZ),
|
||||
DomainMatrix([], (0, 2), ZZ)
|
||||
),
|
||||
|
||||
(
|
||||
|
||||
'zz_empty_2x0',
|
||||
DomainMatrix([[], []], (2, 0), ZZ),
|
||||
DomainMatrix.eye((2, 2), ZZ),
|
||||
DomainMatrix.eye((2, 2), ZZ),
|
||||
DomainMatrix.eye((2, 2), ZZ),
|
||||
DomainMatrix([[], []], (2, 0), ZZ)
|
||||
|
||||
),
|
||||
|
||||
(
|
||||
'zz_negative',
|
||||
DM([[-1, -2], [-3, -4]], ZZ),
|
||||
DM([[1, 0], [0, 1]], ZZ),
|
||||
DM([[-1, 0], [-3, -2]], ZZ),
|
||||
DM([[-1, 0], [0, 2]], ZZ),
|
||||
DM([[-1, -2], [0, -2]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_mixed_signs',
|
||||
DM([[1, -2], [-3, 4]], ZZ),
|
||||
DM([[1, 0], [0, 1]], ZZ),
|
||||
DM([[1, 0], [-3, 1]], ZZ),
|
||||
DM([[1, 0], [0, -2]], ZZ),
|
||||
DM([[1, -2], [0, -2]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_upper_triangular',
|
||||
DM([[1, 2, 3], [0, 4, 5], [0, 0, 6]], ZZ),
|
||||
DM([[1, 0, 0], [0, 1, 0], [0, 0, 1]], ZZ),
|
||||
DM([[1, 0, 0], [0, 4, 0], [0, 0, 24]], ZZ),
|
||||
DM([[1, 0, 0], [0, 4, 0], [0, 0, 96]], ZZ),
|
||||
DM([[1, 2, 3], [0, 4, 5], [0, 0, 24]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_lower_triangular',
|
||||
DM([[1, 0, 0], [2, 3, 0], [4, 5, 6]], ZZ),
|
||||
DM([[1, 0, 0], [0, 1, 0], [0, 0, 1]], ZZ),
|
||||
DM([[1, 0, 0], [2, 3, 0], [4, 5, 18]], ZZ),
|
||||
DM([[1, 0, 0], [0, 3, 0], [0, 0, 54]], ZZ),
|
||||
DM([[1, 0, 0], [0, 3, 0], [0, 0, 18]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_diagonal',
|
||||
DM([[2, 0, 0], [0, 3, 0], [0, 0, 4]], ZZ),
|
||||
DM([[1, 0, 0], [0, 1, 0], [0, 0, 1]], ZZ),
|
||||
DM([[2, 0, 0], [0, 6, 0], [0, 0, 24]], ZZ),
|
||||
DM([[2, 0, 0], [0, 12, 0], [0, 0, 144]], ZZ),
|
||||
DM([[2, 0, 0], [0, 6, 0], [0, 0, 24]], ZZ)
|
||||
|
||||
),
|
||||
|
||||
(
|
||||
'rank_deficient_3x3',
|
||||
DM([[1, 2, 3], [2, 4, 6], [3, 6, 9]], ZZ),
|
||||
DM([[1, 0, 0], [0, 1, 0], [0, 0, 1]], ZZ),
|
||||
DM([[1, 0, 0], [2, 1, 0], [3, 0, 1]], ZZ),
|
||||
DM([[1, 0, 0], [0, 0, 0], [0, 0, 0]], ZZ),
|
||||
DM([[1, 2, 3], [0, 0, 0], [0, 0, 0]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_1x1',
|
||||
DM([[5]], ZZ),
|
||||
DM([[1]], ZZ),
|
||||
DM([[5]], ZZ),
|
||||
DM([[5]], ZZ),
|
||||
DM([[5]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_nx1_2rows',
|
||||
DM([[81], [54]], ZZ),
|
||||
DM([[1, 0], [0, 1]], ZZ),
|
||||
DM([[81, 0], [54, 81]], ZZ),
|
||||
DM([[81, 0], [0, 81]], ZZ),
|
||||
DM([[81], [0]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_nx2_3rows',
|
||||
DM([[2, 7], [7, 45], [25, 84]], ZZ),
|
||||
DM([[1, 0, 0], [0, 1, 0], [0, 0, 1]], ZZ),
|
||||
DM([[2, 0, 0], [7, 82, 0], [25, 41, 41]], ZZ),
|
||||
DM([[2, 0, 0], [0, 82, 0], [0, 0, 41]], ZZ),
|
||||
DM([[2, 7], [0, 82], [0, 0]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
|
||||
'zz_1x2',
|
||||
DM([[0, 28]], ZZ),
|
||||
DM([[1]], ZZ),
|
||||
DM([[28]], ZZ),
|
||||
DM([[28]], ZZ),
|
||||
DM([[0, 28]], ZZ)
|
||||
),
|
||||
|
||||
(
|
||||
'zz_nx3_4rows',
|
||||
DM([[84, 30, 9], [20, 59, 13], [53, 46, 81], [63, 48, 29]], ZZ),
|
||||
DM([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], ZZ),
|
||||
DM([[84, 0, 0, 0], [20, 365904, 0, 0], [53, 303411, 303411, 0], [63, 303411, 303411, 303411]], ZZ),
|
||||
DM([[84, 0, 0, 0], [0, 365904, 0, 0], [0, 0, 1321658316, 0], [0, 0, 0, 303411]], ZZ),
|
||||
DM([[84, 30, 9], [0, 365904, 13], [0, 0, 1321658316], [0, 0, 0]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'fflu_row_swap',
|
||||
DM([[0, 1, 2], [3, 4, 5], [6, 7, 8]], ZZ),
|
||||
DM([[0, 1, 0], [1, 0, 0], [0, 0, 1]], ZZ),
|
||||
DM([[3, 0, 0], [0, 3, 0], [6, -3, 1]], ZZ),
|
||||
DM([[3, 0, 0], [0, 9, 0], [0, 0, 3]], ZZ),
|
||||
DM([[3, 4, 5], [0, 3, 6], [0, 0, 0]], ZZ)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def _check_fflu(A, P, L, D, U):
|
||||
P_field = P.to_field().to_dense()
|
||||
L_field = L.to_field().to_dense()
|
||||
D_field = D.to_field().to_dense()
|
||||
U_field = U.to_field().to_dense()
|
||||
m, n = A.shape
|
||||
assert P_field.shape == (m, m)
|
||||
assert L_field.shape == (m, m)
|
||||
assert D_field.shape == (m, m)
|
||||
assert U_field.shape == (m, n)
|
||||
assert L_field.is_lower
|
||||
assert D_field.is_diagonal
|
||||
di, d = D.inv_den()
|
||||
assert P.matmul(A).rmul(d) == L.matmul(di).matmul(U)
|
||||
assert U_field.is_upper
|
||||
|
||||
|
||||
def _to_DM(A, ans):
|
||||
if isinstance(A, DomainMatrix):
|
||||
return A
|
||||
elif isinstance(A, Matrix):
|
||||
return A.to_DM(ans.domain)
|
||||
return DomainMatrix(A.to_list(), A.shape, A.domain)
|
||||
|
||||
|
||||
def _check_fflu_result(result, A, P_ans, L_ans, D_ans, U_ans):
|
||||
P, L, D, U = result
|
||||
P = _to_DM(P, P_ans)
|
||||
L = _to_DM(L, L_ans)
|
||||
D = _to_DM(D, D_ans)
|
||||
U = _to_DM(U, U_ans)
|
||||
A = _to_DM(A, P_ans)
|
||||
m, n = A.shape
|
||||
assert P.shape == (m, m)
|
||||
assert L.shape == (m, m)
|
||||
assert D.shape == (m, m)
|
||||
assert U.shape == (m, n)
|
||||
assert L.is_lower
|
||||
assert D.is_diagonal
|
||||
di, d = D.inv_den()
|
||||
assert P.matmul(A).rmul(d) == L.matmul(di).matmul(U)
|
||||
assert U.is_upper
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, P_ans, L_ans, D_ans, U_ans', FFLU_EXAMPLES)
|
||||
def test_dm_dense_fflu(name, A, P_ans, L_ans, D_ans, U_ans):
|
||||
A = A.to_dense()
|
||||
_check_fflu_result(A.fflu(), A, P_ans, L_ans, D_ans, U_ans)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, P_ans, L_ans, D_ans, U_ans', FFLU_EXAMPLES)
|
||||
def test_dm_sparse_fflu(name, A, P_ans, L_ans, D_ans, U_ans):
|
||||
A = A.to_sparse()
|
||||
_check_fflu_result(A.fflu(), A, P_ans, L_ans, D_ans, U_ans)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, P_ans, L_ans, D_ans, U_ans', FFLU_EXAMPLES)
|
||||
def test_ddm_fflu(name, A, P_ans, L_ans, D_ans, U_ans):
|
||||
A = A.to_ddm()
|
||||
_check_fflu_result(A.fflu(), A, P_ans, L_ans, D_ans, U_ans)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, P_ans, L_ans, D_ans, U_ans', FFLU_EXAMPLES)
|
||||
def test_sdm_fflu(name, A, P_ans, L_ans, D_ans, U_ans):
|
||||
A = A.to_sdm()
|
||||
_check_fflu_result(A.fflu(), A, P_ans, L_ans, D_ans, U_ans)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, P_ans, L_ans, D_ans, U_ans', FFLU_EXAMPLES)
|
||||
def test_dfm_fflu(name, A, P_ans, L_ans, D_ans, U_ans):
|
||||
pytest.importorskip('flint')
|
||||
if A.domain not in (ZZ, QQ) and not A.domain.is_FF:
|
||||
pytest.skip("Domain not supported by DFM")
|
||||
A = A.to_dfm()
|
||||
_check_fflu_result(A.fflu(), A, P_ans, L_ans, D_ans, U_ans)
|
||||
|
||||
|
||||
def test_fflu_empty_matrix():
|
||||
A = DomainMatrix([], (0, 0), ZZ)
|
||||
P, L, D, U = A.fflu()
|
||||
assert P.shape == (0, 0)
|
||||
assert L.shape == (0, 0)
|
||||
assert D.shape == (0, 0)
|
||||
assert U.shape == (0, 0)
|
||||
|
||||
|
||||
def test_fflu_properties():
|
||||
A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
|
||||
P, L, D, U = A.fflu()
|
||||
assert P.shape == (2, 2)
|
||||
assert L.shape == (2, 2)
|
||||
assert D.shape == (2, 2)
|
||||
assert U.shape == (2, 2)
|
||||
assert L.is_lower
|
||||
assert U.is_upper
|
||||
assert D.is_diagonal
|
||||
di, d = D.inv_den()
|
||||
assert P.matmul(A).rmul(d) == L.matmul(di).matmul(U)
|
||||
|
||||
|
||||
def test_fflu_rank_deficient():
|
||||
A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(2), ZZ(4)]], (2, 2), ZZ)
|
||||
P, L, D, U = A.fflu()
|
||||
assert P.shape == (2, 2)
|
||||
assert L.shape == (2, 2)
|
||||
assert D.shape == (2, 2)
|
||||
assert U.shape == (2, 2)
|
||||
assert U.getitem_sympy(1, 1) == 0
|
||||
@@ -0,0 +1,193 @@
|
||||
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)
|
||||
@@ -0,0 +1,112 @@
|
||||
#
|
||||
# test_linsolve.py
|
||||
#
|
||||
# Test the internal implementation of linsolve.
|
||||
#
|
||||
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
from sympy.core.numbers import I
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.core.singleton import S
|
||||
from sympy.abc import x, y, z
|
||||
|
||||
from sympy.polys.matrices.linsolve import _linsolve
|
||||
from sympy.polys.solvers import PolyNonlinearError
|
||||
|
||||
|
||||
def test__linsolve():
|
||||
assert _linsolve([], [x]) == {x:x}
|
||||
assert _linsolve([S.Zero], [x]) == {x:x}
|
||||
assert _linsolve([x-1,x-2], [x]) is None
|
||||
assert _linsolve([x-1], [x]) == {x:1}
|
||||
assert _linsolve([x-1, y], [x, y]) == {x:1, y:S.Zero}
|
||||
assert _linsolve([2*I], [x]) is None
|
||||
raises(PolyNonlinearError, lambda: _linsolve([x*(1 + x)], [x]))
|
||||
|
||||
|
||||
def test__linsolve_float():
|
||||
|
||||
# This should give the exact answer:
|
||||
eqs = [
|
||||
y - x,
|
||||
y - 0.0216 * x
|
||||
]
|
||||
# Should _linsolve return floats here?
|
||||
sol = {x:0, y:0}
|
||||
assert _linsolve(eqs, (x, y)) == sol
|
||||
|
||||
# Other cases should be close to eps
|
||||
|
||||
def all_close(sol1, sol2, eps=1e-15):
|
||||
close = lambda a, b: abs(a - b) < eps
|
||||
assert sol1.keys() == sol2.keys()
|
||||
return all(close(sol1[s], sol2[s]) for s in sol1)
|
||||
|
||||
eqs = [
|
||||
0.8*x + 0.8*z + 0.2,
|
||||
0.9*x + 0.7*y + 0.2*z + 0.9,
|
||||
0.7*x + 0.2*y + 0.2*z + 0.5
|
||||
]
|
||||
sol_exact = {x:-29/42, y:-11/21, z:37/84}
|
||||
sol_linsolve = _linsolve(eqs, [x,y,z])
|
||||
assert all_close(sol_exact, sol_linsolve)
|
||||
|
||||
eqs = [
|
||||
0.9*x + 0.3*y + 0.4*z + 0.6,
|
||||
0.6*x + 0.9*y + 0.1*z + 0.7,
|
||||
0.4*x + 0.6*y + 0.9*z + 0.5
|
||||
]
|
||||
sol_exact = {x:-88/175, y:-46/105, z:-1/25}
|
||||
sol_linsolve = _linsolve(eqs, [x,y,z])
|
||||
assert all_close(sol_exact, sol_linsolve)
|
||||
|
||||
eqs = [
|
||||
0.4*x + 0.3*y + 0.6*z + 0.7,
|
||||
0.4*x + 0.3*y + 0.9*z + 0.9,
|
||||
0.7*x + 0.9*y,
|
||||
]
|
||||
sol_exact = {x:-9/5, y:7/5, z:-2/3}
|
||||
sol_linsolve = _linsolve(eqs, [x,y,z])
|
||||
assert all_close(sol_exact, sol_linsolve)
|
||||
|
||||
eqs = [
|
||||
x*(0.7 + 0.6*I) + y*(0.4 + 0.7*I) + z*(0.9 + 0.1*I) + 0.5,
|
||||
0.2*I*x + 0.2*I*y + z*(0.9 + 0.2*I) + 0.1,
|
||||
x*(0.9 + 0.7*I) + y*(0.9 + 0.7*I) + z*(0.9 + 0.4*I) + 0.4,
|
||||
]
|
||||
sol_exact = {
|
||||
x:-6157/7995 - 411/5330*I,
|
||||
y:8519/15990 + 1784/7995*I,
|
||||
z:-34/533 + 107/1599*I,
|
||||
}
|
||||
sol_linsolve = _linsolve(eqs, [x,y,z])
|
||||
assert all_close(sol_exact, sol_linsolve)
|
||||
|
||||
# XXX: This system for x and y over RR(z) is problematic.
|
||||
#
|
||||
# eqs = [
|
||||
# x*(0.2*z + 0.9) + y*(0.5*z + 0.8) + 0.6,
|
||||
# 0.1*x*z + y*(0.1*z + 0.6) + 0.9,
|
||||
# ]
|
||||
#
|
||||
# linsolve(eqs, [x, y])
|
||||
# The solution for x comes out as
|
||||
#
|
||||
# -3.9e-5*z**2 - 3.6e-5*z - 8.67361737988404e-20
|
||||
# x = ----------------------------------------------
|
||||
# 3.0e-6*z**3 - 1.3e-5*z**2 - 5.4e-5*z
|
||||
#
|
||||
# The 8e-20 in the numerator should be zero which would allow z to cancel
|
||||
# from top and bottom. It should be possible to avoid this somehow because
|
||||
# the inverse of the matrix only has a quadratic factor (the determinant)
|
||||
# in the denominator.
|
||||
|
||||
|
||||
def test__linsolve_deprecated():
|
||||
raises(PolyNonlinearError, lambda:
|
||||
_linsolve([Eq(x**2, x**2 + y)], [x, y]))
|
||||
raises(PolyNonlinearError, lambda:
|
||||
_linsolve([(x + y)**2 - x**2], [x]))
|
||||
raises(PolyNonlinearError, lambda:
|
||||
_linsolve([Eq((x + y)**2, x**2)], [x]))
|
||||
@@ -0,0 +1,145 @@
|
||||
from sympy.polys.domains import ZZ, QQ
|
||||
from sympy.polys.matrices import DM
|
||||
from sympy.polys.matrices.domainmatrix import DomainMatrix
|
||||
from sympy.polys.matrices.exceptions import DMRankError, DMValueError, DMShapeError, DMDomainError
|
||||
from sympy.polys.matrices.lll import _ddm_lll, ddm_lll, ddm_lll_transform
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_lll():
|
||||
normal_test_data = [
|
||||
(
|
||||
DM([[1, 0, 0, 0, -20160],
|
||||
[0, 1, 0, 0, 33768],
|
||||
[0, 0, 1, 0, 39578],
|
||||
[0, 0, 0, 1, 47757]], ZZ),
|
||||
DM([[10, -3, -2, 8, -4],
|
||||
[3, -9, 8, 1, -11],
|
||||
[-3, 13, -9, -3, -9],
|
||||
[-12, -7, -11, 9, -1]], ZZ)
|
||||
),
|
||||
(
|
||||
DM([[20, 52, 3456],
|
||||
[14, 31, -1],
|
||||
[34, -442, 0]], ZZ),
|
||||
DM([[14, 31, -1],
|
||||
[188, -101, -11],
|
||||
[236, 13, 3443]], ZZ)
|
||||
),
|
||||
(
|
||||
DM([[34, -1, -86, 12],
|
||||
[-54, 34, 55, 678],
|
||||
[23, 3498, 234, 6783],
|
||||
[87, 49, 665, 11]], ZZ),
|
||||
DM([[34, -1, -86, 12],
|
||||
[291, 43, 149, 83],
|
||||
[-54, 34, 55, 678],
|
||||
[-189, 3077, -184, -223]], ZZ)
|
||||
)
|
||||
]
|
||||
delta = QQ(5, 6)
|
||||
for basis_dm, reduced_dm in normal_test_data:
|
||||
reduced = _ddm_lll(basis_dm.rep.to_ddm(), delta=delta)[0]
|
||||
assert reduced == reduced_dm.rep.to_ddm()
|
||||
|
||||
reduced = ddm_lll(basis_dm.rep.to_ddm(), delta=delta)
|
||||
assert reduced == reduced_dm.rep.to_ddm()
|
||||
|
||||
reduced, transform = _ddm_lll(basis_dm.rep.to_ddm(), delta=delta, return_transform=True)
|
||||
assert reduced == reduced_dm.rep.to_ddm()
|
||||
assert transform.matmul(basis_dm.rep.to_ddm()) == reduced_dm.rep.to_ddm()
|
||||
|
||||
reduced, transform = ddm_lll_transform(basis_dm.rep.to_ddm(), delta=delta)
|
||||
assert reduced == reduced_dm.rep.to_ddm()
|
||||
assert transform.matmul(basis_dm.rep.to_ddm()) == reduced_dm.rep.to_ddm()
|
||||
|
||||
reduced = basis_dm.rep.lll(delta=delta)
|
||||
assert reduced == reduced_dm.rep
|
||||
|
||||
reduced, transform = basis_dm.rep.lll_transform(delta=delta)
|
||||
assert reduced == reduced_dm.rep
|
||||
assert transform.matmul(basis_dm.rep) == reduced_dm.rep
|
||||
|
||||
reduced = basis_dm.rep.to_sdm().lll(delta=delta)
|
||||
assert reduced == reduced_dm.rep.to_sdm()
|
||||
|
||||
reduced, transform = basis_dm.rep.to_sdm().lll_transform(delta=delta)
|
||||
assert reduced == reduced_dm.rep.to_sdm()
|
||||
assert transform.matmul(basis_dm.rep.to_sdm()) == reduced_dm.rep.to_sdm()
|
||||
|
||||
reduced = basis_dm.lll(delta=delta)
|
||||
assert reduced == reduced_dm
|
||||
|
||||
reduced, transform = basis_dm.lll_transform(delta=delta)
|
||||
assert reduced == reduced_dm
|
||||
assert transform.matmul(basis_dm) == reduced_dm
|
||||
|
||||
|
||||
def test_lll_linear_dependent():
|
||||
linear_dependent_test_data = [
|
||||
DM([[0, -1, -2, -3],
|
||||
[1, 0, -1, -2],
|
||||
[2, 1, 0, -1],
|
||||
[3, 2, 1, 0]], ZZ),
|
||||
DM([[1, 0, 0, 1],
|
||||
[0, 1, 0, 1],
|
||||
[0, 0, 1, 1],
|
||||
[1, 2, 3, 6]], ZZ),
|
||||
DM([[3, -5, 1],
|
||||
[4, 6, 0],
|
||||
[10, -4, 2]], ZZ)
|
||||
]
|
||||
for not_basis in linear_dependent_test_data:
|
||||
raises(DMRankError, lambda: _ddm_lll(not_basis.rep.to_ddm()))
|
||||
raises(DMRankError, lambda: ddm_lll(not_basis.rep.to_ddm()))
|
||||
raises(DMRankError, lambda: not_basis.rep.lll())
|
||||
raises(DMRankError, lambda: not_basis.rep.to_sdm().lll())
|
||||
raises(DMRankError, lambda: not_basis.lll())
|
||||
raises(DMRankError, lambda: _ddm_lll(not_basis.rep.to_ddm(), return_transform=True))
|
||||
raises(DMRankError, lambda: ddm_lll_transform(not_basis.rep.to_ddm()))
|
||||
raises(DMRankError, lambda: not_basis.rep.lll_transform())
|
||||
raises(DMRankError, lambda: not_basis.rep.to_sdm().lll_transform())
|
||||
raises(DMRankError, lambda: not_basis.lll_transform())
|
||||
|
||||
|
||||
def test_lll_wrong_delta():
|
||||
dummy_matrix = DomainMatrix.ones((3, 3), ZZ)
|
||||
for wrong_delta in [QQ(-1, 4), QQ(0, 1), QQ(1, 4), QQ(1, 1), QQ(100, 1)]:
|
||||
raises(DMValueError, lambda: _ddm_lll(dummy_matrix.rep, delta=wrong_delta))
|
||||
raises(DMValueError, lambda: ddm_lll(dummy_matrix.rep, delta=wrong_delta))
|
||||
raises(DMValueError, lambda: dummy_matrix.rep.lll(delta=wrong_delta))
|
||||
raises(DMValueError, lambda: dummy_matrix.rep.to_sdm().lll(delta=wrong_delta))
|
||||
raises(DMValueError, lambda: dummy_matrix.lll(delta=wrong_delta))
|
||||
raises(DMValueError, lambda: _ddm_lll(dummy_matrix.rep, delta=wrong_delta, return_transform=True))
|
||||
raises(DMValueError, lambda: ddm_lll_transform(dummy_matrix.rep, delta=wrong_delta))
|
||||
raises(DMValueError, lambda: dummy_matrix.rep.lll_transform(delta=wrong_delta))
|
||||
raises(DMValueError, lambda: dummy_matrix.rep.to_sdm().lll_transform(delta=wrong_delta))
|
||||
raises(DMValueError, lambda: dummy_matrix.lll_transform(delta=wrong_delta))
|
||||
|
||||
|
||||
def test_lll_wrong_shape():
|
||||
wrong_shape_matrix = DomainMatrix.ones((4, 3), ZZ)
|
||||
raises(DMShapeError, lambda: _ddm_lll(wrong_shape_matrix.rep))
|
||||
raises(DMShapeError, lambda: ddm_lll(wrong_shape_matrix.rep))
|
||||
raises(DMShapeError, lambda: wrong_shape_matrix.rep.lll())
|
||||
raises(DMShapeError, lambda: wrong_shape_matrix.rep.to_sdm().lll())
|
||||
raises(DMShapeError, lambda: wrong_shape_matrix.lll())
|
||||
raises(DMShapeError, lambda: _ddm_lll(wrong_shape_matrix.rep, return_transform=True))
|
||||
raises(DMShapeError, lambda: ddm_lll_transform(wrong_shape_matrix.rep))
|
||||
raises(DMShapeError, lambda: wrong_shape_matrix.rep.lll_transform())
|
||||
raises(DMShapeError, lambda: wrong_shape_matrix.rep.to_sdm().lll_transform())
|
||||
raises(DMShapeError, lambda: wrong_shape_matrix.lll_transform())
|
||||
|
||||
|
||||
def test_lll_wrong_domain():
|
||||
wrong_domain_matrix = DomainMatrix.ones((3, 3), QQ)
|
||||
raises(DMDomainError, lambda: _ddm_lll(wrong_domain_matrix.rep))
|
||||
raises(DMDomainError, lambda: ddm_lll(wrong_domain_matrix.rep))
|
||||
raises(DMDomainError, lambda: wrong_domain_matrix.rep.lll())
|
||||
raises(DMDomainError, lambda: wrong_domain_matrix.rep.to_sdm().lll())
|
||||
raises(DMDomainError, lambda: wrong_domain_matrix.lll())
|
||||
raises(DMDomainError, lambda: _ddm_lll(wrong_domain_matrix.rep, return_transform=True))
|
||||
raises(DMDomainError, lambda: ddm_lll_transform(wrong_domain_matrix.rep))
|
||||
raises(DMDomainError, lambda: wrong_domain_matrix.rep.lll_transform())
|
||||
raises(DMDomainError, lambda: wrong_domain_matrix.rep.to_sdm().lll_transform())
|
||||
raises(DMDomainError, lambda: wrong_domain_matrix.lll_transform())
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.polys.matrices.normalforms import (
|
||||
invariant_factors,
|
||||
smith_normal_form,
|
||||
smith_normal_decomp,
|
||||
is_smith_normal_form,
|
||||
hermite_normal_form,
|
||||
_hermite_normal_form,
|
||||
_hermite_normal_form_modulo_D
|
||||
)
|
||||
from sympy.polys.domains import ZZ, QQ
|
||||
from sympy.polys.matrices import DomainMatrix, DM
|
||||
from sympy.polys.matrices.exceptions import DMDomainError, DMShapeError
|
||||
|
||||
|
||||
def test_is_smith_normal_form():
|
||||
|
||||
snf_examples = [
|
||||
DM([[0, 0], [0, 0]], ZZ),
|
||||
DM([[1, 0], [0, 0]], ZZ),
|
||||
DM([[1, 0], [0, 1]], ZZ),
|
||||
DM([[1, 0], [0, 2]], ZZ),
|
||||
]
|
||||
|
||||
non_snf_examples = [
|
||||
DM([[0, 1], [0, 0]], ZZ),
|
||||
DM([[0, 0], [0, 1]], ZZ),
|
||||
DM([[2, 0], [0, 3]], ZZ),
|
||||
]
|
||||
|
||||
for m in snf_examples:
|
||||
assert is_smith_normal_form(m) is True
|
||||
|
||||
for m in non_snf_examples:
|
||||
assert is_smith_normal_form(m) is False
|
||||
|
||||
|
||||
def test_smith_normal():
|
||||
|
||||
m = DM([
|
||||
[12, 6, 4, 8],
|
||||
[3, 9, 6, 12],
|
||||
[2, 16, 14, 28],
|
||||
[20, 10, 10, 20]], ZZ)
|
||||
|
||||
smf = DM([
|
||||
[1, 0, 0, 0],
|
||||
[0, 10, 0, 0],
|
||||
[0, 0, 30, 0],
|
||||
[0, 0, 0, 0]], ZZ)
|
||||
|
||||
s = DM([
|
||||
[0, 1, -1, 0],
|
||||
[1, -4, 0, 0],
|
||||
[0, -2, 3, 0],
|
||||
[-2, 2, -1, 1]], ZZ)
|
||||
|
||||
t = DM([
|
||||
[1, 1, 10, 0],
|
||||
[0, -1, -2, 0],
|
||||
[0, 1, 3, -2],
|
||||
[0, 0, 0, 1]], ZZ)
|
||||
|
||||
assert smith_normal_form(m).to_dense() == smf
|
||||
assert smith_normal_decomp(m) == (smf, s, t)
|
||||
assert is_smith_normal_form(smf)
|
||||
assert smf == s * m * t
|
||||
|
||||
m00 = DomainMatrix.zeros((0, 0), ZZ).to_dense()
|
||||
m01 = DomainMatrix.zeros((0, 1), ZZ).to_dense()
|
||||
m10 = DomainMatrix.zeros((1, 0), ZZ).to_dense()
|
||||
i11 = DM([[1]], ZZ)
|
||||
|
||||
assert smith_normal_form(m00) == m00.to_sparse()
|
||||
assert smith_normal_form(m01) == m01.to_sparse()
|
||||
assert smith_normal_form(m10) == m10.to_sparse()
|
||||
assert smith_normal_form(i11) == i11.to_sparse()
|
||||
|
||||
assert smith_normal_decomp(m00) == (m00, m00, m00)
|
||||
assert smith_normal_decomp(m01) == (m01, m00, i11)
|
||||
assert smith_normal_decomp(m10) == (m10, i11, m00)
|
||||
assert smith_normal_decomp(i11) == (i11, i11, i11)
|
||||
|
||||
x = Symbol('x')
|
||||
m = DM([[x-1, 1, -1],
|
||||
[ 0, x, -1],
|
||||
[ 0, -1, x]], QQ[x])
|
||||
dx = m.domain.gens[0]
|
||||
assert invariant_factors(m) == (1, dx-1, dx**2-1)
|
||||
|
||||
zr = DomainMatrix([], (0, 2), ZZ)
|
||||
zc = DomainMatrix([[], []], (2, 0), ZZ)
|
||||
assert smith_normal_form(zr).to_dense() == zr
|
||||
assert smith_normal_form(zc).to_dense() == zc
|
||||
|
||||
assert smith_normal_form(DM([[2, 4]], ZZ)).to_dense() == DM([[2, 0]], ZZ)
|
||||
assert smith_normal_form(DM([[0, -2]], ZZ)).to_dense() == DM([[2, 0]], ZZ)
|
||||
assert smith_normal_form(DM([[0], [-2]], ZZ)).to_dense() == DM([[2], [0]], ZZ)
|
||||
|
||||
assert smith_normal_decomp(DM([[0, -2]], ZZ)) == (
|
||||
DM([[2, 0]], ZZ), DM([[-1]], ZZ), DM([[0, 1], [1, 0]], ZZ)
|
||||
)
|
||||
assert smith_normal_decomp(DM([[0], [-2]], ZZ)) == (
|
||||
DM([[2], [0]], ZZ), DM([[0, -1], [1, 0]], ZZ), DM([[1]], ZZ)
|
||||
)
|
||||
|
||||
m = DM([[3, 0, 0, 0], [0, 0, 0, 0], [0, 0, 2, 0]], ZZ)
|
||||
snf = DM([[1, 0, 0, 0], [0, 6, 0, 0], [0, 0, 0, 0]], ZZ)
|
||||
s = DM([[1, 0, 1], [2, 0, 3], [0, 1, 0]], ZZ)
|
||||
t = DM([[1, -2, 0, 0], [0, 0, 0, 1], [-1, 3, 0, 0], [0, 0, 1, 0]], ZZ)
|
||||
|
||||
assert smith_normal_form(m).to_dense() == snf
|
||||
assert smith_normal_decomp(m) == (snf, s, t)
|
||||
assert is_smith_normal_form(snf)
|
||||
assert snf == s * m * t
|
||||
|
||||
raises(ValueError, lambda: smith_normal_form(DM([[1]], ZZ[x])))
|
||||
|
||||
|
||||
def test_hermite_normal():
|
||||
m = DM([[2, 7, 17, 29, 41], [3, 11, 19, 31, 43], [5, 13, 23, 37, 47]], ZZ)
|
||||
hnf = DM([[1, 0, 0], [0, 2, 1], [0, 0, 1]], ZZ)
|
||||
assert hermite_normal_form(m) == hnf
|
||||
assert hermite_normal_form(m, D=ZZ(2)) == hnf
|
||||
assert hermite_normal_form(m, D=ZZ(2), check_rank=True) == hnf
|
||||
|
||||
m = m.transpose()
|
||||
hnf = DM([[37, 0, 19], [222, -6, 113], [48, 0, 25], [0, 2, 1], [0, 0, 1]], ZZ)
|
||||
assert hermite_normal_form(m) == hnf
|
||||
raises(DMShapeError, lambda: _hermite_normal_form_modulo_D(m, ZZ(96)))
|
||||
raises(DMDomainError, lambda: _hermite_normal_form_modulo_D(m, QQ(96)))
|
||||
|
||||
m = DM([[8, 28, 68, 116, 164], [3, 11, 19, 31, 43], [5, 13, 23, 37, 47]], ZZ)
|
||||
hnf = DM([[4, 0, 0], [0, 2, 1], [0, 0, 1]], ZZ)
|
||||
assert hermite_normal_form(m) == hnf
|
||||
assert hermite_normal_form(m, D=ZZ(8)) == hnf
|
||||
assert hermite_normal_form(m, D=ZZ(8), check_rank=True) == hnf
|
||||
|
||||
m = DM([[10, 8, 6, 30, 2], [45, 36, 27, 18, 9], [5, 4, 3, 2, 1]], ZZ)
|
||||
hnf = DM([[26, 2], [0, 9], [0, 1]], ZZ)
|
||||
assert hermite_normal_form(m) == hnf
|
||||
|
||||
m = DM([[2, 7], [0, 0], [0, 0]], ZZ)
|
||||
hnf = DM([[1], [0], [0]], ZZ)
|
||||
assert hermite_normal_form(m) == hnf
|
||||
|
||||
m = DM([[-2, 1], [0, 1]], ZZ)
|
||||
hnf = DM([[2, 1], [0, 1]], ZZ)
|
||||
assert hermite_normal_form(m) == hnf
|
||||
|
||||
m = DomainMatrix([[QQ(1)]], (1, 1), QQ)
|
||||
raises(DMDomainError, lambda: hermite_normal_form(m))
|
||||
raises(DMDomainError, lambda: _hermite_normal_form(m))
|
||||
raises(DMDomainError, lambda: _hermite_normal_form_modulo_D(m, ZZ(1)))
|
||||
@@ -0,0 +1,209 @@
|
||||
from sympy import ZZ, Matrix
|
||||
from sympy.polys.matrices import DM, DomainMatrix
|
||||
from sympy.polys.matrices.ddm import DDM
|
||||
from sympy.polys.matrices.sdm import SDM
|
||||
|
||||
import pytest
|
||||
|
||||
zeros = lambda shape, K: DomainMatrix.zeros(shape, K).to_dense()
|
||||
eye = lambda n, K: DomainMatrix.eye(n, K).to_dense()
|
||||
|
||||
|
||||
#
|
||||
# DomainMatrix.nullspace can have a divided answer or can return an undivided
|
||||
# uncanonical answer. The uncanonical answer is not unique but we can make it
|
||||
# unique by making it primitive (remove gcd). The tests here all show the
|
||||
# primitive form. We test two things:
|
||||
#
|
||||
# A.nullspace().primitive()[1] == answer.
|
||||
# A.nullspace(divide_last=True) == _divide_last(answer).
|
||||
#
|
||||
# The nullspace as returned by DomainMatrix and related classes is the
|
||||
# transpose of the nullspace as returned by Matrix. Matrix returns a list of
|
||||
# of column vectors whereas DomainMatrix returns a matrix whose rows are the
|
||||
# nullspace vectors.
|
||||
#
|
||||
|
||||
|
||||
NULLSPACE_EXAMPLES = [
|
||||
|
||||
(
|
||||
'zz_1',
|
||||
DM([[ 1, 2, 3]], ZZ),
|
||||
DM([[-2, 1, 0],
|
||||
[-3, 0, 1]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_2',
|
||||
zeros((0, 0), ZZ),
|
||||
zeros((0, 0), ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_3',
|
||||
zeros((2, 0), ZZ),
|
||||
zeros((0, 0), ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_4',
|
||||
zeros((0, 2), ZZ),
|
||||
eye(2, ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_5',
|
||||
zeros((2, 2), ZZ),
|
||||
eye(2, ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_6',
|
||||
DM([[1, 2],
|
||||
[3, 4]], ZZ),
|
||||
zeros((0, 2), ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_7',
|
||||
DM([[1, 1],
|
||||
[1, 1]], ZZ),
|
||||
DM([[-1, 1]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_8',
|
||||
DM([[1],
|
||||
[1]], ZZ),
|
||||
zeros((0, 1), ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_9',
|
||||
DM([[1, 1]], ZZ),
|
||||
DM([[-1, 1]], ZZ),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_10',
|
||||
DM([[0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
|
||||
[1, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 1]], ZZ),
|
||||
DM([[ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
|
||||
[-1, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[ 0, -1, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[ 0, 0, 0, -1, 0, 0, 0, 0, 1, 0],
|
||||
[ 0, 0, 0, 0, -1, 0, 0, 0, 0, 1]], ZZ),
|
||||
),
|
||||
|
||||
]
|
||||
|
||||
|
||||
def _to_DM(A, ans):
|
||||
"""Convert the answer to DomainMatrix."""
|
||||
if isinstance(A, DomainMatrix):
|
||||
return A.to_dense()
|
||||
elif isinstance(A, DDM):
|
||||
return DomainMatrix(list(A), A.shape, A.domain).to_dense()
|
||||
elif isinstance(A, SDM):
|
||||
return DomainMatrix(dict(A), A.shape, A.domain).to_dense()
|
||||
else:
|
||||
assert False # pragma: no cover
|
||||
|
||||
|
||||
def _divide_last(null):
|
||||
"""Normalize the nullspace by the rightmost non-zero entry."""
|
||||
null = null.to_field()
|
||||
|
||||
if null.is_zero_matrix:
|
||||
return null
|
||||
|
||||
rows = []
|
||||
for i in range(null.shape[0]):
|
||||
for j in reversed(range(null.shape[1])):
|
||||
if null[i, j]:
|
||||
rows.append(null[i, :] / null[i, j])
|
||||
break
|
||||
else:
|
||||
assert False # pragma: no cover
|
||||
|
||||
return DomainMatrix.vstack(*rows)
|
||||
|
||||
|
||||
def _check_primitive(null, null_ans):
|
||||
"""Check that the primitive of the answer matches."""
|
||||
null = _to_DM(null, null_ans)
|
||||
cont, null_prim = null.primitive()
|
||||
assert null_prim == null_ans
|
||||
|
||||
|
||||
def _check_divided(null, null_ans):
|
||||
"""Check the divided answer."""
|
||||
null = _to_DM(null, null_ans)
|
||||
null_ans_norm = _divide_last(null_ans)
|
||||
assert null == null_ans_norm
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_null', NULLSPACE_EXAMPLES)
|
||||
def test_Matrix_nullspace(name, A, A_null):
|
||||
A = A.to_Matrix()
|
||||
|
||||
A_null_cols = A.nullspace()
|
||||
|
||||
# We have to patch up the case where the nullspace is empty
|
||||
if A_null_cols:
|
||||
A_null_found = Matrix.hstack(*A_null_cols)
|
||||
else:
|
||||
A_null_found = Matrix.zeros(A.cols, 0)
|
||||
|
||||
A_null_found = A_null_found.to_DM().to_field().to_dense()
|
||||
|
||||
# The Matrix result is the transpose of DomainMatrix result.
|
||||
A_null_found = A_null_found.transpose()
|
||||
|
||||
_check_divided(A_null_found, A_null)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_null', NULLSPACE_EXAMPLES)
|
||||
def test_dm_dense_nullspace(name, A, A_null):
|
||||
A = A.to_field().to_dense()
|
||||
A_null_found = A.nullspace(divide_last=True)
|
||||
_check_divided(A_null_found, A_null)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_null', NULLSPACE_EXAMPLES)
|
||||
def test_dm_sparse_nullspace(name, A, A_null):
|
||||
A = A.to_field().to_sparse()
|
||||
A_null_found = A.nullspace(divide_last=True)
|
||||
_check_divided(A_null_found, A_null)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_null', NULLSPACE_EXAMPLES)
|
||||
def test_ddm_nullspace(name, A, A_null):
|
||||
A = A.to_field().to_ddm()
|
||||
A_null_found, _ = A.nullspace()
|
||||
_check_divided(A_null_found, A_null)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_null', NULLSPACE_EXAMPLES)
|
||||
def test_sdm_nullspace(name, A, A_null):
|
||||
A = A.to_field().to_sdm()
|
||||
A_null_found, _ = A.nullspace()
|
||||
_check_divided(A_null_found, A_null)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_null', NULLSPACE_EXAMPLES)
|
||||
def test_dm_dense_nullspace_fracfree(name, A, A_null):
|
||||
A = A.to_dense()
|
||||
A_null_found = A.nullspace()
|
||||
_check_primitive(A_null_found, A_null)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_null', NULLSPACE_EXAMPLES)
|
||||
def test_dm_sparse_nullspace_fracfree(name, A, A_null):
|
||||
A = A.to_sparse()
|
||||
A_null_found = A.nullspace()
|
||||
_check_primitive(A_null_found, A_null)
|
||||
@@ -0,0 +1,737 @@
|
||||
from sympy import ZZ, QQ, ZZ_I, EX, Matrix, eye, zeros, symbols
|
||||
from sympy.polys.matrices import DM, DomainMatrix
|
||||
from sympy.polys.matrices.dense import ddm_irref_den, ddm_irref
|
||||
from sympy.polys.matrices.ddm import DDM
|
||||
from sympy.polys.matrices.sdm import SDM, sdm_irref, sdm_rref_den
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
#
|
||||
# The dense and sparse implementations of rref_den are ddm_irref_den and
|
||||
# sdm_irref_den. These can give results that differ by some factor and also
|
||||
# give different results if the order of the rows is changed. The tests below
|
||||
# show all results on lowest terms as should be returned by cancel_denom.
|
||||
#
|
||||
# The EX domain is also a case where the dense and sparse implementations
|
||||
# can give results in different forms: the results should be equivalent but
|
||||
# are not canonical because EX does not have a canonical form.
|
||||
#
|
||||
|
||||
|
||||
a, b, c, d = symbols('a, b, c, d')
|
||||
|
||||
|
||||
qq_large_1 = DM([
|
||||
[ (1,2), (1,3), (1,5), (1,7), (1,11), (1,13), (1,17), (1,19), (1,23), (1,29), (1,31)],
|
||||
[ (1,37), (1,41), (1,43), (1,47), (1,53), (1,59), (1,61), (1,67), (1,71), (1,73), (1,79)],
|
||||
[ (1,83), (1,89), (1,97),(1,101),(1,103),(1,107),(1,109),(1,113),(1,127),(1,131),(1,137)],
|
||||
[(1,139),(1,149),(1,151),(1,157),(1,163),(1,167),(1,173),(1,179),(1,181),(1,191),(1,193)],
|
||||
[(1,197),(1,199),(1,211),(1,223),(1,227),(1,229),(1,233),(1,239),(1,241),(1,251),(1,257)],
|
||||
[(1,263),(1,269),(1,271),(1,277),(1,281),(1,283),(1,293),(1,307),(1,311),(1,313),(1,317)],
|
||||
[(1,331),(1,337),(1,347),(1,349),(1,353),(1,359),(1,367),(1,373),(1,379),(1,383),(1,389)],
|
||||
[(1,397),(1,401),(1,409),(1,419),(1,421),(1,431),(1,433),(1,439),(1,443),(1,449),(1,457)],
|
||||
[(1,461),(1,463),(1,467),(1,479),(1,487),(1,491),(1,499),(1,503),(1,509),(1,521),(1,523)],
|
||||
[(1,541),(1,547),(1,557),(1,563),(1,569),(1,571),(1,577),(1,587),(1,593),(1,599),(1,601)],
|
||||
[(1,607),(1,613),(1,617),(1,619),(1,631),(1,641),(1,643),(1,647),(1,653),(1,659),(1,661)]],
|
||||
QQ)
|
||||
|
||||
qq_large_2 = qq_large_1 + 10**100 * DomainMatrix.eye(11, QQ)
|
||||
|
||||
|
||||
RREF_EXAMPLES = [
|
||||
(
|
||||
'zz_1',
|
||||
DM([[1, 2, 3]], ZZ),
|
||||
DM([[1, 2, 3]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_2',
|
||||
DomainMatrix([], (0, 0), ZZ),
|
||||
DomainMatrix([], (0, 0), ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_3',
|
||||
DM([[1, 2],
|
||||
[3, 4]], ZZ),
|
||||
DM([[1, 0],
|
||||
[0, 1]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_4',
|
||||
DM([[1, 0],
|
||||
[3, 4]], ZZ),
|
||||
DM([[1, 0],
|
||||
[0, 1]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_5',
|
||||
DM([[0, 2],
|
||||
[3, 4]], ZZ),
|
||||
DM([[1, 0],
|
||||
[0, 1]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_6',
|
||||
DM([[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7, 8, 9]], ZZ),
|
||||
DM([[1, 0, -1],
|
||||
[0, 1, 2],
|
||||
[0, 0, 0]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_7',
|
||||
DM([[0, 0, 0],
|
||||
[0, 0, 0],
|
||||
[1, 0, 0]], ZZ),
|
||||
DM([[1, 0, 0],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_8',
|
||||
DM([[0, 0, 0],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0]], ZZ),
|
||||
DM([[0, 0, 0],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_9',
|
||||
DM([[1, 1, 0],
|
||||
[0, 0, 2],
|
||||
[0, 0, 0]], ZZ),
|
||||
DM([[1, 1, 0],
|
||||
[0, 0, 1],
|
||||
[0, 0, 0]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_10',
|
||||
DM([[2, 2, 0],
|
||||
[0, 0, 2],
|
||||
[0, 0, 0]], ZZ),
|
||||
DM([[1, 1, 0],
|
||||
[0, 0, 1],
|
||||
[0, 0, 0]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_11',
|
||||
DM([[2, 2, 0],
|
||||
[0, 2, 2],
|
||||
[0, 0, 2]], ZZ),
|
||||
DM([[1, 0, 0],
|
||||
[0, 1, 0],
|
||||
[0, 0, 1]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_12',
|
||||
DM([[ 1, 2, 3],
|
||||
[ 4, 5, 6],
|
||||
[ 7, 8, 9],
|
||||
[10, 11, 12]], ZZ),
|
||||
DM([[1, 0, -1],
|
||||
[0, 1, 2],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_13',
|
||||
DM([[ 1, 2, 3],
|
||||
[ 4, 5, 6],
|
||||
[ 7, 8, 9],
|
||||
[10, 11, 13]], ZZ),
|
||||
DM([[ 1, 0, 0],
|
||||
[ 0, 1, 0],
|
||||
[ 0, 0, 1],
|
||||
[ 0, 0, 0]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_14',
|
||||
DM([[1, 2, 4, 3],
|
||||
[4, 5, 10, 6],
|
||||
[7, 8, 16, 9]], ZZ),
|
||||
DM([[1, 0, 0, -1],
|
||||
[0, 1, 2, 2],
|
||||
[0, 0, 0, 0]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_15',
|
||||
DM([[1, 2, 4, 3],
|
||||
[4, 5, 10, 6],
|
||||
[7, 8, 17, 9]], ZZ),
|
||||
DM([[1, 0, 0, -1],
|
||||
[0, 1, 0, 2],
|
||||
[0, 0, 1, 0]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_16',
|
||||
DM([[1, 2, 0, 1],
|
||||
[1, 1, 9, 0]], ZZ),
|
||||
DM([[1, 0, 18, -1],
|
||||
[0, 1, -9, 1]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_17',
|
||||
DM([[1, 1, 1],
|
||||
[1, 2, 2]], ZZ),
|
||||
DM([[1, 0, 0],
|
||||
[0, 1, 1]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
# Here the sparse implementation and dense implementation give very
|
||||
# different denominators: 4061232 and -1765176.
|
||||
'zz_18',
|
||||
DM([[94, 24, 0, 27, 0],
|
||||
[79, 0, 0, 0, 0],
|
||||
[85, 16, 71, 81, 0],
|
||||
[ 0, 0, 72, 77, 0],
|
||||
[21, 0, 34, 0, 0]], ZZ),
|
||||
DM([[ 1, 0, 0, 0, 0],
|
||||
[ 0, 1, 0, 0, 0],
|
||||
[ 0, 0, 1, 0, 0],
|
||||
[ 0, 0, 0, 1, 0],
|
||||
[ 0, 0, 0, 0, 0]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
# Let's have a denominator that cannot be cancelled.
|
||||
'zz_19',
|
||||
DM([[1, 2, 4],
|
||||
[4, 5, 6]], ZZ),
|
||||
DM([[3, 0, -8],
|
||||
[0, 3, 10]], ZZ),
|
||||
ZZ(3),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_20',
|
||||
DM([[0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 4]], ZZ),
|
||||
DM([[0, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_21',
|
||||
DM([[0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
|
||||
[1, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 1]], ZZ),
|
||||
DM([[1, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_22',
|
||||
DM([[1, 1, 1, 0, 1],
|
||||
[1, 1, 0, 1, 0],
|
||||
[1, 0, 1, 0, 1],
|
||||
[1, 1, 0, 1, 0],
|
||||
[1, 0, 0, 0, 0]], ZZ),
|
||||
DM([[1, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 0],
|
||||
[0, 0, 1, 0, 1],
|
||||
[0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_large_1',
|
||||
DM([
|
||||
[ 0, 0, 0, 81, 0, 0, 75, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 86, 0, 92, 79, 54, 0, 7, 0, 0, 0, 0, 79, 0, 0, 0],
|
||||
[89, 54, 81, 0, 0, 20, 0, 0, 0, 0, 0, 0, 51, 0, 94, 0, 0, 77, 0, 0],
|
||||
[ 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 48, 29, 0, 0, 5, 0, 32, 0],
|
||||
[ 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 11],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 43, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 38, 91, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 26, 0, 0],
|
||||
[69, 0, 0, 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55],
|
||||
[ 0, 13, 18, 49, 49, 88, 0, 0, 35, 54, 0, 0, 51, 0, 0, 0, 0, 0, 0, 87],
|
||||
[ 0, 0, 0, 0, 31, 0, 40, 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 88, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 98, 0, 0, 0, 15, 53, 0, 92, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 95, 0, 0, 0, 36, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 73, 19],
|
||||
[ 0, 65, 14, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 34, 0, 0],
|
||||
[ 0, 0, 0, 16, 39, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0],
|
||||
[ 0, 17, 0, 0, 0, 99, 84, 13, 50, 84, 0, 0, 0, 0, 95, 0, 43, 33, 20, 0],
|
||||
[79, 0, 17, 52, 99, 12, 69, 0, 98, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 82, 0, 44, 0, 0, 0, 97, 0, 0, 0, 0, 0, 10, 0, 0, 31, 0],
|
||||
[ 0, 0, 21, 0, 67, 0, 0, 0, 0, 0, 4, 0, 50, 0, 0, 0, 33, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 9, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8],
|
||||
[ 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 34, 93, 0, 0, 0, 0, 47, 0, 0, 0]],
|
||||
ZZ),
|
||||
DM([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]], ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_large_2',
|
||||
DM([
|
||||
[ 0, 0, 0, 0, 50, 0, 6, 81, 0, 1, 86, 0, 0, 98, 82, 94, 4, 0, 0, 29],
|
||||
[ 0, 44, 43, 0, 62, 0, 0, 0, 60, 0, 0, 0, 0, 71, 9, 0, 57, 41, 0, 93],
|
||||
[ 0, 0, 28, 0, 74, 89, 42, 0, 28, 0, 6, 0, 0, 0, 44, 0, 0, 0, 77, 19],
|
||||
[ 0, 21, 82, 0, 30, 88, 0, 89, 68, 0, 0, 0, 79, 41, 0, 0, 99, 0, 0, 0],
|
||||
[31, 0, 0, 0, 19, 64, 0, 0, 79, 0, 5, 0, 72, 10, 60, 32, 64, 59, 0, 24],
|
||||
[ 0, 0, 0, 0, 0, 57, 0, 94, 0, 83, 20, 0, 0, 9, 31, 0, 49, 26, 58, 0],
|
||||
[ 0, 65, 56, 31, 64, 0, 0, 0, 0, 0, 0, 52, 85, 0, 0, 0, 0, 51, 0, 0],
|
||||
[ 0, 35, 0, 0, 0, 69, 0, 0, 64, 0, 0, 0, 0, 70, 0, 0, 90, 0, 75, 76],
|
||||
[69, 7, 0, 90, 0, 0, 84, 0, 47, 69, 19, 20, 42, 0, 0, 32, 71, 35, 0, 0],
|
||||
[39, 0, 90, 0, 0, 4, 85, 0, 0, 55, 0, 0, 0, 35, 67, 40, 0, 40, 0, 77],
|
||||
[98, 63, 0, 71, 0, 50, 0, 2, 61, 0, 38, 0, 0, 0, 0, 75, 0, 40, 33, 56],
|
||||
[ 0, 73, 0, 64, 0, 38, 0, 35, 61, 0, 0, 52, 0, 7, 0, 51, 0, 0, 0, 34],
|
||||
[ 0, 0, 28, 0, 34, 5, 63, 45, 14, 42, 60, 16, 76, 54, 99, 0, 28, 30, 0, 0],
|
||||
[58, 37, 14, 0, 0, 0, 94, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 8, 90, 53],
|
||||
[86, 74, 94, 0, 49, 10, 60, 0, 40, 18, 0, 0, 0, 31, 60, 24, 0, 1, 0, 29],
|
||||
[53, 0, 0, 97, 0, 0, 58, 0, 0, 39, 44, 47, 0, 0, 0, 12, 50, 0, 0, 11],
|
||||
[ 4, 0, 92, 10, 28, 0, 0, 89, 0, 0, 18, 54, 23, 39, 0, 2, 0, 48, 0, 92],
|
||||
[ 0, 0, 90, 77, 95, 33, 0, 0, 49, 22, 39, 0, 0, 0, 0, 0, 0, 40, 0, 0],
|
||||
[96, 0, 0, 0, 0, 38, 86, 0, 22, 76, 0, 0, 0, 0, 83, 88, 95, 65, 72, 0],
|
||||
[81, 65, 0, 4, 60, 0, 19, 0, 0, 68, 0, 0, 89, 0, 67, 22, 0, 0, 55, 33]],
|
||||
ZZ),
|
||||
DM([
|
||||
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]],
|
||||
ZZ),
|
||||
ZZ(1),
|
||||
),
|
||||
|
||||
(
|
||||
'zz_large_3',
|
||||
DM([
|
||||
[62,35,89,58,22,47,30,28,52,72,17,56,80,26,64,21,10,35,24,42,96,32,23,50,92,37,76,94,63,66],
|
||||
[20,47,96,34,10,98,19,6,29,2,19,92,61,94,38,41,32,9,5,94,31,58,27,41,72,85,61,62,40,46],
|
||||
[69,26,35,68,25,52,94,13,38,65,81,10,29,15,5,4,13,99,85,0,80,51,60,60,26,77,85,2,87,25],
|
||||
[99,58,69,15,52,12,18,7,27,56,12,54,21,92,38,95,33,83,28,1,44,8,29,84,92,12,2,25,46,46],
|
||||
[93,13,55,48,35,87,24,40,23,35,25,32,0,19,0,85,4,79,26,11,46,75,7,96,76,11,7,57,99,75],
|
||||
[128,85,26,51,161,173,77,78,85,103,123,58,91,147,38,91,161,36,123,81,102,25,75,59,17,150,112,65,77,143],
|
||||
[15,59,61,82,12,83,34,8,94,71,66,7,91,21,48,69,26,12,64,38,97,87,38,15,51,33,93,43,66,89],
|
||||
[74,74,53,39,69,90,41,80,32,66,40,83,87,87,61,38,12,80,24,49,37,90,19,33,56,0,46,57,56,60],
|
||||
[82,11,0,25,56,58,39,49,92,93,80,38,19,62,33,85,19,61,14,30,45,91,97,34,97,53,92,28,33,43],
|
||||
[83,79,41,16,95,35,53,45,26,4,71,76,61,69,69,72,87,92,59,72,54,11,22,83,8,57,77,55,19,22],
|
||||
[49,34,13,31,72,77,52,70,46,41,37,6,42,66,35,6,75,33,62,57,30,14,26,31,9,95,89,13,12,90],
|
||||
[29,3,49,30,51,32,77,41,38,50,16,1,87,81,93,88,58,91,83,0,38,67,29,64,60,84,5,60,23,28],
|
||||
[79,51,13,20,89,96,25,8,39,62,86,52,49,81,3,85,86,3,61,24,72,11,49,28,8,55,23,52,65,53],
|
||||
[96,86,73,20,41,20,37,18,10,61,85,24,40,83,69,41,4,92,23,99,64,33,18,36,32,56,60,98,39,24],
|
||||
[32,62,47,80,51,66,17,1,9,30,65,75,75,88,99,92,64,53,53,86,38,51,41,14,35,18,39,25,26,32],
|
||||
[39,21,8,16,33,6,35,85,75,62,43,34,18,68,71,28,32,18,12,0,81,53,1,99,3,5,45,99,35,33],
|
||||
[19,95,89,45,75,94,92,5,84,93,34,17,50,56,79,98,68,82,65,81,51,90,5,95,33,71,46,61,14,7],
|
||||
[53,92,8,49,67,84,21,79,49,95,66,48,36,14,62,97,26,45,58,31,83,48,11,89,67,72,91,34,56,89],
|
||||
[56,76,99,92,40,8,0,16,15,48,35,72,91,46,81,14,86,60,51,7,33,12,53,78,48,21,3,89,15,79],
|
||||
[81,43,33,49,6,49,36,32,57,74,87,91,17,37,31,17,67,1,40,38,69,8,3,48,59,37,64,97,11,3],
|
||||
[98,48,77,16,2,48,57,38,63,59,79,35,16,71,60,86,71,41,14,76,80,97,77,69,4,58,22,55,26,73],
|
||||
[80,47,78,44,31,48,47,29,29,62,19,21,17,24,19,3,53,93,97,57,13,54,12,10,77,66,60,75,32,21],
|
||||
[86,63,2,13,71,38,86,23,18,15,91,65,77,65,9,92,50,0,17,42,99,80,99,27,10,99,92,9,87,84],
|
||||
[66,27,72,13,13,15,72,75,39,3,14,71,15,68,10,19,49,54,11,29,47,20,63,13,97,47,24,62,16,96],
|
||||
[42,63,83,60,49,68,9,53,75,87,40,25,12,63,0,12,0,95,46,46,55,25,89,1,51,1,1,96,80,52],
|
||||
[35,9,97,13,86,39,66,48,41,57,23,38,11,9,35,72,88,13,41,60,10,64,71,23,1,5,23,57,6,19],
|
||||
[70,61,5,50,72,60,77,13,41,94,1,45,52,22,99,47,27,18,99,42,16,48,26,9,88,77,10,94,11,92],
|
||||
[55,68,58,2,72,56,81,52,79,37,1,40,21,46,27,60,37,13,97,42,85,98,69,60,76,44,42,46,29,73],
|
||||
[73,0,43,17,89,97,45,2,68,14,55,60,95,2,74,85,88,68,93,76,38,76,2,51,45,76,50,79,56,18],
|
||||
[72,58,41,39,24,80,23,79,44,7,98,75,30,6,85,60,20,58,77,71,90,51,38,80,30,15,33,10,82,8]],
|
||||
ZZ),
|
||||
Matrix([
|
||||
[eye(29) * 2028539767964472550625641331179545072876560857886207583101,
|
||||
Matrix([ 4260575808093245475167216057435155595594339172099000182569,
|
||||
169148395880755256182802335904188369274227936894862744452,
|
||||
4915975976683942569102447281579134986891620721539038348914,
|
||||
6113916866367364958834844982578214901958429746875633283248,
|
||||
5585689617819894460378537031623265659753379011388162534838,
|
||||
359776822829880747716695359574308645968094838905181892423,
|
||||
-2800926112141776386671436511182421432449325232461665113305,
|
||||
941642292388230001722444876624818265766384442910688463158,
|
||||
3648811843256146649321864698600908938933015862008642023935,
|
||||
-4104526163246702252932955226754097174212129127510547462419,
|
||||
-704814955438106792441896903238080197619233342348191408078,
|
||||
1640882266829725529929398131287244562048075707575030019335,
|
||||
-4068330845192910563212155694231438198040299927120544468520,
|
||||
136589038308366497790495711534532612862715724187671166593,
|
||||
2544937011460702462290799932536905731142196510605191645593,
|
||||
755591839174293940486133926192300657264122907519174116472,
|
||||
-3683838489869297144348089243628436188645897133242795965021,
|
||||
-522207137101161299969706310062775465103537953077871128403,
|
||||
-2260451796032703984456606059649402832441331339246756656334,
|
||||
-6476809325293587953616004856993300606040336446656916663680,
|
||||
3521944238996782387785653800944972787867472610035040989081,
|
||||
2270762115788407950241944504104975551914297395787473242379,
|
||||
-3259947194628712441902262570532921252128444706733549251156,
|
||||
-5624569821491886970999097239695637132075823246850431083557,
|
||||
-3262698255682055804320585332902837076064075936601504555698,
|
||||
5786719943788937667411185880136324396357603606944869545501,
|
||||
-955257841973865996077323863289453200904051299086000660036,
|
||||
-1294235552446355326174641248209752679127075717918392702116,
|
||||
-3718353510747301598130831152458342785269166356215331448279,
|
||||
]),],
|
||||
[zeros(1, 29), zeros(1, 1)],
|
||||
]).to_DM().to_dense(),
|
||||
ZZ(2028539767964472550625641331179545072876560857886207583101),
|
||||
),
|
||||
|
||||
|
||||
(
|
||||
'qq_1',
|
||||
DM([[(1,2), 0], [0, 2]], QQ),
|
||||
DM([[1, 0], [0, 1]], QQ),
|
||||
QQ(1),
|
||||
),
|
||||
|
||||
(
|
||||
# Standard square case
|
||||
'qq_2',
|
||||
DM([[0, 1],
|
||||
[1, 1]], QQ),
|
||||
DM([[1, 0],
|
||||
[0, 1]], QQ),
|
||||
QQ(1),
|
||||
),
|
||||
|
||||
(
|
||||
# m < n case
|
||||
'qq_3',
|
||||
DM([[1, 2, 1],
|
||||
[3, 4, 1]], QQ),
|
||||
DM([[1, 0, -1],
|
||||
[0, 1, 1]], QQ),
|
||||
QQ(1),
|
||||
),
|
||||
|
||||
(
|
||||
# same m < n but reversed
|
||||
'qq_4',
|
||||
DM([[3, 4, 1],
|
||||
[1, 2, 1]], QQ),
|
||||
DM([[1, 0, -1],
|
||||
[0, 1, 1]], QQ),
|
||||
QQ(1),
|
||||
),
|
||||
|
||||
(
|
||||
# m > n case
|
||||
'qq_5',
|
||||
DM([[1, 0],
|
||||
[1, 3],
|
||||
[0, 1]], QQ),
|
||||
DM([[1, 0],
|
||||
[0, 1],
|
||||
[0, 0]], QQ),
|
||||
QQ(1),
|
||||
),
|
||||
|
||||
(
|
||||
# Example with missing pivot
|
||||
'qq_6',
|
||||
DM([[1, 0, 1],
|
||||
[3, 0, 1]], QQ),
|
||||
DM([[1, 0, 0],
|
||||
[0, 0, 1]], QQ),
|
||||
QQ(1),
|
||||
),
|
||||
|
||||
(
|
||||
# This is intended to trigger the threshold where we give up on
|
||||
# clearing denominators.
|
||||
'qq_large_1',
|
||||
qq_large_1,
|
||||
DomainMatrix.eye(11, QQ).to_dense(),
|
||||
QQ(1),
|
||||
),
|
||||
|
||||
(
|
||||
# This is intended to trigger the threshold where we use rref_den over
|
||||
# QQ.
|
||||
'qq_large_2',
|
||||
qq_large_2,
|
||||
DomainMatrix.eye(11, QQ).to_dense(),
|
||||
QQ(1),
|
||||
),
|
||||
|
||||
(
|
||||
# Example with missing pivot and no replacement
|
||||
|
||||
# This example is just enough to show a different result from the dense
|
||||
# and sparse versions of the algorithm:
|
||||
#
|
||||
# >>> A = Matrix([[0, 1], [0, 2], [1, 0]])
|
||||
# >>> A.to_DM().to_sparse().rref_den()[0].to_Matrix()
|
||||
# Matrix([
|
||||
# [1, 0],
|
||||
# [0, 1],
|
||||
# [0, 0]])
|
||||
# >>> A.to_DM().to_dense().rref_den()[0].to_Matrix()
|
||||
# Matrix([
|
||||
# [2, 0],
|
||||
# [0, 2],
|
||||
# [0, 0]])
|
||||
#
|
||||
'qq_7',
|
||||
DM([[0, 1],
|
||||
[0, 2],
|
||||
[1, 0]], QQ),
|
||||
DM([[1, 0],
|
||||
[0, 1],
|
||||
[0, 0]], QQ),
|
||||
QQ(1),
|
||||
),
|
||||
|
||||
(
|
||||
# Gaussian integers
|
||||
'zz_i_1',
|
||||
DM([[(0,1), 1, 1],
|
||||
[ 1, 1, 1]], ZZ_I),
|
||||
DM([[1, 0, 0],
|
||||
[0, 1, 1]], ZZ_I),
|
||||
ZZ_I(1),
|
||||
),
|
||||
|
||||
(
|
||||
# EX: test_issue_23718
|
||||
'EX_1',
|
||||
DM([
|
||||
[a, b, 1],
|
||||
[c, d, 1]], EX),
|
||||
DM([[a*d - b*c, 0, -b + d],
|
||||
[ 0, a*d - b*c, a - c]], EX),
|
||||
EX(a*d - b*c),
|
||||
),
|
||||
|
||||
]
|
||||
|
||||
|
||||
def _to_DM(A, ans):
|
||||
"""Convert the answer to DomainMatrix."""
|
||||
if isinstance(A, DomainMatrix):
|
||||
return A.to_dense()
|
||||
elif isinstance(A, Matrix):
|
||||
return A.to_DM(ans.domain).to_dense()
|
||||
|
||||
if not (hasattr(A, 'shape') and hasattr(A, 'domain')):
|
||||
shape, domain = ans.shape, ans.domain
|
||||
else:
|
||||
shape, domain = A.shape, A.domain
|
||||
|
||||
if isinstance(A, (DDM, list)):
|
||||
return DomainMatrix(list(A), shape, domain).to_dense()
|
||||
elif isinstance(A, (SDM, dict)):
|
||||
return DomainMatrix(dict(A), shape, domain).to_dense()
|
||||
else:
|
||||
assert False # pragma: no cover
|
||||
|
||||
|
||||
def _pivots(A_rref):
|
||||
"""Return the pivots from the rref of A."""
|
||||
return tuple(sorted(map(min, A_rref.to_sdm().values())))
|
||||
|
||||
|
||||
def _check_cancel(result, rref_ans, den_ans):
|
||||
"""Check the cancelled result."""
|
||||
rref, den, pivots = result
|
||||
if isinstance(rref, (DDM, SDM, list, dict)):
|
||||
assert type(pivots) is list
|
||||
pivots = tuple(pivots)
|
||||
rref = _to_DM(rref, rref_ans)
|
||||
rref2, den2 = rref.cancel_denom(den)
|
||||
assert rref2 == rref_ans
|
||||
assert den2 == den_ans
|
||||
assert pivots == _pivots(rref)
|
||||
|
||||
|
||||
def _check_divide(result, rref_ans, den_ans):
|
||||
"""Check the divided result."""
|
||||
rref, pivots = result
|
||||
if isinstance(rref, (DDM, SDM, list, dict)):
|
||||
assert type(pivots) is list
|
||||
pivots = tuple(pivots)
|
||||
rref_ans = rref_ans.to_field() / den_ans
|
||||
rref = _to_DM(rref, rref_ans)
|
||||
assert rref == rref_ans
|
||||
assert _pivots(rref) == pivots
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_rref, den', RREF_EXAMPLES)
|
||||
def test_Matrix_rref(name, A, A_rref, den):
|
||||
K = A.domain
|
||||
A = A.to_Matrix()
|
||||
A_rref_found, pivots = A.rref()
|
||||
if K.is_EX:
|
||||
A_rref_found = A_rref_found.expand()
|
||||
_check_divide((A_rref_found, pivots), A_rref, den)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_rref, den', RREF_EXAMPLES)
|
||||
def test_dm_dense_rref(name, A, A_rref, den):
|
||||
A = A.to_field()
|
||||
_check_divide(A.rref(), A_rref, den)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_rref, den', RREF_EXAMPLES)
|
||||
def test_dm_dense_rref_den(name, A, A_rref, den):
|
||||
_check_cancel(A.rref_den(), A_rref, den)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_rref, den', RREF_EXAMPLES)
|
||||
def test_dm_sparse_rref(name, A, A_rref, den):
|
||||
A = A.to_field().to_sparse()
|
||||
_check_divide(A.rref(), A_rref, den)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_rref, den', RREF_EXAMPLES)
|
||||
def test_dm_sparse_rref_den(name, A, A_rref, den):
|
||||
A = A.to_sparse()
|
||||
_check_cancel(A.rref_den(), A_rref, den)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_rref, den', RREF_EXAMPLES)
|
||||
def test_dm_sparse_rref_den_keep_domain(name, A, A_rref, den):
|
||||
A = A.to_sparse()
|
||||
A_rref_f, den_f, pivots_f = A.rref_den(keep_domain=False)
|
||||
A_rref_f = A_rref_f.to_field() / den_f
|
||||
_check_divide((A_rref_f, pivots_f), A_rref, den)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_rref, den', RREF_EXAMPLES)
|
||||
def test_dm_sparse_rref_den_keep_domain_CD(name, A, A_rref, den):
|
||||
A = A.to_sparse()
|
||||
A_rref_f, den_f, pivots_f = A.rref_den(keep_domain=False, method='CD')
|
||||
A_rref_f = A_rref_f.to_field() / den_f
|
||||
_check_divide((A_rref_f, pivots_f), A_rref, den)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_rref, den', RREF_EXAMPLES)
|
||||
def test_dm_sparse_rref_den_keep_domain_GJ(name, A, A_rref, den):
|
||||
A = A.to_sparse()
|
||||
A_rref_f, den_f, pivots_f = A.rref_den(keep_domain=False, method='GJ')
|
||||
A_rref_f = A_rref_f.to_field() / den_f
|
||||
_check_divide((A_rref_f, pivots_f), A_rref, den)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_rref, den', RREF_EXAMPLES)
|
||||
def test_ddm_rref_den(name, A, A_rref, den):
|
||||
A = A.to_ddm()
|
||||
_check_cancel(A.rref_den(), A_rref, den)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_rref, den', RREF_EXAMPLES)
|
||||
def test_sdm_rref_den(name, A, A_rref, den):
|
||||
A = A.to_sdm()
|
||||
_check_cancel(A.rref_den(), A_rref, den)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_rref, den', RREF_EXAMPLES)
|
||||
def test_ddm_rref(name, A, A_rref, den):
|
||||
A = A.to_field().to_ddm()
|
||||
_check_divide(A.rref(), A_rref, den)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_rref, den', RREF_EXAMPLES)
|
||||
def test_sdm_rref(name, A, A_rref, den):
|
||||
A = A.to_field().to_sdm()
|
||||
_check_divide(A.rref(), A_rref, den)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_rref, den', RREF_EXAMPLES)
|
||||
def test_ddm_irref(name, A, A_rref, den):
|
||||
A = A.to_field().to_ddm().copy()
|
||||
pivots_found = ddm_irref(A)
|
||||
_check_divide((A, pivots_found), A_rref, den)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_rref, den', RREF_EXAMPLES)
|
||||
def test_ddm_irref_den(name, A, A_rref, den):
|
||||
A = A.to_ddm().copy()
|
||||
(den_found, pivots_found) = ddm_irref_den(A, A.domain)
|
||||
result = (A, den_found, pivots_found)
|
||||
_check_cancel(result, A_rref, den)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_rref, den', RREF_EXAMPLES)
|
||||
def test_sparse_sdm_rref(name, A, A_rref, den):
|
||||
A = A.to_field().to_sdm()
|
||||
_check_divide(sdm_irref(A)[:2], A_rref, den)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, A, A_rref, den', RREF_EXAMPLES)
|
||||
def test_sparse_sdm_rref_den(name, A, A_rref, den):
|
||||
A = A.to_sdm().copy()
|
||||
K = A.domain
|
||||
_check_cancel(sdm_rref_den(A, K), A_rref, den)
|
||||
@@ -0,0 +1,428 @@
|
||||
"""
|
||||
Tests for the basic functionality of the SDM class.
|
||||
"""
|
||||
|
||||
from itertools import product
|
||||
|
||||
from sympy.core.singleton import S
|
||||
from sympy.external.gmpy import GROUND_TYPES
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
from sympy.polys.domains import QQ, ZZ, EXRAW
|
||||
from sympy.polys.matrices.sdm import SDM
|
||||
from sympy.polys.matrices.ddm import DDM
|
||||
from sympy.polys.matrices.exceptions import (DMBadInputError, DMDomainError,
|
||||
DMShapeError)
|
||||
|
||||
|
||||
def test_SDM():
|
||||
A = SDM({0:{0:ZZ(1)}}, (2, 2), ZZ)
|
||||
assert A.domain == ZZ
|
||||
assert A.shape == (2, 2)
|
||||
assert dict(A) == {0:{0:ZZ(1)}}
|
||||
|
||||
raises(DMBadInputError, lambda: SDM({5:{1:ZZ(0)}}, (2, 2), ZZ))
|
||||
raises(DMBadInputError, lambda: SDM({0:{5:ZZ(0)}}, (2, 2), ZZ))
|
||||
|
||||
|
||||
def test_DDM_str():
|
||||
sdm = SDM({0:{0:ZZ(1)}, 1:{1:ZZ(1)}}, (2, 2), ZZ)
|
||||
assert str(sdm) == '{0: {0: 1}, 1: {1: 1}}'
|
||||
if GROUND_TYPES == 'gmpy': # pragma: no cover
|
||||
assert repr(sdm) == 'SDM({0: {0: mpz(1)}, 1: {1: mpz(1)}}, (2, 2), ZZ)'
|
||||
else: # pragma: no cover
|
||||
assert repr(sdm) == 'SDM({0: {0: 1}, 1: {1: 1}}, (2, 2), ZZ)'
|
||||
|
||||
|
||||
def test_SDM_new():
|
||||
A = SDM({0:{0:ZZ(1)}}, (2, 2), ZZ)
|
||||
B = A.new({}, (2, 2), ZZ)
|
||||
assert B == SDM({}, (2, 2), ZZ)
|
||||
|
||||
|
||||
def test_SDM_copy():
|
||||
A = SDM({0:{0:ZZ(1)}}, (2, 2), ZZ)
|
||||
B = A.copy()
|
||||
assert A == B
|
||||
A[0][0] = ZZ(2)
|
||||
assert A != B
|
||||
|
||||
|
||||
def test_SDM_from_list():
|
||||
A = SDM.from_list([[ZZ(0), ZZ(1)], [ZZ(1), ZZ(0)]], (2, 2), ZZ)
|
||||
assert A == SDM({0:{1:ZZ(1)}, 1:{0:ZZ(1)}}, (2, 2), ZZ)
|
||||
|
||||
raises(DMBadInputError, lambda: SDM.from_list([[ZZ(0)], [ZZ(0), ZZ(1)]], (2, 2), ZZ))
|
||||
raises(DMBadInputError, lambda: SDM.from_list([[ZZ(0), ZZ(1)]], (2, 2), ZZ))
|
||||
|
||||
|
||||
def test_SDM_to_list():
|
||||
A = SDM({0:{1: ZZ(1)}}, (2, 2), ZZ)
|
||||
assert A.to_list() == [[ZZ(0), ZZ(1)], [ZZ(0), ZZ(0)]]
|
||||
|
||||
A = SDM({}, (0, 2), ZZ)
|
||||
assert A.to_list() == []
|
||||
|
||||
A = SDM({}, (2, 0), ZZ)
|
||||
assert A.to_list() == [[], []]
|
||||
|
||||
|
||||
def test_SDM_to_list_flat():
|
||||
A = SDM({0:{1: ZZ(1)}}, (2, 2), ZZ)
|
||||
assert A.to_list_flat() == [ZZ(0), ZZ(1), ZZ(0), ZZ(0)]
|
||||
|
||||
|
||||
def test_SDM_to_dok():
|
||||
A = SDM({0:{1: ZZ(1)}}, (2, 2), ZZ)
|
||||
assert A.to_dok() == {(0, 1): ZZ(1)}
|
||||
|
||||
|
||||
def test_SDM_from_ddm():
|
||||
A = DDM([[ZZ(1), ZZ(0)], [ZZ(1), ZZ(0)]], (2, 2), ZZ)
|
||||
B = SDM.from_ddm(A)
|
||||
assert B.domain == ZZ
|
||||
assert B.shape == (2, 2)
|
||||
assert dict(B) == {0:{0:ZZ(1)}, 1:{0:ZZ(1)}}
|
||||
|
||||
|
||||
def test_SDM_to_ddm():
|
||||
A = SDM({0:{1: ZZ(1)}}, (2, 2), ZZ)
|
||||
B = DDM([[ZZ(0), ZZ(1)], [ZZ(0), ZZ(0)]], (2, 2), ZZ)
|
||||
assert A.to_ddm() == B
|
||||
|
||||
|
||||
def test_SDM_to_sdm():
|
||||
A = SDM({0:{1: ZZ(1)}}, (2, 2), ZZ)
|
||||
assert A.to_sdm() == A
|
||||
|
||||
|
||||
def test_SDM_getitem():
|
||||
A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ)
|
||||
assert A.getitem(0, 0) == ZZ.zero
|
||||
assert A.getitem(0, 1) == ZZ.one
|
||||
assert A.getitem(1, 0) == ZZ.zero
|
||||
assert A.getitem(-2, -2) == ZZ.zero
|
||||
assert A.getitem(-2, -1) == ZZ.one
|
||||
assert A.getitem(-1, -2) == ZZ.zero
|
||||
raises(IndexError, lambda: A.getitem(2, 0))
|
||||
raises(IndexError, lambda: A.getitem(0, 2))
|
||||
|
||||
|
||||
def test_SDM_setitem():
|
||||
A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ)
|
||||
A.setitem(0, 0, ZZ(1))
|
||||
assert A == SDM({0:{0:ZZ(1), 1:ZZ(1)}}, (2, 2), ZZ)
|
||||
A.setitem(1, 0, ZZ(1))
|
||||
assert A == SDM({0:{0:ZZ(1), 1:ZZ(1)}, 1:{0:ZZ(1)}}, (2, 2), ZZ)
|
||||
A.setitem(1, 0, ZZ(0))
|
||||
assert A == SDM({0:{0:ZZ(1), 1:ZZ(1)}}, (2, 2), ZZ)
|
||||
# Repeat the above test so that this time the row is empty
|
||||
A.setitem(1, 0, ZZ(0))
|
||||
assert A == SDM({0:{0:ZZ(1), 1:ZZ(1)}}, (2, 2), ZZ)
|
||||
A.setitem(0, 0, ZZ(0))
|
||||
assert A == SDM({0:{1:ZZ(1)}}, (2, 2), ZZ)
|
||||
# This time the row is there but column is empty
|
||||
A.setitem(0, 0, ZZ(0))
|
||||
assert A == SDM({0:{1:ZZ(1)}}, (2, 2), ZZ)
|
||||
raises(IndexError, lambda: A.setitem(2, 0, ZZ(1)))
|
||||
raises(IndexError, lambda: A.setitem(0, 2, ZZ(1)))
|
||||
|
||||
|
||||
def test_SDM_extract_slice():
|
||||
A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ)
|
||||
B = A.extract_slice(slice(1, 2), slice(1, 2))
|
||||
assert B == SDM({0:{0:ZZ(4)}}, (1, 1), ZZ)
|
||||
|
||||
|
||||
def test_SDM_extract():
|
||||
A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ)
|
||||
B = A.extract([1], [1])
|
||||
assert B == SDM({0:{0:ZZ(4)}}, (1, 1), ZZ)
|
||||
B = A.extract([1, 0], [1, 0])
|
||||
assert B == SDM({0:{0:ZZ(4), 1:ZZ(3)}, 1:{0:ZZ(2), 1:ZZ(1)}}, (2, 2), ZZ)
|
||||
B = A.extract([1, 1], [1, 1])
|
||||
assert B == SDM({0:{0:ZZ(4), 1:ZZ(4)}, 1:{0:ZZ(4), 1:ZZ(4)}}, (2, 2), ZZ)
|
||||
B = A.extract([-1], [-1])
|
||||
assert B == SDM({0:{0:ZZ(4)}}, (1, 1), ZZ)
|
||||
|
||||
A = SDM({}, (2, 2), ZZ)
|
||||
B = A.extract([0, 1, 0], [0, 0])
|
||||
assert B == SDM({}, (3, 2), ZZ)
|
||||
|
||||
A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ)
|
||||
assert A.extract([], []) == SDM.zeros((0, 0), ZZ)
|
||||
assert A.extract([1], []) == SDM.zeros((1, 0), ZZ)
|
||||
assert A.extract([], [1]) == SDM.zeros((0, 1), ZZ)
|
||||
|
||||
raises(IndexError, lambda: A.extract([2], [0]))
|
||||
raises(IndexError, lambda: A.extract([0], [2]))
|
||||
raises(IndexError, lambda: A.extract([-3], [0]))
|
||||
raises(IndexError, lambda: A.extract([0], [-3]))
|
||||
|
||||
|
||||
def test_SDM_zeros():
|
||||
A = SDM.zeros((2, 2), ZZ)
|
||||
assert A.domain == ZZ
|
||||
assert A.shape == (2, 2)
|
||||
assert dict(A) == {}
|
||||
|
||||
def test_SDM_ones():
|
||||
A = SDM.ones((1, 2), QQ)
|
||||
assert A.domain == QQ
|
||||
assert A.shape == (1, 2)
|
||||
assert dict(A) == {0:{0:QQ(1), 1:QQ(1)}}
|
||||
|
||||
def test_SDM_eye():
|
||||
A = SDM.eye((2, 2), ZZ)
|
||||
assert A.domain == ZZ
|
||||
assert A.shape == (2, 2)
|
||||
assert dict(A) == {0:{0:ZZ(1)}, 1:{1:ZZ(1)}}
|
||||
|
||||
|
||||
def test_SDM_diag():
|
||||
A = SDM.diag([ZZ(1), ZZ(2)], ZZ, (2, 3))
|
||||
assert A == SDM({0:{0:ZZ(1)}, 1:{1:ZZ(2)}}, (2, 3), ZZ)
|
||||
|
||||
|
||||
def test_SDM_transpose():
|
||||
A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ)
|
||||
B = SDM({0:{0:ZZ(1), 1:ZZ(3)}, 1:{0:ZZ(2), 1:ZZ(4)}}, (2, 2), ZZ)
|
||||
assert A.transpose() == B
|
||||
|
||||
A = SDM({0:{1:ZZ(2)}}, (2, 2), ZZ)
|
||||
B = SDM({1:{0:ZZ(2)}}, (2, 2), ZZ)
|
||||
assert A.transpose() == B
|
||||
|
||||
A = SDM({0:{1:ZZ(2)}}, (1, 2), ZZ)
|
||||
B = SDM({1:{0:ZZ(2)}}, (2, 1), ZZ)
|
||||
assert A.transpose() == B
|
||||
|
||||
|
||||
def test_SDM_mul():
|
||||
A = SDM({0:{0:ZZ(2)}}, (2, 2), ZZ)
|
||||
B = SDM({0:{0:ZZ(4)}}, (2, 2), ZZ)
|
||||
assert A*ZZ(2) == B
|
||||
assert ZZ(2)*A == B
|
||||
|
||||
raises(TypeError, lambda: A*QQ(1, 2))
|
||||
raises(TypeError, lambda: QQ(1, 2)*A)
|
||||
|
||||
|
||||
def test_SDM_mul_elementwise():
|
||||
A = SDM({0:{0:ZZ(2), 1:ZZ(2)}}, (2, 2), ZZ)
|
||||
B = SDM({0:{0:ZZ(4)}, 1:{0:ZZ(3)}}, (2, 2), ZZ)
|
||||
C = SDM({0:{0:ZZ(8)}}, (2, 2), ZZ)
|
||||
assert A.mul_elementwise(B) == C
|
||||
assert B.mul_elementwise(A) == C
|
||||
|
||||
Aq = A.convert_to(QQ)
|
||||
A1 = SDM({0:{0:ZZ(1)}}, (1, 1), ZZ)
|
||||
|
||||
raises(DMDomainError, lambda: Aq.mul_elementwise(B))
|
||||
raises(DMShapeError, lambda: A1.mul_elementwise(B))
|
||||
|
||||
|
||||
def test_SDM_matmul():
|
||||
A = SDM({0:{0:ZZ(2)}}, (2, 2), ZZ)
|
||||
B = SDM({0:{0:ZZ(4)}}, (2, 2), ZZ)
|
||||
assert A.matmul(A) == A*A == B
|
||||
|
||||
C = SDM({0:{0:ZZ(2)}}, (2, 2), QQ)
|
||||
raises(DMDomainError, lambda: A.matmul(C))
|
||||
|
||||
A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ)
|
||||
B = SDM({0:{0:ZZ(7), 1:ZZ(10)}, 1:{0:ZZ(15), 1:ZZ(22)}}, (2, 2), ZZ)
|
||||
assert A.matmul(A) == A*A == B
|
||||
|
||||
A22 = SDM({0:{0:ZZ(4)}}, (2, 2), ZZ)
|
||||
A32 = SDM({0:{0:ZZ(2)}}, (3, 2), ZZ)
|
||||
A23 = SDM({0:{0:ZZ(4)}}, (2, 3), ZZ)
|
||||
A33 = SDM({0:{0:ZZ(8)}}, (3, 3), ZZ)
|
||||
A22 = SDM({0:{0:ZZ(8)}}, (2, 2), ZZ)
|
||||
assert A32.matmul(A23) == A33
|
||||
assert A23.matmul(A32) == A22
|
||||
# XXX: @ not supported by SDM...
|
||||
#assert A32.matmul(A23) == A32 @ A23 == A33
|
||||
#assert A23.matmul(A32) == A23 @ A32 == A22
|
||||
#raises(DMShapeError, lambda: A23 @ A22)
|
||||
raises(DMShapeError, lambda: A23.matmul(A22))
|
||||
|
||||
A = SDM({0: {0: ZZ(-1), 1: ZZ(1)}}, (1, 2), ZZ)
|
||||
B = SDM({0: {0: ZZ(-1)}, 1: {0: ZZ(-1)}}, (2, 1), ZZ)
|
||||
assert A.matmul(B) == A*B == SDM({}, (1, 1), ZZ)
|
||||
|
||||
|
||||
def test_matmul_exraw():
|
||||
|
||||
def dm(d):
|
||||
result = {}
|
||||
for i, row in d.items():
|
||||
row = {j:val for j, val in row.items() if val}
|
||||
if row:
|
||||
result[i] = row
|
||||
return SDM(result, (2, 2), EXRAW)
|
||||
|
||||
values = [S.NegativeInfinity, S.NegativeOne, S.Zero, S.One, S.Infinity]
|
||||
for a, b, c, d in product(*[values]*4):
|
||||
Ad = dm({0: {0:a, 1:b}, 1: {0:c, 1:d}})
|
||||
Ad2 = dm({0: {0:a*a + b*c, 1:a*b + b*d}, 1:{0:c*a + d*c, 1: c*b + d*d}})
|
||||
assert Ad * Ad == Ad2
|
||||
|
||||
|
||||
def test_SDM_add():
|
||||
A = SDM({0:{1:ZZ(1)}, 1:{0:ZZ(2), 1:ZZ(3)}}, (2, 2), ZZ)
|
||||
B = SDM({0:{0:ZZ(1)}, 1:{0:ZZ(-2), 1:ZZ(3)}}, (2, 2), ZZ)
|
||||
C = SDM({0:{0:ZZ(1), 1:ZZ(1)}, 1:{1:ZZ(6)}}, (2, 2), ZZ)
|
||||
assert A.add(B) == B.add(A) == A + B == B + A == C
|
||||
|
||||
A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ)
|
||||
B = SDM({0:{0:ZZ(1)}, 1:{0:ZZ(-2), 1:ZZ(3)}}, (2, 2), ZZ)
|
||||
C = SDM({0:{0:ZZ(1), 1:ZZ(1)}, 1:{0:ZZ(-2), 1:ZZ(3)}}, (2, 2), ZZ)
|
||||
assert A.add(B) == B.add(A) == A + B == B + A == C
|
||||
|
||||
raises(TypeError, lambda: A + [])
|
||||
|
||||
|
||||
def test_SDM_sub():
|
||||
A = SDM({0:{1:ZZ(1)}, 1:{0:ZZ(2), 1:ZZ(3)}}, (2, 2), ZZ)
|
||||
B = SDM({0:{0:ZZ(1)}, 1:{0:ZZ(-2), 1:ZZ(3)}}, (2, 2), ZZ)
|
||||
C = SDM({0:{0:ZZ(-1), 1:ZZ(1)}, 1:{0:ZZ(4)}}, (2, 2), ZZ)
|
||||
assert A.sub(B) == A - B == C
|
||||
|
||||
raises(TypeError, lambda: A - [])
|
||||
|
||||
|
||||
def test_SDM_neg():
|
||||
A = SDM({0:{1:ZZ(1)}, 1:{0:ZZ(2), 1:ZZ(3)}}, (2, 2), ZZ)
|
||||
B = SDM({0:{1:ZZ(-1)}, 1:{0:ZZ(-2), 1:ZZ(-3)}}, (2, 2), ZZ)
|
||||
assert A.neg() == -A == B
|
||||
|
||||
|
||||
def test_SDM_convert_to():
|
||||
A = SDM({0:{1:ZZ(1)}, 1:{0:ZZ(2), 1:ZZ(3)}}, (2, 2), ZZ)
|
||||
B = SDM({0:{1:QQ(1)}, 1:{0:QQ(2), 1:QQ(3)}}, (2, 2), QQ)
|
||||
C = A.convert_to(QQ)
|
||||
assert C == B
|
||||
assert C.domain == QQ
|
||||
|
||||
D = A.convert_to(ZZ)
|
||||
assert D == A
|
||||
assert D.domain == ZZ
|
||||
|
||||
|
||||
def test_SDM_hstack():
|
||||
A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ)
|
||||
B = SDM({1:{1:ZZ(1)}}, (2, 2), ZZ)
|
||||
AA = SDM({0:{1:ZZ(1), 3:ZZ(1)}}, (2, 4), ZZ)
|
||||
AB = SDM({0:{1:ZZ(1)}, 1:{3:ZZ(1)}}, (2, 4), ZZ)
|
||||
assert SDM.hstack(A) == A
|
||||
assert SDM.hstack(A, A) == AA
|
||||
assert SDM.hstack(A, B) == AB
|
||||
|
||||
|
||||
def test_SDM_vstack():
|
||||
A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ)
|
||||
B = SDM({1:{1:ZZ(1)}}, (2, 2), ZZ)
|
||||
AA = SDM({0:{1:ZZ(1)}, 2:{1:ZZ(1)}}, (4, 2), ZZ)
|
||||
AB = SDM({0:{1:ZZ(1)}, 3:{1:ZZ(1)}}, (4, 2), ZZ)
|
||||
assert SDM.vstack(A) == A
|
||||
assert SDM.vstack(A, A) == AA
|
||||
assert SDM.vstack(A, B) == AB
|
||||
|
||||
|
||||
def test_SDM_applyfunc():
|
||||
A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ)
|
||||
B = SDM({0:{1:ZZ(2)}}, (2, 2), ZZ)
|
||||
assert A.applyfunc(lambda x: 2*x, ZZ) == B
|
||||
|
||||
|
||||
def test_SDM_inv():
|
||||
A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ)
|
||||
B = SDM({0:{0:QQ(-2), 1:QQ(1)}, 1:{0:QQ(3, 2), 1:QQ(-1, 2)}}, (2, 2), QQ)
|
||||
assert A.inv() == B
|
||||
|
||||
|
||||
def test_SDM_det():
|
||||
A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ)
|
||||
assert A.det() == QQ(-2)
|
||||
|
||||
|
||||
def test_SDM_lu():
|
||||
A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ)
|
||||
L = SDM({0:{0:QQ(1)}, 1:{0:QQ(3), 1:QQ(1)}}, (2, 2), QQ)
|
||||
#U = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(-2)}}, (2, 2), QQ)
|
||||
#swaps = []
|
||||
# This doesn't quite work. U has some nonzero elements in the lower part.
|
||||
#assert A.lu() == (L, U, swaps)
|
||||
assert A.lu()[0] == L
|
||||
|
||||
|
||||
def test_SDM_lu_solve():
|
||||
A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ)
|
||||
b = SDM({0:{0:QQ(1)}, 1:{0:QQ(2)}}, (2, 1), QQ)
|
||||
x = SDM({1:{0:QQ(1, 2)}}, (2, 1), QQ)
|
||||
assert A.matmul(x) == b
|
||||
assert A.lu_solve(b) == x
|
||||
|
||||
|
||||
def test_SDM_charpoly():
|
||||
A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ)
|
||||
assert A.charpoly() == [ZZ(1), ZZ(-5), ZZ(-2)]
|
||||
|
||||
|
||||
def test_SDM_nullspace():
|
||||
# More tests are in test_nullspace.py
|
||||
A = SDM({0:{0:QQ(1), 1:QQ(1)}}, (2, 2), QQ)
|
||||
assert A.nullspace()[0] == SDM({0:{0:QQ(-1), 1:QQ(1)}}, (1, 2), QQ)
|
||||
|
||||
|
||||
def test_SDM_rref():
|
||||
# More tests are in test_rref.py
|
||||
|
||||
A = SDM({0:{0:QQ(1), 1:QQ(2)},
|
||||
1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ)
|
||||
A_rref = SDM({0:{0:QQ(1)}, 1:{1:QQ(1)}}, (2, 2), QQ)
|
||||
assert A.rref() == (A_rref, [0, 1])
|
||||
|
||||
A = SDM({0: {0: QQ(1), 1: QQ(2), 2: QQ(2)},
|
||||
1: {0: QQ(3), 2: QQ(4)}}, (2, 3), ZZ)
|
||||
A_rref = SDM({0: {0: QQ(1,1), 2: QQ(4,3)},
|
||||
1: {1: QQ(1,1), 2: QQ(1,3)}}, (2, 3), QQ)
|
||||
assert A.rref() == (A_rref, [0, 1])
|
||||
|
||||
|
||||
def test_SDM_particular():
|
||||
A = SDM({0:{0:QQ(1)}}, (2, 2), QQ)
|
||||
Apart = SDM.zeros((1, 2), QQ)
|
||||
assert A.particular() == Apart
|
||||
|
||||
|
||||
def test_SDM_is_zero_matrix():
|
||||
A = SDM({0: {0: QQ(1)}}, (2, 2), QQ)
|
||||
Azero = SDM.zeros((1, 2), QQ)
|
||||
assert A.is_zero_matrix() is False
|
||||
assert Azero.is_zero_matrix() is True
|
||||
|
||||
|
||||
def test_SDM_is_upper():
|
||||
A = SDM({0: {0: QQ(1), 1: QQ(2), 2: QQ(3), 3: QQ(4)},
|
||||
1: {1: QQ(5), 2: QQ(6), 3: QQ(7)},
|
||||
2: {2: QQ(8), 3: QQ(9)}}, (3, 4), QQ)
|
||||
B = SDM({0: {0: QQ(1), 1: QQ(2), 2: QQ(3), 3: QQ(4)},
|
||||
1: {1: QQ(5), 2: QQ(6), 3: QQ(7)},
|
||||
2: {1: QQ(7), 2: QQ(8), 3: QQ(9)}}, (3, 4), QQ)
|
||||
assert A.is_upper() is True
|
||||
assert B.is_upper() is False
|
||||
|
||||
|
||||
def test_SDM_is_lower():
|
||||
A = SDM({0: {0: QQ(1), 1: QQ(2), 2: QQ(3), 3: QQ(4)},
|
||||
1: {1: QQ(5), 2: QQ(6), 3: QQ(7)},
|
||||
2: {2: QQ(8), 3: QQ(9)}}, (3, 4), QQ
|
||||
).transpose()
|
||||
B = SDM({0: {0: QQ(1), 1: QQ(2), 2: QQ(3), 3: QQ(4)},
|
||||
1: {1: QQ(5), 2: QQ(6), 3: QQ(7)},
|
||||
2: {1: QQ(7), 2: QQ(8), 3: QQ(9)}}, (3, 4), QQ
|
||||
).transpose()
|
||||
assert A.is_lower() is True
|
||||
assert B.is_lower() is False
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user