Coverage for /usr/lib/python3/dist-packages/sympy/matrices/expressions/matadd.py: 49%
76 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1from functools import reduce
2import operator
4from sympy.core import Basic, sympify
5from sympy.core.add import add, Add, _could_extract_minus_sign
6from sympy.core.sorting import default_sort_key
7from sympy.functions import adjoint
8from sympy.matrices.matrices import MatrixBase
9from sympy.matrices.expressions.transpose import transpose
10from sympy.strategies import (rm_id, unpack, flatten, sort, condition,
11 exhaust, do_one, glom)
12from sympy.matrices.expressions.matexpr import MatrixExpr
13from sympy.matrices.expressions.special import ZeroMatrix, GenericZeroMatrix
14from sympy.matrices.expressions._shape import validate_matadd_integer as validate
15from sympy.utilities.iterables import sift
16from sympy.utilities.exceptions import sympy_deprecation_warning
18# XXX: MatAdd should perhaps not subclass directly from Add
19class MatAdd(MatrixExpr, Add):
20 """A Sum of Matrix Expressions
22 MatAdd inherits from and operates like SymPy Add
24 Examples
25 ========
27 >>> from sympy import MatAdd, MatrixSymbol
28 >>> A = MatrixSymbol('A', 5, 5)
29 >>> B = MatrixSymbol('B', 5, 5)
30 >>> C = MatrixSymbol('C', 5, 5)
31 >>> MatAdd(A, B, C)
32 A + B + C
33 """
34 is_MatAdd = True
36 identity = GenericZeroMatrix()
38 def __new__(cls, *args, evaluate=False, check=None, _sympify=True):
39 if not args:
40 return cls.identity
42 # This must be removed aggressively in the constructor to avoid
43 # TypeErrors from GenericZeroMatrix().shape
44 args = list(filter(lambda i: cls.identity != i, args))
45 if _sympify:
46 args = list(map(sympify, args))
48 if not all(isinstance(arg, MatrixExpr) for arg in args):
49 raise TypeError("Mix of Matrix and Scalar symbols")
51 obj = Basic.__new__(cls, *args)
53 if check is not None:
54 sympy_deprecation_warning(
55 "Passing check to MatAdd is deprecated and the check argument will be removed in a future version.",
56 deprecated_since_version="1.11",
57 active_deprecations_target='remove-check-argument-from-matrix-operations')
59 if check is not False:
60 validate(*args)
62 if evaluate:
63 obj = cls._evaluate(obj)
65 return obj
67 @classmethod
68 def _evaluate(cls, expr):
69 return canonicalize(expr)
71 @property
72 def shape(self):
73 return self.args[0].shape
75 def could_extract_minus_sign(self):
76 return _could_extract_minus_sign(self)
78 def expand(self, **kwargs):
79 expanded = super(MatAdd, self).expand(**kwargs)
80 return self._evaluate(expanded)
82 def _entry(self, i, j, **kwargs):
83 return Add(*[arg._entry(i, j, **kwargs) for arg in self.args])
85 def _eval_transpose(self):
86 return MatAdd(*[transpose(arg) for arg in self.args]).doit()
88 def _eval_adjoint(self):
89 return MatAdd(*[adjoint(arg) for arg in self.args]).doit()
91 def _eval_trace(self):
92 from .trace import trace
93 return Add(*[trace(arg) for arg in self.args]).doit()
95 def doit(self, **hints):
96 deep = hints.get('deep', True)
97 if deep:
98 args = [arg.doit(**hints) for arg in self.args]
99 else:
100 args = self.args
101 return canonicalize(MatAdd(*args))
103 def _eval_derivative_matrix_lines(self, x):
104 add_lines = [arg._eval_derivative_matrix_lines(x) for arg in self.args]
105 return [j for i in add_lines for j in i]
107add.register_handlerclass((Add, MatAdd), MatAdd)
110factor_of = lambda arg: arg.as_coeff_mmul()[0]
111matrix_of = lambda arg: unpack(arg.as_coeff_mmul()[1])
112def combine(cnt, mat):
113 if cnt == 1:
114 return mat
115 else:
116 return cnt * mat
119def merge_explicit(matadd):
120 """ Merge explicit MatrixBase arguments
122 Examples
123 ========
125 >>> from sympy import MatrixSymbol, eye, Matrix, MatAdd, pprint
126 >>> from sympy.matrices.expressions.matadd import merge_explicit
127 >>> A = MatrixSymbol('A', 2, 2)
128 >>> B = eye(2)
129 >>> C = Matrix([[1, 2], [3, 4]])
130 >>> X = MatAdd(A, B, C)
131 >>> pprint(X)
132 [1 0] [1 2]
133 A + [ ] + [ ]
134 [0 1] [3 4]
135 >>> pprint(merge_explicit(X))
136 [2 2]
137 A + [ ]
138 [3 5]
139 """
140 groups = sift(matadd.args, lambda arg: isinstance(arg, MatrixBase))
141 if len(groups[True]) > 1:
142 return MatAdd(*(groups[False] + [reduce(operator.add, groups[True])]))
143 else:
144 return matadd
147rules = (rm_id(lambda x: x == 0 or isinstance(x, ZeroMatrix)),
148 unpack,
149 flatten,
150 glom(matrix_of, factor_of, combine),
151 merge_explicit,
152 sort(default_sort_key))
154canonicalize = exhaust(condition(lambda x: isinstance(x, MatAdd),
155 do_one(*rules)))