|
|
|
|
|
|
|
|
|
from sympy.core.basic import Basic |
|
from sympy.core.symbol import Dummy |
|
|
|
from .common import MatrixCommon |
|
|
|
from .exceptions import NonSquareMatrixError |
|
|
|
from .utilities import _iszero, _is_zero_after_expand_mul, _simplify |
|
|
|
from .determinant import ( |
|
_find_reasonable_pivot, _find_reasonable_pivot_naive, |
|
_adjugate, _charpoly, _cofactor, _cofactor_matrix, _per, |
|
_det, _det_bareiss, _det_berkowitz, _det_bird, _det_laplace, _det_LU, |
|
_minor, _minor_submatrix) |
|
|
|
from .reductions import _is_echelon, _echelon_form, _rank, _rref |
|
from .subspaces import _columnspace, _nullspace, _rowspace, _orthogonalize |
|
|
|
from .eigen import ( |
|
_eigenvals, _eigenvects, |
|
_bidiagonalize, _bidiagonal_decomposition, |
|
_is_diagonalizable, _diagonalize, |
|
_is_positive_definite, _is_positive_semidefinite, |
|
_is_negative_definite, _is_negative_semidefinite, _is_indefinite, |
|
_jordan_form, _left_eigenvects, _singular_values) |
|
|
|
|
|
|
|
|
|
|
|
from .matrixbase import MatrixBase |
|
|
|
|
|
__doctest_requires__ = { |
|
('MatrixEigen.is_indefinite', |
|
'MatrixEigen.is_negative_definite', |
|
'MatrixEigen.is_negative_semidefinite', |
|
'MatrixEigen.is_positive_definite', |
|
'MatrixEigen.is_positive_semidefinite'): ['matplotlib'], |
|
} |
|
|
|
|
|
class MatrixDeterminant(MatrixCommon): |
|
"""Provides basic matrix determinant operations. Should not be instantiated |
|
directly. See ``determinant.py`` for their implementations.""" |
|
|
|
def _eval_det_bareiss(self, iszerofunc=_is_zero_after_expand_mul): |
|
return _det_bareiss(self, iszerofunc=iszerofunc) |
|
|
|
def _eval_det_berkowitz(self): |
|
return _det_berkowitz(self) |
|
|
|
def _eval_det_lu(self, iszerofunc=_iszero, simpfunc=None): |
|
return _det_LU(self, iszerofunc=iszerofunc, simpfunc=simpfunc) |
|
|
|
def _eval_det_bird(self): |
|
return _det_bird(self) |
|
|
|
def _eval_det_laplace(self): |
|
return _det_laplace(self) |
|
|
|
def _eval_determinant(self): |
|
return _det(self) |
|
|
|
def adjugate(self, method="berkowitz"): |
|
return _adjugate(self, method=method) |
|
|
|
def charpoly(self, x='lambda', simplify=_simplify): |
|
return _charpoly(self, x=x, simplify=simplify) |
|
|
|
def cofactor(self, i, j, method="berkowitz"): |
|
return _cofactor(self, i, j, method=method) |
|
|
|
def cofactor_matrix(self, method="berkowitz"): |
|
return _cofactor_matrix(self, method=method) |
|
|
|
def det(self, method="bareiss", iszerofunc=None): |
|
return _det(self, method=method, iszerofunc=iszerofunc) |
|
|
|
def per(self): |
|
return _per(self) |
|
|
|
def minor(self, i, j, method="berkowitz"): |
|
return _minor(self, i, j, method=method) |
|
|
|
def minor_submatrix(self, i, j): |
|
return _minor_submatrix(self, i, j) |
|
|
|
_find_reasonable_pivot.__doc__ = _find_reasonable_pivot.__doc__ |
|
_find_reasonable_pivot_naive.__doc__ = _find_reasonable_pivot_naive.__doc__ |
|
_eval_det_bareiss.__doc__ = _det_bareiss.__doc__ |
|
_eval_det_berkowitz.__doc__ = _det_berkowitz.__doc__ |
|
_eval_det_bird.__doc__ = _det_bird.__doc__ |
|
_eval_det_laplace.__doc__ = _det_laplace.__doc__ |
|
_eval_det_lu.__doc__ = _det_LU.__doc__ |
|
_eval_determinant.__doc__ = _det.__doc__ |
|
adjugate.__doc__ = _adjugate.__doc__ |
|
charpoly.__doc__ = _charpoly.__doc__ |
|
cofactor.__doc__ = _cofactor.__doc__ |
|
cofactor_matrix.__doc__ = _cofactor_matrix.__doc__ |
|
det.__doc__ = _det.__doc__ |
|
per.__doc__ = _per.__doc__ |
|
minor.__doc__ = _minor.__doc__ |
|
minor_submatrix.__doc__ = _minor_submatrix.__doc__ |
|
|
|
|
|
class MatrixReductions(MatrixDeterminant): |
|
"""Provides basic matrix row/column operations. Should not be instantiated |
|
directly. See ``reductions.py`` for some of their implementations.""" |
|
|
|
def echelon_form(self, iszerofunc=_iszero, simplify=False, with_pivots=False): |
|
return _echelon_form(self, iszerofunc=iszerofunc, simplify=simplify, |
|
with_pivots=with_pivots) |
|
|
|
@property |
|
def is_echelon(self): |
|
return _is_echelon(self) |
|
|
|
def rank(self, iszerofunc=_iszero, simplify=False): |
|
return _rank(self, iszerofunc=iszerofunc, simplify=simplify) |
|
|
|
def rref_rhs(self, rhs): |
|
"""Return reduced row-echelon form of matrix, matrix showing |
|
rhs after reduction steps. ``rhs`` must have the same number |
|
of rows as ``self``. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import Matrix, symbols |
|
>>> r1, r2 = symbols('r1 r2') |
|
>>> Matrix([[1, 1], [2, 1]]).rref_rhs(Matrix([r1, r2])) |
|
(Matrix([ |
|
[1, 0], |
|
[0, 1]]), Matrix([ |
|
[ -r1 + r2], |
|
[2*r1 - r2]])) |
|
""" |
|
r, _ = _rref(self.hstack(self, self.eye(self.rows), rhs)) |
|
return r[:, :self.cols], r[:, -rhs.cols:] |
|
|
|
def rref(self, iszerofunc=_iszero, simplify=False, pivots=True, |
|
normalize_last=True): |
|
return _rref(self, iszerofunc=iszerofunc, simplify=simplify, |
|
pivots=pivots, normalize_last=normalize_last) |
|
|
|
echelon_form.__doc__ = _echelon_form.__doc__ |
|
is_echelon.__doc__ = _is_echelon.__doc__ |
|
rank.__doc__ = _rank.__doc__ |
|
rref.__doc__ = _rref.__doc__ |
|
|
|
def _normalize_op_args(self, op, col, k, col1, col2, error_str="col"): |
|
"""Validate the arguments for a row/column operation. ``error_str`` |
|
can be one of "row" or "col" depending on the arguments being parsed.""" |
|
if op not in ["n->kn", "n<->m", "n->n+km"]: |
|
raise ValueError("Unknown {} operation '{}'. Valid col operations " |
|
"are 'n->kn', 'n<->m', 'n->n+km'".format(error_str, op)) |
|
|
|
|
|
self_cols = self.cols if error_str == 'col' else self.rows |
|
|
|
|
|
if op == "n->kn": |
|
col = col if col is not None else col1 |
|
if col is None or k is None: |
|
raise ValueError("For a {0} operation 'n->kn' you must provide the " |
|
"kwargs `{0}` and `k`".format(error_str)) |
|
if not 0 <= col < self_cols: |
|
raise ValueError("This matrix does not have a {} '{}'".format(error_str, col)) |
|
|
|
elif op == "n<->m": |
|
|
|
|
|
|
|
cols = {col, k, col1, col2}.difference([None]) |
|
if len(cols) > 2: |
|
|
|
cols = {col, col1, col2}.difference([None]) |
|
if len(cols) != 2: |
|
raise ValueError("For a {0} operation 'n<->m' you must provide the " |
|
"kwargs `{0}1` and `{0}2`".format(error_str)) |
|
col1, col2 = cols |
|
if not 0 <= col1 < self_cols: |
|
raise ValueError("This matrix does not have a {} '{}'".format(error_str, col1)) |
|
if not 0 <= col2 < self_cols: |
|
raise ValueError("This matrix does not have a {} '{}'".format(error_str, col2)) |
|
|
|
elif op == "n->n+km": |
|
col = col1 if col is None else col |
|
col2 = col1 if col2 is None else col2 |
|
if col is None or col2 is None or k is None: |
|
raise ValueError("For a {0} operation 'n->n+km' you must provide the " |
|
"kwargs `{0}`, `k`, and `{0}2`".format(error_str)) |
|
if col == col2: |
|
raise ValueError("For a {0} operation 'n->n+km' `{0}` and `{0}2` must " |
|
"be different.".format(error_str)) |
|
if not 0 <= col < self_cols: |
|
raise ValueError("This matrix does not have a {} '{}'".format(error_str, col)) |
|
if not 0 <= col2 < self_cols: |
|
raise ValueError("This matrix does not have a {} '{}'".format(error_str, col2)) |
|
|
|
else: |
|
raise ValueError('invalid operation %s' % repr(op)) |
|
|
|
return op, col, k, col1, col2 |
|
|
|
def _eval_col_op_multiply_col_by_const(self, col, k): |
|
def entry(i, j): |
|
if j == col: |
|
return k * self[i, j] |
|
return self[i, j] |
|
return self._new(self.rows, self.cols, entry) |
|
|
|
def _eval_col_op_swap(self, col1, col2): |
|
def entry(i, j): |
|
if j == col1: |
|
return self[i, col2] |
|
elif j == col2: |
|
return self[i, col1] |
|
return self[i, j] |
|
return self._new(self.rows, self.cols, entry) |
|
|
|
def _eval_col_op_add_multiple_to_other_col(self, col, k, col2): |
|
def entry(i, j): |
|
if j == col: |
|
return self[i, j] + k * self[i, col2] |
|
return self[i, j] |
|
return self._new(self.rows, self.cols, entry) |
|
|
|
def _eval_row_op_swap(self, row1, row2): |
|
def entry(i, j): |
|
if i == row1: |
|
return self[row2, j] |
|
elif i == row2: |
|
return self[row1, j] |
|
return self[i, j] |
|
return self._new(self.rows, self.cols, entry) |
|
|
|
def _eval_row_op_multiply_row_by_const(self, row, k): |
|
def entry(i, j): |
|
if i == row: |
|
return k * self[i, j] |
|
return self[i, j] |
|
return self._new(self.rows, self.cols, entry) |
|
|
|
def _eval_row_op_add_multiple_to_other_row(self, row, k, row2): |
|
def entry(i, j): |
|
if i == row: |
|
return self[i, j] + k * self[row2, j] |
|
return self[i, j] |
|
return self._new(self.rows, self.cols, entry) |
|
|
|
def elementary_col_op(self, op="n->kn", col=None, k=None, col1=None, col2=None): |
|
"""Performs the elementary column operation `op`. |
|
|
|
`op` may be one of |
|
|
|
* ``"n->kn"`` (column n goes to k*n) |
|
* ``"n<->m"`` (swap column n and column m) |
|
* ``"n->n+km"`` (column n goes to column n + k*column m) |
|
|
|
Parameters |
|
========== |
|
|
|
op : string; the elementary row operation |
|
col : the column to apply the column operation |
|
k : the multiple to apply in the column operation |
|
col1 : one column of a column swap |
|
col2 : second column of a column swap or column "m" in the column operation |
|
"n->n+km" |
|
""" |
|
|
|
op, col, k, col1, col2 = self._normalize_op_args(op, col, k, col1, col2, "col") |
|
|
|
|
|
if op == "n->kn": |
|
return self._eval_col_op_multiply_col_by_const(col, k) |
|
if op == "n<->m": |
|
return self._eval_col_op_swap(col1, col2) |
|
if op == "n->n+km": |
|
return self._eval_col_op_add_multiple_to_other_col(col, k, col2) |
|
|
|
def elementary_row_op(self, op="n->kn", row=None, k=None, row1=None, row2=None): |
|
"""Performs the elementary row operation `op`. |
|
|
|
`op` may be one of |
|
|
|
* ``"n->kn"`` (row n goes to k*n) |
|
* ``"n<->m"`` (swap row n and row m) |
|
* ``"n->n+km"`` (row n goes to row n + k*row m) |
|
|
|
Parameters |
|
========== |
|
|
|
op : string; the elementary row operation |
|
row : the row to apply the row operation |
|
k : the multiple to apply in the row operation |
|
row1 : one row of a row swap |
|
row2 : second row of a row swap or row "m" in the row operation |
|
"n->n+km" |
|
""" |
|
|
|
op, row, k, row1, row2 = self._normalize_op_args(op, row, k, row1, row2, "row") |
|
|
|
|
|
if op == "n->kn": |
|
return self._eval_row_op_multiply_row_by_const(row, k) |
|
if op == "n<->m": |
|
return self._eval_row_op_swap(row1, row2) |
|
if op == "n->n+km": |
|
return self._eval_row_op_add_multiple_to_other_row(row, k, row2) |
|
|
|
|
|
class MatrixSubspaces(MatrixReductions): |
|
"""Provides methods relating to the fundamental subspaces of a matrix. |
|
Should not be instantiated directly. See ``subspaces.py`` for their |
|
implementations.""" |
|
|
|
def columnspace(self, simplify=False): |
|
return _columnspace(self, simplify=simplify) |
|
|
|
def nullspace(self, simplify=False, iszerofunc=_iszero): |
|
return _nullspace(self, simplify=simplify, iszerofunc=iszerofunc) |
|
|
|
def rowspace(self, simplify=False): |
|
return _rowspace(self, simplify=simplify) |
|
|
|
|
|
|
|
|
|
def orthogonalize(cls, *vecs, **kwargs): |
|
return _orthogonalize(cls, *vecs, **kwargs) |
|
|
|
columnspace.__doc__ = _columnspace.__doc__ |
|
nullspace.__doc__ = _nullspace.__doc__ |
|
rowspace.__doc__ = _rowspace.__doc__ |
|
orthogonalize.__doc__ = _orthogonalize.__doc__ |
|
|
|
orthogonalize = classmethod(orthogonalize) |
|
|
|
|
|
class MatrixEigen(MatrixSubspaces): |
|
"""Provides basic matrix eigenvalue/vector operations. |
|
Should not be instantiated directly. See ``eigen.py`` for their |
|
implementations.""" |
|
|
|
def eigenvals(self, error_when_incomplete=True, **flags): |
|
return _eigenvals(self, error_when_incomplete=error_when_incomplete, **flags) |
|
|
|
def eigenvects(self, error_when_incomplete=True, iszerofunc=_iszero, **flags): |
|
return _eigenvects(self, error_when_incomplete=error_when_incomplete, |
|
iszerofunc=iszerofunc, **flags) |
|
|
|
def is_diagonalizable(self, reals_only=False, **kwargs): |
|
return _is_diagonalizable(self, reals_only=reals_only, **kwargs) |
|
|
|
def diagonalize(self, reals_only=False, sort=False, normalize=False): |
|
return _diagonalize(self, reals_only=reals_only, sort=sort, |
|
normalize=normalize) |
|
|
|
def bidiagonalize(self, upper=True): |
|
return _bidiagonalize(self, upper=upper) |
|
|
|
def bidiagonal_decomposition(self, upper=True): |
|
return _bidiagonal_decomposition(self, upper=upper) |
|
|
|
@property |
|
def is_positive_definite(self): |
|
return _is_positive_definite(self) |
|
|
|
@property |
|
def is_positive_semidefinite(self): |
|
return _is_positive_semidefinite(self) |
|
|
|
@property |
|
def is_negative_definite(self): |
|
return _is_negative_definite(self) |
|
|
|
@property |
|
def is_negative_semidefinite(self): |
|
return _is_negative_semidefinite(self) |
|
|
|
@property |
|
def is_indefinite(self): |
|
return _is_indefinite(self) |
|
|
|
def jordan_form(self, calc_transform=True, **kwargs): |
|
return _jordan_form(self, calc_transform=calc_transform, **kwargs) |
|
|
|
def left_eigenvects(self, **flags): |
|
return _left_eigenvects(self, **flags) |
|
|
|
def singular_values(self): |
|
return _singular_values(self) |
|
|
|
eigenvals.__doc__ = _eigenvals.__doc__ |
|
eigenvects.__doc__ = _eigenvects.__doc__ |
|
is_diagonalizable.__doc__ = _is_diagonalizable.__doc__ |
|
diagonalize.__doc__ = _diagonalize.__doc__ |
|
is_positive_definite.__doc__ = _is_positive_definite.__doc__ |
|
is_positive_semidefinite.__doc__ = _is_positive_semidefinite.__doc__ |
|
is_negative_definite.__doc__ = _is_negative_definite.__doc__ |
|
is_negative_semidefinite.__doc__ = _is_negative_semidefinite.__doc__ |
|
is_indefinite.__doc__ = _is_indefinite.__doc__ |
|
jordan_form.__doc__ = _jordan_form.__doc__ |
|
left_eigenvects.__doc__ = _left_eigenvects.__doc__ |
|
singular_values.__doc__ = _singular_values.__doc__ |
|
bidiagonalize.__doc__ = _bidiagonalize.__doc__ |
|
bidiagonal_decomposition.__doc__ = _bidiagonal_decomposition.__doc__ |
|
|
|
|
|
class MatrixCalculus(MatrixCommon): |
|
"""Provides calculus-related matrix operations.""" |
|
|
|
def diff(self, *args, evaluate=True, **kwargs): |
|
"""Calculate the derivative of each element in the matrix. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import Matrix |
|
>>> from sympy.abc import x, y |
|
>>> M = Matrix([[x, y], [1, 0]]) |
|
>>> M.diff(x) |
|
Matrix([ |
|
[1, 0], |
|
[0, 0]]) |
|
|
|
See Also |
|
======== |
|
|
|
integrate |
|
limit |
|
""" |
|
|
|
from sympy.tensor.array.array_derivatives import ArrayDerivative |
|
deriv = ArrayDerivative(self, *args, evaluate=evaluate) |
|
|
|
if not isinstance(self, Basic) and evaluate: |
|
return deriv.as_mutable() |
|
return deriv |
|
|
|
def _eval_derivative(self, arg): |
|
return self.applyfunc(lambda x: x.diff(arg)) |
|
|
|
def integrate(self, *args, **kwargs): |
|
"""Integrate each element of the matrix. ``args`` will |
|
be passed to the ``integrate`` function. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import Matrix |
|
>>> from sympy.abc import x, y |
|
>>> M = Matrix([[x, y], [1, 0]]) |
|
>>> M.integrate((x, )) |
|
Matrix([ |
|
[x**2/2, x*y], |
|
[ x, 0]]) |
|
>>> M.integrate((x, 0, 2)) |
|
Matrix([ |
|
[2, 2*y], |
|
[2, 0]]) |
|
|
|
See Also |
|
======== |
|
|
|
limit |
|
diff |
|
""" |
|
return self.applyfunc(lambda x: x.integrate(*args, **kwargs)) |
|
|
|
def jacobian(self, X): |
|
"""Calculates the Jacobian matrix (derivative of a vector-valued function). |
|
|
|
Parameters |
|
========== |
|
|
|
``self`` : vector of expressions representing functions f_i(x_1, ..., x_n). |
|
X : set of x_i's in order, it can be a list or a Matrix |
|
|
|
Both ``self`` and X can be a row or a column matrix in any order |
|
(i.e., jacobian() should always work). |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import sin, cos, Matrix |
|
>>> from sympy.abc import rho, phi |
|
>>> X = Matrix([rho*cos(phi), rho*sin(phi), rho**2]) |
|
>>> Y = Matrix([rho, phi]) |
|
>>> X.jacobian(Y) |
|
Matrix([ |
|
[cos(phi), -rho*sin(phi)], |
|
[sin(phi), rho*cos(phi)], |
|
[ 2*rho, 0]]) |
|
>>> X = Matrix([rho*cos(phi), rho*sin(phi)]) |
|
>>> X.jacobian(Y) |
|
Matrix([ |
|
[cos(phi), -rho*sin(phi)], |
|
[sin(phi), rho*cos(phi)]]) |
|
|
|
See Also |
|
======== |
|
|
|
hessian |
|
wronskian |
|
""" |
|
if not isinstance(X, MatrixBase): |
|
X = self._new(X) |
|
|
|
|
|
if self.shape[0] == 1: |
|
m = self.shape[1] |
|
elif self.shape[1] == 1: |
|
m = self.shape[0] |
|
else: |
|
raise TypeError("``self`` must be a row or a column matrix") |
|
if X.shape[0] == 1: |
|
n = X.shape[1] |
|
elif X.shape[1] == 1: |
|
n = X.shape[0] |
|
else: |
|
raise TypeError("X must be a row or a column matrix") |
|
|
|
|
|
|
|
return self._new(m, n, lambda j, i: self[j].diff(X[i])) |
|
|
|
def limit(self, *args): |
|
"""Calculate the limit of each element in the matrix. |
|
``args`` will be passed to the ``limit`` function. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import Matrix |
|
>>> from sympy.abc import x, y |
|
>>> M = Matrix([[x, y], [1, 0]]) |
|
>>> M.limit(x, 2) |
|
Matrix([ |
|
[2, y], |
|
[1, 0]]) |
|
|
|
See Also |
|
======== |
|
|
|
integrate |
|
diff |
|
""" |
|
return self.applyfunc(lambda x: x.limit(*args)) |
|
|
|
|
|
|
|
class MatrixDeprecated(MatrixCommon): |
|
"""A class to house deprecated matrix methods.""" |
|
def berkowitz_charpoly(self, x=Dummy('lambda'), simplify=_simplify): |
|
return self.charpoly(x=x) |
|
|
|
def berkowitz_det(self): |
|
"""Computes determinant using Berkowitz method. |
|
|
|
See Also |
|
======== |
|
|
|
det |
|
berkowitz |
|
""" |
|
return self.det(method='berkowitz') |
|
|
|
def berkowitz_eigenvals(self, **flags): |
|
"""Computes eigenvalues of a Matrix using Berkowitz method. |
|
|
|
See Also |
|
======== |
|
|
|
berkowitz |
|
""" |
|
return self.eigenvals(**flags) |
|
|
|
def berkowitz_minors(self): |
|
"""Computes principal minors using Berkowitz method. |
|
|
|
See Also |
|
======== |
|
|
|
berkowitz |
|
""" |
|
sign, minors = self.one, [] |
|
|
|
for poly in self.berkowitz(): |
|
minors.append(sign * poly[-1]) |
|
sign = -sign |
|
|
|
return tuple(minors) |
|
|
|
def berkowitz(self): |
|
from sympy.matrices import zeros |
|
berk = ((1,),) |
|
if not self: |
|
return berk |
|
|
|
if not self.is_square: |
|
raise NonSquareMatrixError() |
|
|
|
A, N = self, self.rows |
|
transforms = [0] * (N - 1) |
|
|
|
for n in range(N, 1, -1): |
|
T, k = zeros(n + 1, n), n - 1 |
|
|
|
R, C = -A[k, :k], A[:k, k] |
|
A, a = A[:k, :k], -A[k, k] |
|
|
|
items = [C] |
|
|
|
for i in range(0, n - 2): |
|
items.append(A * items[i]) |
|
|
|
for i, B in enumerate(items): |
|
items[i] = (R * B)[0, 0] |
|
|
|
items = [self.one, a] + items |
|
|
|
for i in range(n): |
|
T[i:, i] = items[:n - i + 1] |
|
|
|
transforms[k - 1] = T |
|
|
|
polys = [self._new([self.one, -A[0, 0]])] |
|
|
|
for i, T in enumerate(transforms): |
|
polys.append(T * polys[i]) |
|
|
|
return berk + tuple(map(tuple, polys)) |
|
|
|
def cofactorMatrix(self, method="berkowitz"): |
|
return self.cofactor_matrix(method=method) |
|
|
|
def det_bareis(self): |
|
return _det_bareiss(self) |
|
|
|
def det_LU_decomposition(self): |
|
"""Compute matrix determinant using LU decomposition. |
|
|
|
|
|
Note that this method fails if the LU decomposition itself |
|
fails. In particular, if the matrix has no inverse this method |
|
will fail. |
|
|
|
TODO: Implement algorithm for sparse matrices (SFF), |
|
https://www.eecis.udel.edu/~saunders/papers/sffge/it5.ps |
|
|
|
See Also |
|
======== |
|
|
|
|
|
det |
|
det_bareiss |
|
berkowitz_det |
|
""" |
|
return self.det(method='lu') |
|
|
|
def jordan_cell(self, eigenval, n): |
|
return self.jordan_block(size=n, eigenvalue=eigenval) |
|
|
|
def jordan_cells(self, calc_transformation=True): |
|
P, J = self.jordan_form() |
|
return P, J.get_diag_blocks() |
|
|
|
def minorEntry(self, i, j, method="berkowitz"): |
|
return self.minor(i, j, method=method) |
|
|
|
def minorMatrix(self, i, j): |
|
return self.minor_submatrix(i, j) |
|
|
|
def permuteBkwd(self, perm): |
|
"""Permute the rows of the matrix with the given permutation in reverse.""" |
|
return self.permute_rows(perm, direction='backward') |
|
|
|
def permuteFwd(self, perm): |
|
"""Permute the rows of the matrix with the given permutation.""" |
|
return self.permute_rows(perm, direction='forward') |
|
|