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

1from functools import reduce 

2import operator 

3 

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 

17 

18# XXX: MatAdd should perhaps not subclass directly from Add 

19class MatAdd(MatrixExpr, Add): 

20 """A Sum of Matrix Expressions 

21 

22 MatAdd inherits from and operates like SymPy Add 

23 

24 Examples 

25 ======== 

26 

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 

35 

36 identity = GenericZeroMatrix() 

37 

38 def __new__(cls, *args, evaluate=False, check=None, _sympify=True): 

39 if not args: 

40 return cls.identity 

41 

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)) 

47 

48 if not all(isinstance(arg, MatrixExpr) for arg in args): 

49 raise TypeError("Mix of Matrix and Scalar symbols") 

50 

51 obj = Basic.__new__(cls, *args) 

52 

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') 

58 

59 if check is not False: 

60 validate(*args) 

61 

62 if evaluate: 

63 obj = cls._evaluate(obj) 

64 

65 return obj 

66 

67 @classmethod 

68 def _evaluate(cls, expr): 

69 return canonicalize(expr) 

70 

71 @property 

72 def shape(self): 

73 return self.args[0].shape 

74 

75 def could_extract_minus_sign(self): 

76 return _could_extract_minus_sign(self) 

77 

78 def expand(self, **kwargs): 

79 expanded = super(MatAdd, self).expand(**kwargs) 

80 return self._evaluate(expanded) 

81 

82 def _entry(self, i, j, **kwargs): 

83 return Add(*[arg._entry(i, j, **kwargs) for arg in self.args]) 

84 

85 def _eval_transpose(self): 

86 return MatAdd(*[transpose(arg) for arg in self.args]).doit() 

87 

88 def _eval_adjoint(self): 

89 return MatAdd(*[adjoint(arg) for arg in self.args]).doit() 

90 

91 def _eval_trace(self): 

92 from .trace import trace 

93 return Add(*[trace(arg) for arg in self.args]).doit() 

94 

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)) 

102 

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] 

106 

107add.register_handlerclass((Add, MatAdd), MatAdd) 

108 

109 

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 

117 

118 

119def merge_explicit(matadd): 

120 """ Merge explicit MatrixBase arguments 

121 

122 Examples 

123 ======== 

124 

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 

145 

146 

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)) 

153 

154canonicalize = exhaust(condition(lambda x: isinstance(x, MatAdd), 

155 do_one(*rules)))