def test_squareBlockMatrix(): 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]]) Y = BlockMatrix([[A]]) assert X.is_square assert (block_collapse(X + Identity(m + n)) == BlockMatrix( [[A + Identity(n), B], [C, D + Identity(m)]])) Q = X + Identity(m + n) assert (X + MatrixSymbol('Q', n + m, n + m)).is_MatAdd assert (X * MatrixSymbol('Q', n + m, n + m)).is_MatMul assert block_collapse(Y.I) == A.I assert block_collapse(X.inverse()) == BlockMatrix([[ (-B * D.I * C + A).I, -A.I * B * (D + -C * A.I * B).I ], [-(D - C * A.I * B).I * C * A.I, (D - C * A.I * B).I]]) assert isinstance(X.inverse(), Inverse) assert not X.is_Identity Z = BlockMatrix([[Identity(n), B], [C, D]]) assert not Z.is_Identity
def test_squareBlockMatrix(): 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]]) Y = BlockMatrix([[A]]) assert X.is_square assert block_collapse(X + Identity(m + n)) == BlockMatrix([[A + Identity(n), B], [C, D + Identity(m)]]) Q = X + Identity(m + n) assert (X + MatrixSymbol("Q", n + m, n + m)).is_MatAdd assert (X * MatrixSymbol("Q", n + m, n + m)).is_MatMul assert Y.I.blocks[0, 0] == A.I assert X.inverse(expand=True) == BlockMatrix( [[(-B * D.I * C + A).I, -A.I * B * (D + -C * A.I * B).I], [-(D - C * A.I * B).I * C * A.I, (D - C * A.I * B).I]] ) assert isinstance(X.inverse(expand=False), Inverse) assert isinstance(X.inverse(), Inverse) assert not X.is_Identity Z = BlockMatrix([[Identity(n), B], [C, D]]) assert not Z.is_Identity
def test_BlockMatrix_inverse(): A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', n, n) C = MatrixSymbol('C', m, m) D = MatrixSymbol('D', m, n) X = BlockMatrix([[A, B], [C, D]]) assert X.is_square assert isinstance(block_collapse(X.inverse()), Inverse) # Can't inverse when A, D aren't square # test code path for non-invertible D matrix A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', n, m) C = MatrixSymbol('C', m, n) D = OneMatrix(m, m) X = BlockMatrix([[A, B], [C, D]]) assert block_collapse(X.inverse()) == BlockMatrix([ [ A.I + A.I * B * (D - C * A.I * B).I * C * A.I, -A.I * B * (D - C * A.I * B).I ], [-(D - C * A.I * B).I * C * A.I, (D - C * A.I * B).I], ]) # test code path for non-invertible A matrix A = OneMatrix(n, n) D = MatrixSymbol('D', m, m) X = BlockMatrix([[A, B], [C, D]]) assert block_collapse(X.inverse()) == BlockMatrix([ [(A - B * D.I * C).I, -(A - B * D.I * C).I * B * D.I], [ -D.I * C * (A - B * D.I * C).I, D.I + D.I * C * (A - B * D.I * C).I * B * D.I ], ])
def test_squareBlockMatrix(): 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]]) Y = BlockMatrix([[A]]) assert X.is_square assert (block_collapse(X + Identity(m + n)) == BlockMatrix([[A + Identity(n), B], [C, D + Identity(m)]])) Q = X + Identity(m + n) assert (X + MatrixSymbol('Q', n + m, n + m)).is_MatAdd assert (X * MatrixSymbol('Q', n + m, n + m)).is_MatMul assert block_collapse(Y.I) == A.I assert block_collapse(X.inverse()) == BlockMatrix([ [(-B*D.I*C + A).I, -A.I*B*(D + -C*A.I*B).I], [-(D - C*A.I*B).I*C*A.I, (D - C*A.I*B).I]]) assert isinstance(X.inverse(), Inverse) assert not X.is_Identity Z = BlockMatrix([[Identity(n), B], [C, D]]) assert not Z.is_Identity
def test_BlockMatrix_2x2_inverse_symbolic(): A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', n, k - m) C = MatrixSymbol('C', k - n, m) D = MatrixSymbol('D', k - n, k - m) X = BlockMatrix([[A, B], [C, D]]) assert X.is_square and X.shape == (k, k) assert isinstance(block_collapse( X.I), Inverse) # Can't invert when none of the blocks is square # test code path where only A is invertible A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', n, m) C = MatrixSymbol('C', m, n) D = ZeroMatrix(m, m) X = BlockMatrix([[A, B], [C, D]]) assert block_collapse(X.inverse()) == BlockMatrix([ [A.I + A.I * B * X.schur('A').I * C * A.I, -A.I * B * X.schur('A').I], [-X.schur('A').I * C * A.I, X.schur('A').I], ]) # test code path where only B is invertible A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', n, n) C = ZeroMatrix(m, m) D = MatrixSymbol('D', m, n) X = BlockMatrix([[A, B], [C, D]]) assert block_collapse(X.inverse()) == BlockMatrix([ [-X.schur('B').I * D * B.I, X.schur('B').I], [B.I + B.I * A * X.schur('B').I * D * B.I, -B.I * A * X.schur('B').I], ]) # test code path where only C is invertible A = MatrixSymbol('A', n, m) B = ZeroMatrix(n, n) C = MatrixSymbol('C', m, m) D = MatrixSymbol('D', m, n) X = BlockMatrix([[A, B], [C, D]]) assert block_collapse(X.inverse()) == BlockMatrix([ [-C.I * D * X.schur('C').I, C.I + C.I * D * X.schur('C').I * A * C.I], [X.schur('C').I, -X.schur('C').I * A * C.I], ]) # test code path where only D is invertible A = ZeroMatrix(n, n) B = MatrixSymbol('B', n, m) C = MatrixSymbol('C', m, n) D = MatrixSymbol('D', m, m) X = BlockMatrix([[A, B], [C, D]]) assert block_collapse(X.inverse()) == BlockMatrix([ [X.schur('D').I, -X.schur('D').I * B * D.I], [-D.I * C * X.schur('D').I, D.I + D.I * C * X.schur('D').I * B * D.I], ])