123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- 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.common 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)
- @property
- 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_trace(self):
- return S.Zero
- def _eval_determinant(self):
- return S.Zero
- def _eval_inverse(self):
- raise NonInvertibleMatrixError("Matrix det == 0; not invertible.")
- def 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)
- @property
- def rows(self):
- raise TypeError("GenericZeroMatrix does not have a specified shape")
- @property
- def cols(self):
- raise TypeError("GenericZeroMatrix does not have a specified shape")
- @property
- 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)
- @property
- def rows(self):
- return self.args[0]
- @property
- def cols(self):
- return self.args[0]
- @property
- def shape(self):
- return (self.args[0], self.args[0])
- @property
- 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 conjugate(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)
- @property
- def rows(self):
- raise TypeError("GenericIdentity does not have a specified shape")
- @property
- def cols(self):
- raise TypeError("GenericIdentity does not have a specified shape")
- @property
- def shape(self):
- raise TypeError("GenericIdentity does not have a specified shape")
- # 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
- @property
- def shape(self):
- return self._args
- @property
- 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_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 conjugate(self):
- return self
- def _entry(self, i, j, **kwargs):
- return S.One
|