Buckets:
MisterAI/LocalAI_Demo_backends / cpu-diffusers.upgrade-tmp /venv /lib /python3.10 /site-packages /sympy /matrices /common.py
| """ | |
| A module containing deprecated matrix mixin classes. | |
| The classes in this module are deprecated and will be removed in a future | |
| release. They are kept here for backwards compatibility in case downstream | |
| code was subclassing them. | |
| Importing anything else from this module is deprecated so anything here | |
| should either not be used or should be imported from somewhere else. | |
| """ | |
| from __future__ import annotations | |
| from collections import defaultdict | |
| from collections.abc import Iterable | |
| from inspect import isfunction | |
| from functools import reduce | |
| from sympy.assumptions.refine import refine | |
| from sympy.core import SympifyError, Add | |
| from sympy.core.basic import Atom | |
| from sympy.core.decorators import call_highest_priority | |
| from sympy.core.logic import fuzzy_and, FuzzyBool | |
| from sympy.core.numbers import Integer | |
| from sympy.core.mod import Mod | |
| from sympy.core.singleton import S | |
| from sympy.core.symbol import Symbol | |
| from sympy.core.sympify import sympify | |
| from sympy.functions.elementary.complexes import Abs, re, im | |
| from sympy.utilities.exceptions import sympy_deprecation_warning | |
| from .utilities import _dotprodsimp, _simplify | |
| from sympy.polys.polytools import Poly | |
| from sympy.utilities.iterables import flatten, is_sequence | |
| from sympy.utilities.misc import as_int, filldedent | |
| from sympy.tensor.array import NDimArray | |
| from .utilities import _get_intermediate_simp_bool | |
| # These exception types were previously defined in this module but were moved | |
| # to exceptions.py. We reimport them here for backwards compatibility in case | |
| # downstream code was importing them from here. | |
| from .exceptions import ( # noqa: F401 | |
| MatrixError, ShapeError, NonSquareMatrixError, NonInvertibleMatrixError, | |
| NonPositiveDefiniteMatrixError | |
| ) | |
| _DEPRECATED_MIXINS = ( | |
| 'MatrixShaping', | |
| 'MatrixSpecial', | |
| 'MatrixProperties', | |
| 'MatrixOperations', | |
| 'MatrixArithmetic', | |
| 'MatrixCommon', | |
| 'MatrixDeterminant', | |
| 'MatrixReductions', | |
| 'MatrixSubspaces', | |
| 'MatrixEigen', | |
| 'MatrixCalculus', | |
| 'MatrixDeprecated', | |
| ) | |
| class _MatrixDeprecatedMeta(type): | |
| # | |
| # Override the default __instancecheck__ implementation to ensure that | |
| # e.g. isinstance(M, MatrixCommon) still works when M is one of the | |
| # matrix classes. Matrix no longer inherits from MatrixCommon so | |
| # isinstance(M, MatrixCommon) would now return False by default. | |
| # | |
| # There were lots of places in the codebase where this was being done | |
| # so it seems likely that downstream code may be doing it too. All use | |
| # of these mixins is deprecated though so we give a deprecation warning | |
| # unconditionally if they are being used with isinstance. | |
| # | |
| # Any code seeing this deprecation warning should be changed to use | |
| # isinstance(M, MatrixBase) instead which also works in previous versions | |
| # of SymPy. | |
| # | |
| def __instancecheck__(cls, instance): | |
| sympy_deprecation_warning( | |
| f""" | |
| Checking whether an object is an instance of {cls.__name__} is | |
| deprecated. | |
| Use `isinstance(obj, Matrix)` instead of `isinstance(obj, {cls.__name__})`. | |
| """, | |
| deprecated_since_version="1.13", | |
| active_deprecations_target="deprecated-matrix-mixins", | |
| stacklevel=3, | |
| ) | |
| from sympy.matrices.matrixbase import MatrixBase | |
| from sympy.matrices.matrices import ( | |
| MatrixDeterminant, | |
| MatrixReductions, | |
| MatrixSubspaces, | |
| MatrixEigen, | |
| MatrixCalculus, | |
| MatrixDeprecated | |
| ) | |
| all_mixins = ( | |
| MatrixRequired, | |
| MatrixShaping, | |
| MatrixSpecial, | |
| MatrixProperties, | |
| MatrixOperations, | |
| MatrixArithmetic, | |
| MatrixCommon, | |
| MatrixDeterminant, | |
| MatrixReductions, | |
| MatrixSubspaces, | |
| MatrixEigen, | |
| MatrixCalculus, | |
| MatrixDeprecated | |
| ) | |
| if cls in all_mixins and isinstance(instance, MatrixBase): | |
| return True | |
| else: | |
| return super().__instancecheck__(instance) | |
| class MatrixRequired(metaclass=_MatrixDeprecatedMeta): | |
| """Deprecated mixin class for making matrix classes.""" | |
| rows: int | |
| cols: int | |
| _simplify = None | |
| def __init_subclass__(cls, **kwargs): | |
| # Warn if any downstream code is subclassing this class or any of the | |
| # deprecated mixin classes that are all ultimately subclasses of this | |
| # class. | |
| # | |
| # We don't want to warn about the deprecated mixins themselves being | |
| # created, but only about them being used as mixins by downstream code. | |
| # Otherwise just importing this module would trigger a warning. | |
| # Ultimately the whole module should be deprecated and removed but for | |
| # SymPy 1.13 it is premature to do that given that this module was the | |
| # main way to import matrix exception types in all previous versions. | |
| if cls.__name__ not in _DEPRECATED_MIXINS: | |
| sympy_deprecation_warning( | |
| f""" | |
| Inheriting from the Matrix mixin classes is deprecated. | |
| The class {cls.__name__} is subclassing a deprecated mixin. | |
| """, | |
| deprecated_since_version="1.13", | |
| active_deprecations_target="deprecated-matrix-mixins", | |
| stacklevel=3, | |
| ) | |
| super().__init_subclass__(**kwargs) | |
| def _new(cls, *args, **kwargs): | |
| """`_new` must, at minimum, be callable as | |
| `_new(rows, cols, mat) where mat is a flat list of the | |
| elements of the matrix.""" | |
| raise NotImplementedError("Subclasses must implement this.") | |
| def __eq__(self, other): | |
| raise NotImplementedError("Subclasses must implement this.") | |
| def __getitem__(self, key): | |
| """Implementations of __getitem__ should accept ints, in which | |
| case the matrix is indexed as a flat list, tuples (i,j) in which | |
| case the (i,j) entry is returned, slices, or mixed tuples (a,b) | |
| where a and b are any combination of slices and integers.""" | |
| raise NotImplementedError("Subclasses must implement this.") | |
| def __len__(self): | |
| """The total number of entries in the matrix.""" | |
| raise NotImplementedError("Subclasses must implement this.") | |
| def shape(self): | |
| raise NotImplementedError("Subclasses must implement this.") | |
| class MatrixShaping(MatrixRequired): | |
| """Provides basic matrix shaping and extracting of submatrices""" | |
| def _eval_col_del(self, col): | |
| def entry(i, j): | |
| return self[i, j] if j < col else self[i, j + 1] | |
| return self._new(self.rows, self.cols - 1, entry) | |
| def _eval_col_insert(self, pos, other): | |
| def entry(i, j): | |
| if j < pos: | |
| return self[i, j] | |
| elif pos <= j < pos + other.cols: | |
| return other[i, j - pos] | |
| return self[i, j - other.cols] | |
| return self._new(self.rows, self.cols + other.cols, entry) | |
| def _eval_col_join(self, other): | |
| rows = self.rows | |
| def entry(i, j): | |
| if i < rows: | |
| return self[i, j] | |
| return other[i - rows, j] | |
| return classof(self, other)._new(self.rows + other.rows, self.cols, | |
| entry) | |
| def _eval_extract(self, rowsList, colsList): | |
| mat = list(self) | |
| cols = self.cols | |
| indices = (i * cols + j for i in rowsList for j in colsList) | |
| return self._new(len(rowsList), len(colsList), | |
| [mat[i] for i in indices]) | |
| def _eval_get_diag_blocks(self): | |
| sub_blocks = [] | |
| def recurse_sub_blocks(M): | |
| for i in range(1, M.shape[0] + 1): | |
| if i == 1: | |
| to_the_right = M[0, i:] | |
| to_the_bottom = M[i:, 0] | |
| else: | |
| to_the_right = M[:i, i:] | |
| to_the_bottom = M[i:, :i] | |
| if any(to_the_right) or any(to_the_bottom): | |
| continue | |
| sub_blocks.append(M[:i, :i]) | |
| if M.shape != M[:i, :i].shape: | |
| recurse_sub_blocks(M[i:, i:]) | |
| return | |
| recurse_sub_blocks(self) | |
| return sub_blocks | |
| def _eval_row_del(self, row): | |
| def entry(i, j): | |
| return self[i, j] if i < row else self[i + 1, j] | |
| return self._new(self.rows - 1, self.cols, entry) | |
| def _eval_row_insert(self, pos, other): | |
| entries = list(self) | |
| insert_pos = pos * self.cols | |
| entries[insert_pos:insert_pos] = list(other) | |
| return self._new(self.rows + other.rows, self.cols, entries) | |
| def _eval_row_join(self, other): | |
| cols = self.cols | |
| def entry(i, j): | |
| if j < cols: | |
| return self[i, j] | |
| return other[i, j - cols] | |
| return classof(self, other)._new(self.rows, self.cols + other.cols, | |
| entry) | |
| def _eval_tolist(self): | |
| return [list(self[i,:]) for i in range(self.rows)] | |
| def _eval_todok(self): | |
| dok = {} | |
| rows, cols = self.shape | |
| for i in range(rows): | |
| for j in range(cols): | |
| val = self[i, j] | |
| if val != self.zero: | |
| dok[i, j] = val | |
| return dok | |
| def _eval_vec(self): | |
| rows = self.rows | |
| def entry(n, _): | |
| # we want to read off the columns first | |
| j = n // rows | |
| i = n - j * rows | |
| return self[i, j] | |
| return self._new(len(self), 1, entry) | |
| def _eval_vech(self, diagonal): | |
| c = self.cols | |
| v = [] | |
| if diagonal: | |
| for j in range(c): | |
| for i in range(j, c): | |
| v.append(self[i, j]) | |
| else: | |
| for j in range(c): | |
| for i in range(j + 1, c): | |
| v.append(self[i, j]) | |
| return self._new(len(v), 1, v) | |
| def col_del(self, col): | |
| """Delete the specified column.""" | |
| if col < 0: | |
| col += self.cols | |
| if not 0 <= col < self.cols: | |
| raise IndexError("Column {} is out of range.".format(col)) | |
| return self._eval_col_del(col) | |
| def col_insert(self, pos, other): | |
| """Insert one or more columns at the given column position. | |
| Examples | |
| ======== | |
| >>> from sympy import zeros, ones | |
| >>> M = zeros(3) | |
| >>> V = ones(3, 1) | |
| >>> M.col_insert(1, V) | |
| Matrix([ | |
| [0, 1, 0, 0], | |
| [0, 1, 0, 0], | |
| [0, 1, 0, 0]]) | |
| See Also | |
| ======== | |
| col | |
| row_insert | |
| """ | |
| # Allows you to build a matrix even if it is null matrix | |
| if not self: | |
| return type(self)(other) | |
| pos = as_int(pos) | |
| if pos < 0: | |
| pos = self.cols + pos | |
| if pos < 0: | |
| pos = 0 | |
| elif pos > self.cols: | |
| pos = self.cols | |
| if self.rows != other.rows: | |
| raise ShapeError( | |
| "The matrices have incompatible number of rows ({} and {})" | |
| .format(self.rows, other.rows)) | |
| return self._eval_col_insert(pos, other) | |
| def col_join(self, other): | |
| """Concatenates two matrices along self's last and other's first row. | |
| Examples | |
| ======== | |
| >>> from sympy import zeros, ones | |
| >>> M = zeros(3) | |
| >>> V = ones(1, 3) | |
| >>> M.col_join(V) | |
| Matrix([ | |
| [0, 0, 0], | |
| [0, 0, 0], | |
| [0, 0, 0], | |
| [1, 1, 1]]) | |
| See Also | |
| ======== | |
| col | |
| row_join | |
| """ | |
| # A null matrix can always be stacked (see #10770) | |
| if self.rows == 0 and self.cols != other.cols: | |
| return self._new(0, other.cols, []).col_join(other) | |
| if self.cols != other.cols: | |
| raise ShapeError( | |
| "The matrices have incompatible number of columns ({} and {})" | |
| .format(self.cols, other.cols)) | |
| return self._eval_col_join(other) | |
| def col(self, j): | |
| """Elementary column selector. | |
| Examples | |
| ======== | |
| >>> from sympy import eye | |
| >>> eye(2).col(0) | |
| Matrix([ | |
| [1], | |
| [0]]) | |
| See Also | |
| ======== | |
| row | |
| col_del | |
| col_join | |
| col_insert | |
| """ | |
| return self[:, j] | |
| def extract(self, rowsList, colsList): | |
| r"""Return a submatrix by specifying a list of rows and columns. | |
| Negative indices can be given. All indices must be in the range | |
| $-n \le i < n$ where $n$ is the number of rows or columns. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> m = Matrix(4, 3, range(12)) | |
| >>> m | |
| Matrix([ | |
| [0, 1, 2], | |
| [3, 4, 5], | |
| [6, 7, 8], | |
| [9, 10, 11]]) | |
| >>> m.extract([0, 1, 3], [0, 1]) | |
| Matrix([ | |
| [0, 1], | |
| [3, 4], | |
| [9, 10]]) | |
| Rows or columns can be repeated: | |
| >>> m.extract([0, 0, 1], [-1]) | |
| Matrix([ | |
| [2], | |
| [2], | |
| [5]]) | |
| Every other row can be taken by using range to provide the indices: | |
| >>> m.extract(range(0, m.rows, 2), [-1]) | |
| Matrix([ | |
| [2], | |
| [8]]) | |
| RowsList or colsList can also be a list of booleans, in which case | |
| the rows or columns corresponding to the True values will be selected: | |
| >>> m.extract([0, 1, 2, 3], [True, False, True]) | |
| Matrix([ | |
| [0, 2], | |
| [3, 5], | |
| [6, 8], | |
| [9, 11]]) | |
| """ | |
| if not is_sequence(rowsList) or not is_sequence(colsList): | |
| raise TypeError("rowsList and colsList must be iterable") | |
| # ensure rowsList and colsList are lists of integers | |
| if rowsList and all(isinstance(i, bool) for i in rowsList): | |
| rowsList = [index for index, item in enumerate(rowsList) if item] | |
| if colsList and all(isinstance(i, bool) for i in colsList): | |
| colsList = [index for index, item in enumerate(colsList) if item] | |
| # ensure everything is in range | |
| rowsList = [a2idx(k, self.rows) for k in rowsList] | |
| colsList = [a2idx(k, self.cols) for k in colsList] | |
| return self._eval_extract(rowsList, colsList) | |
| def get_diag_blocks(self): | |
| """Obtains the square sub-matrices on the main diagonal of a square matrix. | |
| Useful for inverting symbolic matrices or solving systems of | |
| linear equations which may be decoupled by having a block diagonal | |
| structure. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> from sympy.abc import x, y, z | |
| >>> A = Matrix([[1, 3, 0, 0], [y, z*z, 0, 0], [0, 0, x, 0], [0, 0, 0, 0]]) | |
| >>> a1, a2, a3 = A.get_diag_blocks() | |
| >>> a1 | |
| Matrix([ | |
| [1, 3], | |
| [y, z**2]]) | |
| >>> a2 | |
| Matrix([[x]]) | |
| >>> a3 | |
| Matrix([[0]]) | |
| """ | |
| return self._eval_get_diag_blocks() | |
| def hstack(cls, *args): | |
| """Return a matrix formed by joining args horizontally (i.e. | |
| by repeated application of row_join). | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix, eye | |
| >>> Matrix.hstack(eye(2), 2*eye(2)) | |
| Matrix([ | |
| [1, 0, 2, 0], | |
| [0, 1, 0, 2]]) | |
| """ | |
| if len(args) == 0: | |
| return cls._new() | |
| kls = type(args[0]) | |
| return reduce(kls.row_join, args) | |
| def reshape(self, rows, cols): | |
| """Reshape the matrix. Total number of elements must remain the same. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> m = Matrix(2, 3, lambda i, j: 1) | |
| >>> m | |
| Matrix([ | |
| [1, 1, 1], | |
| [1, 1, 1]]) | |
| >>> m.reshape(1, 6) | |
| Matrix([[1, 1, 1, 1, 1, 1]]) | |
| >>> m.reshape(3, 2) | |
| Matrix([ | |
| [1, 1], | |
| [1, 1], | |
| [1, 1]]) | |
| """ | |
| if self.rows * self.cols != rows * cols: | |
| raise ValueError("Invalid reshape parameters %d %d" % (rows, cols)) | |
| return self._new(rows, cols, lambda i, j: self[i * cols + j]) | |
| def row_del(self, row): | |
| """Delete the specified row.""" | |
| if row < 0: | |
| row += self.rows | |
| if not 0 <= row < self.rows: | |
| raise IndexError("Row {} is out of range.".format(row)) | |
| return self._eval_row_del(row) | |
| def row_insert(self, pos, other): | |
| """Insert one or more rows at the given row position. | |
| Examples | |
| ======== | |
| >>> from sympy import zeros, ones | |
| >>> M = zeros(3) | |
| >>> V = ones(1, 3) | |
| >>> M.row_insert(1, V) | |
| Matrix([ | |
| [0, 0, 0], | |
| [1, 1, 1], | |
| [0, 0, 0], | |
| [0, 0, 0]]) | |
| See Also | |
| ======== | |
| row | |
| col_insert | |
| """ | |
| # Allows you to build a matrix even if it is null matrix | |
| if not self: | |
| return self._new(other) | |
| pos = as_int(pos) | |
| if pos < 0: | |
| pos = self.rows + pos | |
| if pos < 0: | |
| pos = 0 | |
| elif pos > self.rows: | |
| pos = self.rows | |
| if self.cols != other.cols: | |
| raise ShapeError( | |
| "The matrices have incompatible number of columns ({} and {})" | |
| .format(self.cols, other.cols)) | |
| return self._eval_row_insert(pos, other) | |
| def row_join(self, other): | |
| """Concatenates two matrices along self's last and rhs's first column | |
| Examples | |
| ======== | |
| >>> from sympy import zeros, ones | |
| >>> M = zeros(3) | |
| >>> V = ones(3, 1) | |
| >>> M.row_join(V) | |
| Matrix([ | |
| [0, 0, 0, 1], | |
| [0, 0, 0, 1], | |
| [0, 0, 0, 1]]) | |
| See Also | |
| ======== | |
| row | |
| col_join | |
| """ | |
| # A null matrix can always be stacked (see #10770) | |
| if self.cols == 0 and self.rows != other.rows: | |
| return self._new(other.rows, 0, []).row_join(other) | |
| if self.rows != other.rows: | |
| raise ShapeError( | |
| "The matrices have incompatible number of rows ({} and {})" | |
| .format(self.rows, other.rows)) | |
| return self._eval_row_join(other) | |
| def diagonal(self, k=0): | |
| """Returns the kth diagonal of self. The main diagonal | |
| corresponds to `k=0`; diagonals above and below correspond to | |
| `k > 0` and `k < 0`, respectively. The values of `self[i, j]` | |
| for which `j - i = k`, are returned in order of increasing | |
| `i + j`, starting with `i + j = |k|`. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> m = Matrix(3, 3, lambda i, j: j - i); m | |
| Matrix([ | |
| [ 0, 1, 2], | |
| [-1, 0, 1], | |
| [-2, -1, 0]]) | |
| >>> _.diagonal() | |
| Matrix([[0, 0, 0]]) | |
| >>> m.diagonal(1) | |
| Matrix([[1, 1]]) | |
| >>> m.diagonal(-2) | |
| Matrix([[-2]]) | |
| Even though the diagonal is returned as a Matrix, the element | |
| retrieval can be done with a single index: | |
| >>> Matrix.diag(1, 2, 3).diagonal()[1] # instead of [0, 1] | |
| 2 | |
| See Also | |
| ======== | |
| diag | |
| """ | |
| rv = [] | |
| k = as_int(k) | |
| r = 0 if k > 0 else -k | |
| c = 0 if r else k | |
| while True: | |
| if r == self.rows or c == self.cols: | |
| break | |
| rv.append(self[r, c]) | |
| r += 1 | |
| c += 1 | |
| if not rv: | |
| raise ValueError(filldedent(''' | |
| The %s diagonal is out of range [%s, %s]''' % ( | |
| k, 1 - self.rows, self.cols - 1))) | |
| return self._new(1, len(rv), rv) | |
| def row(self, i): | |
| """Elementary row selector. | |
| Examples | |
| ======== | |
| >>> from sympy import eye | |
| >>> eye(2).row(0) | |
| Matrix([[1, 0]]) | |
| See Also | |
| ======== | |
| col | |
| row_del | |
| row_join | |
| row_insert | |
| """ | |
| return self[i, :] | |
| def shape(self): | |
| """The shape (dimensions) of the matrix as the 2-tuple (rows, cols). | |
| Examples | |
| ======== | |
| >>> from sympy import zeros | |
| >>> M = zeros(2, 3) | |
| >>> M.shape | |
| (2, 3) | |
| >>> M.rows | |
| 2 | |
| >>> M.cols | |
| 3 | |
| """ | |
| return (self.rows, self.cols) | |
| def todok(self): | |
| """Return the matrix as dictionary of keys. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> M = Matrix.eye(3) | |
| >>> M.todok() | |
| {(0, 0): 1, (1, 1): 1, (2, 2): 1} | |
| """ | |
| return self._eval_todok() | |
| def tolist(self): | |
| """Return the Matrix as a nested Python list. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix, ones | |
| >>> m = Matrix(3, 3, range(9)) | |
| >>> m | |
| Matrix([ | |
| [0, 1, 2], | |
| [3, 4, 5], | |
| [6, 7, 8]]) | |
| >>> m.tolist() | |
| [[0, 1, 2], [3, 4, 5], [6, 7, 8]] | |
| >>> ones(3, 0).tolist() | |
| [[], [], []] | |
| When there are no rows then it will not be possible to tell how | |
| many columns were in the original matrix: | |
| >>> ones(0, 3).tolist() | |
| [] | |
| """ | |
| if not self.rows: | |
| return [] | |
| if not self.cols: | |
| return [[] for i in range(self.rows)] | |
| return self._eval_tolist() | |
| def todod(M): | |
| """Returns matrix as dict of dicts containing non-zero elements of the Matrix | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> A = Matrix([[0, 1],[0, 3]]) | |
| >>> A | |
| Matrix([ | |
| [0, 1], | |
| [0, 3]]) | |
| >>> A.todod() | |
| {0: {1: 1}, 1: {1: 3}} | |
| """ | |
| rowsdict = {} | |
| Mlol = M.tolist() | |
| for i, Mi in enumerate(Mlol): | |
| row = {j: Mij for j, Mij in enumerate(Mi) if Mij} | |
| if row: | |
| rowsdict[i] = row | |
| return rowsdict | |
| def vec(self): | |
| """Return the Matrix converted into a one column matrix by stacking columns | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> m=Matrix([[1, 3], [2, 4]]) | |
| >>> m | |
| Matrix([ | |
| [1, 3], | |
| [2, 4]]) | |
| >>> m.vec() | |
| Matrix([ | |
| [1], | |
| [2], | |
| [3], | |
| [4]]) | |
| See Also | |
| ======== | |
| vech | |
| """ | |
| return self._eval_vec() | |
| def vech(self, diagonal=True, check_symmetry=True): | |
| """Reshapes the matrix into a column vector by stacking the | |
| elements in the lower triangle. | |
| Parameters | |
| ========== | |
| diagonal : bool, optional | |
| If ``True``, it includes the diagonal elements. | |
| check_symmetry : bool, optional | |
| If ``True``, it checks whether the matrix is symmetric. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> m=Matrix([[1, 2], [2, 3]]) | |
| >>> m | |
| Matrix([ | |
| [1, 2], | |
| [2, 3]]) | |
| >>> m.vech() | |
| Matrix([ | |
| [1], | |
| [2], | |
| [3]]) | |
| >>> m.vech(diagonal=False) | |
| Matrix([[2]]) | |
| Notes | |
| ===== | |
| This should work for symmetric matrices and ``vech`` can | |
| represent symmetric matrices in vector form with less size than | |
| ``vec``. | |
| See Also | |
| ======== | |
| vec | |
| """ | |
| if not self.is_square: | |
| raise NonSquareMatrixError | |
| if check_symmetry and not self.is_symmetric(): | |
| raise ValueError("The matrix is not symmetric.") | |
| return self._eval_vech(diagonal) | |
| def vstack(cls, *args): | |
| """Return a matrix formed by joining args vertically (i.e. | |
| by repeated application of col_join). | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix, eye | |
| >>> Matrix.vstack(eye(2), 2*eye(2)) | |
| Matrix([ | |
| [1, 0], | |
| [0, 1], | |
| [2, 0], | |
| [0, 2]]) | |
| """ | |
| if len(args) == 0: | |
| return cls._new() | |
| kls = type(args[0]) | |
| return reduce(kls.col_join, args) | |
| class MatrixSpecial(MatrixRequired): | |
| """Construction of special matrices""" | |
| def _eval_diag(cls, rows, cols, diag_dict): | |
| """diag_dict is a defaultdict containing | |
| all the entries of the diagonal matrix.""" | |
| def entry(i, j): | |
| return diag_dict[(i, j)] | |
| return cls._new(rows, cols, entry) | |
| def _eval_eye(cls, rows, cols): | |
| vals = [cls.zero]*(rows*cols) | |
| vals[::cols+1] = [cls.one]*min(rows, cols) | |
| return cls._new(rows, cols, vals, copy=False) | |
| def _eval_jordan_block(cls, size: int, eigenvalue, band='upper'): | |
| if band == 'lower': | |
| def entry(i, j): | |
| if i == j: | |
| return eigenvalue | |
| elif j + 1 == i: | |
| return cls.one | |
| return cls.zero | |
| else: | |
| def entry(i, j): | |
| if i == j: | |
| return eigenvalue | |
| elif i + 1 == j: | |
| return cls.one | |
| return cls.zero | |
| return cls._new(size, size, entry) | |
| def _eval_ones(cls, rows, cols): | |
| def entry(i, j): | |
| return cls.one | |
| return cls._new(rows, cols, entry) | |
| def _eval_zeros(cls, rows, cols): | |
| return cls._new(rows, cols, [cls.zero]*(rows*cols), copy=False) | |
| def _eval_wilkinson(cls, n): | |
| def entry(i, j): | |
| return cls.one if i + 1 == j else cls.zero | |
| D = cls._new(2*n + 1, 2*n + 1, entry) | |
| wminus = cls.diag(list(range(-n, n + 1)), unpack=True) + D + D.T | |
| wplus = abs(cls.diag(list(range(-n, n + 1)), unpack=True)) + D + D.T | |
| return wminus, wplus | |
| def diag(kls, *args, strict=False, unpack=True, rows=None, cols=None, **kwargs): | |
| """Returns a matrix with the specified diagonal. | |
| If matrices are passed, a block-diagonal matrix | |
| is created (i.e. the "direct sum" of the matrices). | |
| kwargs | |
| ====== | |
| rows : rows of the resulting matrix; computed if | |
| not given. | |
| cols : columns of the resulting matrix; computed if | |
| not given. | |
| cls : class for the resulting matrix | |
| unpack : bool which, when True (default), unpacks a single | |
| sequence rather than interpreting it as a Matrix. | |
| strict : bool which, when False (default), allows Matrices to | |
| have variable-length rows. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> Matrix.diag(1, 2, 3) | |
| Matrix([ | |
| [1, 0, 0], | |
| [0, 2, 0], | |
| [0, 0, 3]]) | |
| The current default is to unpack a single sequence. If this is | |
| not desired, set `unpack=False` and it will be interpreted as | |
| a matrix. | |
| >>> Matrix.diag([1, 2, 3]) == Matrix.diag(1, 2, 3) | |
| True | |
| When more than one element is passed, each is interpreted as | |
| something to put on the diagonal. Lists are converted to | |
| matrices. Filling of the diagonal always continues from | |
| the bottom right hand corner of the previous item: this | |
| will create a block-diagonal matrix whether the matrices | |
| are square or not. | |
| >>> col = [1, 2, 3] | |
| >>> row = [[4, 5]] | |
| >>> Matrix.diag(col, row) | |
| Matrix([ | |
| [1, 0, 0], | |
| [2, 0, 0], | |
| [3, 0, 0], | |
| [0, 4, 5]]) | |
| When `unpack` is False, elements within a list need not all be | |
| of the same length. Setting `strict` to True would raise a | |
| ValueError for the following: | |
| >>> Matrix.diag([[1, 2, 3], [4, 5], [6]], unpack=False) | |
| Matrix([ | |
| [1, 2, 3], | |
| [4, 5, 0], | |
| [6, 0, 0]]) | |
| The type of the returned matrix can be set with the ``cls`` | |
| keyword. | |
| >>> from sympy import ImmutableMatrix | |
| >>> from sympy.utilities.misc import func_name | |
| >>> func_name(Matrix.diag(1, cls=ImmutableMatrix)) | |
| 'ImmutableDenseMatrix' | |
| A zero dimension matrix can be used to position the start of | |
| the filling at the start of an arbitrary row or column: | |
| >>> from sympy import ones | |
| >>> r2 = ones(0, 2) | |
| >>> Matrix.diag(r2, 1, 2) | |
| Matrix([ | |
| [0, 0, 1, 0], | |
| [0, 0, 0, 2]]) | |
| See Also | |
| ======== | |
| eye | |
| diagonal | |
| .dense.diag | |
| .expressions.blockmatrix.BlockMatrix | |
| .sparsetools.banded | |
| """ | |
| from sympy.matrices.matrixbase import MatrixBase | |
| from sympy.matrices.dense import Matrix | |
| from sympy.matrices import SparseMatrix | |
| klass = kwargs.get('cls', kls) | |
| if unpack and len(args) == 1 and is_sequence(args[0]) and \ | |
| not isinstance(args[0], MatrixBase): | |
| args = args[0] | |
| # fill a default dict with the diagonal entries | |
| diag_entries = defaultdict(int) | |
| rmax = cmax = 0 # keep track of the biggest index seen | |
| for m in args: | |
| if isinstance(m, list): | |
| if strict: | |
| # if malformed, Matrix will raise an error | |
| _ = Matrix(m) | |
| r, c = _.shape | |
| m = _.tolist() | |
| else: | |
| r, c, smat = SparseMatrix._handle_creation_inputs(m) | |
| for (i, j), _ in smat.items(): | |
| diag_entries[(i + rmax, j + cmax)] = _ | |
| m = [] # to skip process below | |
| elif hasattr(m, 'shape'): # a Matrix | |
| # convert to list of lists | |
| r, c = m.shape | |
| m = m.tolist() | |
| else: # in this case, we're a single value | |
| diag_entries[(rmax, cmax)] = m | |
| rmax += 1 | |
| cmax += 1 | |
| continue | |
| # process list of lists | |
| for i, mi in enumerate(m): | |
| for j, _ in enumerate(mi): | |
| diag_entries[(i + rmax, j + cmax)] = _ | |
| rmax += r | |
| cmax += c | |
| if rows is None: | |
| rows, cols = cols, rows | |
| if rows is None: | |
| rows, cols = rmax, cmax | |
| else: | |
| cols = rows if cols is None else cols | |
| if rows < rmax or cols < cmax: | |
| raise ValueError(filldedent(''' | |
| The constructed matrix is {} x {} but a size of {} x {} | |
| was specified.'''.format(rmax, cmax, rows, cols))) | |
| return klass._eval_diag(rows, cols, diag_entries) | |
| def eye(kls, rows, cols=None, **kwargs): | |
| """Returns an identity matrix. | |
| Parameters | |
| ========== | |
| rows : rows of the matrix | |
| cols : cols of the matrix (if None, cols=rows) | |
| kwargs | |
| ====== | |
| cls : class of the returned matrix | |
| """ | |
| if cols is None: | |
| cols = rows | |
| if rows < 0 or cols < 0: | |
| raise ValueError("Cannot create a {} x {} matrix. " | |
| "Both dimensions must be positive".format(rows, cols)) | |
| klass = kwargs.get('cls', kls) | |
| rows, cols = as_int(rows), as_int(cols) | |
| return klass._eval_eye(rows, cols) | |
| def jordan_block(kls, size=None, eigenvalue=None, *, band='upper', **kwargs): | |
| """Returns a Jordan block | |
| Parameters | |
| ========== | |
| size : Integer, optional | |
| Specifies the shape of the Jordan block matrix. | |
| eigenvalue : Number or Symbol | |
| Specifies the value for the main diagonal of the matrix. | |
| .. note:: | |
| The keyword ``eigenval`` is also specified as an alias | |
| of this keyword, but it is not recommended to use. | |
| We may deprecate the alias in later release. | |
| band : 'upper' or 'lower', optional | |
| Specifies the position of the off-diagonal to put `1` s on. | |
| cls : Matrix, optional | |
| Specifies the matrix class of the output form. | |
| If it is not specified, the class type where the method is | |
| being executed on will be returned. | |
| Returns | |
| ======= | |
| Matrix | |
| A Jordan block matrix. | |
| Raises | |
| ====== | |
| ValueError | |
| If insufficient arguments are given for matrix size | |
| specification, or no eigenvalue is given. | |
| Examples | |
| ======== | |
| Creating a default Jordan block: | |
| >>> from sympy import Matrix | |
| >>> from sympy.abc import x | |
| >>> Matrix.jordan_block(4, x) | |
| Matrix([ | |
| [x, 1, 0, 0], | |
| [0, x, 1, 0], | |
| [0, 0, x, 1], | |
| [0, 0, 0, x]]) | |
| Creating an alternative Jordan block matrix where `1` is on | |
| lower off-diagonal: | |
| >>> Matrix.jordan_block(4, x, band='lower') | |
| Matrix([ | |
| [x, 0, 0, 0], | |
| [1, x, 0, 0], | |
| [0, 1, x, 0], | |
| [0, 0, 1, x]]) | |
| Creating a Jordan block with keyword arguments | |
| >>> Matrix.jordan_block(size=4, eigenvalue=x) | |
| Matrix([ | |
| [x, 1, 0, 0], | |
| [0, x, 1, 0], | |
| [0, 0, x, 1], | |
| [0, 0, 0, x]]) | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Jordan_matrix | |
| """ | |
| klass = kwargs.pop('cls', kls) | |
| eigenval = kwargs.get('eigenval', None) | |
| if eigenvalue is None and eigenval is None: | |
| raise ValueError("Must supply an eigenvalue") | |
| elif eigenvalue != eigenval and None not in (eigenval, eigenvalue): | |
| raise ValueError( | |
| "Inconsistent values are given: 'eigenval'={}, " | |
| "'eigenvalue'={}".format(eigenval, eigenvalue)) | |
| else: | |
| if eigenval is not None: | |
| eigenvalue = eigenval | |
| if size is None: | |
| raise ValueError("Must supply a matrix size") | |
| size = as_int(size) | |
| return klass._eval_jordan_block(size, eigenvalue, band) | |
| def ones(kls, rows, cols=None, **kwargs): | |
| """Returns a matrix of ones. | |
| Parameters | |
| ========== | |
| rows : rows of the matrix | |
| cols : cols of the matrix (if None, cols=rows) | |
| kwargs | |
| ====== | |
| cls : class of the returned matrix | |
| """ | |
| if cols is None: | |
| cols = rows | |
| klass = kwargs.get('cls', kls) | |
| rows, cols = as_int(rows), as_int(cols) | |
| return klass._eval_ones(rows, cols) | |
| def zeros(kls, rows, cols=None, **kwargs): | |
| """Returns a matrix of zeros. | |
| Parameters | |
| ========== | |
| rows : rows of the matrix | |
| cols : cols of the matrix (if None, cols=rows) | |
| kwargs | |
| ====== | |
| cls : class of the returned matrix | |
| """ | |
| if cols is None: | |
| cols = rows | |
| if rows < 0 or cols < 0: | |
| raise ValueError("Cannot create a {} x {} matrix. " | |
| "Both dimensions must be positive".format(rows, cols)) | |
| klass = kwargs.get('cls', kls) | |
| rows, cols = as_int(rows), as_int(cols) | |
| return klass._eval_zeros(rows, cols) | |
| def companion(kls, poly): | |
| """Returns a companion matrix of a polynomial. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix, Poly, Symbol, symbols | |
| >>> x = Symbol('x') | |
| >>> c0, c1, c2, c3, c4 = symbols('c0:5') | |
| >>> p = Poly(c0 + c1*x + c2*x**2 + c3*x**3 + c4*x**4 + x**5, x) | |
| >>> Matrix.companion(p) | |
| Matrix([ | |
| [0, 0, 0, 0, -c0], | |
| [1, 0, 0, 0, -c1], | |
| [0, 1, 0, 0, -c2], | |
| [0, 0, 1, 0, -c3], | |
| [0, 0, 0, 1, -c4]]) | |
| """ | |
| poly = kls._sympify(poly) | |
| if not isinstance(poly, Poly): | |
| raise ValueError("{} must be a Poly instance.".format(poly)) | |
| if not poly.is_monic: | |
| raise ValueError("{} must be a monic polynomial.".format(poly)) | |
| if not poly.is_univariate: | |
| raise ValueError( | |
| "{} must be a univariate polynomial.".format(poly)) | |
| size = poly.degree() | |
| if not size >= 1: | |
| raise ValueError( | |
| "{} must have degree not less than 1.".format(poly)) | |
| coeffs = poly.all_coeffs() | |
| def entry(i, j): | |
| if j == size - 1: | |
| return -coeffs[-1 - i] | |
| elif i == j + 1: | |
| return kls.one | |
| return kls.zero | |
| return kls._new(size, size, entry) | |
| def wilkinson(kls, n, **kwargs): | |
| """Returns two square Wilkinson Matrix of size 2*n + 1 | |
| $W_{2n + 1}^-, W_{2n + 1}^+ =$ Wilkinson(n) | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> wminus, wplus = Matrix.wilkinson(3) | |
| >>> wminus | |
| Matrix([ | |
| [-3, 1, 0, 0, 0, 0, 0], | |
| [ 1, -2, 1, 0, 0, 0, 0], | |
| [ 0, 1, -1, 1, 0, 0, 0], | |
| [ 0, 0, 1, 0, 1, 0, 0], | |
| [ 0, 0, 0, 1, 1, 1, 0], | |
| [ 0, 0, 0, 0, 1, 2, 1], | |
| [ 0, 0, 0, 0, 0, 1, 3]]) | |
| >>> wplus | |
| Matrix([ | |
| [3, 1, 0, 0, 0, 0, 0], | |
| [1, 2, 1, 0, 0, 0, 0], | |
| [0, 1, 1, 1, 0, 0, 0], | |
| [0, 0, 1, 0, 1, 0, 0], | |
| [0, 0, 0, 1, 1, 1, 0], | |
| [0, 0, 0, 0, 1, 2, 1], | |
| [0, 0, 0, 0, 0, 1, 3]]) | |
| References | |
| ========== | |
| .. [1] https://blogs.mathworks.com/cleve/2013/04/15/wilkinsons-matrices-2/ | |
| .. [2] J. H. Wilkinson, The Algebraic Eigenvalue Problem, Claredon Press, Oxford, 1965, 662 pp. | |
| """ | |
| klass = kwargs.get('cls', kls) | |
| n = as_int(n) | |
| return klass._eval_wilkinson(n) | |
| class MatrixProperties(MatrixRequired): | |
| """Provides basic properties of a matrix.""" | |
| def _eval_atoms(self, *types): | |
| result = set() | |
| for i in self: | |
| result.update(i.atoms(*types)) | |
| return result | |
| def _eval_free_symbols(self): | |
| return set().union(*(i.free_symbols for i in self if i)) | |
| def _eval_has(self, *patterns): | |
| return any(a.has(*patterns) for a in self) | |
| def _eval_is_anti_symmetric(self, simpfunc): | |
| if not all(simpfunc(self[i, j] + self[j, i]).is_zero for i in range(self.rows) for j in range(self.cols)): | |
| return False | |
| return True | |
| def _eval_is_diagonal(self): | |
| for i in range(self.rows): | |
| for j in range(self.cols): | |
| if i != j and self[i, j]: | |
| return False | |
| return True | |
| # _eval_is_hermitian is called by some general SymPy | |
| # routines and has a different *args signature. Make | |
| # sure the names don't clash by adding `_matrix_` in name. | |
| def _eval_is_matrix_hermitian(self, simpfunc): | |
| mat = self._new(self.rows, self.cols, lambda i, j: simpfunc(self[i, j] - self[j, i].conjugate())) | |
| return mat.is_zero_matrix | |
| def _eval_is_Identity(self) -> FuzzyBool: | |
| def dirac(i, j): | |
| if i == j: | |
| return 1 | |
| return 0 | |
| return all(self[i, j] == dirac(i, j) | |
| for i in range(self.rows) | |
| for j in range(self.cols)) | |
| def _eval_is_lower_hessenberg(self): | |
| return all(self[i, j].is_zero | |
| for i in range(self.rows) | |
| for j in range(i + 2, self.cols)) | |
| def _eval_is_lower(self): | |
| return all(self[i, j].is_zero | |
| for i in range(self.rows) | |
| for j in range(i + 1, self.cols)) | |
| def _eval_is_symbolic(self): | |
| return self.has(Symbol) | |
| def _eval_is_symmetric(self, simpfunc): | |
| mat = self._new(self.rows, self.cols, lambda i, j: simpfunc(self[i, j] - self[j, i])) | |
| return mat.is_zero_matrix | |
| def _eval_is_zero_matrix(self): | |
| if any(i.is_zero == False for i in self): | |
| return False | |
| if any(i.is_zero is None for i in self): | |
| return None | |
| return True | |
| def _eval_is_upper_hessenberg(self): | |
| return all(self[i, j].is_zero | |
| for i in range(2, self.rows) | |
| for j in range(min(self.cols, (i - 1)))) | |
| def _eval_values(self): | |
| return [i for i in self if not i.is_zero] | |
| def _has_positive_diagonals(self): | |
| diagonal_entries = (self[i, i] for i in range(self.rows)) | |
| return fuzzy_and(x.is_positive for x in diagonal_entries) | |
| def _has_nonnegative_diagonals(self): | |
| diagonal_entries = (self[i, i] for i in range(self.rows)) | |
| return fuzzy_and(x.is_nonnegative for x in diagonal_entries) | |
| def atoms(self, *types): | |
| """Returns the atoms that form the current object. | |
| Examples | |
| ======== | |
| >>> from sympy.abc import x, y | |
| >>> from sympy import Matrix | |
| >>> Matrix([[x]]) | |
| Matrix([[x]]) | |
| >>> _.atoms() | |
| {x} | |
| >>> Matrix([[x, y], [y, x]]) | |
| Matrix([ | |
| [x, y], | |
| [y, x]]) | |
| >>> _.atoms() | |
| {x, y} | |
| """ | |
| types = tuple(t if isinstance(t, type) else type(t) for t in types) | |
| if not types: | |
| types = (Atom,) | |
| return self._eval_atoms(*types) | |
| def free_symbols(self): | |
| """Returns the free symbols within the matrix. | |
| Examples | |
| ======== | |
| >>> from sympy.abc import x | |
| >>> from sympy import Matrix | |
| >>> Matrix([[x], [1]]).free_symbols | |
| {x} | |
| """ | |
| return self._eval_free_symbols() | |
| def has(self, *patterns): | |
| """Test whether any subexpression matches any of the patterns. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix, SparseMatrix, Float | |
| >>> from sympy.abc import x, y | |
| >>> A = Matrix(((1, x), (0.2, 3))) | |
| >>> B = SparseMatrix(((1, x), (0.2, 3))) | |
| >>> A.has(x) | |
| True | |
| >>> A.has(y) | |
| False | |
| >>> A.has(Float) | |
| True | |
| >>> B.has(x) | |
| True | |
| >>> B.has(y) | |
| False | |
| >>> B.has(Float) | |
| True | |
| """ | |
| return self._eval_has(*patterns) | |
| def is_anti_symmetric(self, simplify=True): | |
| """Check if matrix M is an antisymmetric matrix, | |
| that is, M is a square matrix with all M[i, j] == -M[j, i]. | |
| When ``simplify=True`` (default), the sum M[i, j] + M[j, i] is | |
| simplified before testing to see if it is zero. By default, | |
| the SymPy simplify function is used. To use a custom function | |
| set simplify to a function that accepts a single argument which | |
| returns a simplified expression. To skip simplification, set | |
| simplify to False but note that although this will be faster, | |
| it may induce false negatives. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix, symbols | |
| >>> m = Matrix(2, 2, [0, 1, -1, 0]) | |
| >>> m | |
| Matrix([ | |
| [ 0, 1], | |
| [-1, 0]]) | |
| >>> m.is_anti_symmetric() | |
| True | |
| >>> x, y = symbols('x y') | |
| >>> m = Matrix(2, 3, [0, 0, x, -y, 0, 0]) | |
| >>> m | |
| Matrix([ | |
| [ 0, 0, x], | |
| [-y, 0, 0]]) | |
| >>> m.is_anti_symmetric() | |
| False | |
| >>> from sympy.abc import x, y | |
| >>> m = Matrix(3, 3, [0, x**2 + 2*x + 1, y, | |
| ... -(x + 1)**2, 0, x*y, | |
| ... -y, -x*y, 0]) | |
| Simplification of matrix elements is done by default so even | |
| though two elements which should be equal and opposite would not | |
| pass an equality test, the matrix is still reported as | |
| anti-symmetric: | |
| >>> m[0, 1] == -m[1, 0] | |
| False | |
| >>> m.is_anti_symmetric() | |
| True | |
| If ``simplify=False`` is used for the case when a Matrix is already | |
| simplified, this will speed things up. Here, we see that without | |
| simplification the matrix does not appear anti-symmetric: | |
| >>> print(m.is_anti_symmetric(simplify=False)) | |
| None | |
| But if the matrix were already expanded, then it would appear | |
| anti-symmetric and simplification in the is_anti_symmetric routine | |
| is not needed: | |
| >>> m = m.expand() | |
| >>> m.is_anti_symmetric(simplify=False) | |
| True | |
| """ | |
| # accept custom simplification | |
| simpfunc = simplify | |
| if not isfunction(simplify): | |
| simpfunc = _simplify if simplify else lambda x: x | |
| if not self.is_square: | |
| return False | |
| return self._eval_is_anti_symmetric(simpfunc) | |
| def is_diagonal(self): | |
| """Check if matrix is diagonal, | |
| that is matrix in which the entries outside the main diagonal are all zero. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix, diag | |
| >>> m = Matrix(2, 2, [1, 0, 0, 2]) | |
| >>> m | |
| Matrix([ | |
| [1, 0], | |
| [0, 2]]) | |
| >>> m.is_diagonal() | |
| True | |
| >>> m = Matrix(2, 2, [1, 1, 0, 2]) | |
| >>> m | |
| Matrix([ | |
| [1, 1], | |
| [0, 2]]) | |
| >>> m.is_diagonal() | |
| False | |
| >>> m = diag(1, 2, 3) | |
| >>> m | |
| Matrix([ | |
| [1, 0, 0], | |
| [0, 2, 0], | |
| [0, 0, 3]]) | |
| >>> m.is_diagonal() | |
| True | |
| See Also | |
| ======== | |
| is_lower | |
| is_upper | |
| sympy.matrices.matrixbase.MatrixCommon.is_diagonalizable | |
| diagonalize | |
| """ | |
| return self._eval_is_diagonal() | |
| def is_weakly_diagonally_dominant(self): | |
| r"""Tests if the matrix is row weakly diagonally dominant. | |
| Explanation | |
| =========== | |
| A $n, n$ matrix $A$ is row weakly diagonally dominant if | |
| .. math:: | |
| \left|A_{i, i}\right| \ge \sum_{j = 0, j \neq i}^{n-1} | |
| \left|A_{i, j}\right| \quad {\text{for all }} | |
| i \in \{ 0, ..., n-1 \} | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> A = Matrix([[3, -2, 1], [1, -3, 2], [-1, 2, 4]]) | |
| >>> A.is_weakly_diagonally_dominant | |
| True | |
| >>> A = Matrix([[-2, 2, 1], [1, 3, 2], [1, -2, 0]]) | |
| >>> A.is_weakly_diagonally_dominant | |
| False | |
| >>> A = Matrix([[-4, 2, 1], [1, 6, 2], [1, -2, 5]]) | |
| >>> A.is_weakly_diagonally_dominant | |
| True | |
| Notes | |
| ===== | |
| If you want to test whether a matrix is column diagonally | |
| dominant, you can apply the test after transposing the matrix. | |
| """ | |
| if not self.is_square: | |
| return False | |
| rows, cols = self.shape | |
| def test_row(i): | |
| summation = self.zero | |
| for j in range(cols): | |
| if i != j: | |
| summation += Abs(self[i, j]) | |
| return (Abs(self[i, i]) - summation).is_nonnegative | |
| return fuzzy_and(test_row(i) for i in range(rows)) | |
| def is_strongly_diagonally_dominant(self): | |
| r"""Tests if the matrix is row strongly diagonally dominant. | |
| Explanation | |
| =========== | |
| A $n, n$ matrix $A$ is row strongly diagonally dominant if | |
| .. math:: | |
| \left|A_{i, i}\right| > \sum_{j = 0, j \neq i}^{n-1} | |
| \left|A_{i, j}\right| \quad {\text{for all }} | |
| i \in \{ 0, ..., n-1 \} | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> A = Matrix([[3, -2, 1], [1, -3, 2], [-1, 2, 4]]) | |
| >>> A.is_strongly_diagonally_dominant | |
| False | |
| >>> A = Matrix([[-2, 2, 1], [1, 3, 2], [1, -2, 0]]) | |
| >>> A.is_strongly_diagonally_dominant | |
| False | |
| >>> A = Matrix([[-4, 2, 1], [1, 6, 2], [1, -2, 5]]) | |
| >>> A.is_strongly_diagonally_dominant | |
| True | |
| Notes | |
| ===== | |
| If you want to test whether a matrix is column diagonally | |
| dominant, you can apply the test after transposing the matrix. | |
| """ | |
| if not self.is_square: | |
| return False | |
| rows, cols = self.shape | |
| def test_row(i): | |
| summation = self.zero | |
| for j in range(cols): | |
| if i != j: | |
| summation += Abs(self[i, j]) | |
| return (Abs(self[i, i]) - summation).is_positive | |
| return fuzzy_and(test_row(i) for i in range(rows)) | |
| def is_hermitian(self): | |
| """Checks if the matrix is Hermitian. | |
| In a Hermitian matrix element i,j is the complex conjugate of | |
| element j,i. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> from sympy import I | |
| >>> from sympy.abc import x | |
| >>> a = Matrix([[1, I], [-I, 1]]) | |
| >>> a | |
| Matrix([ | |
| [ 1, I], | |
| [-I, 1]]) | |
| >>> a.is_hermitian | |
| True | |
| >>> a[0, 0] = 2*I | |
| >>> a.is_hermitian | |
| False | |
| >>> a[0, 0] = x | |
| >>> a.is_hermitian | |
| >>> a[0, 1] = a[1, 0]*I | |
| >>> a.is_hermitian | |
| False | |
| """ | |
| if not self.is_square: | |
| return False | |
| return self._eval_is_matrix_hermitian(_simplify) | |
| def is_Identity(self) -> FuzzyBool: | |
| if not self.is_square: | |
| return False | |
| return self._eval_is_Identity() | |
| def is_lower_hessenberg(self): | |
| r"""Checks if the matrix is in the lower-Hessenberg form. | |
| The lower hessenberg matrix has zero entries | |
| above the first superdiagonal. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> a = Matrix([[1, 2, 0, 0], [5, 2, 3, 0], [3, 4, 3, 7], [5, 6, 1, 1]]) | |
| >>> a | |
| Matrix([ | |
| [1, 2, 0, 0], | |
| [5, 2, 3, 0], | |
| [3, 4, 3, 7], | |
| [5, 6, 1, 1]]) | |
| >>> a.is_lower_hessenberg | |
| True | |
| See Also | |
| ======== | |
| is_upper_hessenberg | |
| is_lower | |
| """ | |
| return self._eval_is_lower_hessenberg() | |
| def is_lower(self): | |
| """Check if matrix is a lower triangular matrix. True can be returned | |
| even if the matrix is not square. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> m = Matrix(2, 2, [1, 0, 0, 1]) | |
| >>> m | |
| Matrix([ | |
| [1, 0], | |
| [0, 1]]) | |
| >>> m.is_lower | |
| True | |
| >>> m = Matrix(4, 3, [0, 0, 0, 2, 0, 0, 1, 4, 0, 6, 6, 5]) | |
| >>> m | |
| Matrix([ | |
| [0, 0, 0], | |
| [2, 0, 0], | |
| [1, 4, 0], | |
| [6, 6, 5]]) | |
| >>> m.is_lower | |
| True | |
| >>> from sympy.abc import x, y | |
| >>> m = Matrix(2, 2, [x**2 + y, y**2 + x, 0, x + y]) | |
| >>> m | |
| Matrix([ | |
| [x**2 + y, x + y**2], | |
| [ 0, x + y]]) | |
| >>> m.is_lower | |
| False | |
| See Also | |
| ======== | |
| is_upper | |
| is_diagonal | |
| is_lower_hessenberg | |
| """ | |
| return self._eval_is_lower() | |
| def is_square(self): | |
| """Checks if a matrix is square. | |
| A matrix is square if the number of rows equals the number of columns. | |
| The empty matrix is square by definition, since the number of rows and | |
| the number of columns are both zero. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> a = Matrix([[1, 2, 3], [4, 5, 6]]) | |
| >>> b = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) | |
| >>> c = Matrix([]) | |
| >>> a.is_square | |
| False | |
| >>> b.is_square | |
| True | |
| >>> c.is_square | |
| True | |
| """ | |
| return self.rows == self.cols | |
| def is_symbolic(self): | |
| """Checks if any elements contain Symbols. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> from sympy.abc import x, y | |
| >>> M = Matrix([[x, y], [1, 0]]) | |
| >>> M.is_symbolic() | |
| True | |
| """ | |
| return self._eval_is_symbolic() | |
| def is_symmetric(self, simplify=True): | |
| """Check if matrix is symmetric matrix, | |
| that is square matrix and is equal to its transpose. | |
| By default, simplifications occur before testing symmetry. | |
| They can be skipped using 'simplify=False'; while speeding things a bit, | |
| this may however induce false negatives. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> m = Matrix(2, 2, [0, 1, 1, 2]) | |
| >>> m | |
| Matrix([ | |
| [0, 1], | |
| [1, 2]]) | |
| >>> m.is_symmetric() | |
| True | |
| >>> m = Matrix(2, 2, [0, 1, 2, 0]) | |
| >>> m | |
| Matrix([ | |
| [0, 1], | |
| [2, 0]]) | |
| >>> m.is_symmetric() | |
| False | |
| >>> m = Matrix(2, 3, [0, 0, 0, 0, 0, 0]) | |
| >>> m | |
| Matrix([ | |
| [0, 0, 0], | |
| [0, 0, 0]]) | |
| >>> m.is_symmetric() | |
| False | |
| >>> from sympy.abc import x, y | |
| >>> m = Matrix(3, 3, [1, x**2 + 2*x + 1, y, (x + 1)**2, 2, 0, y, 0, 3]) | |
| >>> m | |
| Matrix([ | |
| [ 1, x**2 + 2*x + 1, y], | |
| [(x + 1)**2, 2, 0], | |
| [ y, 0, 3]]) | |
| >>> m.is_symmetric() | |
| True | |
| If the matrix is already simplified, you may speed-up is_symmetric() | |
| test by using 'simplify=False'. | |
| >>> bool(m.is_symmetric(simplify=False)) | |
| False | |
| >>> m1 = m.expand() | |
| >>> m1.is_symmetric(simplify=False) | |
| True | |
| """ | |
| simpfunc = simplify | |
| if not isfunction(simplify): | |
| simpfunc = _simplify if simplify else lambda x: x | |
| if not self.is_square: | |
| return False | |
| return self._eval_is_symmetric(simpfunc) | |
| def is_upper_hessenberg(self): | |
| """Checks if the matrix is the upper-Hessenberg form. | |
| The upper hessenberg matrix has zero entries | |
| below the first subdiagonal. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> a = Matrix([[1, 4, 2, 3], [3, 4, 1, 7], [0, 2, 3, 4], [0, 0, 1, 3]]) | |
| >>> a | |
| Matrix([ | |
| [1, 4, 2, 3], | |
| [3, 4, 1, 7], | |
| [0, 2, 3, 4], | |
| [0, 0, 1, 3]]) | |
| >>> a.is_upper_hessenberg | |
| True | |
| See Also | |
| ======== | |
| is_lower_hessenberg | |
| is_upper | |
| """ | |
| return self._eval_is_upper_hessenberg() | |
| def is_upper(self): | |
| """Check if matrix is an upper triangular matrix. True can be returned | |
| even if the matrix is not square. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> m = Matrix(2, 2, [1, 0, 0, 1]) | |
| >>> m | |
| Matrix([ | |
| [1, 0], | |
| [0, 1]]) | |
| >>> m.is_upper | |
| True | |
| >>> m = Matrix(4, 3, [5, 1, 9, 0, 4, 6, 0, 0, 5, 0, 0, 0]) | |
| >>> m | |
| Matrix([ | |
| [5, 1, 9], | |
| [0, 4, 6], | |
| [0, 0, 5], | |
| [0, 0, 0]]) | |
| >>> m.is_upper | |
| True | |
| >>> m = Matrix(2, 3, [4, 2, 5, 6, 1, 1]) | |
| >>> m | |
| Matrix([ | |
| [4, 2, 5], | |
| [6, 1, 1]]) | |
| >>> m.is_upper | |
| False | |
| See Also | |
| ======== | |
| is_lower | |
| is_diagonal | |
| is_upper_hessenberg | |
| """ | |
| return all(self[i, j].is_zero | |
| for i in range(1, self.rows) | |
| for j in range(min(i, self.cols))) | |
| def is_zero_matrix(self): | |
| """Checks if a matrix is a zero matrix. | |
| A matrix is zero if every element is zero. A matrix need not be square | |
| to be considered zero. The empty matrix is zero by the principle of | |
| vacuous truth. For a matrix that may or may not be zero (e.g. | |
| contains a symbol), this will be None | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix, zeros | |
| >>> from sympy.abc import x | |
| >>> a = Matrix([[0, 0], [0, 0]]) | |
| >>> b = zeros(3, 4) | |
| >>> c = Matrix([[0, 1], [0, 0]]) | |
| >>> d = Matrix([]) | |
| >>> e = Matrix([[x, 0], [0, 0]]) | |
| >>> a.is_zero_matrix | |
| True | |
| >>> b.is_zero_matrix | |
| True | |
| >>> c.is_zero_matrix | |
| False | |
| >>> d.is_zero_matrix | |
| True | |
| >>> e.is_zero_matrix | |
| """ | |
| return self._eval_is_zero_matrix() | |
| def values(self): | |
| """Return non-zero values of self.""" | |
| return self._eval_values() | |
| class MatrixOperations(MatrixRequired): | |
| """Provides basic matrix shape and elementwise | |
| operations. Should not be instantiated directly.""" | |
| def _eval_adjoint(self): | |
| return self.transpose().conjugate() | |
| def _eval_applyfunc(self, f): | |
| out = self._new(self.rows, self.cols, [f(x) for x in self]) | |
| return out | |
| def _eval_as_real_imag(self): # type: ignore | |
| return (self.applyfunc(re), self.applyfunc(im)) | |
| def _eval_conjugate(self): | |
| return self.applyfunc(lambda x: x.conjugate()) | |
| def _eval_permute_cols(self, perm): | |
| # apply the permutation to a list | |
| mapping = list(perm) | |
| def entry(i, j): | |
| return self[i, mapping[j]] | |
| return self._new(self.rows, self.cols, entry) | |
| def _eval_permute_rows(self, perm): | |
| # apply the permutation to a list | |
| mapping = list(perm) | |
| def entry(i, j): | |
| return self[mapping[i], j] | |
| return self._new(self.rows, self.cols, entry) | |
| def _eval_trace(self): | |
| return sum(self[i, i] for i in range(self.rows)) | |
| def _eval_transpose(self): | |
| return self._new(self.cols, self.rows, lambda i, j: self[j, i]) | |
| def adjoint(self): | |
| """Conjugate transpose or Hermitian conjugation.""" | |
| return self._eval_adjoint() | |
| def applyfunc(self, f): | |
| """Apply a function to each element of the matrix. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> m = Matrix(2, 2, lambda i, j: i*2+j) | |
| >>> m | |
| Matrix([ | |
| [0, 1], | |
| [2, 3]]) | |
| >>> m.applyfunc(lambda i: 2*i) | |
| Matrix([ | |
| [0, 2], | |
| [4, 6]]) | |
| """ | |
| if not callable(f): | |
| raise TypeError("`f` must be callable.") | |
| return self._eval_applyfunc(f) | |
| def as_real_imag(self, deep=True, **hints): | |
| """Returns a tuple containing the (real, imaginary) part of matrix.""" | |
| # XXX: Ignoring deep and hints... | |
| return self._eval_as_real_imag() | |
| def conjugate(self): | |
| """Return the by-element conjugation. | |
| Examples | |
| ======== | |
| >>> from sympy import SparseMatrix, I | |
| >>> a = SparseMatrix(((1, 2 + I), (3, 4), (I, -I))) | |
| >>> a | |
| Matrix([ | |
| [1, 2 + I], | |
| [3, 4], | |
| [I, -I]]) | |
| >>> a.C | |
| Matrix([ | |
| [ 1, 2 - I], | |
| [ 3, 4], | |
| [-I, I]]) | |
| See Also | |
| ======== | |
| transpose: Matrix transposition | |
| H: Hermite conjugation | |
| sympy.matrices.matrixbase.MatrixBase.D: Dirac conjugation | |
| """ | |
| return self._eval_conjugate() | |
| def doit(self, **hints): | |
| return self.applyfunc(lambda x: x.doit(**hints)) | |
| def evalf(self, n=15, subs=None, maxn=100, chop=False, strict=False, quad=None, verbose=False): | |
| """Apply evalf() to each element of self.""" | |
| options = {'subs':subs, 'maxn':maxn, 'chop':chop, 'strict':strict, | |
| 'quad':quad, 'verbose':verbose} | |
| return self.applyfunc(lambda i: i.evalf(n, **options)) | |
| def expand(self, deep=True, modulus=None, power_base=True, power_exp=True, | |
| mul=True, log=True, multinomial=True, basic=True, **hints): | |
| """Apply core.function.expand to each entry of the matrix. | |
| Examples | |
| ======== | |
| >>> from sympy.abc import x | |
| >>> from sympy import Matrix | |
| >>> Matrix(1, 1, [x*(x+1)]) | |
| Matrix([[x*(x + 1)]]) | |
| >>> _.expand() | |
| Matrix([[x**2 + x]]) | |
| """ | |
| return self.applyfunc(lambda x: x.expand( | |
| deep, modulus, power_base, power_exp, mul, log, multinomial, basic, | |
| **hints)) | |
| def H(self): | |
| """Return Hermite conjugate. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix, I | |
| >>> m = Matrix((0, 1 + I, 2, 3)) | |
| >>> m | |
| Matrix([ | |
| [ 0], | |
| [1 + I], | |
| [ 2], | |
| [ 3]]) | |
| >>> m.H | |
| Matrix([[0, 1 - I, 2, 3]]) | |
| See Also | |
| ======== | |
| conjugate: By-element conjugation | |
| sympy.matrices.matrixbase.MatrixBase.D: Dirac conjugation | |
| """ | |
| return self.T.C | |
| def permute(self, perm, orientation='rows', direction='forward'): | |
| r"""Permute the rows or columns of a matrix by the given list of | |
| swaps. | |
| Parameters | |
| ========== | |
| perm : Permutation, list, or list of lists | |
| A representation for the permutation. | |
| If it is ``Permutation``, it is used directly with some | |
| resizing with respect to the matrix size. | |
| If it is specified as list of lists, | |
| (e.g., ``[[0, 1], [0, 2]]``), then the permutation is formed | |
| from applying the product of cycles. The direction how the | |
| cyclic product is applied is described in below. | |
| If it is specified as a list, the list should represent | |
| an array form of a permutation. (e.g., ``[1, 2, 0]``) which | |
| would would form the swapping function | |
| `0 \mapsto 1, 1 \mapsto 2, 2\mapsto 0`. | |
| orientation : 'rows', 'cols' | |
| A flag to control whether to permute the rows or the columns | |
| direction : 'forward', 'backward' | |
| A flag to control whether to apply the permutations from | |
| the start of the list first, or from the back of the list | |
| first. | |
| For example, if the permutation specification is | |
| ``[[0, 1], [0, 2]]``, | |
| If the flag is set to ``'forward'``, the cycle would be | |
| formed as `0 \mapsto 2, 2 \mapsto 1, 1 \mapsto 0`. | |
| If the flag is set to ``'backward'``, the cycle would be | |
| formed as `0 \mapsto 1, 1 \mapsto 2, 2 \mapsto 0`. | |
| If the argument ``perm`` is not in a form of list of lists, | |
| this flag takes no effect. | |
| Examples | |
| ======== | |
| >>> from sympy import eye | |
| >>> M = eye(3) | |
| >>> M.permute([[0, 1], [0, 2]], orientation='rows', direction='forward') | |
| Matrix([ | |
| [0, 0, 1], | |
| [1, 0, 0], | |
| [0, 1, 0]]) | |
| >>> from sympy import eye | |
| >>> M = eye(3) | |
| >>> M.permute([[0, 1], [0, 2]], orientation='rows', direction='backward') | |
| Matrix([ | |
| [0, 1, 0], | |
| [0, 0, 1], | |
| [1, 0, 0]]) | |
| Notes | |
| ===== | |
| If a bijective function | |
| `\sigma : \mathbb{N}_0 \rightarrow \mathbb{N}_0` denotes the | |
| permutation. | |
| If the matrix `A` is the matrix to permute, represented as | |
| a horizontal or a vertical stack of vectors: | |
| .. math:: | |
| A = | |
| \begin{bmatrix} | |
| a_0 \\ a_1 \\ \vdots \\ a_{n-1} | |
| \end{bmatrix} = | |
| \begin{bmatrix} | |
| \alpha_0 & \alpha_1 & \cdots & \alpha_{n-1} | |
| \end{bmatrix} | |
| If the matrix `B` is the result, the permutation of matrix rows | |
| is defined as: | |
| .. math:: | |
| B := \begin{bmatrix} | |
| a_{\sigma(0)} \\ a_{\sigma(1)} \\ \vdots \\ a_{\sigma(n-1)} | |
| \end{bmatrix} | |
| And the permutation of matrix columns is defined as: | |
| .. math:: | |
| B := \begin{bmatrix} | |
| \alpha_{\sigma(0)} & \alpha_{\sigma(1)} & | |
| \cdots & \alpha_{\sigma(n-1)} | |
| \end{bmatrix} | |
| """ | |
| from sympy.combinatorics import Permutation | |
| # allow british variants and `columns` | |
| if direction == 'forwards': | |
| direction = 'forward' | |
| if direction == 'backwards': | |
| direction = 'backward' | |
| if orientation == 'columns': | |
| orientation = 'cols' | |
| if direction not in ('forward', 'backward'): | |
| raise TypeError("direction='{}' is an invalid kwarg. " | |
| "Try 'forward' or 'backward'".format(direction)) | |
| if orientation not in ('rows', 'cols'): | |
| raise TypeError("orientation='{}' is an invalid kwarg. " | |
| "Try 'rows' or 'cols'".format(orientation)) | |
| if not isinstance(perm, (Permutation, Iterable)): | |
| raise ValueError( | |
| "{} must be a list, a list of lists, " | |
| "or a SymPy permutation object.".format(perm)) | |
| # ensure all swaps are in range | |
| max_index = self.rows if orientation == 'rows' else self.cols | |
| if not all(0 <= t <= max_index for t in flatten(list(perm))): | |
| raise IndexError("`swap` indices out of range.") | |
| if perm and not isinstance(perm, Permutation) and \ | |
| isinstance(perm[0], Iterable): | |
| if direction == 'forward': | |
| perm = list(reversed(perm)) | |
| perm = Permutation(perm, size=max_index+1) | |
| else: | |
| perm = Permutation(perm, size=max_index+1) | |
| if orientation == 'rows': | |
| return self._eval_permute_rows(perm) | |
| if orientation == 'cols': | |
| return self._eval_permute_cols(perm) | |
| def permute_cols(self, swaps, direction='forward'): | |
| """Alias for | |
| ``self.permute(swaps, orientation='cols', direction=direction)`` | |
| See Also | |
| ======== | |
| permute | |
| """ | |
| return self.permute(swaps, orientation='cols', direction=direction) | |
| def permute_rows(self, swaps, direction='forward'): | |
| """Alias for | |
| ``self.permute(swaps, orientation='rows', direction=direction)`` | |
| See Also | |
| ======== | |
| permute | |
| """ | |
| return self.permute(swaps, orientation='rows', direction=direction) | |
| def refine(self, assumptions=True): | |
| """Apply refine to each element of the matrix. | |
| Examples | |
| ======== | |
| >>> from sympy import Symbol, Matrix, Abs, sqrt, Q | |
| >>> x = Symbol('x') | |
| >>> Matrix([[Abs(x)**2, sqrt(x**2)],[sqrt(x**2), Abs(x)**2]]) | |
| Matrix([ | |
| [ Abs(x)**2, sqrt(x**2)], | |
| [sqrt(x**2), Abs(x)**2]]) | |
| >>> _.refine(Q.real(x)) | |
| Matrix([ | |
| [ x**2, Abs(x)], | |
| [Abs(x), x**2]]) | |
| """ | |
| return self.applyfunc(lambda x: refine(x, assumptions)) | |
| def replace(self, F, G, map=False, simultaneous=True, exact=None): | |
| """Replaces Function F in Matrix entries with Function G. | |
| Examples | |
| ======== | |
| >>> from sympy import symbols, Function, Matrix | |
| >>> F, G = symbols('F, G', cls=Function) | |
| >>> M = Matrix(2, 2, lambda i, j: F(i+j)) ; M | |
| Matrix([ | |
| [F(0), F(1)], | |
| [F(1), F(2)]]) | |
| >>> N = M.replace(F,G) | |
| >>> N | |
| Matrix([ | |
| [G(0), G(1)], | |
| [G(1), G(2)]]) | |
| """ | |
| return self.applyfunc( | |
| lambda x: x.replace(F, G, map=map, simultaneous=simultaneous, exact=exact)) | |
| def rot90(self, k=1): | |
| """Rotates Matrix by 90 degrees | |
| Parameters | |
| ========== | |
| k : int | |
| Specifies how many times the matrix is rotated by 90 degrees | |
| (clockwise when positive, counter-clockwise when negative). | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix, symbols | |
| >>> A = Matrix(2, 2, symbols('a:d')) | |
| >>> A | |
| Matrix([ | |
| [a, b], | |
| [c, d]]) | |
| Rotating the matrix clockwise one time: | |
| >>> A.rot90(1) | |
| Matrix([ | |
| [c, a], | |
| [d, b]]) | |
| Rotating the matrix anticlockwise two times: | |
| >>> A.rot90(-2) | |
| Matrix([ | |
| [d, c], | |
| [b, a]]) | |
| """ | |
| mod = k%4 | |
| if mod == 0: | |
| return self | |
| if mod == 1: | |
| return self[::-1, ::].T | |
| if mod == 2: | |
| return self[::-1, ::-1] | |
| if mod == 3: | |
| return self[::, ::-1].T | |
| def simplify(self, **kwargs): | |
| """Apply simplify to each element of the matrix. | |
| Examples | |
| ======== | |
| >>> from sympy.abc import x, y | |
| >>> from sympy import SparseMatrix, sin, cos | |
| >>> SparseMatrix(1, 1, [x*sin(y)**2 + x*cos(y)**2]) | |
| Matrix([[x*sin(y)**2 + x*cos(y)**2]]) | |
| >>> _.simplify() | |
| Matrix([[x]]) | |
| """ | |
| return self.applyfunc(lambda x: x.simplify(**kwargs)) | |
| def subs(self, *args, **kwargs): # should mirror core.basic.subs | |
| """Return a new matrix with subs applied to each entry. | |
| Examples | |
| ======== | |
| >>> from sympy.abc import x, y | |
| >>> from sympy import SparseMatrix, Matrix | |
| >>> SparseMatrix(1, 1, [x]) | |
| Matrix([[x]]) | |
| >>> _.subs(x, y) | |
| Matrix([[y]]) | |
| >>> Matrix(_).subs(y, x) | |
| Matrix([[x]]) | |
| """ | |
| if len(args) == 1 and not isinstance(args[0], (dict, set)) and iter(args[0]) and not is_sequence(args[0]): | |
| args = (list(args[0]),) | |
| return self.applyfunc(lambda x: x.subs(*args, **kwargs)) | |
| def trace(self): | |
| """ | |
| Returns the trace of a square matrix i.e. the sum of the | |
| diagonal elements. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> A = Matrix(2, 2, [1, 2, 3, 4]) | |
| >>> A.trace() | |
| 5 | |
| """ | |
| if self.rows != self.cols: | |
| raise NonSquareMatrixError() | |
| return self._eval_trace() | |
| def transpose(self): | |
| """ | |
| Returns the transpose of the matrix. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> A = Matrix(2, 2, [1, 2, 3, 4]) | |
| >>> A.transpose() | |
| Matrix([ | |
| [1, 3], | |
| [2, 4]]) | |
| >>> from sympy import Matrix, I | |
| >>> m=Matrix(((1, 2+I), (3, 4))) | |
| >>> m | |
| Matrix([ | |
| [1, 2 + I], | |
| [3, 4]]) | |
| >>> m.transpose() | |
| Matrix([ | |
| [ 1, 3], | |
| [2 + I, 4]]) | |
| >>> m.T == m.transpose() | |
| True | |
| See Also | |
| ======== | |
| conjugate: By-element conjugation | |
| """ | |
| return self._eval_transpose() | |
| def T(self): | |
| '''Matrix transposition''' | |
| return self.transpose() | |
| def C(self): | |
| '''By-element conjugation''' | |
| return self.conjugate() | |
| def n(self, *args, **kwargs): | |
| """Apply evalf() to each element of self.""" | |
| return self.evalf(*args, **kwargs) | |
| def xreplace(self, rule): # should mirror core.basic.xreplace | |
| """Return a new matrix with xreplace applied to each entry. | |
| Examples | |
| ======== | |
| >>> from sympy.abc import x, y | |
| >>> from sympy import SparseMatrix, Matrix | |
| >>> SparseMatrix(1, 1, [x]) | |
| Matrix([[x]]) | |
| >>> _.xreplace({x: y}) | |
| Matrix([[y]]) | |
| >>> Matrix(_).xreplace({y: x}) | |
| Matrix([[x]]) | |
| """ | |
| return self.applyfunc(lambda x: x.xreplace(rule)) | |
| def _eval_simplify(self, **kwargs): | |
| # XXX: We can't use self.simplify here as mutable subclasses will | |
| # override simplify and have it return None | |
| return MatrixOperations.simplify(self, **kwargs) | |
| def _eval_trigsimp(self, **opts): | |
| from sympy.simplify.trigsimp import trigsimp | |
| return self.applyfunc(lambda x: trigsimp(x, **opts)) | |
| def upper_triangular(self, k=0): | |
| """Return the elements on and above the kth diagonal of a matrix. | |
| If k is not specified then simply returns upper-triangular portion | |
| of a matrix | |
| Examples | |
| ======== | |
| >>> from sympy import ones | |
| >>> A = ones(4) | |
| >>> A.upper_triangular() | |
| Matrix([ | |
| [1, 1, 1, 1], | |
| [0, 1, 1, 1], | |
| [0, 0, 1, 1], | |
| [0, 0, 0, 1]]) | |
| >>> A.upper_triangular(2) | |
| Matrix([ | |
| [0, 0, 1, 1], | |
| [0, 0, 0, 1], | |
| [0, 0, 0, 0], | |
| [0, 0, 0, 0]]) | |
| >>> A.upper_triangular(-1) | |
| Matrix([ | |
| [1, 1, 1, 1], | |
| [1, 1, 1, 1], | |
| [0, 1, 1, 1], | |
| [0, 0, 1, 1]]) | |
| """ | |
| def entry(i, j): | |
| return self[i, j] if i + k <= j else self.zero | |
| return self._new(self.rows, self.cols, entry) | |
| def lower_triangular(self, k=0): | |
| """Return the elements on and below the kth diagonal of a matrix. | |
| If k is not specified then simply returns lower-triangular portion | |
| of a matrix | |
| Examples | |
| ======== | |
| >>> from sympy import ones | |
| >>> A = ones(4) | |
| >>> A.lower_triangular() | |
| Matrix([ | |
| [1, 0, 0, 0], | |
| [1, 1, 0, 0], | |
| [1, 1, 1, 0], | |
| [1, 1, 1, 1]]) | |
| >>> A.lower_triangular(-2) | |
| Matrix([ | |
| [0, 0, 0, 0], | |
| [0, 0, 0, 0], | |
| [1, 0, 0, 0], | |
| [1, 1, 0, 0]]) | |
| >>> A.lower_triangular(1) | |
| Matrix([ | |
| [1, 1, 0, 0], | |
| [1, 1, 1, 0], | |
| [1, 1, 1, 1], | |
| [1, 1, 1, 1]]) | |
| """ | |
| def entry(i, j): | |
| return self[i, j] if i + k >= j else self.zero | |
| return self._new(self.rows, self.cols, entry) | |
| class MatrixArithmetic(MatrixRequired): | |
| """Provides basic matrix arithmetic operations. | |
| Should not be instantiated directly.""" | |
| _op_priority = 10.01 | |
| def _eval_Abs(self): | |
| return self._new(self.rows, self.cols, lambda i, j: Abs(self[i, j])) | |
| def _eval_add(self, other): | |
| return self._new(self.rows, self.cols, | |
| lambda i, j: self[i, j] + other[i, j]) | |
| def _eval_matrix_mul(self, other): | |
| def entry(i, j): | |
| vec = [self[i,k]*other[k,j] for k in range(self.cols)] | |
| try: | |
| return Add(*vec) | |
| except (TypeError, SympifyError): | |
| # Some matrices don't work with `sum` or `Add` | |
| # They don't work with `sum` because `sum` tries to add `0` | |
| # Fall back to a safe way to multiply if the `Add` fails. | |
| return reduce(lambda a, b: a + b, vec) | |
| return self._new(self.rows, other.cols, entry) | |
| def _eval_matrix_mul_elementwise(self, other): | |
| return self._new(self.rows, self.cols, lambda i, j: self[i,j]*other[i,j]) | |
| def _eval_matrix_rmul(self, other): | |
| def entry(i, j): | |
| return sum(other[i,k]*self[k,j] for k in range(other.cols)) | |
| return self._new(other.rows, self.cols, entry) | |
| def _eval_pow_by_recursion(self, num): | |
| if num == 1: | |
| return self | |
| if num % 2 == 1: | |
| a, b = self, self._eval_pow_by_recursion(num - 1) | |
| else: | |
| a = b = self._eval_pow_by_recursion(num // 2) | |
| return a.multiply(b) | |
| def _eval_pow_by_cayley(self, exp): | |
| from sympy.discrete.recurrences import linrec_coeffs | |
| row = self.shape[0] | |
| p = self.charpoly() | |
| coeffs = (-p).all_coeffs()[1:] | |
| coeffs = linrec_coeffs(coeffs, exp) | |
| new_mat = self.eye(row) | |
| ans = self.zeros(row) | |
| for i in range(row): | |
| ans += coeffs[i]*new_mat | |
| new_mat *= self | |
| return ans | |
| def _eval_pow_by_recursion_dotprodsimp(self, num, prevsimp=None): | |
| if prevsimp is None: | |
| prevsimp = [True]*len(self) | |
| if num == 1: | |
| return self | |
| if num % 2 == 1: | |
| a, b = self, self._eval_pow_by_recursion_dotprodsimp(num - 1, | |
| prevsimp=prevsimp) | |
| else: | |
| a = b = self._eval_pow_by_recursion_dotprodsimp(num // 2, | |
| prevsimp=prevsimp) | |
| m = a.multiply(b, dotprodsimp=False) | |
| lenm = len(m) | |
| elems = [None]*lenm | |
| for i in range(lenm): | |
| if prevsimp[i]: | |
| elems[i], prevsimp[i] = _dotprodsimp(m[i], withsimp=True) | |
| else: | |
| elems[i] = m[i] | |
| return m._new(m.rows, m.cols, elems) | |
| def _eval_scalar_mul(self, other): | |
| return self._new(self.rows, self.cols, lambda i, j: self[i,j]*other) | |
| def _eval_scalar_rmul(self, other): | |
| return self._new(self.rows, self.cols, lambda i, j: other*self[i,j]) | |
| def _eval_Mod(self, other): | |
| return self._new(self.rows, self.cols, lambda i, j: Mod(self[i, j], other)) | |
| # Python arithmetic functions | |
| def __abs__(self): | |
| """Returns a new matrix with entry-wise absolute values.""" | |
| return self._eval_Abs() | |
| def __add__(self, other): | |
| """Return self + other, raising ShapeError if shapes do not match.""" | |
| if isinstance(other, NDimArray): # Matrix and array addition is currently not implemented | |
| return NotImplemented | |
| other = _matrixify(other) | |
| # matrix-like objects can have shapes. This is | |
| # our first sanity check. | |
| if hasattr(other, 'shape'): | |
| if self.shape != other.shape: | |
| raise ShapeError("Matrix size mismatch: %s + %s" % ( | |
| self.shape, other.shape)) | |
| # honest SymPy matrices defer to their class's routine | |
| if getattr(other, 'is_Matrix', False): | |
| # call the highest-priority class's _eval_add | |
| a, b = self, other | |
| if a.__class__ != classof(a, b): | |
| b, a = a, b | |
| return a._eval_add(b) | |
| # Matrix-like objects can be passed to CommonMatrix routines directly. | |
| if getattr(other, 'is_MatrixLike', False): | |
| return MatrixArithmetic._eval_add(self, other) | |
| raise TypeError('cannot add %s and %s' % (type(self), type(other))) | |
| def __truediv__(self, other): | |
| return self * (self.one / other) | |
| def __matmul__(self, other): | |
| other = _matrixify(other) | |
| if not getattr(other, 'is_Matrix', False) and not getattr(other, 'is_MatrixLike', False): | |
| return NotImplemented | |
| return self.__mul__(other) | |
| def __mod__(self, other): | |
| return self.applyfunc(lambda x: x % other) | |
| def __mul__(self, other): | |
| """Return self*other where other is either a scalar or a matrix | |
| of compatible dimensions. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> A = Matrix([[1, 2, 3], [4, 5, 6]]) | |
| >>> 2*A == A*2 == Matrix([[2, 4, 6], [8, 10, 12]]) | |
| True | |
| >>> B = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) | |
| >>> A*B | |
| Matrix([ | |
| [30, 36, 42], | |
| [66, 81, 96]]) | |
| >>> B*A | |
| Traceback (most recent call last): | |
| ... | |
| ShapeError: Matrices size mismatch. | |
| >>> | |
| See Also | |
| ======== | |
| matrix_multiply_elementwise | |
| """ | |
| return self.multiply(other) | |
| def multiply(self, other, dotprodsimp=None): | |
| """Same as __mul__() but with optional simplification. | |
| Parameters | |
| ========== | |
| dotprodsimp : bool, optional | |
| Specifies whether intermediate term algebraic simplification is used | |
| during matrix multiplications to control expression blowup and thus | |
| speed up calculation. Default is off. | |
| """ | |
| isimpbool = _get_intermediate_simp_bool(False, dotprodsimp) | |
| other = _matrixify(other) | |
| # matrix-like objects can have shapes. This is | |
| # our first sanity check. Double check other is not explicitly not a Matrix. | |
| if (hasattr(other, 'shape') and len(other.shape) == 2 and | |
| (getattr(other, 'is_Matrix', True) or | |
| getattr(other, 'is_MatrixLike', True))): | |
| if self.shape[1] != other.shape[0]: | |
| raise ShapeError("Matrix size mismatch: %s * %s." % ( | |
| self.shape, other.shape)) | |
| # honest SymPy matrices defer to their class's routine | |
| if getattr(other, 'is_Matrix', False): | |
| m = self._eval_matrix_mul(other) | |
| if isimpbool: | |
| return m._new(m.rows, m.cols, [_dotprodsimp(e) for e in m]) | |
| return m | |
| # Matrix-like objects can be passed to CommonMatrix routines directly. | |
| if getattr(other, 'is_MatrixLike', False): | |
| return MatrixArithmetic._eval_matrix_mul(self, other) | |
| # if 'other' is not iterable then scalar multiplication. | |
| if not isinstance(other, Iterable): | |
| try: | |
| return self._eval_scalar_mul(other) | |
| except TypeError: | |
| pass | |
| return NotImplemented | |
| def multiply_elementwise(self, other): | |
| """Return the Hadamard product (elementwise product) of A and B | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix | |
| >>> A = Matrix([[0, 1, 2], [3, 4, 5]]) | |
| >>> B = Matrix([[1, 10, 100], [100, 10, 1]]) | |
| >>> A.multiply_elementwise(B) | |
| Matrix([ | |
| [ 0, 10, 200], | |
| [300, 40, 5]]) | |
| See Also | |
| ======== | |
| sympy.matrices.matrixbase.MatrixBase.cross | |
| sympy.matrices.matrixbase.MatrixBase.dot | |
| multiply | |
| """ | |
| if self.shape != other.shape: | |
| raise ShapeError("Matrix shapes must agree {} != {}".format(self.shape, other.shape)) | |
| return self._eval_matrix_mul_elementwise(other) | |
| def __neg__(self): | |
| return self._eval_scalar_mul(-1) | |
| def __pow__(self, exp): | |
| """Return self**exp a scalar or symbol.""" | |
| return self.pow(exp) | |
| def pow(self, exp, method=None): | |
| r"""Return self**exp a scalar or symbol. | |
| Parameters | |
| ========== | |
| method : multiply, mulsimp, jordan, cayley | |
| If multiply then it returns exponentiation using recursion. | |
| If jordan then Jordan form exponentiation will be used. | |
| If cayley then the exponentiation is done using Cayley-Hamilton | |
| theorem. | |
| If mulsimp then the exponentiation is done using recursion | |
| with dotprodsimp. This specifies whether intermediate term | |
| algebraic simplification is used during naive matrix power to | |
| control expression blowup and thus speed up calculation. | |
| If None, then it heuristically decides which method to use. | |
| """ | |
| if method is not None and method not in ['multiply', 'mulsimp', 'jordan', 'cayley']: | |
| raise TypeError('No such method') | |
| if self.rows != self.cols: | |
| raise NonSquareMatrixError() | |
| a = self | |
| jordan_pow = getattr(a, '_matrix_pow_by_jordan_blocks', None) | |
| exp = sympify(exp) | |
| if exp.is_zero: | |
| return a._new(a.rows, a.cols, lambda i, j: int(i == j)) | |
| if exp == 1: | |
| return a | |
| diagonal = getattr(a, 'is_diagonal', None) | |
| if diagonal is not None and diagonal(): | |
| return a._new(a.rows, a.cols, lambda i, j: a[i,j]**exp if i == j else 0) | |
| if exp.is_Number and exp % 1 == 0: | |
| if a.rows == 1: | |
| return a._new([[a[0]**exp]]) | |
| if exp < 0: | |
| exp = -exp | |
| a = a.inv() | |
| # When certain conditions are met, | |
| # Jordan block algorithm is faster than | |
| # computation by recursion. | |
| if method == 'jordan': | |
| try: | |
| return jordan_pow(exp) | |
| except MatrixError: | |
| if method == 'jordan': | |
| raise | |
| elif method == 'cayley': | |
| if not exp.is_Number or exp % 1 != 0: | |
| raise ValueError("cayley method is only valid for integer powers") | |
| return a._eval_pow_by_cayley(exp) | |
| elif method == "mulsimp": | |
| if not exp.is_Number or exp % 1 != 0: | |
| raise ValueError("mulsimp method is only valid for integer powers") | |
| return a._eval_pow_by_recursion_dotprodsimp(exp) | |
| elif method == "multiply": | |
| if not exp.is_Number or exp % 1 != 0: | |
| raise ValueError("multiply method is only valid for integer powers") | |
| return a._eval_pow_by_recursion(exp) | |
| elif method is None and exp.is_Number and exp % 1 == 0: | |
| if exp.is_Float: | |
| exp = Integer(exp) | |
| # Decide heuristically which method to apply | |
| if a.rows == 2 and exp > 100000: | |
| return jordan_pow(exp) | |
| elif _get_intermediate_simp_bool(True, None): | |
| return a._eval_pow_by_recursion_dotprodsimp(exp) | |
| elif exp > 10000: | |
| return a._eval_pow_by_cayley(exp) | |
| else: | |
| return a._eval_pow_by_recursion(exp) | |
| if jordan_pow: | |
| try: | |
| return jordan_pow(exp) | |
| except NonInvertibleMatrixError: | |
| # Raised by jordan_pow on zero determinant matrix unless exp is | |
| # definitely known to be a non-negative integer. | |
| # Here we raise if n is definitely not a non-negative integer | |
| # but otherwise we can leave this as an unevaluated MatPow. | |
| if exp.is_integer is False or exp.is_nonnegative is False: | |
| raise | |
| from sympy.matrices.expressions import MatPow | |
| return MatPow(a, exp) | |
| def __radd__(self, other): | |
| return self + other | |
| def __rmatmul__(self, other): | |
| other = _matrixify(other) | |
| if not getattr(other, 'is_Matrix', False) and not getattr(other, 'is_MatrixLike', False): | |
| return NotImplemented | |
| return self.__rmul__(other) | |
| def __rmul__(self, other): | |
| return self.rmultiply(other) | |
| def rmultiply(self, other, dotprodsimp=None): | |
| """Same as __rmul__() but with optional simplification. | |
| Parameters | |
| ========== | |
| dotprodsimp : bool, optional | |
| Specifies whether intermediate term algebraic simplification is used | |
| during matrix multiplications to control expression blowup and thus | |
| speed up calculation. Default is off. | |
| """ | |
| isimpbool = _get_intermediate_simp_bool(False, dotprodsimp) | |
| other = _matrixify(other) | |
| # matrix-like objects can have shapes. This is | |
| # our first sanity check. Double check other is not explicitly not a Matrix. | |
| if (hasattr(other, 'shape') and len(other.shape) == 2 and | |
| (getattr(other, 'is_Matrix', True) or | |
| getattr(other, 'is_MatrixLike', True))): | |
| if self.shape[0] != other.shape[1]: | |
| raise ShapeError("Matrix size mismatch.") | |
| # honest SymPy matrices defer to their class's routine | |
| if getattr(other, 'is_Matrix', False): | |
| m = self._eval_matrix_rmul(other) | |
| if isimpbool: | |
| return m._new(m.rows, m.cols, [_dotprodsimp(e) for e in m]) | |
| return m | |
| # Matrix-like objects can be passed to CommonMatrix routines directly. | |
| if getattr(other, 'is_MatrixLike', False): | |
| return MatrixArithmetic._eval_matrix_rmul(self, other) | |
| # if 'other' is not iterable then scalar multiplication. | |
| if not isinstance(other, Iterable): | |
| try: | |
| return self._eval_scalar_rmul(other) | |
| except TypeError: | |
| pass | |
| return NotImplemented | |
| def __rsub__(self, a): | |
| return (-self) + a | |
| def __sub__(self, a): | |
| return self + (-a) | |
| class MatrixCommon(MatrixArithmetic, MatrixOperations, MatrixProperties, | |
| MatrixSpecial, MatrixShaping): | |
| """All common matrix operations including basic arithmetic, shaping, | |
| and special matrices like `zeros`, and `eye`.""" | |
| _diff_wrt: bool = True | |
| class _MinimalMatrix: | |
| """Class providing the minimum functionality | |
| for a matrix-like object and implementing every method | |
| required for a `MatrixRequired`. This class does not have everything | |
| needed to become a full-fledged SymPy object, but it will satisfy the | |
| requirements of anything inheriting from `MatrixRequired`. If you wish | |
| to make a specialized matrix type, make sure to implement these | |
| methods and properties with the exception of `__init__` and `__repr__` | |
| which are included for convenience.""" | |
| is_MatrixLike = True | |
| _sympify = staticmethod(sympify) | |
| _class_priority = 3 | |
| zero = S.Zero | |
| one = S.One | |
| is_Matrix = True | |
| is_MatrixExpr = False | |
| def _new(cls, *args, **kwargs): | |
| return cls(*args, **kwargs) | |
| def __init__(self, rows, cols=None, mat=None, copy=False): | |
| if isfunction(mat): | |
| # if we passed in a function, use that to populate the indices | |
| mat = [mat(i, j) for i in range(rows) for j in range(cols)] | |
| if cols is None and mat is None: | |
| mat = rows | |
| rows, cols = getattr(mat, 'shape', (rows, cols)) | |
| try: | |
| # if we passed in a list of lists, flatten it and set the size | |
| if cols is None and mat is None: | |
| mat = rows | |
| cols = len(mat[0]) | |
| rows = len(mat) | |
| mat = [x for l in mat for x in l] | |
| except (IndexError, TypeError): | |
| pass | |
| self.mat = tuple(self._sympify(x) for x in mat) | |
| self.rows, self.cols = rows, cols | |
| if self.rows is None or self.cols is None: | |
| raise NotImplementedError("Cannot initialize matrix with given parameters") | |
| def __getitem__(self, key): | |
| def _normalize_slices(row_slice, col_slice): | |
| """Ensure that row_slice and col_slice do not have | |
| `None` in their arguments. Any integers are converted | |
| to slices of length 1""" | |
| if not isinstance(row_slice, slice): | |
| row_slice = slice(row_slice, row_slice + 1, None) | |
| row_slice = slice(*row_slice.indices(self.rows)) | |
| if not isinstance(col_slice, slice): | |
| col_slice = slice(col_slice, col_slice + 1, None) | |
| col_slice = slice(*col_slice.indices(self.cols)) | |
| return (row_slice, col_slice) | |
| def _coord_to_index(i, j): | |
| """Return the index in _mat corresponding | |
| to the (i,j) position in the matrix. """ | |
| return i * self.cols + j | |
| if isinstance(key, tuple): | |
| i, j = key | |
| if isinstance(i, slice) or isinstance(j, slice): | |
| # if the coordinates are not slices, make them so | |
| # and expand the slices so they don't contain `None` | |
| i, j = _normalize_slices(i, j) | |
| rowsList, colsList = list(range(self.rows))[i], \ | |
| list(range(self.cols))[j] | |
| indices = (i * self.cols + j for i in rowsList for j in | |
| colsList) | |
| return self._new(len(rowsList), len(colsList), | |
| [self.mat[i] for i in indices]) | |
| # if the key is a tuple of ints, change | |
| # it to an array index | |
| key = _coord_to_index(i, j) | |
| return self.mat[key] | |
| def __eq__(self, other): | |
| try: | |
| classof(self, other) | |
| except TypeError: | |
| return False | |
| return ( | |
| self.shape == other.shape and list(self) == list(other)) | |
| def __len__(self): | |
| return self.rows*self.cols | |
| def __repr__(self): | |
| return "_MinimalMatrix({}, {}, {})".format(self.rows, self.cols, | |
| self.mat) | |
| def shape(self): | |
| return (self.rows, self.cols) | |
| class _CastableMatrix: # this is needed here ONLY FOR TESTS. | |
| def as_mutable(self): | |
| return self | |
| def as_immutable(self): | |
| return self | |
| class _MatrixWrapper: | |
| """Wrapper class providing the minimum functionality for a matrix-like | |
| object: .rows, .cols, .shape, indexability, and iterability. CommonMatrix | |
| math operations should work on matrix-like objects. This one is intended for | |
| matrix-like objects which use the same indexing format as SymPy with respect | |
| to returning matrix elements instead of rows for non-tuple indexes. | |
| """ | |
| is_Matrix = False # needs to be here because of __getattr__ | |
| is_MatrixLike = True | |
| def __init__(self, mat, shape): | |
| self.mat = mat | |
| self.shape = shape | |
| self.rows, self.cols = shape | |
| def __getitem__(self, key): | |
| if isinstance(key, tuple): | |
| return sympify(self.mat.__getitem__(key)) | |
| return sympify(self.mat.__getitem__((key // self.rows, key % self.cols))) | |
| def __iter__(self): # supports numpy.matrix and numpy.array | |
| mat = self.mat | |
| cols = self.cols | |
| return iter(sympify(mat[r, c]) for r in range(self.rows) for c in range(cols)) | |
| def _matrixify(mat): | |
| """If `mat` is a Matrix or is matrix-like, | |
| return a Matrix or MatrixWrapper object. Otherwise | |
| `mat` is passed through without modification.""" | |
| if getattr(mat, 'is_Matrix', False) or getattr(mat, 'is_MatrixLike', False): | |
| return mat | |
| if not(getattr(mat, 'is_Matrix', True) or getattr(mat, 'is_MatrixLike', True)): | |
| return mat | |
| shape = None | |
| if hasattr(mat, 'shape'): # numpy, scipy.sparse | |
| if len(mat.shape) == 2: | |
| shape = mat.shape | |
| elif hasattr(mat, 'rows') and hasattr(mat, 'cols'): # mpmath | |
| shape = (mat.rows, mat.cols) | |
| if shape: | |
| return _MatrixWrapper(mat, shape) | |
| return mat | |
| def a2idx(j, n=None): | |
| """Return integer after making positive and validating against n.""" | |
| if not isinstance(j, int): | |
| jindex = getattr(j, '__index__', None) | |
| if jindex is not None: | |
| j = jindex() | |
| else: | |
| raise IndexError("Invalid index a[%r]" % (j,)) | |
| if n is not None: | |
| if j < 0: | |
| j += n | |
| if not (j >= 0 and j < n): | |
| raise IndexError("Index out of range: a[%s]" % (j,)) | |
| return int(j) | |
| def classof(A, B): | |
| """ | |
| Get the type of the result when combining matrices of different types. | |
| Currently the strategy is that immutability is contagious. | |
| Examples | |
| ======== | |
| >>> from sympy import Matrix, ImmutableMatrix | |
| >>> from sympy.matrices.matrixbase import classof | |
| >>> M = Matrix([[1, 2], [3, 4]]) # a Mutable Matrix | |
| >>> IM = ImmutableMatrix([[1, 2], [3, 4]]) | |
| >>> classof(M, IM) | |
| <class 'sympy.matrices.immutable.ImmutableDenseMatrix'> | |
| """ | |
| priority_A = getattr(A, '_class_priority', None) | |
| priority_B = getattr(B, '_class_priority', None) | |
| if None not in (priority_A, priority_B): | |
| if A._class_priority > B._class_priority: | |
| return A.__class__ | |
| else: | |
| return B.__class__ | |
| try: | |
| import numpy | |
| except ImportError: | |
| pass | |
| else: | |
| if isinstance(A, numpy.ndarray): | |
| return B.__class__ | |
| if isinstance(B, numpy.ndarray): | |
| return A.__class__ | |
| raise TypeError("Incompatible classes %s, %s" % (A.__class__, B.__class__)) | |
Xet Storage Details
- Size:
- 95.4 kB
- Xet hash:
- 11d357fe1639190cb1673975b4223206da16b700741a754fb14a78f718866efc
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.