def block_collapse(expr): """Evaluates a block matrix expression >>> 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]]) >>> B Matrix([ [X, Z], [0, Y]]) >>> C = BlockMatrix([[Identity(n), Z]]) >>> C Matrix([[I, Z]]) >>> block_collapse(C*B) Matrix([[X, Z + Z*Y]]) """ def hasbm(expr): return isinstance(expr, MatrixExpr) and expr.has(BlockMatrix) rule = exhaust( bottom_up(exhaust(condition(hasbm, typed( {MatAdd: do_one([bc_matadd, bc_block_plus_ident]), MatMul: do_one([bc_matmul, bc_dist]), Transpose: bc_transpose, Inverse: bc_inverse, BlockMatrix: do_one([bc_unpack, deblock])}))))) result = rule(expr) return result.doit()
>>> A = MatrixSymbol('A', 2, 2) >>> B = eye(2) >>> C = Matrix([[1, 2], [3, 4]]) >>> X = MatAdd(A, B, C) >>> pprint(X, use_unicode=False) [1 0] [1 2] A + [ ] + [ ] [0 1] [3 4] >>> pprint(merge_explicit(X), use_unicode=False) [2 2] A + [ ] [3 5] """ groups = sift(matadd.args, lambda arg: isinstance(arg, MatrixBase)) if len(groups[True]) > 1: return MatAdd(*(groups[False] + [reduce(add, groups[True])])) else: return matadd rules = (rm_id(lambda x: x == 0 or isinstance(x, ZeroMatrix)), unpack, flatten, glom(matrix_of, factor_of, combine), merge_explicit, sort(default_sort_key)) canonicalize = exhaust(condition(lambda x: isinstance(x, MatAdd), do_one(rules)))
""" Merge explicit MatrixBase arguments >>> from diofant import MatrixSymbol, eye, Matrix, MatAdd, pprint >>> from diofant.matrices.expressions.matadd import merge_explicit >>> A = MatrixSymbol('A', 2, 2) >>> B = eye(2) >>> C = Matrix([[1, 2], [3, 4]]) >>> X = MatAdd(A, B, C) >>> pprint(X, use_unicode=False) A + [1 0] + [1 2] [ ] [ ] [0 1] [3 4] >>> pprint(merge_explicit(X), use_unicode=False) A + [2 2] [ ] [3 5] """ groups = sift(matadd.args, lambda arg: isinstance(arg, MatrixBase)) if len(groups[True]) > 1: return MatAdd(*(groups[False] + [reduce(add, groups[True])])) else: return matadd rules = (rm_id(lambda x: x == 0 or isinstance(x, ZeroMatrix)), unpack, flatten, glom(matrix_of, factor_of, combine), merge_explicit, sort(default_sort_key)) canonicalize = exhaust( condition(lambda x: isinstance(x, MatAdd), do_one(rules)))
>>> A = MatrixSymbol('A', 2, 2) >>> B = eye(2) >>> C = Matrix([[1, 2], [3, 4]]) >>> X = MatAdd(A, B, C) >>> pprint(X, use_unicode=False) A + [1 0] + [1 2] [ ] [ ] [0 1] [3 4] >>> pprint(merge_explicit(X), use_unicode=False) A + [2 2] [ ] [3 5] """ groups = sift(matadd.args, lambda arg: isinstance(arg, MatrixBase)) if len(groups[True]) > 1: return MatAdd(*(groups[False] + [reduce(add, groups[True])])) else: return matadd rules = (rm_id(lambda x: x == 0 or isinstance(x, ZeroMatrix)), unpack, flatten, glom(matrix_of, factor_of, combine), merge_explicit, sort(default_sort_key)) canonicalize = exhaust(condition(lambda x: isinstance(x, MatAdd), do_one(rules)))
return super().__new__(cls, *args) @property def shape(self): return self.args[0].shape def _entry(self, i, j): return Mul(*[arg._entry(i, j) for arg in self.args]) def _eval_transpose(self): from .transpose import transpose return HadamardProduct(*list(map(transpose, self.args))) def doit(self, **ignored): 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)) rules = (unpack, flatten) canonicalize = exhaust( condition(lambda x: isinstance(x, HadamardProduct), do_one(rules)))
return super().__new__(cls, *args) @property def shape(self): return self.args[0].shape def _entry(self, i, j): return Mul(*[arg._entry(i, j) for arg in self.args]) def _eval_transpose(self): from .transpose import transpose return HadamardProduct(*list(map(transpose, self.args))) def doit(self, **ignored): 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)) rules = (unpack, flatten) canonicalize = exhaust(condition(lambda x: isinstance(x, HadamardProduct), do_one(rules)))
return super(HadamardProduct, cls).__new__(cls, *args) @property def shape(self): return self.args[0].shape def _entry(self, i, j): return Mul(*[arg._entry(i, j) for arg in self.args]) def _eval_transpose(self): from diofant.matrices.expressions.transpose import transpose return HadamardProduct(*list(map(transpose, self.args))) def doit(self, **ignored): 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)) rules = (unpack, flatten) canonicalize = exhaust(condition(lambda x: isinstance(x, HadamardProduct), do_one(rules)))