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 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) Matrix([ [X, Z], [0, Y]]) >>> C = BlockMatrix([[Identity(n), Z]]) >>> print(C) Matrix([[I, Z]]) >>> print(block_collapse(C*B)) Matrix([[X, Z*Y + Z]]) """ hasbm = lambda expr: 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) try: return result.doit() 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 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) Matrix([ [X, Z], [0, Y]]) >>> C = BlockMatrix([[Identity(n), Z]]) >>> print(C) Matrix([[I, Z]]) >>> print(block_collapse(C*B)) Matrix([[X, Z + Z*Y]]) """ from sympy.strategies.util import expr_fns hasbm = lambda expr: isinstance(expr, MatrixExpr) and expr.has(BlockMatrix) conditioned_rl = condition( hasbm, typed( {MatAdd: do_one(bc_matadd, bc_block_plus_ident), MatMul: do_one(bc_matmul, bc_dist), MatPow: bc_matmul, Transpose: bc_transpose, Inverse: bc_inverse, BlockMatrix: do_one(bc_unpack, deblock)} ) ) rule = exhaust( bottom_up( exhaust(conditioned_rl), fns=expr_fns ) ) result = rule(expr) doit = getattr(result, 'doit', None) if doit is not None: return doit() else: return result
if exp == 1: args.append(base) else: args.append(base**exp) exp = current_exp base = current_base if exp == 1: args.append(base) else: args.append(base**exp) return newmul(factor, *args) rules = (any_zeros, remove_ids, xxinv, unpack, rm_id(lambda x: x == 1), merge_explicit, factor_in_front, flatten, combine_powers) canonicalize = exhaust(typed({MatMul: do_one(*rules)})) def only_squares(*matrices): """factor matrices only if they are square""" if matrices[0].rows != matrices[-1].cols: raise RuntimeError("Invalid matrices being multiplied") out = [] start = 0 for i, M in enumerate(matrices): if M.cols == matrices[start].rows: out.append(MatMul(*matrices[start:i+1]).doit()) start = i+1 return out from sympy.assumptions.ask import ask, Q
""" Merge explicit MatrixBase arguments >>> from sympy import MatrixSymbol, eye, Matrix, MatAdd, pprint >>> from sympy.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) [1 0] [1 2] A + [ ] + [ ] [0 1] [3 4] >>> pprint(merge_explicit(X)) [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)))
def explicit_kronecker_product(kron): # Make sure we have a sequence of Matrices if not all(isinstance(m, MatrixBase) for m in kron.args): return kron return matrix_kronecker_product(*kron.args) rules = (unpack, explicit_kronecker_product, flatten, extract_commutative) canonicalize = exhaust(condition(lambda x: isinstance(x, KroneckerProduct), do_one(*rules))) def _kronecker_dims_key(expr): if isinstance(expr, KroneckerProduct): return tuple(a.shape for a in expr.args) else: return (0,) def kronecker_mat_add(expr): from functools import reduce args = sift(expr.args, _kronecker_dims_key) nonkrons = args.pop((0,), None) if not args: return expr
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))) def hadamard_power(base, exp): base = sympify(base) exp = sympify(exp) if exp == 1: return base if not base.is_Matrix: return base**exp if exp.is_Matrix: raise ValueError("cannot raise expression to a matrix") return HadamardPower(base, exp) class HadamardPower(MatrixExpr):
validate(*args) 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 sympy.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)))
""" Remove Identities from a MatMul This is a modified version of sympy.strategies.rm_id. This is necesssary because MatMul may contain both MatrixExprs and Exprs as args. See Also -------- sympy.strategies.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)))
else: return MatrixClass(matrix_expansion) def explicit_kronecker_product(kron): # Make sure we have a sequence of Matrices if not all(isinstance(m, MatrixBase) for m in kron.args): return kron return matrix_kronecker_product(*kron.args) rules = (unpack, explicit_kronecker_product, flatten, extract_commutative) canonicalize = exhaust( condition(lambda x: isinstance(x, KroneckerProduct), do_one(*rules))) def _kronecker_dims_key(expr): if isinstance(expr, KroneckerProduct): return tuple(a.shape for a in expr.args) else: return (0, ) def kronecker_mat_add(expr): from functools import reduce args = sift(expr.args, _kronecker_dims_key) nonkrons = args.pop((0, ), None) if not args: return expr
return [a.func(*a.args) for a in args] # Adapted from sympy.matrices.expressions.matadd.py groups = sift(vecadd.args, lambda arg: isinstance(arg, (Vector))) if len(groups[True]) > 1: return VecAdd(*(recreate_args(groups[False]) + [reduce(add, recreate_args(groups[True]))])) # return VecAdd(*(groups[False] + [reduce(add, groups[True])])) else: return vecadd rules = (merge_explicit, sort(default_sort_key)) canonicalize = exhaust( condition(lambda x: isinstance(x, VecAdd), do_one(*rules))) class VecMul(VectorExpr, Mul): """ A product of Vector expressions. VecMul inherits from and operates like SymPy Mul. """ is_VecMul = True is_commutative = True def __new__(cls, *args, **kwargs): evaluate = kwargs.get('evaluate', True) print("VecMul __new__", args) if not args: