Coverage for /usr/lib/python3/dist-packages/sympy/matrices/expressions/special.py: 47%
181 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 sympy.assumptions.ask import ask, Q
2from sympy.core.relational import Eq
3from sympy.core.singleton import S
4from sympy.core.sympify import _sympify
5from sympy.functions.special.tensor_functions import KroneckerDelta
6from sympy.matrices.common import NonInvertibleMatrixError
7from .matexpr import MatrixExpr
10class ZeroMatrix(MatrixExpr):
11 """The Matrix Zero 0 - additive identity
13 Examples
14 ========
16 >>> from sympy import MatrixSymbol, ZeroMatrix
17 >>> A = MatrixSymbol('A', 3, 5)
18 >>> Z = ZeroMatrix(3, 5)
19 >>> A + Z
20 A
21 >>> Z*A.T
22 0
23 """
24 is_ZeroMatrix = True
26 def __new__(cls, m, n):
27 m, n = _sympify(m), _sympify(n)
28 cls._check_dim(m)
29 cls._check_dim(n)
31 return super().__new__(cls, m, n)
33 @property
34 def shape(self):
35 return (self.args[0], self.args[1])
37 def _eval_power(self, exp):
38 # exp = -1, 0, 1 are already handled at this stage
39 if (exp < 0) == True:
40 raise NonInvertibleMatrixError("Matrix det == 0; not invertible")
41 return self
43 def _eval_transpose(self):
44 return ZeroMatrix(self.cols, self.rows)
46 def _eval_adjoint(self):
47 return ZeroMatrix(self.cols, self.rows)
49 def _eval_trace(self):
50 return S.Zero
52 def _eval_determinant(self):
53 return S.Zero
55 def _eval_inverse(self):
56 raise NonInvertibleMatrixError("Matrix det == 0; not invertible.")
58 def _eval_as_real_imag(self):
59 return (self, self)
61 def _eval_conjugate(self):
62 return self
64 def _entry(self, i, j, **kwargs):
65 return S.Zero
68class GenericZeroMatrix(ZeroMatrix):
69 """
70 A zero matrix without a specified shape
72 This exists primarily so MatAdd() with no arguments can return something
73 meaningful.
74 """
75 def __new__(cls):
76 # super(ZeroMatrix, cls) instead of super(GenericZeroMatrix, cls)
77 # because ZeroMatrix.__new__ doesn't have the same signature
78 return super(ZeroMatrix, cls).__new__(cls)
80 @property
81 def rows(self):
82 raise TypeError("GenericZeroMatrix does not have a specified shape")
84 @property
85 def cols(self):
86 raise TypeError("GenericZeroMatrix does not have a specified shape")
88 @property
89 def shape(self):
90 raise TypeError("GenericZeroMatrix does not have a specified shape")
92 # Avoid Matrix.__eq__ which might call .shape
93 def __eq__(self, other):
94 return isinstance(other, GenericZeroMatrix)
96 def __ne__(self, other):
97 return not (self == other)
99 def __hash__(self):
100 return super().__hash__()
104class Identity(MatrixExpr):
105 """The Matrix Identity I - multiplicative identity
107 Examples
108 ========
110 >>> from sympy import Identity, MatrixSymbol
111 >>> A = MatrixSymbol('A', 3, 5)
112 >>> I = Identity(3)
113 >>> I*A
114 A
115 """
117 is_Identity = True
119 def __new__(cls, n):
120 n = _sympify(n)
121 cls._check_dim(n)
123 return super().__new__(cls, n)
125 @property
126 def rows(self):
127 return self.args[0]
129 @property
130 def cols(self):
131 return self.args[0]
133 @property
134 def shape(self):
135 return (self.args[0], self.args[0])
137 @property
138 def is_square(self):
139 return True
141 def _eval_transpose(self):
142 return self
144 def _eval_trace(self):
145 return self.rows
147 def _eval_inverse(self):
148 return self
150 def _eval_as_real_imag(self):
151 return (self, ZeroMatrix(*self.shape))
153 def _eval_conjugate(self):
154 return self
156 def _eval_adjoint(self):
157 return self
159 def _entry(self, i, j, **kwargs):
160 eq = Eq(i, j)
161 if eq is S.true:
162 return S.One
163 elif eq is S.false:
164 return S.Zero
165 return KroneckerDelta(i, j, (0, self.cols-1))
167 def _eval_determinant(self):
168 return S.One
170 def _eval_power(self, exp):
171 return self
174class GenericIdentity(Identity):
175 """
176 An identity matrix without a specified shape
178 This exists primarily so MatMul() with no arguments can return something
179 meaningful.
180 """
181 def __new__(cls):
182 # super(Identity, cls) instead of super(GenericIdentity, cls) because
183 # Identity.__new__ doesn't have the same signature
184 return super(Identity, cls).__new__(cls)
186 @property
187 def rows(self):
188 raise TypeError("GenericIdentity does not have a specified shape")
190 @property
191 def cols(self):
192 raise TypeError("GenericIdentity does not have a specified shape")
194 @property
195 def shape(self):
196 raise TypeError("GenericIdentity does not have a specified shape")
198 @property
199 def is_square(self):
200 return True
202 # Avoid Matrix.__eq__ which might call .shape
203 def __eq__(self, other):
204 return isinstance(other, GenericIdentity)
206 def __ne__(self, other):
207 return not (self == other)
209 def __hash__(self):
210 return super().__hash__()
213class OneMatrix(MatrixExpr):
214 """
215 Matrix whose all entries are ones.
216 """
217 def __new__(cls, m, n, evaluate=False):
218 m, n = _sympify(m), _sympify(n)
219 cls._check_dim(m)
220 cls._check_dim(n)
222 if evaluate:
223 condition = Eq(m, 1) & Eq(n, 1)
224 if condition == True:
225 return Identity(1)
227 obj = super().__new__(cls, m, n)
228 return obj
230 @property
231 def shape(self):
232 return self._args
234 @property
235 def is_Identity(self):
236 return self._is_1x1() == True
238 def as_explicit(self):
239 from sympy.matrices.immutable import ImmutableDenseMatrix
240 return ImmutableDenseMatrix.ones(*self.shape)
242 def doit(self, **hints):
243 args = self.args
244 if hints.get('deep', True):
245 args = [a.doit(**hints) for a in args]
246 return self.func(*args, evaluate=True)
248 def _eval_power(self, exp):
249 # exp = -1, 0, 1 are already handled at this stage
250 if self._is_1x1() == True:
251 return Identity(1)
252 if (exp < 0) == True:
253 raise NonInvertibleMatrixError("Matrix det == 0; not invertible")
254 if ask(Q.integer(exp)):
255 return self.shape[0] ** (exp - 1) * OneMatrix(*self.shape)
256 return super()._eval_power(exp)
258 def _eval_transpose(self):
259 return OneMatrix(self.cols, self.rows)
261 def _eval_adjoint(self):
262 return OneMatrix(self.cols, self.rows)
264 def _eval_trace(self):
265 return S.One*self.rows
267 def _is_1x1(self):
268 """Returns true if the matrix is known to be 1x1"""
269 shape = self.shape
270 return Eq(shape[0], 1) & Eq(shape[1], 1)
272 def _eval_determinant(self):
273 condition = self._is_1x1()
274 if condition == True:
275 return S.One
276 elif condition == False:
277 return S.Zero
278 else:
279 from sympy.matrices.expressions.determinant import Determinant
280 return Determinant(self)
282 def _eval_inverse(self):
283 condition = self._is_1x1()
284 if condition == True:
285 return Identity(1)
286 elif condition == False:
287 raise NonInvertibleMatrixError("Matrix det == 0; not invertible.")
288 else:
289 from .inverse import Inverse
290 return Inverse(self)
292 def _eval_as_real_imag(self):
293 return (self, ZeroMatrix(*self.shape))
295 def _eval_conjugate(self):
296 return self
298 def _entry(self, i, j, **kwargs):
299 return S.One