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] """ rule = canon(typed({MatAdd: do_one(bc_matadd, bc_block_plus_ident), MatMul: do_one(bc_matmul, bc_dist), MatPow: bc_matpow, BlockMatrix: bc_unpack})) result = rule(expr) try: return result.canonicalize() except AttributeError: return result
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] """ rule = canon( typed({ MatAdd: do_one(bc_matadd, bc_block_plus_ident), MatMul: do_one(bc_matmul, bc_dist), BlockMatrix: bc_unpack })) result = rule(expr) try: return result.doit() except AttributeError: return result
def test_do_one(): rl1 = lambda x: 2 if x == 1 else x rl2 = lambda x: 3 if x == 2 else x rule = do_one(rl1, rl2) assert rule(1) == 2 assert rule(rule(1)) == 3
""" Remove Identities from a MatMul This is a modified version of sympy.rules.rm_id. This is necesssary because MatMul may contain both MatrixExprs and Exprs as args. See Also -------- sympy.rules.rm_id """ # Separate Exprs from MatrixExprs in args factor, mmul = mul.as_coeff_mmul() # Apply standard rm_id for MatMuls result = rm_id(lambda x: x.is_Identity is True)(mmul) if result != mmul: return newmul(factor, *result.args) # Recombine and return else: return mul def factor_in_front(mul): factor, matrices = mul.as_coeff_matrices() if factor != 1: return newmul(factor, *matrices) return mul rules = (any_zeros, remove_ids, xxinv, unpack, rm_id(lambda x: x == 1), factor_in_front, flatten) canonicalize = exhaust(condition(lambda x: isinstance(x, MatMul), do_one(*rules)))
def canonicalize(self): return canonicalize(self) def validate(*args): if not all(arg.is_Matrix for arg in args): raise TypeError("Mix of Matrix and Scalar symbols") A = args[0] for B in args[1:]: if A.shape != B.shape: raise ShapeError("Matrices %s and %s are not aligned" % (A, B)) factor_of = lambda arg: arg.as_coeff_mmul()[0] matrix_of = lambda arg: unpack(arg.as_coeff_mmul()[1]) def combine(cnt, mat): from matmul import MatMul if cnt == 1: return mat else: return cnt * mat rules = (rm_id(lambda x: x == 0 or isinstance(x, ZeroMatrix)), unpack, flatten, glom(matrix_of, factor_of, combine), sort(str)) canonicalize = exhaust( condition(lambda x: isinstance(x, MatAdd), do_one(*rules)))