| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428 |
- 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, Basic
- from sympy.core.kind import UndefinedKind
- from sympy.core.numbers import Integer
- from sympy.core.mod import Mod
- from sympy.core.symbol import Symbol, Dummy
- from sympy.core.sympify import sympify, _sympify
- from sympy.core.function import diff
- from sympy.polys import cancel
- from sympy.functions.elementary.complexes import Abs, re, im
- from sympy.printing import sstr
- from sympy.functions.elementary.miscellaneous import Max, Min, sqrt
- from sympy.functions.special.tensor_functions import KroneckerDelta, LeviCivita
- from sympy.core.singleton import S
- from sympy.printing.defaults import Printable
- from sympy.printing.str import StrPrinter
- from sympy.functions.elementary.exponential import exp, log
- from sympy.functions.combinatorial.factorials import binomial, factorial
- import mpmath as mp
- from collections.abc import Callable
- from sympy.utilities.iterables import reshape
- from sympy.core.expr import Expr
- from sympy.core.power import Pow
- from sympy.core.symbol import uniquely_named_symbol
- from .utilities import _dotprodsimp, _simplify as _utilities_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.core.decorators import call_highest_priority
- from sympy.core.logic import fuzzy_and, FuzzyBool
- from sympy.tensor.array import NDimArray
- from sympy.utilities.iterables import NotIterable
- from .utilities import _get_intermediate_simp_bool
- from .kind import MatrixKind
- from .exceptions import (
- MatrixError, ShapeError, NonSquareMatrixError, NonInvertibleMatrixError,
- )
- from .utilities import _iszero, _is_zero_after_expand_mul
- 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 .solvers import (
- _diagonal_solve, _lower_triangular_solve, _upper_triangular_solve,
- _cholesky_solve, _LDLsolve, _LUsolve, _QRsolve, _gauss_jordan_solve,
- _pinv_solve, _cramer_solve, _solve, _solve_least_squares)
- from .inverse import (
- _pinv, _inv_ADJ, _inv_GE, _inv_LU, _inv_CH, _inv_LDL, _inv_QR,
- _inv, _inv_block)
- 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)
- __doctest_requires__ = {
- ('MatrixBase.is_indefinite',
- 'MatrixBase.is_positive_definite',
- 'MatrixBase.is_positive_semidefinite',
- 'MatrixBase.is_negative_definite',
- 'MatrixBase.is_negative_semidefinite'): ['matplotlib'],
- }
- class MatrixBase(Printable):
- """All common matrix operations including basic arithmetic, shaping,
- and special matrices like `zeros`, and `eye`."""
- _op_priority = 10.01
- # Added just for numpy compatibility
- __array_priority__ = 11
- is_Matrix = True
- _class_priority = 3
- _sympify = staticmethod(sympify)
- zero = S.Zero
- one = S.One
- _diff_wrt: bool = True
- rows: int
- cols: int
- _simplify = None
- @classmethod
- 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.")
- @property
- 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 _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
- @classmethod
- def _eval_from_dok(cls, rows, cols, dok):
- out_flat = [cls.zero] * (rows * cols)
- for (i, j), val in dok.items():
- out_flat[i * cols + j] = val
- return cls._new(rows, cols, out_flat)
- 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()
- @classmethod
- 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))
- dok = {divmod(i*self.cols + j, cols):
- v for (i, j), v in self.todok().items()}
- return self._eval_from_dok(rows, cols, dok)
- 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 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()
- @classmethod
- def from_dok(cls, rows, cols, dok):
- """Create a matrix from a dictionary of keys.
- Examples
- ========
- >>> from sympy import Matrix
- >>> d = {(0, 0): 1, (1, 2): 3, (2, 1): 4}
- >>> Matrix.from_dok(3, 3, d)
- Matrix([
- [1, 0, 0],
- [0, 0, 3],
- [0, 4, 0]])
- """
- dok = {ij: cls._sympify(val) for ij, val in dok.items()}
- return cls._eval_from_dok(rows, cols, dok)
- 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)
- @classmethod
- 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)
- @classmethod
- 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)
- @classmethod
- 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)
- @classmethod
- 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)
- @classmethod
- def _eval_ones(cls, rows, cols):
- def entry(i, j):
- return cls.one
- return cls._new(rows, cols, entry)
- @classmethod
- def _eval_zeros(cls, rows, cols):
- return cls._new(rows, cols, [cls.zero]*(rows*cols), copy=False)
- @classmethod
- 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
- @classmethod
- 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)
- @classmethod
- 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)
- @classmethod
- 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)
- @classmethod
- 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)
- @classmethod
- 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)
- @classmethod
- 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)
- @classmethod
- 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)
- # The RepMatrix subclass uses more efficient sparse implementations of
- # _eval_iter_values and other things.
- def _eval_iter_values(self):
- return (i for i in self if i is not S.Zero)
- def _eval_values(self):
- return list(self.iter_values())
- def _eval_iter_items(self):
- for i in range(self.rows):
- for j in range(self.cols):
- if self[i, j]:
- yield (i, j), self[i, j]
- def _eval_atoms(self, *types):
- values = self.values()
- if len(values) < self.rows * self.cols and isinstance(S.Zero, types):
- s = {S.Zero}
- else:
- s = set()
- return s.union(*[v.atoms(*types) for v in values])
- def _eval_free_symbols(self):
- return set().union(*(i.free_symbols for i in set(self.values())))
- def _eval_has(self, *patterns):
- return any(a.has(*patterns) for a in self.iter_values())
- def _eval_is_symbolic(self):
- return self.has(Symbol)
- # _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):
- herm = lambda i, j: simpfunc(self[i, j] - self[j, i].adjoint()).is_zero
- return fuzzy_and(herm(i, j) for (i, j), v in self.iter_items())
- def _eval_is_zero_matrix(self):
- return fuzzy_and(v.is_zero for v in self.iter_values())
- def _eval_is_Identity(self) -> FuzzyBool:
- one = self.one
- zero = self.zero
- ident = lambda i, j, v: v is one if i == j else v is zero
- return all(ident(i, j, v) for (i, j), v in self.iter_items())
- def _eval_is_diagonal(self):
- return fuzzy_and(v.is_zero for (i, j), v in self.iter_items() if i != j)
- def _eval_is_lower(self):
- return all(v.is_zero for (i, j), v in self.iter_items() if i < j)
- def _eval_is_upper(self):
- return all(v.is_zero for (i, j), v in self.iter_items() if i > j)
- def _eval_is_lower_hessenberg(self):
- return all(v.is_zero for (i, j), v in self.iter_items() if i + 1 < j)
- def _eval_is_upper_hessenberg(self):
- return all(v.is_zero for (i, j), v in self.iter_items() if i > j + 1)
- def _eval_is_symmetric(self, simpfunc):
- sym = lambda i, j: simpfunc(self[i, j] - self[j, i]).is_zero
- return fuzzy_and(sym(i, j) for (i, j), v in self.iter_items())
- def _eval_is_anti_symmetric(self, simpfunc):
- anti = lambda i, j: simpfunc(self[i, j] + self[j, i]).is_zero
- return fuzzy_and(anti(i, j) for (i, j), v in self.iter_items())
- 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)
- @property
- 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 = _utilities_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.MatrixBase.is_diagonalizable
- diagonalize
- """
- return self._eval_is_diagonal()
- @property
- 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))
- @property
- 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))
- @property
- 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(_utilities_simplify)
- @property
- def is_Identity(self) -> FuzzyBool:
- if not self.is_square:
- return False
- return self._eval_is_Identity()
- @property
- 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()
- @property
- 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()
- @property
- 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 = _utilities_simplify if simplify else lambda x: x
- if not self.is_square:
- return False
- return self._eval_is_symmetric(simpfunc)
- @property
- 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()
- @property
- 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 self._eval_is_upper()
- @property
- 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.
- Examples
- ========
- >>> from sympy import Matrix
- >>> m = Matrix([[0, 1], [2, 3]])
- >>> m.values()
- [1, 2, 3]
- See Also
- ========
- iter_values
- tolist
- flat
- """
- return self._eval_values()
- def iter_values(self):
- """
- Iterate over non-zero values of self.
- Examples
- ========
- >>> from sympy import Matrix
- >>> m = Matrix([[0, 1], [2, 3]])
- >>> list(m.iter_values())
- [1, 2, 3]
- See Also
- ========
- values
- """
- return self._eval_iter_values()
- def iter_items(self):
- """Iterate over indices and values of nonzero items.
- Examples
- ========
- >>> from sympy import Matrix
- >>> m = Matrix([[0, 1], [2, 3]])
- >>> list(m.iter_items())
- [((0, 1), 1), ((1, 0), 2), ((1, 1), 3)]
- See Also
- ========
- iter_values
- todok
- """
- return self._eval_iter_items()
- def _eval_adjoint(self):
- return self.transpose().applyfunc(lambda x: x.adjoint())
- def _eval_applyfunc(self, f):
- cols = self.cols
- size = self.rows*self.cols
- dok = self.todok()
- valmap = {v: f(v) for v in dok.values()}
- if len(dok) < size and ((fzero := f(S.Zero)) is not S.Zero):
- out_flat = [fzero]*size
- for (i, j), v in dok.items():
- out_flat[i*cols + j] = valmap[v]
- out = self._new(self.rows, self.cols, out_flat)
- else:
- fdok = {ij: valmap[v] for ij, v in dok.items()}
- out = self.from_dok(self.rows, self.cols, fdok)
- 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))
- @property
- 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.adjoint()
- 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)]])
- """
- kwargs = {'map': map, 'simultaneous': simultaneous, 'exact': exact}
- if map:
- d = {}
- def func(eij):
- eij, dij = eij.replace(F, G, **kwargs)
- d.update(dij)
- return eij
- M = self.applyfunc(func)
- return M, d
- else:
- return self.applyfunc(lambda i: i.replace(F, G, **kwargs))
- 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()
- @property
- def T(self):
- '''Matrix transposition'''
- return self.transpose()
- @property
- 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 self.applyfunc(lambda x: x.simplify(**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)
- 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()
- @call_highest_priority('__radd__')
- def __add__(self, other):
- """Return self + other, raising ShapeError if shapes do not match."""
- other, T = _coerce_operand(self, other)
- if T != "is_matrix":
- return NotImplemented
- if self.shape != other.shape:
- raise ShapeError(f"Matrix size mismatch: {self.shape} + {other.shape}.")
- # Unify matrix types
- a, b = self, other
- if a.__class__ != classof(a, b):
- b, a = a, b
- return a._eval_add(b)
- @call_highest_priority('__rtruediv__')
- def __truediv__(self, other):
- return self * (self.one / other)
- @call_highest_priority('__rmatmul__')
- def __matmul__(self, other):
- self, other, T = _unify_with_other(self, other)
- if T != "is_matrix":
- return NotImplemented
- return self.__mul__(other)
- def __mod__(self, other):
- return self.applyfunc(lambda x: x % other)
- @call_highest_priority('__rmul__')
- 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)
- self, other, T = _unify_with_other(self, other)
- if T == "possible_scalar":
- try:
- return self._eval_scalar_mul(other)
- except TypeError:
- return NotImplemented
- elif T == "is_matrix":
- if self.shape[1] != other.shape[0]:
- raise ShapeError(f"Matrix size mismatch: {self.shape} * {other.shape}.")
- m = self._eval_matrix_mul(other)
- if isimpbool:
- m = m._new(m.rows, m.cols, [_dotprodsimp(e) for e in m])
- return m
- else:
- 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)
- @call_highest_priority('__rpow__')
- 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)
- @call_highest_priority('__add__')
- def __radd__(self, other):
- return self.__add__(other)
- @call_highest_priority('__matmul__')
- def __rmatmul__(self, other):
- self, other, T = _unify_with_other(self, other)
- if T != "is_matrix":
- return NotImplemented
- return self.__rmul__(other)
- @call_highest_priority('__mul__')
- 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)
- self, other, T = _unify_with_other(self, other)
- if T == "possible_scalar":
- try:
- return self._eval_scalar_rmul(other)
- except TypeError:
- return NotImplemented
- elif T == "is_matrix":
- if self.shape[0] != other.shape[1]:
- raise ShapeError("Matrix size mismatch.")
- m = self._eval_matrix_rmul(other)
- if isimpbool:
- return m._new(m.rows, m.cols, [_dotprodsimp(e) for e in m])
- return m
- else:
- return NotImplemented
- @call_highest_priority('__sub__')
- def __rsub__(self, a):
- return (-self) + a
- @call_highest_priority('__rsub__')
- def __sub__(self, a):
- return self + (-a)
- 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): # for expressions.determinant.Determinant
- return _det(self)
- def adjugate(self, method="berkowitz"):
- return _adjugate(self, method=method)
- def charpoly(self, x='lambda', simplify=_utilities_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__
- 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))
- # 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)
- 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
- 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__
- 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
- """
- # XXX this should be handled here rather than in Derivative
- from sympy.tensor.array.array_derivatives import ArrayDerivative
- deriv = ArrayDerivative(self, *args, evaluate=evaluate)
- # XXX This can rather changed to always return immutable matrix
- 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
- """
- from sympy.matrices.matrixbase import MatrixBase
- 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))
- def berkowitz_charpoly(self, x=Dummy('lambda'), simplify=_utilities_simplify):
- return self.charpoly(x=x)
- def berkowitz_det(self):
- """Computes determinant using Berkowitz method.
- See Also
- ========
- det
- """
- return self.det(method='berkowitz')
- def berkowitz_eigenvals(self, **flags):
- """Computes eigenvalues of a Matrix using Berkowitz method."""
- return self.eigenvals(**flags)
- def berkowitz_minors(self):
- """Computes principal minors using Berkowitz method."""
- 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
- 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')
- @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):
- """
- Returns a flat list of all elements in the matrix.
- Examples
- ========
- >>> from sympy import Matrix
- >>> m = Matrix([[0, 2], [3, 4]])
- >>> m.flat()
- [0, 2, 3, 4]
- See Also
- ========
- tolist
- values
- """
- return [self[i, j] for i in range(self.rows) for j in range(self.cols)]
- def __array__(self, dtype=object, copy=None):
- if copy is not None and not copy:
- raise TypeError("Cannot implement copy=False when converting Matrix to ndarray")
- 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, 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 len(dat) == 0:
- rows = cols = 0
- flat_list = []
- elif all(raw(i) for i in dat) and len(dat[0]) == 0:
- if not all(len(i) == 0 for i in dat):
- raise ValueError('mismatched dimensions')
- rows = len(dat)
- 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
- 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
- hat
- vee
- 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])))
- def hat(self):
- r"""
- Return the skew-symmetric matrix representing the cross product,
- so that ``self.hat() * b`` is equivalent to ``self.cross(b)``.
- Examples
- ========
- Calling ``hat`` creates a skew-symmetric 3x3 Matrix from a 3x1 Matrix:
- >>> from sympy import Matrix
- >>> a = Matrix([1, 2, 3])
- >>> a.hat()
- Matrix([
- [ 0, -3, 2],
- [ 3, 0, -1],
- [-2, 1, 0]])
- Multiplying it with another 3x1 Matrix calculates the cross product:
- >>> b = Matrix([3, 2, 1])
- >>> a.hat() * b
- Matrix([
- [-4],
- [ 8],
- [-4]])
- Which is equivalent to calling the ``cross`` method:
- >>> a.cross(b)
- Matrix([
- [-4],
- [ 8],
- [-4]])
- See Also
- ========
- dot
- cross
- vee
- multiply
- multiply_elementwise
- """
- if self.shape != (3, 1):
- raise ShapeError("Dimensions incorrect, expected (3, 1), got " +
- str(self.shape))
- else:
- x, y, z = self
- return self._new(3, 3, (
- 0, -z, y,
- z, 0, -x,
- -y, x, 0))
- def vee(self):
- r"""
- Return a 3x1 vector from a skew-symmetric matrix representing the cross product,
- so that ``self * b`` is equivalent to ``self.vee().cross(b)``.
- Examples
- ========
- Calling ``vee`` creates a vector from a skew-symmetric Matrix:
- >>> from sympy import Matrix
- >>> A = Matrix([[0, -3, 2], [3, 0, -1], [-2, 1, 0]])
- >>> a = A.vee()
- >>> a
- Matrix([
- [1],
- [2],
- [3]])
- Calculating the matrix product of the original matrix with a vector
- is equivalent to a cross product:
- >>> b = Matrix([3, 2, 1])
- >>> A * b
- Matrix([
- [-4],
- [ 8],
- [-4]])
- >>> a.cross(b)
- Matrix([
- [-4],
- [ 8],
- [-4]])
- ``vee`` can also be used to retrieve angular velocity expressions.
- Defining a rotation matrix:
- >>> from sympy import rot_ccw_axis3, trigsimp
- >>> from sympy.physics.mechanics import dynamicsymbols
- >>> theta = dynamicsymbols('theta')
- >>> R = rot_ccw_axis3(theta)
- >>> R
- Matrix([
- [cos(theta(t)), -sin(theta(t)), 0],
- [sin(theta(t)), cos(theta(t)), 0],
- [ 0, 0, 1]])
- We can retrieve the angular velocity:
- >>> Omega = R.T * R.diff()
- >>> Omega = trigsimp(Omega)
- >>> Omega.vee()
- Matrix([
- [ 0],
- [ 0],
- [Derivative(theta(t), t)]])
- See Also
- ========
- dot
- cross
- hat
- multiply
- multiply_elementwise
- """
- if self.shape != (3, 3):
- raise ShapeError("Dimensions incorrect, expected (3, 3), got " +
- str(self.shape))
- elif not self.is_anti_symmetric():
- raise ValueError("Matrix is not skew-symmetric")
- else:
- return self._new(3, 1, (
- self[2, 1],
- self[0, 2],
- self[1, 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.matrixbase.MatrixBase.conjugate: By-element conjugation
- sympy.matrices.matrixbase.MatrixBase.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 cramer_solve(self, rhs, det_method="laplace"):
- return _cramer_solve(self, rhs, det_method=det_method)
- 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 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__
- cramer_solve.__doc__ = _cramer_solve.__doc__
- solve.__doc__ = _solve.__doc__
- solve_least_squares.__doc__ = _solve_least_squares.__doc__
- pinv.__doc__ = _pinv.__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__
- def _convert_matrix(typ, mat):
- """Convert mat to a Matrix of type typ."""
- from sympy.matrices.matrixbase import MatrixBase
- if getattr(mat, "is_Matrix", False) and not isinstance(mat, MatrixBase):
- # This is needed for interop between Matrix and the redundant matrix
- # mixin types like _MinimalMatrix etc. If anyone should happen to be
- # using those then this keeps them working. Really _MinimalMatrix etc
- # should be deprecated and removed though.
- return typ(*mat.shape, list(mat))
- else:
- return typ(mat)
- def _has_matrix_shape(other):
- shape = getattr(other, 'shape', None)
- if shape is None:
- return False
- return isinstance(shape, tuple) and len(shape) == 2
- def _has_rows_cols(other):
- return hasattr(other, 'rows') and hasattr(other, 'cols')
- def _coerce_operand(self, other):
- """Convert other to a Matrix, or check for possible scalar."""
- INVALID = None, 'invalid_type'
- # Disallow mixing Matrix and Array
- if isinstance(other, NDimArray):
- return INVALID
- is_Matrix = getattr(other, 'is_Matrix', None)
- # Return a Matrix as-is
- if is_Matrix:
- return other, 'is_matrix'
- # Try to convert numpy array, mpmath matrix etc.
- if is_Matrix is None:
- if _has_matrix_shape(other) or _has_rows_cols(other):
- return _convert_matrix(type(self), other), 'is_matrix'
- # Could be a scalar but only if not iterable...
- if not isinstance(other, Iterable):
- return other, 'possible_scalar'
- return INVALID
- 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__))
- def _unify_with_other(self, other):
- """Unify self and other into a single matrix type, or check for scalar."""
- other, T = _coerce_operand(self, other)
- if T == "is_matrix":
- typ = classof(self, other)
- if typ != self.__class__:
- self = _convert_matrix(typ, self)
- if typ != other.__class__:
- other = _convert_matrix(typ, other)
- return self, other, T
- 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)
- class DeferredVector(Symbol, NotIterable): # type: ignore
- """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
|