def transpose(self): if isinstance(self, Transpose): return self.arg if self.is_Mul: return MatMul(*[Transpose(arg) for arg in self.args[::-1]]) if self.is_Add: return MatAdd(*[Transpose(arg) for arg in self.args]) try: return self._eval_transpose() except (AttributeError, NotImplementedError): return Basic.__new__(Transpose, self)
def eval_transpose(self): # Flip all the individual matrices matrices = [Transpose(matrix) for matrix in self.mat.mat] # Make a copy mat = Matrix(self.blockshape[0], self.blockshape[1], matrices) # Transpose the block structure mat = mat.transpose() return BlockMatrix(mat)
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 T(self): return Transpose(self)
def _eval_transpose(self): from transpose import Transpose return HadamardProduct(*[Transpose(arg) for arg in self.args])
def _eval_transpose(self): from transpose import Transpose return MatAdd(*[Transpose(arg) for arg in self.args])
def _eval_transpose(self): from transpose import Transpose return MatMul(*[Transpose(arg) for arg in self.args[::-1]])