def eval_inverse(self, expand=False): # Inverse of one by one block matrix is easy if self.blockshape==(1,1): mat = Matrix(1, 1, (Inverse(self.blocks[0]), )) return BlockMatrix(mat) # Inverse of a two by two block matrix is known elif expand and self.blockshape==(2,2): # Cite: The Matrix Cookbook Section 9.1.3 A11, A12, A21, A22 = (self.blocks[0,0], self.blocks[0,1], self.blocks[1,0], self.blocks[1,1]) C1 = A11 - A12*Inverse(A22)*A21 C2 = A22 - A21*Inverse(A11)*A12 mat = Matrix([[Inverse(C1), Inverse(-A11)*A12*Inverse(C2)], [-Inverse(C2)*A21*Inverse(A11), Inverse(C2)]]) return BlockMatrix(mat) else: raise NotImplementedError()
def xxinv(mul): """ Y * X * X.I -> Y """ from sympy.matrices.expressions import Inverse factor, matrices = mul.as_coeff_matrices() for i, (X, Y) in enumerate(zip(matrices[:-1], matrices[1:])): try: if X.is_square and Y.is_square and X == Inverse(Y): I = Identity(X.rows) return newmul(factor, *(matrices[:i] + [I] + matrices[i + 2:])) except ValueError: # Y might not be invertible pass return mul
def block_collapse(expr): """Evaluates a block matrix expression >>> from sympy import MatrixSymbol, BlockMatrix, symbols, Identity, Matrix, ZeroMatrix, block_collapse >>> n,m,l = symbols('n m l') >>> X = MatrixSymbol('X', n, n) >>> Y = MatrixSymbol('Y', m ,m) >>> Z = MatrixSymbol('Z', n, m) >>> B = BlockMatrix([[X, Z], [ZeroMatrix(m, n), Y]]) >>> print B [X, Z] [0, Y] >>> C = BlockMatrix([[Identity(n), Z]]) >>> print C [I, Z] >>> print block_collapse(C*B) [X, Z + Z*Y] """ if expr.__class__ in [tuple, list, set, frozenset]: return expr.__class__([block_collapse(arg) for arg in expr]) if expr.__class__ in [Tuple, FiniteSet]: return expr.__class__(*[block_collapse(arg) for arg in expr]) if not expr.is_Matrix or (not expr.is_Add and not expr.is_Mul and not expr.is_Transpose and not expr.is_Pow and not expr.is_Inverse): return expr if expr.is_Transpose: expr = Transpose(block_collapse(expr.arg)) if expr.is_Transpose and expr.arg.is_BlockMatrix: expr = expr.arg.eval_transpose() return expr if expr.is_Inverse: return Inverse(block_collapse(expr.arg)) # Recurse on the subargs args = list(expr.args) for i in range(len(args)): arg = args[i] newarg = block_collapse(arg) while(newarg != arg): # Repeat until no new changes arg = newarg newarg = block_collapse(arg) args[i] = newarg if tuple(args) != expr.args: expr = expr.__class__(*args) # Turn -[X, Y] into [-X, -Y] if (expr.is_Mul and len(expr.args)==2 and not expr.args[0].is_Matrix and expr.args[1].is_BlockMatrix): if expr.args[1].is_BlockDiagMatrix: return BlockDiagMatrix( *[expr.args[0]*arg for arg in expr.args[1].diag]) else: return BlockMatrix(expr.args[0]*expr.args[1].mat) if expr.is_Add: nonblocks = [arg for arg in expr.args if not arg.is_BlockMatrix] blocks = [arg for arg in expr.args if arg.is_BlockMatrix] if not blocks: return MatAdd(*nonblocks) block = blocks[0] for b in blocks[1:]: block = block._blockadd(b) if block.blockshape == (1,1): # Bring all the non-blocks into the block_matrix mat = Matrix(1, 1, (block.blocks[0,0] + MatAdd(*nonblocks), )) return BlockMatrix(mat) # Add identities to the blocks as block identities for i, mat in enumerate(nonblocks): c, M = mat.as_coeff_Mul() if M.is_Identity and block.is_structurally_symmetric: block_id = BlockDiagMatrix( *[c*Identity(k) for k in block.rowblocksizes]) nonblocks.pop(i) block = block._blockadd(block_id) return MatAdd(*(nonblocks+[block])) if expr.is_Mul: nonmatrices = [arg for arg in expr.args if not arg.is_Matrix] matrices = [arg for arg in expr.args if arg.is_Matrix] i = 0 while (i+1 < len(matrices)): A, B = matrices[i:i+2] if A.is_BlockMatrix and B.is_BlockMatrix: matrices[i] = A._blockmul(B) matrices.pop(i+1) else: i+=1 return MatMul(*(nonmatrices + matrices)) if expr.is_Pow: rv = expr.base for i in range(1, expr.exp): rv = rv._blockmul(expr.base) return rv
def eval_inverse(self): return BlockDiagMatrix(*[Inverse(mat) for mat in self.diag])
def inverse(self): return Inverse(self)
def __pow__(self, other): if other == -S.One: return Inverse(self) return MatPow(self, other)
def I(self): return Inverse(self)
def inverse(self): # XXX document how this is different than inv return Inverse(self)
def _eval_inverse(self): from inverse import Inverse try: return MatMul(*[Inverse(arg) for arg in self.args[::-1]]) except ShapeError: raise NotImplementedError("Can not decompose this Inverse")