switching to high quality piper tts and added label translations

This commit is contained in:
Matthias Hinrichs
2026-01-29 23:48:19 +01:00
commit d80c619df9
3934 changed files with 1451600 additions and 0 deletions
@@ -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))
@@ -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())
@@ -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