1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233 |
- import mpmath as mp
- from collections.abc import Callable
- from sympy.core.add import Add
- from sympy.core.basic import Basic
- from sympy.core.function import diff
- from sympy.core.expr import Expr
- from sympy.core.kind import _NumberKind, UndefinedKind
- from sympy.core.mul import Mul
- from sympy.core.power import Pow
- from sympy.core.singleton import S
- from sympy.core.symbol import Dummy, Symbol, uniquely_named_symbol
- from sympy.core.sympify import sympify, _sympify
- from sympy.functions.combinatorial.factorials import binomial, factorial
- from sympy.functions.elementary.complexes import re
- from sympy.functions.elementary.exponential import exp, log
- from sympy.functions.elementary.miscellaneous import Max, Min, sqrt
- from sympy.functions.special.tensor_functions import KroneckerDelta, LeviCivita
- from sympy.polys import cancel
- from sympy.printing import sstr
- from sympy.printing.defaults import Printable
- from sympy.printing.str import StrPrinter
- from sympy.utilities.iterables import flatten, NotIterable, is_sequence, reshape
- from sympy.utilities.misc import as_int, filldedent
- from .common import (
- MatrixCommon, MatrixError, NonSquareMatrixError, NonInvertibleMatrixError,
- ShapeError, MatrixKind, a2idx)
- 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_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 .decompositions import (
- _rank_decomposition, _cholesky, _LDLdecomposition,
- _LUdecomposition, _LUdecomposition_Simple, _LUdecompositionFF,
- _singular_value_decomposition, _QRdecomposition, _upper_hessenberg_decomposition)
- from .graph import (
- _connected_components, _connected_components_decomposition,
- _strongly_connected_components, _strongly_connected_components_decomposition)
- from .solvers import (
- _diagonal_solve, _lower_triangular_solve, _upper_triangular_solve,
- _cholesky_solve, _LDLsolve, _LUsolve, _QRsolve, _gauss_jordan_solve,
- _pinv_solve, _solve, _solve_least_squares)
- from .inverse import (
- _pinv, _inv_mod, _inv_ADJ, _inv_GE, _inv_LU, _inv_CH, _inv_LDL, _inv_QR,
- _inv, _inv_block)
- class DeferredVector(Symbol, NotIterable):
- """A vector whose components are deferred (e.g. for use with lambdify).
- Examples
- ========
- >>> from sympy import DeferredVector, lambdify
- >>> X = DeferredVector( 'X' )
- >>> X
- X
- >>> expr = (X[0] + 2, X[2] + 3)
- >>> func = lambdify( X, expr)
- >>> func( [1, 2, 3] )
- (3, 6)
- """
- def __getitem__(self, i):
- if i == -0:
- i = 0
- if i < 0:
- raise IndexError('DeferredVector index out of range')
- component_name = '%s[%d]' % (self.name, i)
- return Symbol(component_name)
- def __str__(self):
- return sstr(self)
- def __repr__(self):
- return "DeferredVector('%s')" % self.name
- 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_determinant(self): # for expressions.determinant.Determinant
- 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_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(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))
- # define self_col according to error_str
- self_cols = self.cols if error_str == 'col' else self.rows
- # normalize and validate the arguments
- 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":
- # we need two cols to swap. It does not matter
- # how they were specified, so gather them together and
- # remove `None`
- cols = {col, k, col1, col2}.difference([None])
- if len(cols) > 2:
- # maybe the user left `k` by mistake?
- 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")
- # now that we've validated, we're all good to dispatch
- 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")
- # now that we've validated, we're all good to dispatch
- 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)
- # This is a classmethod but is converted to such later in order to allow
- # assignment of __doc__ since that does not work for already wrapped
- # classmethods in Python 3.6.
- 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) # type:ignore
- 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, **kwargs):
- """Calculate the derivative of each element in 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.diff(x)
- Matrix([
- [1, 0],
- [0, 0]])
- See Also
- ========
- integrate
- limit
- """
- # XXX this should be handled here rather than in Derivative
- from sympy.tensor.array.array_derivatives import ArrayDerivative
- kwargs.setdefault('evaluate', True)
- deriv = ArrayDerivative(self, *args, evaluate=True)
- if not isinstance(self, Basic):
- return deriv.as_mutable()
- else:
- 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)
- # Both X and ``self`` can be a row or a column matrix, so we need to make
- # sure all valid combinations work, but everything else fails:
- 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")
- # m is the number of functions and n is the number of variables
- # computing the Jacobian is now easy:
- 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))
- # https://github.com/sympy/sympy/pull/12854
- 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),
- http://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')
- @Mul._kind_dispatcher.register(_NumberKind, MatrixKind)
- def num_mat_mul(k1, k2):
- """
- Return MatrixKind. The element kind is selected by recursive dispatching.
- Do not need to dispatch in reversed order because KindDispatcher
- searches for this automatically.
- """
- # Deal with Mul._kind_dispatcher's commutativity
- # XXX: this function is called with either k1 or k2 as MatrixKind because
- # the Mul kind dispatcher is commutative. Maybe it shouldn't be. Need to
- # swap the args here because NumberKind does not have an element_kind
- # attribute.
- if not isinstance(k2, MatrixKind):
- k1, k2 = k2, k1
- elemk = Mul._kind_dispatcher(k1, k2.element_kind)
- return MatrixKind(elemk)
- @Mul._kind_dispatcher.register(MatrixKind, MatrixKind)
- def mat_mat_mul(k1, k2):
- """
- Return MatrixKind. The element kind is selected by recursive dispatching.
- """
- elemk = Mul._kind_dispatcher(k1.element_kind, k2.element_kind)
- return MatrixKind(elemk)
- class MatrixBase(MatrixDeprecated,
- MatrixCalculus,
- MatrixEigen,
- MatrixCommon,
- Printable):
- """Base class for matrix objects."""
- # Added just for numpy compatibility
- __array_priority__ = 11
- is_Matrix = True
- _class_priority = 3
- _sympify = staticmethod(sympify)
- zero = S.Zero
- one = S.One
- @property
- def kind(self) -> MatrixKind:
- elem_kinds = {e.kind for e in self.flat()}
- if len(elem_kinds) == 1:
- elemkind, = elem_kinds
- else:
- elemkind = UndefinedKind
- return MatrixKind(elemkind)
- def flat(self):
- return [self[i, j] for i in range(self.rows) for j in range(self.cols)]
- def __array__(self, dtype=object):
- from .dense import matrix2numpy
- return matrix2numpy(self, dtype=dtype)
- def __len__(self):
- """Return the number of elements of ``self``.
- Implemented mainly so bool(Matrix()) == False.
- """
- return self.rows * self.cols
- def _matrix_pow_by_jordan_blocks(self, num):
- from sympy.matrices import diag, MutableMatrix
- def jordan_cell_power(jc, n):
- N = jc.shape[0]
- l = jc[0,0]
- if l.is_zero:
- if N == 1 and n.is_nonnegative:
- jc[0,0] = l**n
- elif not (n.is_integer and n.is_nonnegative):
- raise NonInvertibleMatrixError("Non-invertible matrix can only be raised to a nonnegative integer")
- else:
- for i in range(N):
- jc[0,i] = KroneckerDelta(i, n)
- else:
- for i in range(N):
- bn = binomial(n, i)
- if isinstance(bn, binomial):
- bn = bn._eval_expand_func()
- jc[0,i] = l**(n-i)*bn
- for i in range(N):
- for j in range(1, N-i):
- jc[j,i+j] = jc [j-1,i+j-1]
- P, J = self.jordan_form()
- jordan_cells = J.get_diag_blocks()
- # Make sure jordan_cells matrices are mutable:
- jordan_cells = [MutableMatrix(j) for j in jordan_cells]
- for j in jordan_cells:
- jordan_cell_power(j, num)
- return self._new(P.multiply(diag(*jordan_cells))
- .multiply(P.inv()))
- def __str__(self):
- if S.Zero in self.shape:
- return 'Matrix(%s, %s, [])' % (self.rows, self.cols)
- return "Matrix(%s)" % str(self.tolist())
- def _format_str(self, printer=None):
- if not printer:
- printer = StrPrinter()
- # Handle zero dimensions:
- if S.Zero in self.shape:
- return 'Matrix(%s, %s, [])' % (self.rows, self.cols)
- if self.rows == 1:
- return "Matrix([%s])" % self.table(printer, rowsep=',\n')
- return "Matrix([\n%s])" % self.table(printer, rowsep=',\n')
- @classmethod
- def irregular(cls, ntop, *matrices, **kwargs):
- """Return a matrix filled by the given matrices which
- are listed in order of appearance from left to right, top to
- bottom as they first appear in the matrix. They must fill the
- matrix completely.
- Examples
- ========
- >>> from sympy import ones, Matrix
- >>> Matrix.irregular(3, ones(2,1), ones(3,3)*2, ones(2,2)*3,
- ... ones(1,1)*4, ones(2,2)*5, ones(1,2)*6, ones(1,2)*7)
- Matrix([
- [1, 2, 2, 2, 3, 3],
- [1, 2, 2, 2, 3, 3],
- [4, 2, 2, 2, 5, 5],
- [6, 6, 7, 7, 5, 5]])
- """
- ntop = as_int(ntop)
- # make sure we are working with explicit matrices
- b = [i.as_explicit() if hasattr(i, 'as_explicit') else i
- for i in matrices]
- q = list(range(len(b)))
- dat = [i.rows for i in b]
- active = [q.pop(0) for _ in range(ntop)]
- cols = sum([b[i].cols for i in active])
- rows = []
- while any(dat):
- r = []
- for a, j in enumerate(active):
- r.extend(b[j][-dat[j], :])
- dat[j] -= 1
- if dat[j] == 0 and q:
- active[a] = q.pop(0)
- if len(r) != cols:
- raise ValueError(filldedent('''
- Matrices provided do not appear to fill
- the space completely.'''))
- rows.append(r)
- return cls._new(rows)
- @classmethod
- def _handle_ndarray(cls, arg):
- # NumPy array or matrix or some other object that implements
- # __array__. So let's first use this method to get a
- # numpy.array() and then make a Python list out of it.
- arr = arg.__array__()
- if len(arr.shape) == 2:
- rows, cols = arr.shape[0], arr.shape[1]
- flat_list = [cls._sympify(i) for i in arr.ravel()]
- return rows, cols, flat_list
- elif len(arr.shape) == 1:
- flat_list = [cls._sympify(i) for i in arr]
- return arr.shape[0], 1, flat_list
- else:
- raise NotImplementedError(
- "SymPy supports just 1D and 2D matrices")
- @classmethod
- def _handle_creation_inputs(cls, *args, **kwargs):
- """Return the number of rows, cols and flat matrix elements.
- Examples
- ========
- >>> from sympy import Matrix, I
- Matrix can be constructed as follows:
- * from a nested list of iterables
- >>> Matrix( ((1, 2+I), (3, 4)) )
- Matrix([
- [1, 2 + I],
- [3, 4]])
- * from un-nested iterable (interpreted as a column)
- >>> Matrix( [1, 2] )
- Matrix([
- [1],
- [2]])
- * from un-nested iterable with dimensions
- >>> Matrix(1, 2, [1, 2] )
- Matrix([[1, 2]])
- * from no arguments (a 0 x 0 matrix)
- >>> Matrix()
- Matrix(0, 0, [])
- * from a rule
- >>> Matrix(2, 2, lambda i, j: i/(j + 1) )
- Matrix([
- [0, 0],
- [1, 1/2]])
- See Also
- ========
- irregular - filling a matrix with irregular blocks
- """
- from sympy.matrices import SparseMatrix
- from sympy.matrices.expressions.matexpr import MatrixSymbol
- from sympy.matrices.expressions.blockmatrix import BlockMatrix
- flat_list = None
- if len(args) == 1:
- # Matrix(SparseMatrix(...))
- if isinstance(args[0], SparseMatrix):
- return args[0].rows, args[0].cols, flatten(args[0].tolist())
- # Matrix(Matrix(...))
- elif isinstance(args[0], MatrixBase):
- return args[0].rows, args[0].cols, args[0].flat()
- # Matrix(MatrixSymbol('X', 2, 2))
- elif isinstance(args[0], Basic) and args[0].is_Matrix:
- return args[0].rows, args[0].cols, args[0].as_explicit().flat()
- elif isinstance(args[0], mp.matrix):
- M = args[0]
- flat_list = [cls._sympify(x) for x in M]
- return M.rows, M.cols, flat_list
- # Matrix(numpy.ones((2, 2)))
- elif hasattr(args[0], "__array__"):
- return cls._handle_ndarray(args[0])
- # Matrix([1, 2, 3]) or Matrix([[1, 2], [3, 4]])
- elif is_sequence(args[0]) \
- and not isinstance(args[0], DeferredVector):
- dat = list(args[0])
- ismat = lambda i: isinstance(i, MatrixBase) and (
- evaluate or
- isinstance(i, BlockMatrix) or
- isinstance(i, MatrixSymbol))
- raw = lambda i: is_sequence(i) and not ismat(i)
- evaluate = kwargs.get('evaluate', True)
- if evaluate:
- def make_explicit(x):
- """make Block and Symbol explicit"""
- if isinstance(x, BlockMatrix):
- return x.as_explicit()
- elif isinstance(x, MatrixSymbol) and all(_.is_Integer for _ in x.shape):
- return x.as_explicit()
- else:
- return x
- def make_explicit_row(row):
- # Could be list or could be list of lists
- if isinstance(row, (list, tuple)):
- return [make_explicit(x) for x in row]
- else:
- return make_explicit(row)
- if isinstance(dat, (list, tuple)):
- dat = [make_explicit_row(row) for row in dat]
- if dat in ([], [[]]):
- rows = cols = 0
- flat_list = []
- elif not any(raw(i) or ismat(i) for i in dat):
- # a column as a list of values
- flat_list = [cls._sympify(i) for i in dat]
- rows = len(flat_list)
- cols = 1 if rows else 0
- elif evaluate and all(ismat(i) for i in dat):
- # a column as a list of matrices
- ncol = {i.cols for i in dat if any(i.shape)}
- if ncol:
- if len(ncol) != 1:
- raise ValueError('mismatched dimensions')
- flat_list = [_ for i in dat for r in i.tolist() for _ in r]
- cols = ncol.pop()
- rows = len(flat_list)//cols
- else:
- rows = cols = 0
- flat_list = []
- elif evaluate and any(ismat(i) for i in dat):
- ncol = set()
- flat_list = []
- for i in dat:
- if ismat(i):
- flat_list.extend(
- [k for j in i.tolist() for k in j])
- if any(i.shape):
- ncol.add(i.cols)
- elif raw(i):
- if i:
- ncol.add(len(i))
- flat_list.extend([cls._sympify(ij) for ij in i])
- else:
- ncol.add(1)
- flat_list.append(i)
- if len(ncol) > 1:
- raise ValueError('mismatched dimensions')
- cols = ncol.pop()
- rows = len(flat_list)//cols
- else:
- # list of lists; each sublist is a logical row
- # which might consist of many rows if the values in
- # the row are matrices
- flat_list = []
- ncol = set()
- rows = cols = 0
- for row in dat:
- if not is_sequence(row) and \
- not getattr(row, 'is_Matrix', False):
- raise ValueError('expecting list of lists')
- if hasattr(row, '__array__'):
- if 0 in row.shape:
- continue
- elif not row:
- continue
- if evaluate and all(ismat(i) for i in row):
- r, c, flatT = cls._handle_creation_inputs(
- [i.T for i in row])
- T = reshape(flatT, [c])
- flat = \
- [T[i][j] for j in range(c) for i in range(r)]
- r, c = c, r
- else:
- r = 1
- if getattr(row, 'is_Matrix', False):
- c = 1
- flat = [row]
- else:
- c = len(row)
- flat = [cls._sympify(i) for i in row]
- ncol.add(c)
- if len(ncol) > 1:
- raise ValueError('mismatched dimensions')
- flat_list.extend(flat)
- rows += r
- cols = ncol.pop() if ncol else 0
- elif len(args) == 3:
- rows = as_int(args[0])
- cols = as_int(args[1])
- if rows < 0 or cols < 0:
- raise ValueError("Cannot create a {} x {} matrix. "
- "Both dimensions must be positive".format(rows, cols))
- # Matrix(2, 2, lambda i, j: i+j)
- if len(args) == 3 and isinstance(args[2], Callable):
- op = args[2]
- flat_list = []
- for i in range(rows):
- flat_list.extend(
- [cls._sympify(op(cls._sympify(i), cls._sympify(j)))
- for j in range(cols)])
- # Matrix(2, 2, [1, 2, 3, 4])
- elif len(args) == 3 and is_sequence(args[2]):
- flat_list = args[2]
- if len(flat_list) != rows * cols:
- raise ValueError(
- 'List length should be equal to rows*columns')
- flat_list = [cls._sympify(i) for i in flat_list]
- # Matrix()
- elif len(args) == 0:
- # Empty Matrix
- rows = cols = 0
- flat_list = []
- if flat_list is None:
- raise TypeError(filldedent('''
- Data type not understood; expecting list of lists
- or lists of values.'''))
- return rows, cols, flat_list
- def _setitem(self, key, value):
- """Helper to set value at location given by key.
- Examples
- ========
- >>> from sympy import Matrix, I, zeros, ones
- >>> m = Matrix(((1, 2+I), (3, 4)))
- >>> m
- Matrix([
- [1, 2 + I],
- [3, 4]])
- >>> m[1, 0] = 9
- >>> m
- Matrix([
- [1, 2 + I],
- [9, 4]])
- >>> m[1, 0] = [[0, 1]]
- To replace row r you assign to position r*m where m
- is the number of columns:
- >>> M = zeros(4)
- >>> m = M.cols
- >>> M[3*m] = ones(1, m)*2; M
- Matrix([
- [0, 0, 0, 0],
- [0, 0, 0, 0],
- [0, 0, 0, 0],
- [2, 2, 2, 2]])
- And to replace column c you can assign to position c:
- >>> M[2] = ones(m, 1)*4; M
- Matrix([
- [0, 0, 4, 0],
- [0, 0, 4, 0],
- [0, 0, 4, 0],
- [2, 2, 4, 2]])
- """
- from .dense import Matrix
- is_slice = isinstance(key, slice)
- i, j = key = self.key2ij(key)
- is_mat = isinstance(value, MatrixBase)
- if isinstance(i, slice) or isinstance(j, slice):
- if is_mat:
- self.copyin_matrix(key, value)
- return
- if not isinstance(value, Expr) and is_sequence(value):
- self.copyin_list(key, value)
- return
- raise ValueError('unexpected value: %s' % value)
- else:
- if (not is_mat and
- not isinstance(value, Basic) and is_sequence(value)):
- value = Matrix(value)
- is_mat = True
- if is_mat:
- if is_slice:
- key = (slice(*divmod(i, self.cols)),
- slice(*divmod(j, self.cols)))
- else:
- key = (slice(i, i + value.rows),
- slice(j, j + value.cols))
- self.copyin_matrix(key, value)
- else:
- return i, j, self._sympify(value)
- return
- def add(self, b):
- """Return self + b."""
- return self + b
- def condition_number(self):
- """Returns the condition number of a matrix.
- This is the maximum singular value divided by the minimum singular value
- Examples
- ========
- >>> from sympy import Matrix, S
- >>> A = Matrix([[1, 0, 0], [0, 10, 0], [0, 0, S.One/10]])
- >>> A.condition_number()
- 100
- See Also
- ========
- singular_values
- """
- if not self:
- return self.zero
- singularvalues = self.singular_values()
- return Max(*singularvalues) / Min(*singularvalues)
- def copy(self):
- """
- Returns the copy of a matrix.
- Examples
- ========
- >>> from sympy import Matrix
- >>> A = Matrix(2, 2, [1, 2, 3, 4])
- >>> A.copy()
- Matrix([
- [1, 2],
- [3, 4]])
- """
- return self._new(self.rows, self.cols, self.flat())
- def cross(self, b):
- r"""
- Return the cross product of ``self`` and ``b`` relaxing the condition
- of compatible dimensions: if each has 3 elements, a matrix of the
- same type and shape as ``self`` will be returned. If ``b`` has the same
- shape as ``self`` then common identities for the cross product (like
- `a \times b = - b \times a`) will hold.
- Parameters
- ==========
- b : 3x1 or 1x3 Matrix
- See Also
- ========
- dot
- multiply
- multiply_elementwise
- """
- from sympy.matrices.expressions.matexpr import MatrixExpr
- if not isinstance(b, (MatrixBase, MatrixExpr)):
- raise TypeError(
- "{} must be a Matrix, not {}.".format(b, type(b)))
- if not (self.rows * self.cols == b.rows * b.cols == 3):
- raise ShapeError("Dimensions incorrect for cross product: %s x %s" %
- ((self.rows, self.cols), (b.rows, b.cols)))
- else:
- return self._new(self.rows, self.cols, (
- (self[1] * b[2] - self[2] * b[1]),
- (self[2] * b[0] - self[0] * b[2]),
- (self[0] * b[1] - self[1] * b[0])))
- @property
- def D(self):
- """Return Dirac conjugate (if ``self.rows == 4``).
- Examples
- ========
- >>> from sympy import Matrix, I, eye
- >>> m = Matrix((0, 1 + I, 2, 3))
- >>> m.D
- Matrix([[0, 1 - I, -2, -3]])
- >>> m = (eye(4) + I*eye(4))
- >>> m[0, 3] = 2
- >>> m.D
- Matrix([
- [1 - I, 0, 0, 0],
- [ 0, 1 - I, 0, 0],
- [ 0, 0, -1 + I, 0],
- [ 2, 0, 0, -1 + I]])
- If the matrix does not have 4 rows an AttributeError will be raised
- because this property is only defined for matrices with 4 rows.
- >>> Matrix(eye(2)).D
- Traceback (most recent call last):
- ...
- AttributeError: Matrix has no attribute D.
- See Also
- ========
- sympy.matrices.common.MatrixCommon.conjugate: By-element conjugation
- sympy.matrices.common.MatrixCommon.H: Hermite conjugation
- """
- from sympy.physics.matrices import mgamma
- if self.rows != 4:
- # In Python 3.2, properties can only return an AttributeError
- # so we can't raise a ShapeError -- see commit which added the
- # first line of this inline comment. Also, there is no need
- # for a message since MatrixBase will raise the AttributeError
- raise AttributeError
- return self.H * mgamma(0)
- def dot(self, b, hermitian=None, conjugate_convention=None):
- """Return the dot or inner product of two vectors of equal length.
- Here ``self`` must be a ``Matrix`` of size 1 x n or n x 1, and ``b``
- must be either a matrix of size 1 x n, n x 1, or a list/tuple of length n.
- A scalar is returned.
- By default, ``dot`` does not conjugate ``self`` or ``b``, even if there are
- complex entries. Set ``hermitian=True`` (and optionally a ``conjugate_convention``)
- to compute the hermitian inner product.
- Possible kwargs are ``hermitian`` and ``conjugate_convention``.
- If ``conjugate_convention`` is ``"left"``, ``"math"`` or ``"maths"``,
- the conjugate of the first vector (``self``) is used. If ``"right"``
- or ``"physics"`` is specified, the conjugate of the second vector ``b`` is used.
- Examples
- ========
- >>> from sympy import Matrix
- >>> M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
- >>> v = Matrix([1, 1, 1])
- >>> M.row(0).dot(v)
- 6
- >>> M.col(0).dot(v)
- 12
- >>> v = [3, 2, 1]
- >>> M.row(0).dot(v)
- 10
- >>> from sympy import I
- >>> q = Matrix([1*I, 1*I, 1*I])
- >>> q.dot(q, hermitian=False)
- -3
- >>> q.dot(q, hermitian=True)
- 3
- >>> q1 = Matrix([1, 1, 1*I])
- >>> q.dot(q1, hermitian=True, conjugate_convention="maths")
- 1 - 2*I
- >>> q.dot(q1, hermitian=True, conjugate_convention="physics")
- 1 + 2*I
- See Also
- ========
- cross
- multiply
- multiply_elementwise
- """
- from .dense import Matrix
- if not isinstance(b, MatrixBase):
- if is_sequence(b):
- if len(b) != self.cols and len(b) != self.rows:
- raise ShapeError(
- "Dimensions incorrect for dot product: %s, %s" % (
- self.shape, len(b)))
- return self.dot(Matrix(b))
- else:
- raise TypeError(
- "`b` must be an ordered iterable or Matrix, not %s." %
- type(b))
- if (1 not in self.shape) or (1 not in b.shape):
- raise ShapeError
- if len(self) != len(b):
- raise ShapeError(
- "Dimensions incorrect for dot product: %s, %s" % (self.shape, b.shape))
- mat = self
- n = len(mat)
- if mat.shape != (1, n):
- mat = mat.reshape(1, n)
- if b.shape != (n, 1):
- b = b.reshape(n, 1)
- # Now ``mat`` is a row vector and ``b`` is a column vector.
- # If it so happens that only conjugate_convention is passed
- # then automatically set hermitian to True. If only hermitian
- # is true but no conjugate_convention is not passed then
- # automatically set it to ``"maths"``
- if conjugate_convention is not None and hermitian is None:
- hermitian = True
- if hermitian and conjugate_convention is None:
- conjugate_convention = "maths"
- if hermitian == True:
- if conjugate_convention in ("maths", "left", "math"):
- mat = mat.conjugate()
- elif conjugate_convention in ("physics", "right"):
- b = b.conjugate()
- else:
- raise ValueError("Unknown conjugate_convention was entered."
- " conjugate_convention must be one of the"
- " following: math, maths, left, physics or right.")
- return (mat * b)[0]
- def dual(self):
- """Returns the dual of a matrix.
- A dual of a matrix is:
- ``(1/2)*levicivita(i, j, k, l)*M(k, l)`` summed over indices `k` and `l`
- Since the levicivita method is anti_symmetric for any pairwise
- exchange of indices, the dual of a symmetric matrix is the zero
- matrix. Strictly speaking the dual defined here assumes that the
- 'matrix' `M` is a contravariant anti_symmetric second rank tensor,
- so that the dual is a covariant second rank tensor.
- """
- from sympy.matrices import zeros
- M, n = self[:, :], self.rows
- work = zeros(n)
- if self.is_symmetric():
- return work
- for i in range(1, n):
- for j in range(1, n):
- acum = 0
- for k in range(1, n):
- acum += LeviCivita(i, j, 0, k) * M[0, k]
- work[i, j] = acum
- work[j, i] = -acum
- for l in range(1, n):
- acum = 0
- for a in range(1, n):
- for b in range(1, n):
- acum += LeviCivita(0, l, a, b) * M[a, b]
- acum /= 2
- work[0, l] = -acum
- work[l, 0] = acum
- return work
- def _eval_matrix_exp_jblock(self):
- """A helper function to compute an exponential of a Jordan block
- matrix
- Examples
- ========
- >>> from sympy import Symbol, Matrix
- >>> l = Symbol('lamda')
- A trivial example of 1*1 Jordan block:
- >>> m = Matrix.jordan_block(1, l)
- >>> m._eval_matrix_exp_jblock()
- Matrix([[exp(lamda)]])
- An example of 3*3 Jordan block:
- >>> m = Matrix.jordan_block(3, l)
- >>> m._eval_matrix_exp_jblock()
- Matrix([
- [exp(lamda), exp(lamda), exp(lamda)/2],
- [ 0, exp(lamda), exp(lamda)],
- [ 0, 0, exp(lamda)]])
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Matrix_function#Jordan_decomposition
- """
- size = self.rows
- l = self[0, 0]
- exp_l = exp(l)
- bands = {i: exp_l / factorial(i) for i in range(size)}
- from .sparsetools import banded
- return self.__class__(banded(size, bands))
- def analytic_func(self, f, x):
- """
- Computes f(A) where A is a Square Matrix
- and f is an analytic function.
- Examples
- ========
- >>> from sympy import Symbol, Matrix, S, log
- >>> x = Symbol('x')
- >>> m = Matrix([[S(5)/4, S(3)/4], [S(3)/4, S(5)/4]])
- >>> f = log(x)
- >>> m.analytic_func(f, x)
- Matrix([
- [ 0, log(2)],
- [log(2), 0]])
- Parameters
- ==========
- f : Expr
- Analytic Function
- x : Symbol
- parameter of f
- """
- f, x = _sympify(f), _sympify(x)
- if not self.is_square:
- raise NonSquareMatrixError
- if not x.is_symbol:
- raise ValueError("{} must be a symbol.".format(x))
- if x not in f.free_symbols:
- raise ValueError(
- "{} must be a parameter of {}.".format(x, f))
- if x in self.free_symbols:
- raise ValueError(
- "{} must not be a parameter of {}.".format(x, self))
- eigen = self.eigenvals()
- max_mul = max(eigen.values())
- derivative = {}
- dd = f
- for i in range(max_mul - 1):
- dd = diff(dd, x)
- derivative[i + 1] = dd
- n = self.shape[0]
- r = self.zeros(n)
- f_val = self.zeros(n, 1)
- row = 0
- for i in eigen:
- mul = eigen[i]
- f_val[row] = f.subs(x, i)
- if f_val[row].is_number and not f_val[row].is_complex:
- raise ValueError(
- "Cannot evaluate the function because the "
- "function {} is not analytic at the given "
- "eigenvalue {}".format(f, f_val[row]))
- val = 1
- for a in range(n):
- r[row, a] = val
- val *= i
- if mul > 1:
- coe = [1 for ii in range(n)]
- deri = 1
- while mul > 1:
- row = row + 1
- mul -= 1
- d_i = derivative[deri].subs(x, i)
- if d_i.is_number and not d_i.is_complex:
- raise ValueError(
- "Cannot evaluate the function because the "
- "derivative {} is not analytic at the given "
- "eigenvalue {}".format(derivative[deri], d_i))
- f_val[row] = d_i
- for a in range(n):
- if a - deri + 1 <= 0:
- r[row, a] = 0
- coe[a] = 0
- continue
- coe[a] = coe[a]*(a - deri + 1)
- r[row, a] = coe[a]*pow(i, a - deri)
- deri += 1
- row += 1
- c = r.solve(f_val)
- ans = self.zeros(n)
- pre = self.eye(n)
- for i in range(n):
- ans = ans + c[i]*pre
- pre *= self
- return ans
- def exp(self):
- """Return the exponential of a square matrix.
- Examples
- ========
- >>> from sympy import Symbol, Matrix
- >>> t = Symbol('t')
- >>> m = Matrix([[0, 1], [-1, 0]]) * t
- >>> m.exp()
- Matrix([
- [ exp(I*t)/2 + exp(-I*t)/2, -I*exp(I*t)/2 + I*exp(-I*t)/2],
- [I*exp(I*t)/2 - I*exp(-I*t)/2, exp(I*t)/2 + exp(-I*t)/2]])
- """
- if not self.is_square:
- raise NonSquareMatrixError(
- "Exponentiation is valid only for square matrices")
- try:
- P, J = self.jordan_form()
- cells = J.get_diag_blocks()
- except MatrixError:
- raise NotImplementedError(
- "Exponentiation is implemented only for matrices for which the Jordan normal form can be computed")
- blocks = [cell._eval_matrix_exp_jblock() for cell in cells]
- from sympy.matrices import diag
- eJ = diag(*blocks)
- # n = self.rows
- ret = P.multiply(eJ, dotprodsimp=None).multiply(P.inv(), dotprodsimp=None)
- if all(value.is_real for value in self.values()):
- return type(self)(re(ret))
- else:
- return type(self)(ret)
- def _eval_matrix_log_jblock(self):
- """Helper function to compute logarithm of a jordan block.
- Examples
- ========
- >>> from sympy import Symbol, Matrix
- >>> l = Symbol('lamda')
- A trivial example of 1*1 Jordan block:
- >>> m = Matrix.jordan_block(1, l)
- >>> m._eval_matrix_log_jblock()
- Matrix([[log(lamda)]])
- An example of 3*3 Jordan block:
- >>> m = Matrix.jordan_block(3, l)
- >>> m._eval_matrix_log_jblock()
- Matrix([
- [log(lamda), 1/lamda, -1/(2*lamda**2)],
- [ 0, log(lamda), 1/lamda],
- [ 0, 0, log(lamda)]])
- """
- size = self.rows
- l = self[0, 0]
- if l.is_zero:
- raise MatrixError(
- 'Could not take logarithm or reciprocal for the given '
- 'eigenvalue {}'.format(l))
- bands = {0: log(l)}
- for i in range(1, size):
- bands[i] = -((-l) ** -i) / i
- from .sparsetools import banded
- return self.__class__(banded(size, bands))
- def log(self, simplify=cancel):
- """Return the logarithm of a square matrix.
- Parameters
- ==========
- simplify : function, bool
- The function to simplify the result with.
- Default is ``cancel``, which is effective to reduce the
- expression growing for taking reciprocals and inverses for
- symbolic matrices.
- Examples
- ========
- >>> from sympy import S, Matrix
- Examples for positive-definite matrices:
- >>> m = Matrix([[1, 1], [0, 1]])
- >>> m.log()
- Matrix([
- [0, 1],
- [0, 0]])
- >>> m = Matrix([[S(5)/4, S(3)/4], [S(3)/4, S(5)/4]])
- >>> m.log()
- Matrix([
- [ 0, log(2)],
- [log(2), 0]])
- Examples for non positive-definite matrices:
- >>> m = Matrix([[S(3)/4, S(5)/4], [S(5)/4, S(3)/4]])
- >>> m.log()
- Matrix([
- [ I*pi/2, log(2) - I*pi/2],
- [log(2) - I*pi/2, I*pi/2]])
- >>> m = Matrix(
- ... [[0, 0, 0, 1],
- ... [0, 0, 1, 0],
- ... [0, 1, 0, 0],
- ... [1, 0, 0, 0]])
- >>> m.log()
- Matrix([
- [ I*pi/2, 0, 0, -I*pi/2],
- [ 0, I*pi/2, -I*pi/2, 0],
- [ 0, -I*pi/2, I*pi/2, 0],
- [-I*pi/2, 0, 0, I*pi/2]])
- """
- if not self.is_square:
- raise NonSquareMatrixError(
- "Logarithm is valid only for square matrices")
- try:
- if simplify:
- P, J = simplify(self).jordan_form()
- else:
- P, J = self.jordan_form()
- cells = J.get_diag_blocks()
- except MatrixError:
- raise NotImplementedError(
- "Logarithm is implemented only for matrices for which "
- "the Jordan normal form can be computed")
- blocks = [
- cell._eval_matrix_log_jblock()
- for cell in cells]
- from sympy.matrices import diag
- eJ = diag(*blocks)
- if simplify:
- ret = simplify(P * eJ * simplify(P.inv()))
- ret = self.__class__(ret)
- else:
- ret = P * eJ * P.inv()
- return ret
- def is_nilpotent(self):
- """Checks if a matrix is nilpotent.
- A matrix B is nilpotent if for some integer k, B**k is
- a zero matrix.
- Examples
- ========
- >>> from sympy import Matrix
- >>> a = Matrix([[0, 0, 0], [1, 0, 0], [1, 1, 0]])
- >>> a.is_nilpotent()
- True
- >>> a = Matrix([[1, 0, 1], [1, 0, 0], [1, 1, 0]])
- >>> a.is_nilpotent()
- False
- """
- if not self:
- return True
- if not self.is_square:
- raise NonSquareMatrixError(
- "Nilpotency is valid only for square matrices")
- x = uniquely_named_symbol('x', self, modify=lambda s: '_' + s)
- p = self.charpoly(x)
- if p.args[0] == x ** self.rows:
- return True
- return False
- def key2bounds(self, keys):
- """Converts a key with potentially mixed types of keys (integer and slice)
- into a tuple of ranges and raises an error if any index is out of ``self``'s
- range.
- See Also
- ========
- key2ij
- """
- islice, jslice = [isinstance(k, slice) for k in keys]
- if islice:
- if not self.rows:
- rlo = rhi = 0
- else:
- rlo, rhi = keys[0].indices(self.rows)[:2]
- else:
- rlo = a2idx(keys[0], self.rows)
- rhi = rlo + 1
- if jslice:
- if not self.cols:
- clo = chi = 0
- else:
- clo, chi = keys[1].indices(self.cols)[:2]
- else:
- clo = a2idx(keys[1], self.cols)
- chi = clo + 1
- return rlo, rhi, clo, chi
- def key2ij(self, key):
- """Converts key into canonical form, converting integers or indexable
- items into valid integers for ``self``'s range or returning slices
- unchanged.
- See Also
- ========
- key2bounds
- """
- if is_sequence(key):
- if not len(key) == 2:
- raise TypeError('key must be a sequence of length 2')
- return [a2idx(i, n) if not isinstance(i, slice) else i
- for i, n in zip(key, self.shape)]
- elif isinstance(key, slice):
- return key.indices(len(self))[:2]
- else:
- return divmod(a2idx(key, len(self)), self.cols)
- def normalized(self, iszerofunc=_iszero):
- """Return the normalized version of ``self``.
- Parameters
- ==========
- iszerofunc : Function, optional
- A function to determine whether ``self`` is a zero vector.
- The default ``_iszero`` tests to see if each element is
- exactly zero.
- Returns
- =======
- Matrix
- Normalized vector form of ``self``.
- It has the same length as a unit vector. However, a zero vector
- will be returned for a vector with norm 0.
- Raises
- ======
- ShapeError
- If the matrix is not in a vector form.
- See Also
- ========
- norm
- """
- if self.rows != 1 and self.cols != 1:
- raise ShapeError("A Matrix must be a vector to normalize.")
- norm = self.norm()
- if iszerofunc(norm):
- out = self.zeros(self.rows, self.cols)
- else:
- out = self.applyfunc(lambda i: i / norm)
- return out
- def norm(self, ord=None):
- """Return the Norm of a Matrix or Vector.
- In the simplest case this is the geometric size of the vector
- Other norms can be specified by the ord parameter
- ===== ============================ ==========================
- ord norm for matrices norm for vectors
- ===== ============================ ==========================
- None Frobenius norm 2-norm
- 'fro' Frobenius norm - does not exist
- inf maximum row sum max(abs(x))
- -inf -- min(abs(x))
- 1 maximum column sum as below
- -1 -- as below
- 2 2-norm (largest sing. value) as below
- -2 smallest singular value as below
- other - does not exist sum(abs(x)**ord)**(1./ord)
- ===== ============================ ==========================
- Examples
- ========
- >>> from sympy import Matrix, Symbol, trigsimp, cos, sin, oo
- >>> x = Symbol('x', real=True)
- >>> v = Matrix([cos(x), sin(x)])
- >>> trigsimp( v.norm() )
- 1
- >>> v.norm(10)
- (sin(x)**10 + cos(x)**10)**(1/10)
- >>> A = Matrix([[1, 1], [1, 1]])
- >>> A.norm(1) # maximum sum of absolute values of A is 2
- 2
- >>> A.norm(2) # Spectral norm (max of |Ax|/|x| under 2-vector-norm)
- 2
- >>> A.norm(-2) # Inverse spectral norm (smallest singular value)
- 0
- >>> A.norm() # Frobenius Norm
- 2
- >>> A.norm(oo) # Infinity Norm
- 2
- >>> Matrix([1, -2]).norm(oo)
- 2
- >>> Matrix([-1, 2]).norm(-oo)
- 1
- See Also
- ========
- normalized
- """
- # Row or Column Vector Norms
- vals = list(self.values()) or [0]
- if S.One in self.shape:
- if ord in (2, None): # Common case sqrt(<x, x>)
- return sqrt(Add(*(abs(i) ** 2 for i in vals)))
- elif ord == 1: # sum(abs(x))
- return Add(*(abs(i) for i in vals))
- elif ord is S.Infinity: # max(abs(x))
- return Max(*[abs(i) for i in vals])
- elif ord is S.NegativeInfinity: # min(abs(x))
- return Min(*[abs(i) for i in vals])
- # Otherwise generalize the 2-norm, Sum(x_i**ord)**(1/ord)
- # Note that while useful this is not mathematically a norm
- try:
- return Pow(Add(*(abs(i) ** ord for i in vals)), S.One / ord)
- except (NotImplementedError, TypeError):
- raise ValueError("Expected order to be Number, Symbol, oo")
- # Matrix Norms
- else:
- if ord == 1: # Maximum column sum
- m = self.applyfunc(abs)
- return Max(*[sum(m.col(i)) for i in range(m.cols)])
- elif ord == 2: # Spectral Norm
- # Maximum singular value
- return Max(*self.singular_values())
- elif ord == -2:
- # Minimum singular value
- return Min(*self.singular_values())
- elif ord is S.Infinity: # Infinity Norm - Maximum row sum
- m = self.applyfunc(abs)
- return Max(*[sum(m.row(i)) for i in range(m.rows)])
- elif (ord is None or isinstance(ord,
- str) and ord.lower() in
- ['f', 'fro', 'frobenius', 'vector']):
- # Reshape as vector and send back to norm function
- return self.vec().norm(ord=2)
- else:
- raise NotImplementedError("Matrix Norms under development")
- def print_nonzero(self, symb="X"):
- """Shows location of non-zero entries for fast shape lookup.
- Examples
- ========
- >>> from sympy import Matrix, eye
- >>> m = Matrix(2, 3, lambda i, j: i*3+j)
- >>> m
- Matrix([
- [0, 1, 2],
- [3, 4, 5]])
- >>> m.print_nonzero()
- [ XX]
- [XXX]
- >>> m = eye(4)
- >>> m.print_nonzero("x")
- [x ]
- [ x ]
- [ x ]
- [ x]
- """
- s = []
- for i in range(self.rows):
- line = []
- for j in range(self.cols):
- if self[i, j] == 0:
- line.append(" ")
- else:
- line.append(str(symb))
- s.append("[%s]" % ''.join(line))
- print('\n'.join(s))
- def project(self, v):
- """Return the projection of ``self`` onto the line containing ``v``.
- Examples
- ========
- >>> from sympy import Matrix, S, sqrt
- >>> V = Matrix([sqrt(3)/2, S.Half])
- >>> x = Matrix([[1, 0]])
- >>> V.project(x)
- Matrix([[sqrt(3)/2, 0]])
- >>> V.project(-x)
- Matrix([[sqrt(3)/2, 0]])
- """
- return v * (self.dot(v) / v.dot(v))
- def table(self, printer, rowstart='[', rowend=']', rowsep='\n',
- colsep=', ', align='right'):
- r"""
- String form of Matrix as a table.
- ``printer`` is the printer to use for on the elements (generally
- something like StrPrinter())
- ``rowstart`` is the string used to start each row (by default '[').
- ``rowend`` is the string used to end each row (by default ']').
- ``rowsep`` is the string used to separate rows (by default a newline).
- ``colsep`` is the string used to separate columns (by default ', ').
- ``align`` defines how the elements are aligned. Must be one of 'left',
- 'right', or 'center'. You can also use '<', '>', and '^' to mean the
- same thing, respectively.
- This is used by the string printer for Matrix.
- Examples
- ========
- >>> from sympy import Matrix, StrPrinter
- >>> M = Matrix([[1, 2], [-33, 4]])
- >>> printer = StrPrinter()
- >>> M.table(printer)
- '[ 1, 2]\n[-33, 4]'
- >>> print(M.table(printer))
- [ 1, 2]
- [-33, 4]
- >>> print(M.table(printer, rowsep=',\n'))
- [ 1, 2],
- [-33, 4]
- >>> print('[%s]' % M.table(printer, rowsep=',\n'))
- [[ 1, 2],
- [-33, 4]]
- >>> print(M.table(printer, colsep=' '))
- [ 1 2]
- [-33 4]
- >>> print(M.table(printer, align='center'))
- [ 1 , 2]
- [-33, 4]
- >>> print(M.table(printer, rowstart='{', rowend='}'))
- { 1, 2}
- {-33, 4}
- """
- # Handle zero dimensions:
- if S.Zero in self.shape:
- return '[]'
- # Build table of string representations of the elements
- res = []
- # Track per-column max lengths for pretty alignment
- maxlen = [0] * self.cols
- for i in range(self.rows):
- res.append([])
- for j in range(self.cols):
- s = printer._print(self[i, j])
- res[-1].append(s)
- maxlen[j] = max(len(s), maxlen[j])
- # Patch strings together
- align = {
- 'left': 'ljust',
- 'right': 'rjust',
- 'center': 'center',
- '<': 'ljust',
- '>': 'rjust',
- '^': 'center',
- }[align]
- for i, row in enumerate(res):
- for j, elem in enumerate(row):
- row[j] = getattr(elem, align)(maxlen[j])
- res[i] = rowstart + colsep.join(row) + rowend
- return rowsep.join(res)
- def rank_decomposition(self, iszerofunc=_iszero, simplify=False):
- return _rank_decomposition(self, iszerofunc=iszerofunc,
- simplify=simplify)
- def cholesky(self, hermitian=True):
- raise NotImplementedError('This function is implemented in DenseMatrix or SparseMatrix')
- def LDLdecomposition(self, hermitian=True):
- raise NotImplementedError('This function is implemented in DenseMatrix or SparseMatrix')
- def LUdecomposition(self, iszerofunc=_iszero, simpfunc=None,
- rankcheck=False):
- return _LUdecomposition(self, iszerofunc=iszerofunc, simpfunc=simpfunc,
- rankcheck=rankcheck)
- def LUdecomposition_Simple(self, iszerofunc=_iszero, simpfunc=None,
- rankcheck=False):
- return _LUdecomposition_Simple(self, iszerofunc=iszerofunc,
- simpfunc=simpfunc, rankcheck=rankcheck)
- def LUdecompositionFF(self):
- return _LUdecompositionFF(self)
- def singular_value_decomposition(self):
- return _singular_value_decomposition(self)
- def QRdecomposition(self):
- return _QRdecomposition(self)
- def upper_hessenberg_decomposition(self):
- return _upper_hessenberg_decomposition(self)
- def diagonal_solve(self, rhs):
- return _diagonal_solve(self, rhs)
- def lower_triangular_solve(self, rhs):
- raise NotImplementedError('This function is implemented in DenseMatrix or SparseMatrix')
- def upper_triangular_solve(self, rhs):
- raise NotImplementedError('This function is implemented in DenseMatrix or SparseMatrix')
- def cholesky_solve(self, rhs):
- return _cholesky_solve(self, rhs)
- def LDLsolve(self, rhs):
- return _LDLsolve(self, rhs)
- def LUsolve(self, rhs, iszerofunc=_iszero):
- return _LUsolve(self, rhs, iszerofunc=iszerofunc)
- def QRsolve(self, b):
- return _QRsolve(self, b)
- def gauss_jordan_solve(self, B, freevar=False):
- return _gauss_jordan_solve(self, B, freevar=freevar)
- def pinv_solve(self, B, arbitrary_matrix=None):
- return _pinv_solve(self, B, arbitrary_matrix=arbitrary_matrix)
- def solve(self, rhs, method='GJ'):
- return _solve(self, rhs, method=method)
- def solve_least_squares(self, rhs, method='CH'):
- return _solve_least_squares(self, rhs, method=method)
- def pinv(self, method='RD'):
- return _pinv(self, method=method)
- def inv_mod(self, m):
- return _inv_mod(self, m)
- def inverse_ADJ(self, iszerofunc=_iszero):
- return _inv_ADJ(self, iszerofunc=iszerofunc)
- def inverse_BLOCK(self, iszerofunc=_iszero):
- return _inv_block(self, iszerofunc=iszerofunc)
- def inverse_GE(self, iszerofunc=_iszero):
- return _inv_GE(self, iszerofunc=iszerofunc)
- def inverse_LU(self, iszerofunc=_iszero):
- return _inv_LU(self, iszerofunc=iszerofunc)
- def inverse_CH(self, iszerofunc=_iszero):
- return _inv_CH(self, iszerofunc=iszerofunc)
- def inverse_LDL(self, iszerofunc=_iszero):
- return _inv_LDL(self, iszerofunc=iszerofunc)
- def inverse_QR(self, iszerofunc=_iszero):
- return _inv_QR(self, iszerofunc=iszerofunc)
- def inv(self, method=None, iszerofunc=_iszero, try_block_diag=False):
- return _inv(self, method=method, iszerofunc=iszerofunc,
- try_block_diag=try_block_diag)
- def connected_components(self):
- return _connected_components(self)
- def connected_components_decomposition(self):
- return _connected_components_decomposition(self)
- def strongly_connected_components(self):
- return _strongly_connected_components(self)
- def strongly_connected_components_decomposition(self, lower=True):
- return _strongly_connected_components_decomposition(self, lower=lower)
- _sage_ = Basic._sage_
- rank_decomposition.__doc__ = _rank_decomposition.__doc__
- cholesky.__doc__ = _cholesky.__doc__
- LDLdecomposition.__doc__ = _LDLdecomposition.__doc__
- LUdecomposition.__doc__ = _LUdecomposition.__doc__
- LUdecomposition_Simple.__doc__ = _LUdecomposition_Simple.__doc__
- LUdecompositionFF.__doc__ = _LUdecompositionFF.__doc__
- singular_value_decomposition.__doc__ = _singular_value_decomposition.__doc__
- QRdecomposition.__doc__ = _QRdecomposition.__doc__
- upper_hessenberg_decomposition.__doc__ = _upper_hessenberg_decomposition.__doc__
- diagonal_solve.__doc__ = _diagonal_solve.__doc__
- lower_triangular_solve.__doc__ = _lower_triangular_solve.__doc__
- upper_triangular_solve.__doc__ = _upper_triangular_solve.__doc__
- cholesky_solve.__doc__ = _cholesky_solve.__doc__
- LDLsolve.__doc__ = _LDLsolve.__doc__
- LUsolve.__doc__ = _LUsolve.__doc__
- QRsolve.__doc__ = _QRsolve.__doc__
- gauss_jordan_solve.__doc__ = _gauss_jordan_solve.__doc__
- pinv_solve.__doc__ = _pinv_solve.__doc__
- solve.__doc__ = _solve.__doc__
- solve_least_squares.__doc__ = _solve_least_squares.__doc__
- pinv.__doc__ = _pinv.__doc__
- inv_mod.__doc__ = _inv_mod.__doc__
- inverse_ADJ.__doc__ = _inv_ADJ.__doc__
- inverse_GE.__doc__ = _inv_GE.__doc__
- inverse_LU.__doc__ = _inv_LU.__doc__
- inverse_CH.__doc__ = _inv_CH.__doc__
- inverse_LDL.__doc__ = _inv_LDL.__doc__
- inverse_QR.__doc__ = _inv_QR.__doc__
- inverse_BLOCK.__doc__ = _inv_block.__doc__
- inv.__doc__ = _inv.__doc__
- connected_components.__doc__ = _connected_components.__doc__
- connected_components_decomposition.__doc__ = \
- _connected_components_decomposition.__doc__
- strongly_connected_components.__doc__ = \
- _strongly_connected_components.__doc__
- strongly_connected_components_decomposition.__doc__ = \
- _strongly_connected_components_decomposition.__doc__
|