def test_BlockDiagMatrix(): A = MatrixSymbol("A", n, n) B = MatrixSymbol("B", m, m) C = MatrixSymbol("C", l, l) M = MatrixSymbol("M", n + m + l, n + m + l) X = BlockDiagMatrix(A, B, C) Y = BlockDiagMatrix(A, 2 * B, 3 * C) assert X.blocks[1, 1] == B assert X.shape == (n + m + l, n + m + l) assert all( X.blocks[i, j].is_ZeroMatrix if i != j else X.blocks[i, j] in [A, B, C] for i in range(3) for j in range(3) ) assert X.__class__(*X.args) == X assert isinstance(block_collapse(X.I * X), Identity) assert bc_matmul(X * X) == BlockDiagMatrix(A * A, B * B, C * C) assert block_collapse(X * X) == BlockDiagMatrix(A * A, B * B, C * C) # XXX: should be == ?? assert block_collapse(X + X).equals(BlockDiagMatrix(2 * A, 2 * B, 2 * C)) assert block_collapse(X * Y) == BlockDiagMatrix(A * A, 2 * B * B, 3 * C * C) assert block_collapse(X + Y) == BlockDiagMatrix(2 * A, 3 * B, 4 * C) # Ensure that BlockDiagMatrices can still interact with normal MatrixExprs assert (X * (2 * M)).is_MatMul assert (X + (2 * M)).is_MatAdd assert (X._blockmul(M)).is_MatMul assert (X._blockadd(M)).is_MatAdd
def test_bc_dist_diag(): A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', m, m) C = MatrixSymbol('C', l, l) X = BlockDiagMatrix(A, B, C) assert bc_dist(X + X).equals(BlockDiagMatrix(2 * A, 2 * B, 2 * C))
def test_block_collapse_type(): bm1 = BlockDiagMatrix(ImmutableMatrix([1]), ImmutableMatrix([2])) bm2 = BlockDiagMatrix(ImmutableMatrix([3]), ImmutableMatrix([4])) assert bm1.T.__class__ == BlockDiagMatrix assert block_collapse(bm1 - bm2).__class__ == BlockDiagMatrix assert block_collapse(Inverse(bm1)).__class__ == BlockDiagMatrix assert block_collapse(Transpose(bm1)).__class__ == BlockDiagMatrix assert bc_transpose(Transpose(bm1)).__class__ == BlockDiagMatrix assert bc_inverse(Inverse(bm1)).__class__ == BlockDiagMatrix
def test_BlockDiagMatrix_determinant(): A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', m, m) assert det(BlockDiagMatrix()) == 1 assert det(BlockDiagMatrix(A)) == det(A) assert det(BlockDiagMatrix(A, B)) == det(A) * det(B) # non-square blocks C = MatrixSymbol('C', m, n) D = MatrixSymbol('D', n, m) assert det(BlockDiagMatrix(C, D)) == 0
def test_BlockDiagMatrix_trace(): assert trace(BlockDiagMatrix()) == 0 assert trace(BlockDiagMatrix(ZeroMatrix(n, n))) == 0 A = MatrixSymbol('A', n, n) assert trace(BlockDiagMatrix(A)) == trace(A) B = MatrixSymbol('B', m, m) assert trace(BlockDiagMatrix(A, B)) == trace(A) + trace(B) # non-square blocks C = MatrixSymbol('C', m, n) D = MatrixSymbol('D', n, m) assert isinstance(trace(BlockDiagMatrix(C, D)), Trace)
def test_BlockDiagMatrix_nonsquare(): A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', k, l) X = BlockDiagMatrix(A, B) assert X.shape == (n + k, m + l) assert X.shape == (n + k, m + l) assert X.rowblocksizes == [n, k] assert X.colblocksizes == [m, l] C = MatrixSymbol('C', n, m) D = MatrixSymbol('D', k, l) Y = BlockDiagMatrix(C, D) assert block_collapse(X + Y) == BlockDiagMatrix(A + C, B + D) assert block_collapse(X * Y.T) == BlockDiagMatrix(A * C.T, B * D.T) raises(NonInvertibleMatrixError, lambda: BlockDiagMatrix(A, C.T).inverse())
def test_block_plus_ident(): A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', n, m) C = MatrixSymbol('C', m, n) D = MatrixSymbol('D', m, m) X = BlockMatrix([[A, B], [C, D]]) assert bc_block_plus_ident(X+Identity(m+n)) == \ BlockDiagMatrix(Identity(n), Identity(m)) + X
def test_block_plus_ident(): A = MatrixSymbol("A", n, n) B = MatrixSymbol("B", n, m) C = MatrixSymbol("C", m, n) D = MatrixSymbol("D", m, m) X = BlockMatrix([[A, B], [C, D]]) assert (bc_block_plus_ident(X + Identity(m + n)) == BlockDiagMatrix( Identity(n), Identity(m)) + X)
def test_sympy__matrices__expressions__blockmatrix__BlockDiagMatrix(): from sympy.matrices.expressions.blockmatrix import BlockDiagMatrix from sympy.matrices.expressions import MatrixSymbol X = MatrixSymbol('X', x, x) Y = MatrixSymbol('Y', y, y) assert _test_args(BlockDiagMatrix(X, Y))
def test_BlockDiagMatrix(): A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', m, m) C = MatrixSymbol('C', l, l) M = MatrixSymbol('M', n + m + l, n + m + l) X = BlockDiagMatrix(A, B, C) Y = BlockDiagMatrix(A, 2 * B, 3 * C) assert X.blocks[1, 1] == B assert X.shape == (n + m + l, n + m + l) assert all( X.blocks[i, j].is_ZeroMatrix if i != j else X.blocks[i, j] in [A, B, C] for i in range(3) for j in range(3)) assert X.__class__(*X.args) == X assert isinstance(block_collapse(X.I * X), Identity) assert bc_matmul(X * X) == BlockDiagMatrix(A * A, B * B, C * C) assert block_collapse(X * X) == BlockDiagMatrix(A * A, B * B, C * C) #XXX: should be == ?? assert block_collapse(X + X).equals(BlockDiagMatrix(2 * A, 2 * B, 2 * C)) assert block_collapse(X * Y) == BlockDiagMatrix(A * A, 2 * B * B, 3 * C * C) assert block_collapse(X + Y) == BlockDiagMatrix(2 * A, 3 * B, 4 * C) # Ensure that BlockDiagMatrices can still interact with normal MatrixExprs assert (X * (2 * M)).is_MatMul assert (X + (2 * M)).is_MatAdd assert (X._blockmul(M)).is_MatMul assert (X._blockadd(M)).is_MatAdd
def test_issue_2460(): bdm1 = BlockDiagMatrix(Matrix([i]), Matrix([j])) bdm2 = BlockDiagMatrix(Matrix([k]), Matrix([l])) assert block_collapse(bdm1 + bdm2) == BlockDiagMatrix(Matrix([i + k]), Matrix([j + l]))
def test_BlockDiagMatrix_transpose(): A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', k, l) assert transpose(BlockDiagMatrix()) == BlockDiagMatrix() assert transpose(BlockDiagMatrix(A)) == BlockDiagMatrix(A.T) assert transpose(BlockDiagMatrix(A, B)) == BlockDiagMatrix(A.T, B.T)
def test_issue_18618(): A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) assert A == Matrix(BlockDiagMatrix(A))
def _connected_components_decomposition(M): """Decomposes a square matrix into block diagonal form only using the permutations. Explanation =========== The decomposition is in a form of $A = P B P^{-1}$ where $P$ is a permutation matrix and $B$ is a block diagonal matrix. Returns ======= P, B : PermutationMatrix, BlockDiagMatrix *P* is a permutation matrix for the similarity transform as in the explanation. And *B* is the block diagonal matrix of the result of the permutation. If you would like to get the diagonal blocks from the BlockDiagMatrix, see :meth:`~sympy.matrices.expressions.blockmatrix.BlockDiagMatrix.get_diag_blocks`. Examples ======== >>> from sympy import symbols, Matrix >>> a, b, c, d, e, f, g, h = symbols('a:h') >>> A = Matrix([ ... [a, 0, b, 0], ... [0, e, 0, f], ... [c, 0, d, 0], ... [0, g, 0, h]]) >>> P, B = A.connected_components_decomposition() >>> P = P.as_explicit() >>> P_inv = P.inv().as_explicit() >>> B = B.as_explicit() >>> P Matrix([ [1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) >>> B Matrix([ [a, b, 0, 0], [c, d, 0, 0], [0, 0, e, f], [0, 0, g, h]]) >>> P * B * P_inv Matrix([ [a, 0, b, 0], [0, e, 0, f], [c, 0, d, 0], [0, g, 0, h]]) Notes ===== This problem corresponds to the finding of the connected components of a graph, when a matrix is viewed as a weighted graph. """ from sympy.combinatorics.permutations import Permutation from sympy.matrices.expressions.blockmatrix import BlockDiagMatrix from sympy.matrices.expressions.permutation import PermutationMatrix iblocks = M.connected_components() p = Permutation(flatten(iblocks)) P = PermutationMatrix(p) blocks = [] for b in iblocks: blocks.append(M[b, b]) B = BlockDiagMatrix(*blocks) return P, B
def _connected_components_decomposition(M): """Decomposes a square matrix into block diagonal form only using the permutations. Explanation =========== The decomposition is in a form of $A = P^{-1} B P$ where $P$ is a permutation matrix and $B$ is a block diagonal matrix. Returns ======= P, B : PermutationMatrix, BlockDiagMatrix *P* is a permutation matrix for the similarity transform as in the explanation. And *B* is the block diagonal matrix of the result of the permutation. If you would like to get the diagonal blocks from the BlockDiagMatrix, see :meth:`~sympy.matrices.expressions.blockmatrix.BlockDiagMatrix.get_diag_blocks`. Examples ======== >>> from sympy import Matrix, pprint >>> A = Matrix([ ... [66, 0, 0, 68, 0, 0, 0, 0, 67], ... [0, 55, 0, 0, 0, 0, 54, 53, 0], ... [0, 0, 0, 0, 1, 2, 0, 0, 0], ... [86, 0, 0, 88, 0, 0, 0, 0, 87], ... [0, 0, 10, 0, 11, 12, 0, 0, 0], ... [0, 0, 20, 0, 21, 22, 0, 0, 0], ... [0, 45, 0, 0, 0, 0, 44, 43, 0], ... [0, 35, 0, 0, 0, 0, 34, 33, 0], ... [76, 0, 0, 78, 0, 0, 0, 0, 77]]) >>> P, B = A.connected_components_decomposition() >>> pprint(P) PermutationMatrix((1 3)(2 8 5 7 4 6)) >>> pprint(B) [[66 68 67] ] [[ ] ] [[86 88 87] 0 0 ] [[ ] ] [[76 78 77] ] [ ] [ [55 54 53] ] [ [ ] ] [ 0 [45 44 43] 0 ] [ [ ] ] [ [35 34 33] ] [ ] [ [0 1 2 ]] [ [ ]] [ 0 0 [10 11 12]] [ [ ]] [ [20 21 22]] >>> P = P.as_explicit() >>> B = B.as_explicit() >>> P.T*B*P == A True Notes ===== This problem corresponds to the finding of the connected components of a graph, when a matrix is viewed as a weighted graph. """ from sympy.combinatorics.permutations import Permutation from sympy.matrices.expressions.blockmatrix import BlockDiagMatrix from sympy.matrices.expressions.permutation import PermutationMatrix iblocks = M.connected_components() p = Permutation(flatten(iblocks)) P = PermutationMatrix(p) blocks = [] for b in iblocks: blocks.append(M[b, b]) B = BlockDiagMatrix(*blocks) return P, B