Spaces:
Sleeping
Sleeping
from sympy.assumptions.ask import ask, Q | |
from sympy.core.relational import Eq | |
from sympy.core.singleton import S | |
from sympy.core.sympify import _sympify | |
from sympy.functions.special.tensor_functions import KroneckerDelta | |
from sympy.matrices.exceptions import NonInvertibleMatrixError | |
from .matexpr import MatrixExpr | |
class ZeroMatrix(MatrixExpr): | |
"""The Matrix Zero 0 - additive identity | |
Examples | |
======== | |
>>> from sympy import MatrixSymbol, ZeroMatrix | |
>>> A = MatrixSymbol('A', 3, 5) | |
>>> Z = ZeroMatrix(3, 5) | |
>>> A + Z | |
A | |
>>> Z*A.T | |
0 | |
""" | |
is_ZeroMatrix = True | |
def __new__(cls, m, n): | |
m, n = _sympify(m), _sympify(n) | |
cls._check_dim(m) | |
cls._check_dim(n) | |
return super().__new__(cls, m, n) | |
def shape(self): | |
return (self.args[0], self.args[1]) | |
def _eval_power(self, exp): | |
# exp = -1, 0, 1 are already handled at this stage | |
if (exp < 0) == True: | |
raise NonInvertibleMatrixError("Matrix det == 0; not invertible") | |
return self | |
def _eval_transpose(self): | |
return ZeroMatrix(self.cols, self.rows) | |
def _eval_adjoint(self): | |
return ZeroMatrix(self.cols, self.rows) | |
def _eval_trace(self): | |
return S.Zero | |
def _eval_determinant(self): | |
return S.Zero | |
def _eval_inverse(self): | |
raise NonInvertibleMatrixError("Matrix det == 0; not invertible.") | |
def _eval_as_real_imag(self): | |
return (self, self) | |
def _eval_conjugate(self): | |
return self | |
def _entry(self, i, j, **kwargs): | |
return S.Zero | |
class GenericZeroMatrix(ZeroMatrix): | |
""" | |
A zero matrix without a specified shape | |
This exists primarily so MatAdd() with no arguments can return something | |
meaningful. | |
""" | |
def __new__(cls): | |
# super(ZeroMatrix, cls) instead of super(GenericZeroMatrix, cls) | |
# because ZeroMatrix.__new__ doesn't have the same signature | |
return super(ZeroMatrix, cls).__new__(cls) | |
def rows(self): | |
raise TypeError("GenericZeroMatrix does not have a specified shape") | |
def cols(self): | |
raise TypeError("GenericZeroMatrix does not have a specified shape") | |
def shape(self): | |
raise TypeError("GenericZeroMatrix does not have a specified shape") | |
# Avoid Matrix.__eq__ which might call .shape | |
def __eq__(self, other): | |
return isinstance(other, GenericZeroMatrix) | |
def __ne__(self, other): | |
return not (self == other) | |
def __hash__(self): | |
return super().__hash__() | |
class Identity(MatrixExpr): | |
"""The Matrix Identity I - multiplicative identity | |
Examples | |
======== | |
>>> from sympy import Identity, MatrixSymbol | |
>>> A = MatrixSymbol('A', 3, 5) | |
>>> I = Identity(3) | |
>>> I*A | |
A | |
""" | |
is_Identity = True | |
def __new__(cls, n): | |
n = _sympify(n) | |
cls._check_dim(n) | |
return super().__new__(cls, n) | |
def rows(self): | |
return self.args[0] | |
def cols(self): | |
return self.args[0] | |
def shape(self): | |
return (self.args[0], self.args[0]) | |
def is_square(self): | |
return True | |
def _eval_transpose(self): | |
return self | |
def _eval_trace(self): | |
return self.rows | |
def _eval_inverse(self): | |
return self | |
def _eval_as_real_imag(self): | |
return (self, ZeroMatrix(*self.shape)) | |
def _eval_conjugate(self): | |
return self | |
def _eval_adjoint(self): | |
return self | |
def _entry(self, i, j, **kwargs): | |
eq = Eq(i, j) | |
if eq is S.true: | |
return S.One | |
elif eq is S.false: | |
return S.Zero | |
return KroneckerDelta(i, j, (0, self.cols-1)) | |
def _eval_determinant(self): | |
return S.One | |
def _eval_power(self, exp): | |
return self | |
class GenericIdentity(Identity): | |
""" | |
An identity matrix without a specified shape | |
This exists primarily so MatMul() with no arguments can return something | |
meaningful. | |
""" | |
def __new__(cls): | |
# super(Identity, cls) instead of super(GenericIdentity, cls) because | |
# Identity.__new__ doesn't have the same signature | |
return super(Identity, cls).__new__(cls) | |
def rows(self): | |
raise TypeError("GenericIdentity does not have a specified shape") | |
def cols(self): | |
raise TypeError("GenericIdentity does not have a specified shape") | |
def shape(self): | |
raise TypeError("GenericIdentity does not have a specified shape") | |
def is_square(self): | |
return True | |
# Avoid Matrix.__eq__ which might call .shape | |
def __eq__(self, other): | |
return isinstance(other, GenericIdentity) | |
def __ne__(self, other): | |
return not (self == other) | |
def __hash__(self): | |
return super().__hash__() | |
class OneMatrix(MatrixExpr): | |
""" | |
Matrix whose all entries are ones. | |
""" | |
def __new__(cls, m, n, evaluate=False): | |
m, n = _sympify(m), _sympify(n) | |
cls._check_dim(m) | |
cls._check_dim(n) | |
if evaluate: | |
condition = Eq(m, 1) & Eq(n, 1) | |
if condition == True: | |
return Identity(1) | |
obj = super().__new__(cls, m, n) | |
return obj | |
def shape(self): | |
return self._args | |
def is_Identity(self): | |
return self._is_1x1() == True | |
def as_explicit(self): | |
from sympy.matrices.immutable import ImmutableDenseMatrix | |
return ImmutableDenseMatrix.ones(*self.shape) | |
def doit(self, **hints): | |
args = self.args | |
if hints.get('deep', True): | |
args = [a.doit(**hints) for a in args] | |
return self.func(*args, evaluate=True) | |
def _eval_power(self, exp): | |
# exp = -1, 0, 1 are already handled at this stage | |
if self._is_1x1() == True: | |
return Identity(1) | |
if (exp < 0) == True: | |
raise NonInvertibleMatrixError("Matrix det == 0; not invertible") | |
if ask(Q.integer(exp)): | |
return self.shape[0] ** (exp - 1) * OneMatrix(*self.shape) | |
return super()._eval_power(exp) | |
def _eval_transpose(self): | |
return OneMatrix(self.cols, self.rows) | |
def _eval_adjoint(self): | |
return OneMatrix(self.cols, self.rows) | |
def _eval_trace(self): | |
return S.One*self.rows | |
def _is_1x1(self): | |
"""Returns true if the matrix is known to be 1x1""" | |
shape = self.shape | |
return Eq(shape[0], 1) & Eq(shape[1], 1) | |
def _eval_determinant(self): | |
condition = self._is_1x1() | |
if condition == True: | |
return S.One | |
elif condition == False: | |
return S.Zero | |
else: | |
from sympy.matrices.expressions.determinant import Determinant | |
return Determinant(self) | |
def _eval_inverse(self): | |
condition = self._is_1x1() | |
if condition == True: | |
return Identity(1) | |
elif condition == False: | |
raise NonInvertibleMatrixError("Matrix det == 0; not invertible.") | |
else: | |
from .inverse import Inverse | |
return Inverse(self) | |
def _eval_as_real_imag(self): | |
return (self, ZeroMatrix(*self.shape)) | |
def _eval_conjugate(self): | |
return self | |
def _entry(self, i, j, **kwargs): | |
return S.One | |