def LUdecomposition(self): """Returns the Block LU decomposition of a 2x2 Block Matrix Returns ======= (L, U) : Matrices L : Lower Diagonal Matrix U : Upper Diagonal Matrix Examples ======== >>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse >>> m, n = symbols('m n') >>> 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]]) >>> L, U = X.LUdecomposition() >>> block_collapse(L*U) Matrix([ [A, B], [C, D]]) Raises ====== ShapeError If the block matrix is not a 2x2 matrix NonInvertibleMatrixError If the matrix "A" is non-invertible See Also ======== sympy.matrices.expressions.blockmatrix.BlockMatrix.UDLdecomposition sympy.matrices.expressions.blockmatrix.BlockMatrix.LDUdecomposition """ if self.blockshape == (2, 2): [[A, B], [C, D]] = self.blocks.tolist() try: A = A**0.5 AI = A.I except NonInvertibleMatrixError: raise NonInvertibleMatrixError( 'Block LU decomposition cannot be calculated when\ "A" is singular') Z = ZeroMatrix(*B.shape) Q = self.schur()**0.5 L = BlockMatrix([[A, Z], [C * AI, Q]]) U = BlockMatrix([[A, AI * B], [Z.T, Q]]) return L, U else: raise ShapeError( "Block LU decomposition is supported only for 2x2 block matrices" )
def UDLdecomposition(self): """Returns the Block UDL decomposition of a 2x2 Block Matrix Returns ======= (U, D, L) : Matrices U : Upper Diagonal Matrix D : Diagonal Matrix L : Lower Diagonal Matrix Examples ======== >>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse >>> m, n = symbols('m n') >>> 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]]) >>> U, D, L = X.UDLdecomposition() >>> block_collapse(U*D*L) Matrix([ [A, B], [C, D]]) Raises ====== ShapeError If the block matrix is not a 2x2 matrix NonInvertibleMatrixError If the matrix "D" is non-invertible See Also ======== sympy.matrices.expressions.blockmatrix.BlockMatrix.LDUdecomposition sympy.matrices.expressions.blockmatrix.BlockMatrix.LUdecomposition """ if self.blockshape == (2,2): [[A, B], [C, D]] = self.blocks.tolist() try: DI = D.I except NonInvertibleMatrixError: raise NonInvertibleMatrixError('Block UDL decomposition cannot be calculated when\ "D" is singular') Ip = Identity(A.shape[0]) Iq = Identity(B.shape[1]) Z = ZeroMatrix(*B.shape) U = BlockMatrix([[Ip, B*DI], [Z.T, Iq]]) D = BlockDiagMatrix(self.schur('D'), D) L = BlockMatrix([[Ip, Z],[DI*C, Iq]]) return U, D, L else: raise ShapeError("Block UDL decomposition is supported only for 2x2 block matrices")
def __pow__(self, other): if other != 1 and not self.is_square: raise ShapeError("Power of non-square matrix %s" % self) if other == 0: return Identity(self.rows) if other < 1: raise ValueError("Matrix det == 0; not invertible.") return self
def __pow__(self, other): if not self.is_square: raise ShapeError("Power of non-square matrix %s" % self) if other is S.NegativeOne: return Inverse(self) elif other is S.Zero: return Identity(self.rows) elif other is S.One: return self return MatPow(self, other)
def __pow__(self, other): if not self.is_square: raise ShapeError("Power of non-square matrix %s" % self) elif self.is_Identity: return self elif other is S.Zero: return Identity(self.rows) elif other is S.One: return self return MatPow(self, other).doit(deep=False)
def __pow__(self, other): if other != 1 and not self.is_square: raise ShapeError("Power of non-square matrix %s" % self) if other == 0: return Identity(self.rows) return self
def schur(self, mat='A', generalized=False): """Return the Schur Complement of the 2x2 BlockMatrix Parameters ========== mat : String, optional The matrix with respect to which the Schur Complement is calculated. 'A' is used by default generalized : bool, optional If True, returns the generalized Schur Component which uses Moore-Penrose Inverse Examples ======== >>> from sympy import symbols, MatrixSymbol, BlockMatrix >>> m, n = symbols('m n') >>> 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]]) The default Schur Complement is evaluated with "A" >>> X.schur() -C*A**(-1)*B + D >>> X.schur('D') A - B*D**(-1)*C Schur complement with non-invertible matrices is not defined. Instead, the generalized Schur complement can be calculated which uses the Moore-Penrose Inverse. To achieve this, `generalized` must be set to `True` >>> X.schur('B', generalized=True) C - D*(B.T*B)**(-1)*B.T*A >>> X.schur('C', generalized=True) -A*(C.T*C)**(-1)*C.T*D + B Returns ======= M : Matrix The Schur Complement Matrix Raises ====== ShapeError If the block matrix is not a 2x2 matrix NonInvertibleMatrixError If given matrix is non-invertible References ========== .. [1] Wikipedia Article on Schur Component : https://en.wikipedia.org/wiki/Schur_complement See Also ======== sympy.matrices.matrices.MatrixBase.pinv """ if self.blockshape == (2, 2): [[A, B], [C, D]] = self.blocks.tolist() d = {'A': A, 'B': B, 'C': C, 'D': D} try: inv = (d[mat].T * d[mat] ).inv() * d[mat].T if generalized else d[mat].inv() if mat == 'A': return D - C * inv * B elif mat == 'B': return C - D * inv * A elif mat == 'C': return B - A * inv * D elif mat == 'D': return A - B * inv * C #For matrices where no sub-matrix is square return self except NonInvertibleMatrixError: raise NonInvertibleMatrixError( 'The given matrix is not invertible. Please set generalized=True \ to compute the generalized Schur Complement which uses Moore-Penrose Inverse' ) else: raise ShapeError( 'Schur Complement can only be calculated for 2x2 block matrices' )
def linear_factors(expr, *syms): """Reduce a Matrix Expression to a sum of linear factors Given symbols and a matrix expression linear in those symbols return a dict mapping symbol to the linear factor >>> from sympy import MatrixSymbol, linear_factors, symbols >>> n, m, l = symbols('n m l') >>> A = MatrixSymbol('A', n, m) >>> B = MatrixSymbol('B', m, l) >>> C = MatrixSymbol('C', n, l) >>> linear_factors(2*A*B + C, B, C) {B: 2*A, C: I} """ expr = matrixify(expand(expr)) d = {} if expr.is_Matrix and expr.is_Symbol: if expr in syms: d[expr] = Identity(expr.n) if expr.is_Add: for sym in syms: total_factor = 0 for arg in expr.args: factor = arg.coeff(sym) if not factor: # .coeff fails when powers are in the expression if sym in arg.free_symbols: raise ValueError("Expression not linear in symbols") else: factor = 0 factor = sympify(factor) if not factor.is_Matrix: if factor.is_zero: factor = ZeroMatrix(expr.n, sym.n) if not sym.m == expr.m: raise ShapeError( "%s not compatible as factor of %s" % (sym, expr)) else: factor = Identity(sym.n) * factor total_factor += factor d[sym] = total_factor elif expr.is_Mul: for sym in syms: factor = expr.coeff(sym) if not factor: # .coeff fails when powers are in the expression if sym in expr.free_symbols: raise ValueError("Expression not linear in symbols") else: factor = 0 factor = sympify(factor) if not factor.is_Matrix: if factor.is_zero: factor = ZeroMatrix(expr.n, sym.n) if not sym.m == expr.m: raise ShapeError("%s not compatible as factor of %s" % (sym, expr)) else: factor = Identity(sym.n) * factor d[sym] = factor if any(sym in matrix_symbols(Tuple(*d.values())) for sym in syms): raise ValueError("Expression not linear in symbols") return d