test_base.py 219 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908
  1. #
  2. # Authors: Travis Oliphant, Ed Schofield, Robert Cimrman, Nathan Bell, and others
  3. """ Test functions for sparse matrices. Each class in the "Matrix class
  4. based tests" section become subclasses of the classes in the "Generic
  5. tests" section. This is done by the functions in the "Tailored base
  6. class for generic tests" section.
  7. """
  8. import contextlib
  9. import functools
  10. import operator
  11. import platform
  12. import itertools
  13. import sys
  14. import warnings
  15. import pytest
  16. from pytest import raises as assert_raises
  17. import numpy as np
  18. from numpy import (arange, zeros, array, dot, asarray,
  19. vstack, ndarray, transpose, diag, kron, inf, conjugate,
  20. int8)
  21. import random
  22. from numpy.testing import (assert_equal, assert_array_equal,
  23. assert_array_almost_equal, assert_almost_equal, assert_,
  24. assert_allclose)
  25. from numpy.exceptions import ComplexWarning
  26. from types import GenericAlias
  27. import scipy.linalg
  28. import scipy.sparse as sparse
  29. from scipy.sparse import (csc_matrix, csr_matrix, dok_matrix,
  30. coo_matrix, lil_matrix, dia_matrix, bsr_matrix,
  31. csc_array, csr_array, dok_array,
  32. coo_array, lil_array, dia_array, bsr_array,
  33. eye, issparse, SparseEfficiencyWarning, sparray, spmatrix)
  34. from scipy.sparse._base import _formats
  35. from scipy.sparse._sputils import (supported_dtypes, isscalarlike,
  36. get_index_dtype, asmatrix, matrix)
  37. from scipy.sparse.linalg import splu, expm, inv
  38. IS_COLAB = ('google.colab' in sys.modules)
  39. def assert_in(member, collection, msg=None):
  40. message = msg if msg is not None else f"{member!r} not found in {collection!r}"
  41. assert_(member in collection, msg=message)
  42. def assert_array_equal_dtype(x, y, **kwargs):
  43. assert_(x.dtype == y.dtype)
  44. assert_array_equal(x, y, **kwargs)
  45. NON_ARRAY_BACKED_FORMATS = frozenset(['dok'])
  46. WMSG = "Changing the sparsity structure"
  47. def sparse_may_share_memory(A, B):
  48. # Checks if A and B have any numpy array sharing memory.
  49. def _underlying_arrays(x):
  50. # Given any object (e.g. a sparse array), returns all numpy arrays
  51. # stored in any attribute.
  52. arrays = []
  53. for a in x.__dict__.values():
  54. if isinstance(a, np.ndarray | np.generic):
  55. arrays.append(a)
  56. return arrays
  57. for a in _underlying_arrays(A):
  58. for b in _underlying_arrays(B):
  59. if np.may_share_memory(a, b):
  60. return True
  61. return False
  62. def with_64bit_maxval_limit(maxval_limit=None, random=False, fixed_dtype=None,
  63. downcast_maxval=None, assert_32bit=False):
  64. """
  65. Monkeypatch the maxval threshold at which scipy.sparse switches to
  66. 64-bit index arrays, or make it (pseudo-)random.
  67. """
  68. if maxval_limit is None:
  69. maxval_limit = np.int64(10)
  70. else:
  71. # Ensure we use numpy scalars rather than Python scalars (matters for
  72. # NEP 50 casting rule changes)
  73. maxval_limit = np.int64(maxval_limit)
  74. if assert_32bit:
  75. def new_get_index_dtype(arrays=(), maxval=None, check_contents=False):
  76. tp = get_index_dtype(arrays, maxval, check_contents)
  77. assert_equal(np.iinfo(tp).max, np.iinfo(np.int32).max)
  78. assert_(tp == np.int32 or tp == np.intc)
  79. return tp
  80. elif fixed_dtype is not None:
  81. def new_get_index_dtype(arrays=(), maxval=None, check_contents=False):
  82. return fixed_dtype
  83. elif random:
  84. rng = np.random.default_rng(1234)
  85. def new_get_index_dtype(arrays=(), maxval=None, check_contents=False):
  86. return (np.int32, np.int64)[rng.integers(2)]
  87. else:
  88. def new_get_index_dtype(arrays=(), maxval=None, check_contents=False):
  89. dtype = np.int32
  90. if maxval is not None:
  91. if maxval > maxval_limit:
  92. dtype = np.int64
  93. for arr in arrays:
  94. arr = np.asarray(arr)
  95. if arr.dtype > np.int32:
  96. if check_contents:
  97. if arr.size == 0:
  98. # a bigger type not needed
  99. continue
  100. elif np.issubdtype(arr.dtype, np.integer):
  101. maxval = arr.max()
  102. minval = arr.min()
  103. if minval >= -maxval_limit and maxval <= maxval_limit:
  104. # a bigger type not needed
  105. continue
  106. dtype = np.int64
  107. return dtype
  108. if downcast_maxval is not None:
  109. def new_downcast_intp_index(arr):
  110. if arr.max() > downcast_maxval:
  111. raise AssertionError("downcast limited")
  112. return arr.astype(np.intp)
  113. def decorator(func):
  114. backup = []
  115. modules = [scipy.sparse._bsr, scipy.sparse._coo, scipy.sparse._csc,
  116. scipy.sparse._csr, scipy.sparse._dia, scipy.sparse._dok,
  117. scipy.sparse._lil, scipy.sparse._sputils,
  118. scipy.sparse._compressed, scipy.sparse._construct]
  119. @functools.wraps(func)
  120. def wrapper(*a, **kw):
  121. try:
  122. for mod in modules:
  123. backup.append((
  124. mod,
  125. 'get_index_dtype',
  126. getattr(mod, 'get_index_dtype', None)
  127. ))
  128. setattr(mod, 'get_index_dtype', new_get_index_dtype)
  129. if downcast_maxval is not None:
  130. backup.append((
  131. mod,
  132. 'downcast_intp_index',
  133. getattr(mod, 'downcast_intp_index', None)
  134. ))
  135. setattr(mod, 'downcast_intp_index', new_downcast_intp_index)
  136. return func(*a, **kw)
  137. finally:
  138. for mod, name, oldfunc in backup:
  139. if oldfunc is not None:
  140. setattr(mod, name, oldfunc)
  141. return wrapper
  142. return decorator
  143. def toarray(a):
  144. if isinstance(a, np.ndarray) or isscalarlike(a):
  145. return a
  146. return a.toarray()
  147. class BinopTester:
  148. # Custom type to test binary operations on sparse matrices.
  149. def __add__(self, mat):
  150. return "matrix on the right"
  151. def __mul__(self, mat):
  152. return "matrix on the right"
  153. def __sub__(self, mat):
  154. return "matrix on the right"
  155. def __radd__(self, mat):
  156. return "matrix on the left"
  157. def __rmul__(self, mat):
  158. return "matrix on the left"
  159. def __rsub__(self, mat):
  160. return "matrix on the left"
  161. def __matmul__(self, mat):
  162. return "matrix on the right"
  163. def __rmatmul__(self, mat):
  164. return "matrix on the left"
  165. class BinopTester_with_shape:
  166. # Custom type to test binary operations on sparse matrices
  167. # with object which has shape attribute.
  168. def __init__(self,shape):
  169. self._shape = shape
  170. def shape(self):
  171. return self._shape
  172. def ndim(self):
  173. return len(self._shape)
  174. def __add__(self, mat):
  175. return "matrix on the right"
  176. def __mul__(self, mat):
  177. return "matrix on the right"
  178. def __sub__(self, mat):
  179. return "matrix on the right"
  180. def __radd__(self, mat):
  181. return "matrix on the left"
  182. def __rmul__(self, mat):
  183. return "matrix on the left"
  184. def __rsub__(self, mat):
  185. return "matrix on the left"
  186. def __matmul__(self, mat):
  187. return "matrix on the right"
  188. def __rmatmul__(self, mat):
  189. return "matrix on the left"
  190. class ComparisonTester:
  191. # Custom type to test comparison operations on sparse matrices.
  192. def __eq__(self, other):
  193. return "eq"
  194. def __ne__(self, other):
  195. return "ne"
  196. def __lt__(self, other):
  197. return "lt"
  198. def __le__(self, other):
  199. return "le"
  200. def __gt__(self, other):
  201. return "gt"
  202. def __ge__(self, other):
  203. return "ge"
  204. #------------------------------------------------------------------------------
  205. # Generic tests
  206. #------------------------------------------------------------------------------
  207. class _MatrixMixin:
  208. """mixin to easily allow tests of both sparray and spmatrix"""
  209. bsr_container = bsr_matrix
  210. coo_container = coo_matrix
  211. csc_container = csc_matrix
  212. csr_container = csr_matrix
  213. dia_container = dia_matrix
  214. dok_container = dok_matrix
  215. lil_container = lil_matrix
  216. asdense = staticmethod(asmatrix)
  217. def test_getrow(self):
  218. assert_array_equal(self.datsp.getrow(1).toarray(), self.dat[[1], :])
  219. assert_array_equal(self.datsp.getrow(-1).toarray(), self.dat[[-1], :])
  220. def test_getcol(self):
  221. assert_array_equal(self.datsp.getcol(1).toarray(), self.dat[:, [1]])
  222. assert_array_equal(self.datsp.getcol(-1).toarray(), self.dat[:, [-1]])
  223. def test_asfptype(self):
  224. A = self.spcreator(arange(6,dtype='int32').reshape(2,3))
  225. assert_equal(A.asfptype().dtype, np.dtype('float64'))
  226. assert_equal(A.asfptype().format, A.format)
  227. assert_equal(A.astype('int16').asfptype().dtype, np.dtype('float32'))
  228. assert_equal(A.astype('complex128').asfptype().dtype, np.dtype('complex128'))
  229. B = A.asfptype()
  230. C = B.asfptype()
  231. assert_(B is C)
  232. # TODO test prune
  233. # TODO test has_sorted_indices
  234. class _TestCommon:
  235. """test common functionality shared by all sparse formats"""
  236. math_dtypes = supported_dtypes
  237. bsr_container = bsr_array
  238. coo_container = coo_array
  239. csc_container = csc_array
  240. csr_container = csr_array
  241. dia_container = dia_array
  242. dok_container = dok_array
  243. lil_container = lil_array
  244. asdense = array
  245. @classmethod
  246. def init_class(cls):
  247. # Canonical data.
  248. cls.dat = array([[1, 0, 0, 2], [3, 0, 1, 0], [0, 2, 0, 0]], 'd')
  249. cls.datsp = cls.spcreator(cls.dat)
  250. # Some sparse and dense matrices with data for every supported dtype.
  251. # This set union is a workaround for numpy#6295, which means that
  252. # two np.int64 dtypes don't hash to the same value.
  253. cls.checked_dtypes = set(supported_dtypes).union(cls.math_dtypes)
  254. cls.dat_dtypes = {}
  255. cls.datsp_dtypes = {}
  256. for dtype in cls.checked_dtypes:
  257. cls.dat_dtypes[dtype] = cls.dat.astype(dtype)
  258. cls.datsp_dtypes[dtype] = cls.spcreator(cls.dat.astype(dtype))
  259. # Check that the original data is equivalent to the
  260. # corresponding dat_dtypes & datsp_dtypes.
  261. assert_equal(cls.dat, cls.dat_dtypes[np.float64])
  262. assert_equal(cls.datsp.toarray(),
  263. cls.datsp_dtypes[np.float64].toarray())
  264. cls.is_array_test = isinstance(cls.datsp, sparray)
  265. def test_bool(self):
  266. def check(dtype):
  267. datsp = self.datsp_dtypes[dtype]
  268. assert_raises(ValueError, bool, datsp)
  269. assert_(self.spcreator([[1]]))
  270. assert_(not self.spcreator([[0]]))
  271. if isinstance(self, TestDOK):
  272. pytest.skip("Cannot create a rank <= 2 DOK matrix.")
  273. for dtype in self.checked_dtypes:
  274. check(dtype)
  275. def test_bool_rollover(self):
  276. # bool's underlying dtype is 1 byte, check that it does not
  277. # rollover True -> False at 256.
  278. dat = array([[True, False]])
  279. datsp = self.spcreator(dat)
  280. for _ in range(10):
  281. datsp = datsp + datsp
  282. dat = dat + dat
  283. assert_array_equal(dat, datsp.toarray())
  284. def test_eq(self):
  285. def check(dtype):
  286. with warnings.catch_warnings():
  287. warnings.simplefilter("ignore", SparseEfficiencyWarning)
  288. warnings.simplefilter("ignore", ComplexWarning)
  289. dat = self.dat_dtypes[dtype]
  290. datsp = self.datsp_dtypes[dtype]
  291. dat2 = dat.copy()
  292. dat2[:,0] = 0
  293. datsp2 = self.spcreator(dat2)
  294. datbsr = self.bsr_container(dat)
  295. datcsr = self.csr_container(dat)
  296. datcsc = self.csc_container(dat)
  297. datlil = self.lil_container(dat)
  298. # sparse/sparse
  299. assert_array_equal_dtype(dat == dat2, (datsp == datsp2).toarray())
  300. # mix sparse types
  301. assert_array_equal_dtype(dat == dat2, (datbsr == datsp2).toarray())
  302. assert_array_equal_dtype(dat == dat2, (datcsr == datsp2).toarray())
  303. assert_array_equal_dtype(dat == dat2, (datcsc == datsp2).toarray())
  304. assert_array_equal_dtype(dat == dat2, (datlil == datsp2).toarray())
  305. # sparse/dense
  306. assert_array_equal_dtype(dat == datsp2, datsp2 == dat)
  307. # sparse/scalar
  308. assert_array_equal_dtype(dat == 0, (datsp == 0).toarray())
  309. assert_array_equal_dtype(dat == 1, (datsp == 1).toarray())
  310. assert_array_equal_dtype(dat == np.nan,
  311. (datsp == np.nan).toarray())
  312. if self.datsp.format not in ['bsr', 'csc', 'csr']:
  313. pytest.skip("Bool comparisons only implemented for BSR, CSC, and CSR.")
  314. for dtype in self.checked_dtypes:
  315. check(dtype)
  316. def test_ne(self):
  317. def check(dtype):
  318. with warnings.catch_warnings():
  319. warnings.simplefilter("ignore", SparseEfficiencyWarning)
  320. warnings.simplefilter("ignore", ComplexWarning)
  321. dat = self.dat_dtypes[dtype]
  322. datsp = self.datsp_dtypes[dtype]
  323. dat2 = dat.copy()
  324. dat2[:,0] = 0
  325. datsp2 = self.spcreator(dat2)
  326. datbsr = self.bsr_container(dat)
  327. datcsc = self.csc_container(dat)
  328. datcsr = self.csr_container(dat)
  329. datlil = self.lil_container(dat)
  330. # sparse/sparse
  331. assert_array_equal_dtype(dat != dat2, (datsp != datsp2).toarray())
  332. # mix sparse types
  333. assert_array_equal_dtype(dat != dat2, (datbsr != datsp2).toarray())
  334. assert_array_equal_dtype(dat != dat2, (datcsc != datsp2).toarray())
  335. assert_array_equal_dtype(dat != dat2, (datcsr != datsp2).toarray())
  336. assert_array_equal_dtype(dat != dat2, (datlil != datsp2).toarray())
  337. # sparse/dense
  338. assert_array_equal_dtype(dat != datsp2, datsp2 != dat)
  339. # sparse/scalar
  340. assert_array_equal_dtype(dat != 0, (datsp != 0).toarray())
  341. assert_array_equal_dtype(dat != 1, (datsp != 1).toarray())
  342. assert_array_equal_dtype(0 != dat, (0 != datsp).toarray())
  343. assert_array_equal_dtype(1 != dat, (1 != datsp).toarray())
  344. assert_array_equal_dtype(dat != np.nan,
  345. (datsp != np.nan).toarray())
  346. if self.datsp.format not in ['bsr', 'csc', 'csr']:
  347. pytest.skip("Bool comparisons only implemented for BSR, CSC, and CSR.")
  348. for dtype in self.checked_dtypes:
  349. check(dtype)
  350. def test_eq_ne_different_shapes(self):
  351. if self.datsp.format not in ['bsr', 'csc', 'csr']:
  352. pytest.skip("Bool comparisons only implemented for BSR, CSC, and CSR.")
  353. # Is this what we want? numpy raises when shape differs. we return False.
  354. assert (self.datsp == self.datsp.T) is False
  355. assert (self.datsp != self.datsp.T) is True
  356. def test_lt(self):
  357. def check(dtype):
  358. with warnings.catch_warnings():
  359. warnings.simplefilter("ignore", SparseEfficiencyWarning)
  360. warnings.simplefilter("ignore", ComplexWarning)
  361. # data
  362. dat = self.dat_dtypes[dtype]
  363. datsp = self.datsp_dtypes[dtype]
  364. dat2 = dat.copy()
  365. dat2[:,0] = 0
  366. datsp2 = self.spcreator(dat2)
  367. datcomplex = dat.astype(complex)
  368. datcomplex[:,0] = 1 + 1j
  369. datspcomplex = self.spcreator(datcomplex)
  370. datbsr = self.bsr_container(dat)
  371. datcsc = self.csc_container(dat)
  372. datcsr = self.csr_container(dat)
  373. datlil = self.lil_container(dat)
  374. # sparse/sparse
  375. assert_array_equal_dtype(dat < dat2, (datsp < datsp2).toarray())
  376. assert_array_equal_dtype(datcomplex < dat2,
  377. (datspcomplex < datsp2).toarray())
  378. # mix sparse types
  379. assert_array_equal_dtype(dat < dat2, (datbsr < datsp2).toarray())
  380. assert_array_equal_dtype(dat < dat2, (datcsc < datsp2).toarray())
  381. assert_array_equal_dtype(dat < dat2, (datcsr < datsp2).toarray())
  382. assert_array_equal_dtype(dat < dat2, (datlil < datsp2).toarray())
  383. assert_array_equal_dtype(dat2 < dat, (datsp2 < datbsr).toarray())
  384. assert_array_equal_dtype(dat2 < dat, (datsp2 < datcsc).toarray())
  385. assert_array_equal_dtype(dat2 < dat, (datsp2 < datcsr).toarray())
  386. assert_array_equal_dtype(dat2 < dat, (datsp2 < datlil).toarray())
  387. # sparse/dense
  388. assert_array_equal_dtype(dat < dat2, datsp < dat2)
  389. assert_array_equal_dtype(datcomplex < dat2, datspcomplex < dat2)
  390. # sparse/scalar
  391. for val in [2, 1, 0, -1, -2]:
  392. val = np.int64(val) # avoid Python scalar (due to NEP 50 changes)
  393. assert_array_equal_dtype((datsp < val).toarray(), dat < val)
  394. assert_array_equal_dtype((val < datsp).toarray(), val < dat)
  395. with np.errstate(invalid='ignore'):
  396. assert_array_equal_dtype((datsp < np.nan).toarray(),
  397. dat < np.nan)
  398. # data
  399. dat = self.dat_dtypes[dtype]
  400. datsp = self.datsp_dtypes[dtype]
  401. dat2 = dat.copy()
  402. dat2[:,0] = 0
  403. datsp2 = self.spcreator(dat2)
  404. # dense rhs
  405. assert_array_equal_dtype(dat < datsp2, datsp < dat2)
  406. if self.datsp.format not in ['bsr', 'csc', 'csr']:
  407. pytest.skip("Bool comparisons only implemented for BSR, CSC, and CSR.")
  408. for dtype in self.checked_dtypes:
  409. check(dtype)
  410. def test_gt(self):
  411. def check(dtype):
  412. with warnings.catch_warnings():
  413. warnings.simplefilter("ignore", SparseEfficiencyWarning)
  414. warnings.simplefilter("ignore", ComplexWarning)
  415. dat = self.dat_dtypes[dtype]
  416. datsp = self.datsp_dtypes[dtype]
  417. dat2 = dat.copy()
  418. dat2[:,0] = 0
  419. datsp2 = self.spcreator(dat2)
  420. datcomplex = dat.astype(complex)
  421. datcomplex[:,0] = 1 + 1j
  422. datspcomplex = self.spcreator(datcomplex)
  423. datbsr = self.bsr_container(dat)
  424. datcsc = self.csc_container(dat)
  425. datcsr = self.csr_container(dat)
  426. datlil = self.lil_container(dat)
  427. # sparse/sparse
  428. assert_array_equal_dtype(dat > dat2, (datsp > datsp2).toarray())
  429. assert_array_equal_dtype(datcomplex > dat2,
  430. (datspcomplex > datsp2).toarray())
  431. # mix sparse types
  432. assert_array_equal_dtype(dat > dat2, (datbsr > datsp2).toarray())
  433. assert_array_equal_dtype(dat > dat2, (datcsc > datsp2).toarray())
  434. assert_array_equal_dtype(dat > dat2, (datcsr > datsp2).toarray())
  435. assert_array_equal_dtype(dat > dat2, (datlil > datsp2).toarray())
  436. assert_array_equal_dtype(dat2 > dat, (datsp2 > datbsr).toarray())
  437. assert_array_equal_dtype(dat2 > dat, (datsp2 > datcsc).toarray())
  438. assert_array_equal_dtype(dat2 > dat, (datsp2 > datcsr).toarray())
  439. assert_array_equal_dtype(dat2 > dat, (datsp2 > datlil).toarray())
  440. # sparse/dense
  441. assert_array_equal_dtype(dat > dat2, datsp > dat2)
  442. assert_array_equal_dtype(datcomplex > dat2, datspcomplex > dat2)
  443. # sparse/scalar
  444. for val in [2, 1, 0, -1, -2]:
  445. val = np.int64(val) # avoid Python scalar (due to NEP 50 changes)
  446. assert_array_equal_dtype((datsp > val).toarray(), dat > val)
  447. assert_array_equal_dtype((val > datsp).toarray(), val > dat)
  448. with np.errstate(invalid='ignore'):
  449. assert_array_equal_dtype((datsp > np.nan).toarray(),
  450. dat > np.nan)
  451. # data
  452. dat = self.dat_dtypes[dtype]
  453. datsp = self.datsp_dtypes[dtype]
  454. dat2 = dat.copy()
  455. dat2[:,0] = 0
  456. datsp2 = self.spcreator(dat2)
  457. # dense rhs
  458. assert_array_equal_dtype(dat > datsp2, datsp > dat2)
  459. if self.datsp.format not in ['bsr', 'csc', 'csr']:
  460. pytest.skip("Bool comparisons only implemented for BSR, CSC, and CSR.")
  461. for dtype in self.checked_dtypes:
  462. check(dtype)
  463. def test_le(self):
  464. def check(dtype):
  465. with warnings.catch_warnings():
  466. warnings.simplefilter("ignore", SparseEfficiencyWarning)
  467. warnings.simplefilter("ignore", ComplexWarning)
  468. dat = self.dat_dtypes[dtype]
  469. datsp = self.datsp_dtypes[dtype]
  470. dat2 = dat.copy()
  471. dat2[:,0] = 0
  472. datsp2 = self.spcreator(dat2)
  473. datcomplex = dat.astype(complex)
  474. datcomplex[:,0] = 1 + 1j
  475. datspcomplex = self.spcreator(datcomplex)
  476. datbsr = self.bsr_container(dat)
  477. datcsc = self.csc_container(dat)
  478. datcsr = self.csr_container(dat)
  479. datlil = self.lil_container(dat)
  480. # sparse/sparse
  481. assert_array_equal_dtype(dat <= dat2, (datsp <= datsp2).toarray())
  482. assert_array_equal_dtype(datcomplex <= dat2,
  483. (datspcomplex <= datsp2).toarray())
  484. # mix sparse types
  485. assert_array_equal_dtype((datbsr <= datsp2).toarray(), dat <= dat2)
  486. assert_array_equal_dtype((datcsc <= datsp2).toarray(), dat <= dat2)
  487. assert_array_equal_dtype((datcsr <= datsp2).toarray(), dat <= dat2)
  488. assert_array_equal_dtype((datlil <= datsp2).toarray(), dat <= dat2)
  489. assert_array_equal_dtype((datsp2 <= datbsr).toarray(), dat2 <= dat)
  490. assert_array_equal_dtype((datsp2 <= datcsc).toarray(), dat2 <= dat)
  491. assert_array_equal_dtype((datsp2 <= datcsr).toarray(), dat2 <= dat)
  492. assert_array_equal_dtype((datsp2 <= datlil).toarray(), dat2 <= dat)
  493. # sparse/dense
  494. assert_array_equal_dtype(datsp <= dat2, dat <= dat2)
  495. assert_array_equal_dtype(datspcomplex <= dat2, datcomplex <= dat2)
  496. # sparse/scalar
  497. for val in [2, 1, -1, -2]:
  498. val = np.int64(val) # avoid Python scalar (due to NEP 50 changes)
  499. assert_array_equal_dtype((datsp <= val).toarray(), dat <= val)
  500. assert_array_equal_dtype((val <= datsp).toarray(), val <= dat)
  501. # data
  502. dat = self.dat_dtypes[dtype]
  503. datsp = self.datsp_dtypes[dtype]
  504. dat2 = dat.copy()
  505. dat2[:,0] = 0
  506. datsp2 = self.spcreator(dat2)
  507. # dense rhs
  508. assert_array_equal_dtype(dat <= datsp2, datsp <= dat2)
  509. if self.datsp.format not in ['bsr', 'csc', 'csr']:
  510. pytest.skip("Bool comparisons only implemented for BSR, CSC, and CSR.")
  511. for dtype in self.checked_dtypes:
  512. check(dtype)
  513. def test_ge(self):
  514. def check(dtype):
  515. with warnings.catch_warnings():
  516. warnings.simplefilter("ignore", SparseEfficiencyWarning)
  517. warnings.simplefilter("ignore", ComplexWarning)
  518. dat = self.dat_dtypes[dtype]
  519. datsp = self.datsp_dtypes[dtype]
  520. dat2 = dat.copy()
  521. dat2[:,0] = 0
  522. datsp2 = self.spcreator(dat2)
  523. datcomplex = dat.astype(complex)
  524. datcomplex[:,0] = 1 + 1j
  525. datspcomplex = self.spcreator(datcomplex)
  526. datbsr = self.bsr_container(dat)
  527. datcsc = self.csc_container(dat)
  528. datcsr = self.csr_container(dat)
  529. datlil = self.lil_container(dat)
  530. # sparse/sparse
  531. assert_array_equal_dtype(dat >= dat2, (datsp >= datsp2).toarray())
  532. assert_array_equal_dtype(datcomplex >= dat2,
  533. (datspcomplex >= datsp2).toarray())
  534. # mix sparse types
  535. assert_array_equal_dtype((datbsr >= datsp2).toarray(), dat >= dat2)
  536. assert_array_equal_dtype((datcsc >= datsp2).toarray(), dat >= dat2)
  537. assert_array_equal_dtype((datcsr >= datsp2).toarray(), dat >= dat2)
  538. assert_array_equal_dtype((datlil >= datsp2).toarray(), dat >= dat2)
  539. assert_array_equal_dtype((datsp2 >= datbsr).toarray(), dat2 >= dat)
  540. assert_array_equal_dtype((datsp2 >= datcsc).toarray(), dat2 >= dat)
  541. assert_array_equal_dtype((datsp2 >= datcsr).toarray(), dat2 >= dat)
  542. assert_array_equal_dtype((datsp2 >= datlil).toarray(), dat2 >= dat)
  543. # sparse/dense
  544. assert_array_equal_dtype(datsp >= dat2, dat >= dat2)
  545. assert_array_equal_dtype(datspcomplex >= dat2, datcomplex >= dat2)
  546. # sparse/scalar
  547. for val in [2, 1, -1, -2]:
  548. val = np.int64(val) # avoid Python scalar (due to NEP 50 changes)
  549. assert_array_equal_dtype((datsp >= val).toarray(), dat >= val)
  550. assert_array_equal_dtype((val >= datsp).toarray(), val >= dat)
  551. # dense data
  552. dat = self.dat_dtypes[dtype]
  553. datsp = self.datsp_dtypes[dtype]
  554. dat2 = dat.copy()
  555. dat2[:,0] = 0
  556. datsp2 = self.spcreator(dat2)
  557. # dense rhs
  558. assert_array_equal_dtype(dat >= datsp2, datsp >= dat2)
  559. if self.datsp.format not in ['bsr', 'csc', 'csr']:
  560. pytest.skip("Bool comparisons only implemented for BSR, CSC, and CSR.")
  561. for dtype in self.checked_dtypes:
  562. check(dtype)
  563. def test_empty(self):
  564. # create empty matrices
  565. assert_equal(self.spcreator((3, 3)).toarray(), zeros((3, 3)))
  566. assert_equal(self.spcreator((3, 3)).nnz, 0)
  567. assert_equal(self.spcreator((3, 3)).count_nonzero(), 0)
  568. if self.datsp.format in ["coo", "csr", "csc", "lil"]:
  569. assert_equal(self.spcreator((3, 3)).count_nonzero(axis=0), array([0, 0, 0]))
  570. def test_count_nonzero(self):
  571. axis_support = self.datsp.format in ["coo", "csr", "csc", "lil"]
  572. axes = [None, 0, 1, -1, -2] if axis_support else [None]
  573. for A in (self.datsp, self.datsp.T):
  574. for ax in axes:
  575. expected = np.count_nonzero(A.toarray(), axis=ax)
  576. assert_equal(A.count_nonzero(axis=ax), expected)
  577. if not axis_support:
  578. with assert_raises(NotImplementedError, match="not implemented .* format"):
  579. self.datsp.count_nonzero(axis=0)
  580. def test_invalid_shapes(self):
  581. assert_raises(ValueError, self.spcreator, (-1,3))
  582. assert_raises(ValueError, self.spcreator, (3,-1))
  583. assert_raises(ValueError, self.spcreator, (-1,-1))
  584. def test_repr(self):
  585. datsp = self.spcreator([[1, 0, 0], [0, 0, 0], [0, 0, -2]])
  586. extra = (
  587. "(1 diagonals) " if datsp.format == "dia"
  588. else "(blocksize=1x1) " if datsp.format == "bsr"
  589. else ""
  590. )
  591. _, fmt = _formats[datsp.format]
  592. sparse_cls = "array" if self.is_array_test else "matrix"
  593. expected = (
  594. f"<{fmt} sparse {sparse_cls} of dtype '{datsp.dtype}'\n"
  595. f"\twith {datsp.nnz} stored elements {extra}and shape {datsp.shape}>"
  596. )
  597. assert repr(datsp) == expected
  598. def test_str_maxprint(self):
  599. datsp = self.spcreator(np.arange(75).reshape(5, 15))
  600. assert datsp.maxprint == 50
  601. assert len(str(datsp).split('\n')) == 51 + 3
  602. dat = np.arange(15).reshape(5,3)
  603. datsp = self.spcreator(dat)
  604. # format dia reports nnz=15, but we want 14
  605. nnz_small = 14 if datsp.format == 'dia' else datsp.nnz
  606. datsp_mp6 = self.spcreator(dat, maxprint=6)
  607. assert len(str(datsp).split('\n')) == nnz_small + 3
  608. assert len(str(datsp_mp6).split('\n')) == 6 + 4
  609. # Check parameter `maxprint` is keyword only
  610. datsp = self.spcreator(dat, shape=(5, 3), dtype='i', copy=False, maxprint=4)
  611. datsp = self.spcreator(dat, (5, 3), 'i', False, maxprint=4)
  612. with pytest.raises(TypeError, match="positional argument|unpack non-iterable"):
  613. self.spcreator(dat, (5, 3), 'i', False, 4)
  614. def test_str(self):
  615. datsp = self.spcreator([[1, 0, 0], [0, 0, 0], [0, 0, -2]])
  616. if datsp.nnz != 2:
  617. return
  618. extra = (
  619. "(1 diagonals) " if datsp.format == "dia"
  620. else "(blocksize=1x1) " if datsp.format == "bsr"
  621. else ""
  622. )
  623. _, fmt = _formats[datsp.format]
  624. sparse_cls = "array" if self.is_array_test else "matrix"
  625. expected = (
  626. f"<{fmt} sparse {sparse_cls} of dtype '{datsp.dtype}'\n"
  627. f"\twith {datsp.nnz} stored elements {extra}and shape {datsp.shape}>"
  628. "\n Coords\tValues"
  629. "\n (0, 0)\t1"
  630. "\n (2, 2)\t-2"
  631. )
  632. assert str(datsp) == expected
  633. def test_empty_arithmetic(self):
  634. # Test manipulating empty matrices. Fails in SciPy SVN <= r1768
  635. shape = (5, 5)
  636. for mytype in [np.dtype('int32'), np.dtype('float32'),
  637. np.dtype('float64'), np.dtype('complex64'),
  638. np.dtype('complex128')]:
  639. a = self.spcreator(shape, dtype=mytype)
  640. b = a + a
  641. c = 2 * a
  642. d = a @ a.tocsc()
  643. e = a @ a.tocsr()
  644. f = a @ a.tocoo()
  645. for m in [a,b,c,d,e,f]:
  646. assert_equal(m.toarray(), a.toarray()@a.toarray())
  647. # These fail in all revisions <= r1768:
  648. assert_equal(m.dtype,mytype)
  649. assert_equal(m.toarray().dtype,mytype)
  650. def test_abs(self):
  651. A = array([[-1, 0, 17], [0, -5, 0], [1, -4, 0], [0, 0, 0]], 'd')
  652. assert_equal(abs(A), abs(self.spcreator(A)).toarray())
  653. def test_round(self):
  654. decimal = 1
  655. A = array([[-1.35, 0.56], [17.25, -5.98]], 'd')
  656. assert_equal(np.around(A, decimals=decimal),
  657. round(self.spcreator(A), ndigits=decimal).toarray())
  658. def test_elementwise_power(self):
  659. A = array([[-4, -3, -2], [-1, 0, 1], [2, 3, 4]], 'd')
  660. assert_equal(np.power(A, 2), self.spcreator(A).power(2).toarray())
  661. #it's element-wise power function, input has to be a scalar
  662. assert_raises(NotImplementedError, self.spcreator(A).power, A)
  663. def test_neg(self):
  664. A = array([[-1, 0, 17], [0, -5, 0], [1, -4, 0], [0, 0, 0]], 'd')
  665. assert_equal(-A, (-self.spcreator(A)).toarray())
  666. # see gh-5843
  667. A = array([[True, False, False], [False, False, True]])
  668. assert_raises(NotImplementedError, self.spcreator(A).__neg__)
  669. def test_real(self):
  670. D = array([[1 + 3j, 2 - 4j]])
  671. A = self.spcreator(D)
  672. assert_equal(A.real.toarray(), D.real)
  673. def test_imag(self):
  674. D = array([[1 + 3j, 2 - 4j]])
  675. A = self.spcreator(D)
  676. assert_equal(A.imag.toarray(), D.imag)
  677. def test_diagonal(self):
  678. # Does the matrix's .diagonal() method work?
  679. mats = []
  680. mats.append([[1,0,2]])
  681. mats.append([[1],[0],[2]])
  682. mats.append([[0,1],[0,2],[0,3]])
  683. mats.append([[0,0,1],[0,0,2],[0,3,0]])
  684. mats.append([[1,0],[0,0]])
  685. mats.append(kron(mats[0],[[1,2]]))
  686. mats.append(kron(mats[0],[[1],[2]]))
  687. mats.append(kron(mats[1],[[1,2],[3,4]]))
  688. mats.append(kron(mats[2],[[1,2],[3,4]]))
  689. mats.append(kron(mats[3],[[1,2],[3,4]]))
  690. mats.append(kron(mats[3],[[1,2,3,4]]))
  691. for m in mats:
  692. rows, cols = array(m).shape
  693. sparse_mat = self.spcreator(m)
  694. for k in range(-rows-1, cols+2):
  695. assert_equal(sparse_mat.diagonal(k=k), diag(m, k=k))
  696. # Test for k beyond boundaries(issue #11949)
  697. assert_equal(sparse_mat.diagonal(k=10), diag(m, k=10))
  698. assert_equal(sparse_mat.diagonal(k=-99), diag(m, k=-99))
  699. # Test all-zero matrix.
  700. assert_equal(self.spcreator((40, 16130)).diagonal(), np.zeros(40))
  701. # Test empty matrix
  702. # https://github.com/scipy/scipy/issues/11949
  703. assert_equal(self.spcreator((0, 0)).diagonal(), np.empty(0))
  704. assert_equal(self.spcreator((15, 0)).diagonal(), np.empty(0))
  705. assert_equal(self.spcreator((0, 5)).diagonal(10), np.empty(0))
  706. def test_trace(self):
  707. # For square matrix
  708. A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
  709. B = self.spcreator(A)
  710. for k in range(-2, 3):
  711. assert_equal(A.trace(offset=k), B.trace(offset=k))
  712. # For rectangular matrix
  713. A = np.array([[1, 2, 3], [4, 5, 6]])
  714. B = self.spcreator(A)
  715. for k in range(-1, 3):
  716. assert_equal(A.trace(offset=k), B.trace(offset=k))
  717. def test_reshape(self):
  718. x = self.spcreator([[1, 0, 7], [0, 0, 0], [0, 3, 0], [0, 0, 5]])
  719. for order in ['C', 'F']:
  720. for s in [(12, 1), (1, 12)]:
  721. assert_array_equal(x.reshape(s, order=order).toarray(),
  722. x.toarray().reshape(s, order=order))
  723. # This example is taken from the stackoverflow answer at
  724. # https://stackoverflow.com/q/16511879
  725. x = self.spcreator([[0, 10, 0, 0], [0, 0, 0, 0], [0, 20, 30, 40]])
  726. y = x.reshape((2, 6)) # Default order is 'C'
  727. desired = [[0, 10, 0, 0, 0, 0], [0, 0, 0, 20, 30, 40]]
  728. assert_array_equal(y.toarray(), desired)
  729. # Reshape with negative indexes
  730. y = x.reshape((2, -1))
  731. assert_array_equal(y.toarray(), desired)
  732. y = x.reshape((-1, 6))
  733. assert_array_equal(y.toarray(), desired)
  734. assert_raises(ValueError, x.reshape, (-1, -1))
  735. # Reshape with star args
  736. y = x.reshape(2, 6)
  737. assert_array_equal(y.toarray(), desired)
  738. assert_raises(TypeError, x.reshape, 2, 6, not_an_arg=1)
  739. # Reshape with same size is noop unless copy=True
  740. y = x.reshape((3, 4))
  741. assert_(y is x)
  742. y = x.reshape((3, 4), copy=True)
  743. assert_(y is not x)
  744. # Ensure reshape did not alter original size
  745. assert_array_equal(x.shape, (3, 4))
  746. if self.is_array_test:
  747. with assert_raises(AttributeError, match="has no setter|n't set attribute"):
  748. x.shape = (2, 6)
  749. else: # spmatrix test
  750. # Reshape in place
  751. x.shape = (2, 6)
  752. assert_array_equal(x.toarray(), desired)
  753. # Reshape to bad ndim
  754. assert_raises(ValueError, x.reshape, (x.size,))
  755. assert_raises(ValueError, x.reshape, (1, x.size, 1))
  756. @pytest.mark.slow
  757. def test_setdiag_comprehensive(self):
  758. def dense_setdiag(a, v, k):
  759. v = np.asarray(v)
  760. if k >= 0:
  761. n = min(a.shape[0], a.shape[1] - k)
  762. if v.ndim != 0:
  763. n = min(n, len(v))
  764. v = v[:n]
  765. i = np.arange(0, n)
  766. j = np.arange(k, k + n)
  767. a[i,j] = v
  768. elif k < 0:
  769. dense_setdiag(a.T, v, -k)
  770. def check_setdiag(a, b, k):
  771. # Check setting diagonal using a scalar, a vector of
  772. # correct length, and too short or too long vectors
  773. for r in [-1, len(np.diag(a, k)), 2, 30]:
  774. if r < 0:
  775. v = np.random.choice(range(1, 20))
  776. else:
  777. v = np.random.randint(1, 20, size=r)
  778. dense_setdiag(a, v, k)
  779. with warnings.catch_warnings():
  780. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  781. b.setdiag(v, k)
  782. # check that dense_setdiag worked
  783. d = np.diag(a, k)
  784. if np.asarray(v).ndim == 0:
  785. assert_array_equal(d, v, err_msg="{msg} {r}")
  786. else:
  787. n = min(len(d), len(v))
  788. assert_array_equal(d[:n], v[:n], err_msg="{msg} {r}")
  789. # check that sparse setdiag worked
  790. assert_array_equal(b.toarray(), a, err_msg="{msg} {r}")
  791. # comprehensive test
  792. np.random.seed(1234)
  793. shapes = [(0,5), (5,0), (1,5), (5,1), (5,5)]
  794. for dtype in [np.int8, np.float64]:
  795. for m,n in shapes:
  796. ks = np.arange(-m+1, n-1)
  797. for k in ks:
  798. a = np.zeros((m, n), dtype=dtype)
  799. b = self.spcreator((m, n), dtype=dtype)
  800. check_setdiag(a, b, k)
  801. # check overwriting etc
  802. for k2 in np.random.choice(ks, size=min(len(ks), 5)):
  803. check_setdiag(a, b, k2)
  804. def test_setdiag(self):
  805. # simple test cases
  806. m = self.spcreator(np.eye(3))
  807. m2 = self.spcreator((4, 4))
  808. values = [3, 2, 1]
  809. with warnings.catch_warnings():
  810. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  811. assert_raises(ValueError, m.setdiag, values, k=4)
  812. m.setdiag(values)
  813. assert_array_equal(m.diagonal(), values)
  814. m.setdiag(values, k=1)
  815. assert_array_equal(m.toarray(), np.array([[3, 3, 0],
  816. [0, 2, 2],
  817. [0, 0, 1]]))
  818. m.setdiag(values, k=-2)
  819. assert_array_equal(m.toarray(), np.array([[3, 3, 0],
  820. [0, 2, 2],
  821. [3, 0, 1]]))
  822. m.setdiag((9,), k=2)
  823. assert_array_equal(m.toarray()[0,2], 9)
  824. m.setdiag((9,), k=-2)
  825. assert_array_equal(m.toarray()[2,0], 9)
  826. # test short values on an empty matrix
  827. m2.setdiag([1], k=2)
  828. assert_array_equal(m2.toarray()[0], [0, 0, 1, 0])
  829. # test overwriting that same diagonal
  830. m2.setdiag([1, 1], k=2)
  831. assert_array_equal(m2.toarray()[:2], [[0, 0, 1, 0],
  832. [0, 0, 0, 1]])
  833. def test_nonzero(self):
  834. A = array([[1, 0, 1],[0, 1, 1],[0, 0, 1]])
  835. Asp = self.spcreator(A)
  836. A_nz = {tuple(ij) for ij in transpose(A.nonzero())}
  837. Asp_nz = {tuple(ij) for ij in transpose(Asp.nonzero())}
  838. assert_equal(A_nz, Asp_nz)
  839. def test_numpy_nonzero(self):
  840. # See gh-5987
  841. A = array([[1, 0, 1], [0, 1, 1], [0, 0, 1]])
  842. Asp = self.spcreator(A)
  843. A_nz = {tuple(ij) for ij in transpose(np.nonzero(A))}
  844. Asp_nz = {tuple(ij) for ij in transpose(np.nonzero(Asp))}
  845. assert_equal(A_nz, Asp_nz)
  846. def test_sum(self):
  847. np.random.seed(1234)
  848. dat_1 = np.array([[0, 1, 2],
  849. [3, -4, 5],
  850. [-6, 7, 9]])
  851. dat_2 = np.random.rand(5, 5)
  852. dat_3 = np.array([[]])
  853. dat_4 = np.zeros((40, 40))
  854. dat_5 = sparse.rand(5, 5, density=1e-2).toarray()
  855. matrices = [dat_1, dat_2, dat_3, dat_4, dat_5]
  856. def check(dtype, j):
  857. dat = self.asdense(matrices[j], dtype=dtype)
  858. datsp = self.spcreator(dat, dtype=dtype)
  859. with np.errstate(over='ignore'):
  860. assert_array_almost_equal(dat.sum(), datsp.sum())
  861. assert_equal(dat.sum().dtype, datsp.sum().dtype)
  862. assert_(np.isscalar(datsp.sum(axis=None)))
  863. assert_array_almost_equal(dat.sum(axis=None), datsp.sum(axis=None))
  864. assert_equal(dat.sum(axis=None).dtype, datsp.sum(axis=None).dtype)
  865. assert_array_almost_equal(dat.sum(axis=0), datsp.sum(axis=0))
  866. assert_equal(dat.sum(axis=0).dtype, datsp.sum(axis=0).dtype)
  867. assert_array_almost_equal(dat.sum(axis=1), datsp.sum(axis=1))
  868. assert_equal(dat.sum(axis=1).dtype, datsp.sum(axis=1).dtype)
  869. assert_array_almost_equal(dat.sum(axis=-2), datsp.sum(axis=-2))
  870. assert_equal(dat.sum(axis=-2).dtype, datsp.sum(axis=-2).dtype)
  871. assert_array_almost_equal(dat.sum(axis=-1), datsp.sum(axis=-1))
  872. assert_equal(dat.sum(axis=-1).dtype, datsp.sum(axis=-1).dtype)
  873. assert_array_almost_equal(dat.sum(axis=(0, 1)), datsp.sum(axis=(0, 1)))
  874. assert_equal(dat.sum(axis=(0, 1)).dtype, datsp.sum(axis=(0, 1)).dtype)
  875. for dtype in self.checked_dtypes:
  876. for j in range(len(matrices)):
  877. check(dtype, j)
  878. def test_sum_invalid_params(self):
  879. out = np.zeros((1, 3))
  880. dat = array([[0, 1, 2],
  881. [3, -4, 5],
  882. [-6, 7, 9]])
  883. datsp = self.spcreator(dat)
  884. with assert_raises(ValueError, match="axis out of range"):
  885. datsp.sum(axis=3)
  886. with assert_raises(ValueError, match="axis out of range"):
  887. datsp.sum(axis=(0, 3))
  888. with assert_raises(TypeError, match="axis must be an integer"):
  889. datsp.sum(axis=1.5)
  890. # error msg varies by sparray (1d result) or spmatrix (2d result)
  891. with assert_raises(ValueError, match="do.*n.t match.*shape|wrong.*dimensions"):
  892. datsp.mean(axis=1, out=out)
  893. def test_sum_dtype(self):
  894. dat = array([[0, 1, 2],
  895. [3, -4, 5],
  896. [-6, 7, 9]])
  897. datsp = self.spcreator(dat)
  898. def check(dtype):
  899. dat_sum = dat.sum(dtype=dtype)
  900. datsp_sum = datsp.sum(dtype=dtype)
  901. assert_array_almost_equal(dat_sum, datsp_sum)
  902. assert_equal(dat_sum.dtype, datsp_sum.dtype)
  903. for dtype in self.checked_dtypes:
  904. check(dtype)
  905. def test_sum_out(self):
  906. keep = not self.is_array_test
  907. dat = array([[0, 1, 2],
  908. [3, -4, 5],
  909. [-6, 7, 9]])
  910. datsp = self.spcreator(dat)
  911. dat_out = array(0) if self.is_array_test else array([[0]])
  912. datsp_out = array(0) if self.is_array_test else matrix([[0]])
  913. dat.sum(out=dat_out, keepdims=keep)
  914. datsp.sum(out=datsp_out)
  915. assert_array_almost_equal(dat_out, datsp_out)
  916. dat_out = np.zeros((3,)) if self.is_array_test else np.zeros((3, 1))
  917. datsp_out = np.zeros((3,)) if self.is_array_test else matrix(np.zeros((3, 1)))
  918. dat.sum(axis=1, out=dat_out, keepdims=keep)
  919. datsp.sum(axis=1, out=datsp_out)
  920. assert_array_almost_equal(dat_out, datsp_out)
  921. # check that wrong shape out parameter raises
  922. with assert_raises(ValueError, match="output parameter"):
  923. datsp.sum(out=array([0]))
  924. with assert_raises(ValueError, match="output parameter"):
  925. datsp.sum(out=array([[0]] if self.is_array_test else 0))
  926. def test_numpy_sum(self):
  927. # See gh-5987
  928. dat = array([[0, 1, 2],
  929. [3, -4, 5],
  930. [-6, 7, 9]])
  931. datsp = self.spcreator(dat)
  932. dat_sum = np.sum(dat)
  933. datsp_sum = np.sum(datsp)
  934. assert_array_almost_equal(dat_sum, datsp_sum)
  935. assert_equal(dat_sum.dtype, datsp_sum.dtype)
  936. def test_sum_mean_container_type(self):
  937. dat = array([[0, 1, 2],
  938. [3, -4, 5],
  939. [-6, 7, 9]])
  940. datsp = self.spcreator(dat)
  941. assert isscalarlike(datsp.sum())
  942. matrix_or_array = ndarray if self.is_array_test else np.matrix
  943. assert isinstance(datsp.sum(axis=0), matrix_or_array)
  944. assert isinstance(datsp.sum(axis=1), matrix_or_array)
  945. assert isscalarlike(datsp.mean())
  946. assert isinstance(datsp.mean(axis=0), matrix_or_array)
  947. assert isinstance(datsp.mean(axis=1), matrix_or_array)
  948. def test_mean(self):
  949. keep = not self.is_array_test
  950. def check(dtype):
  951. dat = array([[0, 1, 2],
  952. [3, 4, 5],
  953. [6, 7, 9]], dtype=dtype)
  954. datsp = self.spcreator(dat, dtype=dtype)
  955. assert_array_almost_equal(dat.mean(), datsp.mean())
  956. assert_equal(dat.mean().dtype, datsp.mean().dtype)
  957. assert_(np.isscalar(datsp.mean(axis=None)))
  958. assert_array_almost_equal(
  959. dat.mean(axis=None, keepdims=keep), datsp.mean(axis=None)
  960. )
  961. assert_equal(dat.mean(axis=None).dtype, datsp.mean(axis=None).dtype)
  962. assert_array_almost_equal(
  963. dat.mean(axis=0, keepdims=keep), datsp.mean(axis=0)
  964. )
  965. assert_equal(dat.mean(axis=0).dtype, datsp.mean(axis=0).dtype)
  966. assert_array_almost_equal(
  967. dat.mean(axis=1, keepdims=keep), datsp.mean(axis=1)
  968. )
  969. assert_equal(dat.mean(axis=1).dtype, datsp.mean(axis=1).dtype)
  970. assert_array_almost_equal(
  971. dat.mean(axis=-2, keepdims=keep), datsp.mean(axis=-2)
  972. )
  973. assert_equal(dat.mean(axis=-2).dtype, datsp.mean(axis=-2).dtype)
  974. assert_array_almost_equal(
  975. dat.mean(axis=-1, keepdims=keep), datsp.mean(axis=-1)
  976. )
  977. assert_equal(dat.mean(axis=-1).dtype, datsp.mean(axis=-1).dtype)
  978. assert_array_almost_equal(
  979. dat.mean(axis=(0, 1), keepdims=keep), datsp.mean(axis=(0, 1))
  980. )
  981. assert_equal(dat.mean(axis=(0, 1)).dtype, datsp.mean(axis=(0, 1)).dtype)
  982. for dtype in self.checked_dtypes:
  983. check(dtype)
  984. def test_mean_invalid_param(self):
  985. out = self.asdense(np.zeros((1, 3)))
  986. dat = array([[0, 1, 2],
  987. [3, -4, 5],
  988. [-6, 7, 9]])
  989. datsp = self.spcreator(dat)
  990. with assert_raises(ValueError, match="axis out of range"):
  991. datsp.mean(axis=3)
  992. with assert_raises(ValueError, match="axis out of range"):
  993. datsp.mean(axis=(0, 3))
  994. with assert_raises(TypeError, match="axis must be an integer"):
  995. datsp.mean(axis=1.5)
  996. # error msg varies by sparray (1d result) or spmatrix (2d result)
  997. with assert_raises(ValueError, match="do.*n.t match.*shape|wrong.*dimensions"):
  998. datsp.mean(axis=1, out=out)
  999. def test_mean_dtype(self):
  1000. dat = array([[0, 1, 2],
  1001. [3, -4, 5],
  1002. [-6, 7, 9]])
  1003. datsp = self.spcreator(dat)
  1004. def check(dtype):
  1005. dat_mean = dat.mean(dtype=dtype)
  1006. datsp_mean = datsp.mean(dtype=dtype)
  1007. assert_array_almost_equal(dat_mean, datsp_mean)
  1008. assert_equal(dat_mean.dtype, datsp_mean.dtype)
  1009. for dtype in self.checked_dtypes:
  1010. check(dtype)
  1011. def test_mean_out(self):
  1012. keep = not self.is_array_test
  1013. dat = array([[0, 1, 2],
  1014. [3, -4, 5],
  1015. [-6, 7, 9]])
  1016. datsp = self.spcreator(dat)
  1017. dat_out = array(0) if self.is_array_test else array([[0]])
  1018. datsp_out = array(0) if self.is_array_test else matrix([[0]])
  1019. dat.mean(out=dat_out, keepdims=keep)
  1020. datsp.mean(out=datsp_out)
  1021. assert_array_almost_equal(dat_out, datsp_out)
  1022. dat_out = np.zeros((3,)) if self.is_array_test else np.zeros((3, 1))
  1023. datsp_out = np.zeros((3,)) if self.is_array_test else matrix(np.zeros((3, 1)))
  1024. dat.mean(axis=1, out=dat_out, keepdims=keep)
  1025. datsp.mean(axis=1, out=datsp_out)
  1026. assert_array_almost_equal(dat_out, datsp_out)
  1027. # check that wrong shape out parameter raises
  1028. with assert_raises(ValueError, match="output parameter.*wrong.*dimension"):
  1029. datsp.mean(out=array([0]))
  1030. with assert_raises(ValueError, match="output parameter.*wrong.*dimension"):
  1031. datsp.mean(out=array([[0]] if self.is_array_test else 0))
  1032. def test_numpy_mean(self):
  1033. # See gh-5987
  1034. dat = array([[0, 1, 2],
  1035. [3, -4, 5],
  1036. [-6, 7, 9]])
  1037. datsp = self.spcreator(dat)
  1038. dat_mean = np.mean(dat)
  1039. datsp_mean = np.mean(datsp)
  1040. assert_array_almost_equal(dat_mean, datsp_mean)
  1041. assert_equal(dat_mean.dtype, datsp_mean.dtype)
  1042. def test_expm(self):
  1043. M = array([[1, 0, 2], [0, 0, 3], [-4, 5, 6]], float)
  1044. sM = self.spcreator(M, shape=(3,3), dtype=float)
  1045. Mexp = scipy.linalg.expm(M)
  1046. N = array([[3., 0., 1.], [0., 2., 0.], [0., 0., 0.]])
  1047. sN = self.spcreator(N, shape=(3,3), dtype=float)
  1048. Nexp = scipy.linalg.expm(N)
  1049. with warnings.catch_warnings():
  1050. warnings.filterwarnings(
  1051. "ignore",
  1052. "splu converted its input to CSC format",
  1053. SparseEfficiencyWarning,
  1054. )
  1055. warnings.filterwarnings(
  1056. "ignore",
  1057. "spsolve is more efficient when sparse b is in the CSC matrix format",
  1058. SparseEfficiencyWarning,
  1059. )
  1060. warnings.filterwarnings(
  1061. "ignore",
  1062. "spsolve requires A be CSC or CSR matrix format",
  1063. SparseEfficiencyWarning,
  1064. )
  1065. sMexp = expm(sM).toarray()
  1066. sNexp = expm(sN).toarray()
  1067. assert_array_almost_equal((sMexp - Mexp), zeros((3, 3)))
  1068. assert_array_almost_equal((sNexp - Nexp), zeros((3, 3)))
  1069. def test_inv(self):
  1070. def check(dtype):
  1071. M = array([[1, 0, 2], [0, 0, 3], [-4, 5, 6]], dtype)
  1072. with warnings.catch_warnings():
  1073. warnings.filterwarnings(
  1074. "ignore",
  1075. "spsolve requires A be CSC or CSR matrix format",
  1076. SparseEfficiencyWarning,
  1077. )
  1078. warnings.filterwarnings(
  1079. "ignore",
  1080. "spsolve is more efficient when sparse b "
  1081. "is in the CSC matrix format",
  1082. SparseEfficiencyWarning,
  1083. )
  1084. warnings.filterwarnings(
  1085. "ignore",
  1086. "splu converted its input to CSC format",
  1087. SparseEfficiencyWarning,
  1088. )
  1089. sM = self.spcreator(M, shape=(3,3), dtype=dtype)
  1090. sMinv = inv(sM)
  1091. assert_array_almost_equal(sMinv.dot(sM).toarray(), np.eye(3))
  1092. assert_raises(TypeError, inv, M)
  1093. for dtype in [float]:
  1094. check(dtype)
  1095. def test_from_array(self):
  1096. with warnings.catch_warnings():
  1097. warnings.simplefilter("ignore", ComplexWarning)
  1098. A = array([[1,0,0],[2,3,4],[0,5,0],[0,0,0]])
  1099. assert_array_equal(self.spcreator(A).toarray(), A)
  1100. A = array([[1.0 + 3j, 0, 0],
  1101. [0, 2.0 + 5, 0],
  1102. [0, 0, 0]])
  1103. assert_array_equal(self.spcreator(A).toarray(), A)
  1104. assert_array_equal(
  1105. self.spcreator(A, dtype='int16').toarray(),A.astype('int16'))
  1106. def test_from_matrix(self):
  1107. with warnings.catch_warnings():
  1108. warnings.simplefilter("ignore", ComplexWarning)
  1109. A = self.asdense([[1, 0, 0], [2, 3, 4], [0, 5, 0], [0, 0, 0]])
  1110. assert_array_equal(self.spcreator(A).todense(), A)
  1111. A = self.asdense([[1.0 + 3j, 0, 0],
  1112. [0, 2.0 + 5, 0],
  1113. [0, 0, 0]])
  1114. assert_array_equal(self.spcreator(A).todense(), A)
  1115. assert_array_equal(
  1116. self.spcreator(A, dtype='int16').todense(), A.astype('int16')
  1117. )
  1118. def test_from_list(self):
  1119. with warnings.catch_warnings():
  1120. warnings.simplefilter("ignore", ComplexWarning)
  1121. A = [[1,0,0],[2,3,4],[0,5,0],[0,0,0]]
  1122. assert_array_equal(self.spcreator(A).toarray(), A)
  1123. A = [[1.0 + 3j, 0, 0],
  1124. [0, 2.0 + 5, 0],
  1125. [0, 0, 0]]
  1126. assert_array_equal(self.spcreator(A).toarray(), array(A))
  1127. assert_array_equal(
  1128. self.spcreator(A, dtype='int16').toarray(), array(A).astype('int16')
  1129. )
  1130. def test_from_sparse(self):
  1131. with warnings.catch_warnings():
  1132. warnings.simplefilter("ignore", ComplexWarning)
  1133. D = array([[1,0,0],[2,3,4],[0,5,0],[0,0,0]])
  1134. S = self.csr_container(D)
  1135. assert_array_equal(self.spcreator(S).toarray(), D)
  1136. S = self.spcreator(D)
  1137. assert_array_equal(self.spcreator(S).toarray(), D)
  1138. D = array([[1.0 + 3j, 0, 0],
  1139. [0, 2.0 + 5, 0],
  1140. [0, 0, 0]])
  1141. S = self.csr_container(D)
  1142. assert_array_equal(self.spcreator(S).toarray(), D)
  1143. assert_array_equal(self.spcreator(S, dtype='int16').toarray(),
  1144. D.astype('int16'))
  1145. S = self.spcreator(D)
  1146. assert_array_equal(self.spcreator(S).toarray(), D)
  1147. assert_array_equal(self.spcreator(S, dtype='int16').toarray(),
  1148. D.astype('int16'))
  1149. # def test_array(self):
  1150. # """test array(A) where A is in sparse format"""
  1151. # assert_equal( array(self.datsp), self.dat )
  1152. def test_todense(self):
  1153. # Check C- or F-contiguous (default).
  1154. chk = self.datsp.todense()
  1155. assert isinstance(chk, np.ndarray if self.is_array_test else np.matrix)
  1156. assert_array_equal(chk, self.dat)
  1157. assert_(chk.flags.c_contiguous != chk.flags.f_contiguous)
  1158. # Check C-contiguous (with arg).
  1159. chk = self.datsp.todense(order='C')
  1160. assert_array_equal(chk, self.dat)
  1161. assert_(chk.flags.c_contiguous)
  1162. assert_(not chk.flags.f_contiguous)
  1163. # Check F-contiguous (with arg).
  1164. chk = self.datsp.todense(order='F')
  1165. assert_array_equal(chk, self.dat)
  1166. assert_(not chk.flags.c_contiguous)
  1167. assert_(chk.flags.f_contiguous)
  1168. # Check with out argument (array).
  1169. out = np.zeros(self.datsp.shape, dtype=self.datsp.dtype)
  1170. chk = self.datsp.todense(out=out)
  1171. assert_array_equal(self.dat, out)
  1172. assert_array_equal(self.dat, chk)
  1173. assert np.may_share_memory(chk, out)
  1174. # Check with out array (matrix).
  1175. out = self.asdense(np.zeros(self.datsp.shape, dtype=self.datsp.dtype))
  1176. chk = self.datsp.todense(out=out)
  1177. assert_array_equal(self.dat, out)
  1178. assert_array_equal(self.dat, chk)
  1179. assert np.may_share_memory(chk, out)
  1180. a = array([[1.,2.,3.]])
  1181. dense_dot_dense = a @ self.dat
  1182. check = a @ self.datsp.todense()
  1183. assert_array_equal(dense_dot_dense, check)
  1184. b = array([[1.,2.,3.,4.]]).T
  1185. dense_dot_dense = self.dat @ b
  1186. check2 = self.datsp.todense() @ b
  1187. assert_array_equal(dense_dot_dense, check2)
  1188. # Check bool data works.
  1189. spbool = self.spcreator(self.dat, dtype=bool)
  1190. matbool = self.dat.astype(bool)
  1191. assert_array_equal(spbool.todense(), matbool)
  1192. def test_toarray(self):
  1193. # Check C- or F-contiguous (default).
  1194. dat = asarray(self.dat)
  1195. chk = self.datsp.toarray()
  1196. assert_array_equal(chk, dat)
  1197. assert_(chk.flags.c_contiguous != chk.flags.f_contiguous)
  1198. # Check C-contiguous (with arg).
  1199. chk = self.datsp.toarray(order='C')
  1200. assert_array_equal(chk, dat)
  1201. assert_(chk.flags.c_contiguous)
  1202. assert_(not chk.flags.f_contiguous)
  1203. # Check F-contiguous (with arg).
  1204. chk = self.datsp.toarray(order='F')
  1205. assert_array_equal(chk, dat)
  1206. assert_(not chk.flags.c_contiguous)
  1207. assert_(chk.flags.f_contiguous)
  1208. # Check with output arg.
  1209. out = np.zeros(self.datsp.shape, dtype=self.datsp.dtype)
  1210. self.datsp.toarray(out=out)
  1211. assert_array_equal(chk, dat)
  1212. # Check that things are fine when we don't initialize with zeros.
  1213. out[...] = 1.
  1214. self.datsp.toarray(out=out)
  1215. assert_array_equal(chk, dat)
  1216. a = array([1.,2.,3.])
  1217. dense_dot_dense = dot(a, dat)
  1218. check = dot(a, self.datsp.toarray())
  1219. assert_array_equal(dense_dot_dense, check)
  1220. b = array([1.,2.,3.,4.])
  1221. dense_dot_dense = dot(dat, b)
  1222. check2 = dot(self.datsp.toarray(), b)
  1223. assert_array_equal(dense_dot_dense, check2)
  1224. # Check bool data works.
  1225. spbool = self.spcreator(self.dat, dtype=bool)
  1226. arrbool = dat.astype(bool)
  1227. assert_array_equal(spbool.toarray(), arrbool)
  1228. def test_astype(self):
  1229. with warnings.catch_warnings():
  1230. warnings.simplefilter("ignore", ComplexWarning)
  1231. D = array([[2.0 + 3j, 0, 0],
  1232. [0, 4.0 + 5j, 0],
  1233. [0, 0, 0]])
  1234. S = self.spcreator(D)
  1235. for x in supported_dtypes:
  1236. # Check correctly casted
  1237. D_casted = D.astype(x)
  1238. for copy in (True, False):
  1239. S_casted = S.astype(x, copy=copy)
  1240. assert_equal(S_casted.dtype, D_casted.dtype) # correct type
  1241. assert_equal(S_casted.toarray(), D_casted) # correct values
  1242. assert_equal(S_casted.format, S.format) # format preserved
  1243. # Check correctly copied
  1244. assert_(S_casted.astype(x, copy=False) is S_casted)
  1245. S_copied = S_casted.astype(x, copy=True)
  1246. assert_(S_copied is not S_casted)
  1247. def check_equal_but_not_same_array_attribute(attribute):
  1248. a = getattr(S_casted, attribute)
  1249. b = getattr(S_copied, attribute)
  1250. assert_array_equal(a, b)
  1251. assert_(a is not b)
  1252. i = (0,) * b.ndim
  1253. b_i = b[i]
  1254. b[i] = not b[i]
  1255. assert_(a[i] != b[i])
  1256. b[i] = b_i
  1257. if S_casted.format in ('csr', 'csc', 'bsr'):
  1258. for attribute in ('indices', 'indptr', 'data'):
  1259. check_equal_but_not_same_array_attribute(attribute)
  1260. elif S_casted.format == 'coo':
  1261. for attribute in ('row', 'col', 'data'):
  1262. check_equal_but_not_same_array_attribute(attribute)
  1263. elif S_casted.format == 'dia':
  1264. for attribute in ('offsets', 'data'):
  1265. check_equal_but_not_same_array_attribute(attribute)
  1266. def test_astype_immutable(self):
  1267. with warnings.catch_warnings():
  1268. warnings.simplefilter("ignore", ComplexWarning)
  1269. D = array([[2.0 + 3j, 0, 0],
  1270. [0, 4.0 + 5j, 0],
  1271. [0, 0, 0]])
  1272. S = self.spcreator(D)
  1273. if hasattr(S, 'data'):
  1274. S.data.flags.writeable = False
  1275. if S.format in ('csr', 'csc', 'bsr'):
  1276. S.indptr.flags.writeable = False
  1277. S.indices.flags.writeable = False
  1278. for x in supported_dtypes:
  1279. D_casted = D.astype(x)
  1280. S_casted = S.astype(x)
  1281. assert_equal(S_casted.dtype, D_casted.dtype)
  1282. def test_mul_scalar(self):
  1283. def check(dtype):
  1284. dat = self.dat_dtypes[dtype]
  1285. datsp = self.datsp_dtypes[dtype]
  1286. assert_array_equal(dat*2, (datsp*2).toarray())
  1287. assert_array_equal(dat*17.3, (datsp*17.3).toarray())
  1288. for dtype in self.math_dtypes:
  1289. check(dtype)
  1290. def test_rmul_scalar(self):
  1291. def check(dtype):
  1292. dat = self.dat_dtypes[dtype]
  1293. datsp = self.datsp_dtypes[dtype]
  1294. assert_array_equal(2*dat, (2*datsp).toarray())
  1295. assert_array_equal(17.3*dat, (17.3*datsp).toarray())
  1296. for dtype in self.math_dtypes:
  1297. check(dtype)
  1298. # GitHub issue #15210
  1299. def test_rmul_scalar_type_error(self):
  1300. datsp = self.datsp_dtypes[np.float64]
  1301. with assert_raises(TypeError):
  1302. None * datsp
  1303. def test_add(self):
  1304. def check(dtype):
  1305. dat = self.dat_dtypes[dtype]
  1306. datsp = self.datsp_dtypes[dtype]
  1307. a = dat.copy()
  1308. a[0,2] = 2.0
  1309. b = datsp
  1310. c = b + a
  1311. assert_array_equal(c, b.toarray() + a)
  1312. c = b + b.tocsr()
  1313. assert_array_equal(c.toarray(),
  1314. b.toarray() + b.toarray())
  1315. # test broadcasting
  1316. c = b + a[0]
  1317. assert_array_equal(c, b.toarray() + a[0])
  1318. for dtype in self.math_dtypes:
  1319. check(dtype)
  1320. def test_radd(self):
  1321. def check(dtype):
  1322. dat = self.dat_dtypes[dtype]
  1323. datsp = self.datsp_dtypes[dtype]
  1324. a = dat.copy()
  1325. a[0,2] = 2.0
  1326. b = datsp
  1327. c = a + b
  1328. assert_array_equal(c, a + b.toarray())
  1329. for dtype in self.math_dtypes:
  1330. check(dtype)
  1331. def test_sub(self):
  1332. def check(dtype):
  1333. dat = self.dat_dtypes[dtype]
  1334. datsp = self.datsp_dtypes[dtype]
  1335. assert_array_equal((datsp - datsp).toarray(), np.zeros((3, 4)))
  1336. assert_array_equal((datsp - 0).toarray(), dat)
  1337. A = self.spcreator(
  1338. np.array([[1, 0, 0, 4], [-1, 0, 0, 0], [0, 8, 0, -5]], 'd')
  1339. )
  1340. assert_array_equal((datsp - A).toarray(), dat - A.toarray())
  1341. assert_array_equal((A - datsp).toarray(), A.toarray() - dat)
  1342. # test broadcasting
  1343. assert_array_equal(datsp - dat[0], dat - dat[0])
  1344. for dtype in self.math_dtypes:
  1345. if dtype == np.dtype('bool'):
  1346. # boolean array subtraction deprecated in 1.9.0
  1347. continue
  1348. check(dtype)
  1349. def test_rsub(self):
  1350. def check(dtype):
  1351. dat = self.dat_dtypes[dtype]
  1352. datsp = self.datsp_dtypes[dtype]
  1353. assert_array_equal((dat - datsp),[[0,0,0,0],[0,0,0,0],[0,0,0,0]])
  1354. assert_array_equal((datsp - dat),[[0,0,0,0],[0,0,0,0],[0,0,0,0]])
  1355. assert_array_equal((0 - datsp).toarray(), -dat)
  1356. A = self.spcreator([[1,0,0,4],[-1,0,0,0],[0,8,0,-5]],dtype='d')
  1357. assert_array_equal((dat - A), dat - A.toarray())
  1358. assert_array_equal((A - dat), A.toarray() - dat)
  1359. assert_array_equal(A.toarray() - datsp, A.toarray() - dat)
  1360. assert_array_equal(datsp - A.toarray(), dat - A.toarray())
  1361. # test broadcasting
  1362. assert_array_equal(dat[0] - datsp, dat[0] - dat)
  1363. for dtype in self.math_dtypes:
  1364. if dtype == np.dtype('bool'):
  1365. # boolean array subtraction deprecated in 1.9.0
  1366. continue
  1367. check(dtype)
  1368. def test_add0(self):
  1369. def check(dtype):
  1370. dat = self.dat_dtypes[dtype]
  1371. datsp = self.datsp_dtypes[dtype]
  1372. # Adding 0 to a sparse matrix
  1373. assert_array_equal((datsp + 0).toarray(), dat)
  1374. # use sum (which takes 0 as a starting value)
  1375. sumS = sum([k * datsp for k in range(1, 3)])
  1376. sumD = sum([k * dat for k in range(1, 3)])
  1377. assert_almost_equal(sumS.toarray(), sumD)
  1378. for dtype in self.math_dtypes:
  1379. check(dtype)
  1380. def test_elementwise_multiply(self):
  1381. # real/real
  1382. A = array([[4,0,9],[2,-3,5]])
  1383. B = array([[0,7,0],[0,-4,0]])
  1384. Asp = self.spcreator(A)
  1385. Bsp = self.spcreator(B)
  1386. # check output format
  1387. out_fmt = Asp.format if Asp.format in ('csc', 'dia', 'bsr') else 'csr'
  1388. assert (Asp.multiply(Bsp)).format == out_fmt
  1389. assert_almost_equal(Asp.multiply(Bsp).toarray(), A*B) # sparse/sparse
  1390. assert_almost_equal(Asp.multiply(B).toarray(), A*B) # sparse/dense
  1391. # complex/complex
  1392. C = array([[1-2j,0+5j,-1+0j],[4-3j,-3+6j,5]])
  1393. D = array([[5+2j,7-3j,-2+1j],[0-1j,-4+2j,9]])
  1394. Csp = self.spcreator(C)
  1395. Dsp = self.spcreator(D)
  1396. assert_almost_equal(Csp.multiply(Dsp).toarray(), C*D) # sparse/sparse
  1397. assert_almost_equal(Csp.multiply(D).toarray(), C*D) # sparse/dense
  1398. # real/complex
  1399. assert_almost_equal(Asp.multiply(Dsp).toarray(), A*D) # sparse/sparse
  1400. assert_almost_equal(Asp.multiply(D).toarray(), A*D) # sparse/dense
  1401. def test_elementwise_multiply_broadcast(self):
  1402. A = array([4])
  1403. B = array([[-9]])
  1404. C = array([1,-1,0])
  1405. D = array([[7,9,-9]])
  1406. E = array([[3],[2],[1]])
  1407. F = array([[8,6,3],[-4,3,2],[6,6,6]])
  1408. G = [1, 2, 3]
  1409. H = np.ones((3, 4))
  1410. J = H.T
  1411. K = array([[0]])
  1412. L = array([[[1,2],[0,1]]])
  1413. # Some arrays can't be cast as spmatrices (A,C,L) so leave
  1414. # them out.
  1415. Bsp = self.spcreator(B)
  1416. Dsp = self.spcreator(D)
  1417. Esp = self.spcreator(E)
  1418. Fsp = self.spcreator(F)
  1419. Hsp = self.spcreator(H)
  1420. Hspp = self.spcreator(H[0,None])
  1421. Jsp = self.spcreator(J)
  1422. Jspp = self.spcreator(J[:,0,None])
  1423. Ksp = self.spcreator(K)
  1424. matrices = [A, B, C, D, E, F, G, H, J, K, L]
  1425. spmatrices = [Bsp, Dsp, Esp, Fsp, Hsp, Hspp, Jsp, Jspp, Ksp]
  1426. # sparse/sparse
  1427. for i in spmatrices:
  1428. for j in spmatrices:
  1429. try:
  1430. dense_mult = i.toarray() * j.toarray()
  1431. except ValueError:
  1432. assert_raises(ValueError, i.multiply, j)
  1433. continue
  1434. sp_mult = i.multiply(j)
  1435. assert_almost_equal(sp_mult.toarray(), dense_mult)
  1436. # sparse/dense
  1437. for i in spmatrices:
  1438. for j in matrices:
  1439. try:
  1440. dense_mult = i.toarray() * j
  1441. except TypeError:
  1442. continue
  1443. except ValueError:
  1444. assert_raises(ValueError, i.multiply, j)
  1445. continue
  1446. try:
  1447. sp_mult = i.multiply(j)
  1448. except ValueError:
  1449. continue
  1450. if issparse(sp_mult):
  1451. assert_almost_equal(sp_mult.toarray(), dense_mult)
  1452. else:
  1453. assert_almost_equal(sp_mult, dense_mult)
  1454. def test_elementwise_divide(self):
  1455. expected = [[1,np.nan,np.nan,1],
  1456. [1,np.nan,1,np.nan],
  1457. [np.nan,1,np.nan,np.nan]]
  1458. assert_array_equal(toarray(self.datsp / self.datsp), expected)
  1459. denom = self.spcreator([[1,0,0,4],[-1,0,0,0],[0,8,0,-5]],dtype='d')
  1460. expected = [[1,np.nan,np.nan,0.5],
  1461. [-3,np.nan,inf,np.nan],
  1462. [np.nan,0.25,np.nan,0]]
  1463. assert_array_equal(toarray(self.datsp / denom), expected)
  1464. # complex
  1465. A = array([[1-2j,0+5j,-1+0j],[4-3j,-3+6j,5]])
  1466. B = array([[5+2j,7-3j,-2+1j],[0-1j,-4+2j,9]])
  1467. Asp = self.spcreator(A)
  1468. Bsp = self.spcreator(B)
  1469. assert_almost_equal(toarray(Asp / Bsp), A/B)
  1470. # integer
  1471. A = array([[1,2,3],[-3,2,1]])
  1472. B = array([[0,1,2],[0,-2,3]])
  1473. Asp = self.spcreator(A)
  1474. Bsp = self.spcreator(B)
  1475. with np.errstate(divide='ignore'):
  1476. assert_array_equal(toarray(Asp / Bsp), A / B)
  1477. # mismatching sparsity patterns
  1478. A = array([[0,1],[1,0]])
  1479. B = array([[1,0],[1,0]])
  1480. Asp = self.spcreator(A)
  1481. Bsp = self.spcreator(B)
  1482. with np.errstate(divide='ignore', invalid='ignore'):
  1483. assert_array_equal(np.array(toarray(Asp / Bsp)), A / B)
  1484. def test_pow(self):
  1485. A = array([[1, 0, 2, 0], [0, 3, 4, 0], [0, 5, 0, 0], [0, 6, 7, 8]])
  1486. B = self.spcreator(A)
  1487. if self.is_array_test: # sparrays use element-wise power
  1488. for exponent in [1, 2, 2.2, 3, 1+3j]:
  1489. ret_sp = B**exponent
  1490. ret_np = A**exponent
  1491. assert_array_equal(ret_sp.toarray(), ret_np)
  1492. assert_equal(ret_sp.dtype, ret_np.dtype)
  1493. # invalid exponents
  1494. assert_raises(NotImplementedError, B.__pow__, 0)
  1495. assert_raises(ValueError, B.__pow__, -1)
  1496. # nonsquare matrix
  1497. B = self.spcreator(A[:3,:])
  1498. assert_equal((B**1).toarray(), B.toarray())
  1499. else: # test sparse matrix. spmatrices use matrix multiplicative power
  1500. for exponent in [0,1,2,3]:
  1501. ret_sp = B**exponent
  1502. ret_np = np.linalg.matrix_power(A, exponent)
  1503. assert_array_equal(ret_sp.toarray(), ret_np)
  1504. assert_equal(ret_sp.dtype, ret_np.dtype)
  1505. # invalid exponents
  1506. for exponent in [-1, 2.2, 1 + 3j]:
  1507. assert_raises(ValueError, B.__pow__, exponent)
  1508. # nonsquare matrix
  1509. B = self.spcreator(A[:3,:])
  1510. assert_raises(TypeError, B.__pow__, 1)
  1511. def test_rmatvec(self):
  1512. M = self.spcreator([[3,0,0],[0,1,0],[2,0,3.0],[2,3,0]])
  1513. assert_array_almost_equal([1,2,3,4] @ M, dot([1,2,3,4], M.toarray()))
  1514. row = array([[1,2,3,4]])
  1515. assert_array_almost_equal(row @ M, row @ M.toarray())
  1516. def test_small_multiplication(self):
  1517. # test that A*x works for x with shape () (1,) (1,1) and (1,0)
  1518. A = self.spcreator([[1],[2],[3]])
  1519. assert_(issparse(A * array(1)))
  1520. assert_equal((A * array(1)).toarray(), [[1], [2], [3]])
  1521. assert_equal(A @ array([1]), array([1, 2, 3]))
  1522. assert_equal(A @ array([[1]]), array([[1], [2], [3]]))
  1523. assert_equal(A @ np.ones((1, 1)), array([[1], [2], [3]]))
  1524. assert_equal(A @ np.ones((1, 0)), np.ones((3, 0)))
  1525. def test_star_vs_at_sign_for_sparray_and_spmatrix(self):
  1526. # test that * is matmul for spmatrix and mul for sparray
  1527. A = np.array([[1], [2], [3]])
  1528. Asp = self.spcreator(A)
  1529. if self.is_array_test:
  1530. assert_array_almost_equal((Asp * np.ones((3, 1))).toarray(), A)
  1531. assert_array_almost_equal((Asp * array([[1]])).toarray(), A)
  1532. else:
  1533. assert_equal(Asp * array([1]), array([1, 2, 3]))
  1534. assert_equal(Asp * array([[1]]), array([[1], [2], [3]]))
  1535. assert_equal(Asp * np.ones((1, 0)), np.ones((3, 0)))
  1536. def test_binop_custom_type(self):
  1537. # Non-regression test: previously, binary operations would raise
  1538. # NotImplementedError instead of returning NotImplemented
  1539. # (https://docs.python.org/library/constants.html#NotImplemented)
  1540. # so overloading Custom + matrix etc. didn't work.
  1541. A = self.spcreator([[1], [2], [3]])
  1542. B = BinopTester()
  1543. assert_equal(A + B, "matrix on the left")
  1544. assert_equal(A - B, "matrix on the left")
  1545. assert_equal(A * B, "matrix on the left")
  1546. assert_equal(B + A, "matrix on the right")
  1547. assert_equal(B - A, "matrix on the right")
  1548. assert_equal(B * A, "matrix on the right")
  1549. assert_equal(A @ B, "matrix on the left")
  1550. assert_equal(B @ A, "matrix on the right")
  1551. def test_binop_custom_type_with_shape(self):
  1552. A = self.spcreator([[1], [2], [3]])
  1553. B = BinopTester_with_shape((3,1))
  1554. assert_equal(A + B, "matrix on the left")
  1555. assert_equal(A - B, "matrix on the left")
  1556. assert_equal(A * B, "matrix on the left")
  1557. assert_equal(B + A, "matrix on the right")
  1558. assert_equal(B - A, "matrix on the right")
  1559. assert_equal(B * A, "matrix on the right")
  1560. assert_equal(A @ B, "matrix on the left")
  1561. assert_equal(B @ A, "matrix on the right")
  1562. def test_mul_custom_type(self):
  1563. class Custom:
  1564. def __init__(self, scalar):
  1565. self.scalar = scalar
  1566. def __rmul__(self, other):
  1567. return other * self.scalar
  1568. scalar = 2
  1569. A = self.spcreator([[1],[2],[3]])
  1570. c = Custom(scalar)
  1571. A_scalar = A * scalar
  1572. A_c = A * c
  1573. assert_array_equal_dtype(A_scalar.toarray(), A_c.toarray())
  1574. assert_equal(A_scalar.format, A_c.format)
  1575. def test_comparisons_custom_type(self):
  1576. A = self.spcreator([[1], [2], [3]])
  1577. B = ComparisonTester()
  1578. assert_equal(A == B, "eq")
  1579. assert_equal(A != B, "ne")
  1580. assert_equal(A > B, "lt")
  1581. assert_equal(A >= B, "le")
  1582. assert_equal(A < B, "gt")
  1583. assert_equal(A <= B, "ge")
  1584. def test_dot_scalar(self):
  1585. M = self.spcreator(array([[3,0,0],[0,1,0],[2,0,3.0],[2,3,0]]))
  1586. scalar = 10
  1587. actual = M.dot(scalar)
  1588. expected = M * scalar
  1589. assert_allclose(actual.toarray(), expected.toarray())
  1590. def test_matmul(self):
  1591. M = self.spcreator(array([[3,0,0],[0,1,0],[2,0,3.0],[2,3,0]]))
  1592. B = self.spcreator(array([[0,1],[1,0],[0,2]],'d'))
  1593. col = array([[1,2,3]]).T
  1594. matmul = operator.matmul
  1595. # check matrix-vector
  1596. assert_array_almost_equal(matmul(M, col), M.toarray() @ col)
  1597. # check matrix-matrix
  1598. assert_array_almost_equal(matmul(M, B).toarray(), (M @ B).toarray())
  1599. assert_array_almost_equal(matmul(M.toarray(), B), (M @ B).toarray())
  1600. assert_array_almost_equal(matmul(M, B.toarray()), (M @ B).toarray())
  1601. # check error on matrix-scalar
  1602. assert_raises(ValueError, matmul, M, 1)
  1603. assert_raises(ValueError, matmul, 1, M)
  1604. def test_matvec(self):
  1605. M = self.spcreator([[3,0,0],[0,1,0],[2,0,3.0],[2,3,0]])
  1606. col = array([[1,2,3]]).T
  1607. assert_array_almost_equal(M @ col, M.toarray() @ col)
  1608. # check result dimensions (ticket #514)
  1609. assert_equal((M @ array([1,2,3])).shape,(4,))
  1610. assert_equal((M @ array([[1],[2],[3]])).shape,(4,1))
  1611. assert_equal((M @ matrix([[1],[2],[3]])).shape,(4,1))
  1612. # check result type
  1613. assert_(isinstance(M @ array([1,2,3]), ndarray))
  1614. matrix_or_array = ndarray if self.is_array_test else np.matrix
  1615. assert_(isinstance(M @ matrix([1,2,3]).T, matrix_or_array))
  1616. # ensure exception is raised for improper dimensions
  1617. bad_vecs = [array([1,2]), array([1,2,3,4]), array([[1],[2]]),
  1618. matrix([1,2,3]), matrix([[1],[2]])]
  1619. for x in bad_vecs:
  1620. assert_raises(ValueError, M.__matmul__, x)
  1621. # The current relationship between sparse matrix products and array
  1622. # products is as follows:
  1623. assert_almost_equal(M@array([1,2,3]), dot(M.toarray(),[1,2,3]))
  1624. assert_almost_equal(M@[[1],[2],[3]], np.atleast_2d(dot(M.toarray(),[1,2,3])).T)
  1625. # Note that the result of M * x is dense if x has a singleton dimension.
  1626. # Currently M.matvec(asarray(col)) is rank-1, whereas M.matvec(col)
  1627. # is rank-2. Is this desirable?
  1628. def test_matmat_sparse(self):
  1629. a = matrix([[3,0,0],[0,1,0],[2,0,3.0],[2,3,0]])
  1630. a2 = array([[3,0,0],[0,1,0],[2,0,3.0],[2,3,0]])
  1631. b = matrix([[0,1],[1,0],[0,2]],'d')
  1632. asp = self.spcreator(a)
  1633. bsp = self.spcreator(b)
  1634. assert_array_almost_equal((asp @ bsp).toarray(), a @ b)
  1635. assert_array_almost_equal(asp @ b, a @ b)
  1636. assert_array_almost_equal(a @ bsp, a @ b)
  1637. assert_array_almost_equal(a2 @ bsp, a @ b)
  1638. # Now try performing cross-type multiplication:
  1639. csp = bsp.tocsc()
  1640. c = b
  1641. want = a @ c
  1642. assert_array_almost_equal((asp @ csp).toarray(), want)
  1643. assert_array_almost_equal(asp @ c, want)
  1644. assert_array_almost_equal(a @ csp, want)
  1645. assert_array_almost_equal(a2 @ csp, want)
  1646. csp = bsp.tocsr()
  1647. assert_array_almost_equal((asp @ csp).toarray(), want)
  1648. assert_array_almost_equal(asp @ c, want)
  1649. assert_array_almost_equal(a @ csp, want)
  1650. assert_array_almost_equal(a2 @ csp, want)
  1651. csp = bsp.tocoo()
  1652. assert_array_almost_equal((asp @ csp).toarray(), want)
  1653. assert_array_almost_equal(asp @ c, want)
  1654. assert_array_almost_equal(a @ csp, want)
  1655. assert_array_almost_equal(a2 @ csp, want)
  1656. # Test provided by Andy Fraser, 2006-03-26
  1657. L = 30
  1658. frac = .3
  1659. random.seed(0) # make runs repeatable
  1660. A = zeros((L,2))
  1661. for i in range(L):
  1662. for j in range(2):
  1663. r = random.random()
  1664. if r < frac:
  1665. A[i,j] = r/frac
  1666. A = self.spcreator(A)
  1667. B = A @ A.T
  1668. assert_array_almost_equal(B.toarray(), A.toarray() @ A.T.toarray())
  1669. assert_array_almost_equal(B.toarray(), A.toarray() @ A.toarray().T)
  1670. # check dimension mismatch 2x2 times 3x2
  1671. A = self.spcreator([[1,2],[3,4]])
  1672. B = self.spcreator([[1,2],[3,4],[5,6]])
  1673. assert_raises(ValueError, A.__matmul__, B)
  1674. if self.is_array_test:
  1675. assert_raises(ValueError, A.__mul__, B)
  1676. def test_matmat_dense(self):
  1677. a = [[3,0,0],[0,1,0],[2,0,3.0],[2,3,0]]
  1678. asp = self.spcreator(a)
  1679. # check both array and matrix types
  1680. bs = [array([[1,2],[3,4],[5,6]]), matrix([[1,2],[3,4],[5,6]])]
  1681. for b in bs:
  1682. result = asp @ b
  1683. assert_(isinstance(result, ndarray if self.is_array_test else type(b)))
  1684. assert_equal(result.shape, (4,2))
  1685. assert_equal(result, dot(a,b))
  1686. def test_sparse_format_conversions(self):
  1687. A = sparse.kron([[1,0,2],[0,3,4],[5,0,0]], [[1,2],[0,3]])
  1688. D = A.toarray()
  1689. A = self.spcreator(A)
  1690. for format in ['bsr','coo','csc','csr','dia','dok','lil']:
  1691. a = A.asformat(format)
  1692. assert_equal(a.format,format)
  1693. assert_array_equal(a.toarray(), D)
  1694. b = self.spcreator(D+3j).asformat(format)
  1695. assert_equal(b.format,format)
  1696. assert_array_equal(b.toarray(), D+3j)
  1697. c = self.spcreator(D).asformat(format)
  1698. assert_equal(c.format,format)
  1699. assert_array_equal(c.toarray(), D)
  1700. for format in ['array', 'dense']:
  1701. a = A.asformat(format)
  1702. assert_array_equal(a, D)
  1703. b = self.spcreator(D+3j).asformat(format)
  1704. assert_array_equal(b, D+3j)
  1705. def test_tobsr(self):
  1706. x = array([[1,0,2,0],[0,0,0,0],[0,0,4,5]])
  1707. y = array([[0,1,2],[3,0,5]])
  1708. A = kron(x,y)
  1709. Asp = self.spcreator(A)
  1710. for format in ['bsr']:
  1711. fn = getattr(Asp, 'to' + format)
  1712. for X in [1, 2, 3, 6]:
  1713. for Y in [1, 2, 3, 4, 6, 12]:
  1714. assert_equal(fn(blocksize=(X, Y)).toarray(), A)
  1715. def test_transpose(self):
  1716. dat_1 = self.dat
  1717. dat_2 = np.array([[]])
  1718. matrices = [dat_1, dat_2]
  1719. def check(dtype, j):
  1720. dat = array(matrices[j], dtype=dtype)
  1721. datsp = self.spcreator(dat)
  1722. a = datsp.transpose()
  1723. b = dat.transpose()
  1724. assert_array_equal(a.toarray(), b)
  1725. assert_array_equal(a.transpose().toarray(), dat)
  1726. assert_array_equal(datsp.transpose(axes=(1, 0)).toarray(), b)
  1727. assert_equal(a.dtype, b.dtype)
  1728. # See gh-5987
  1729. empty = self.spcreator((3, 4))
  1730. assert_array_equal(np.transpose(empty).toarray(),
  1731. np.transpose(zeros((3, 4))))
  1732. assert_array_equal(empty.T.toarray(), zeros((4, 3)))
  1733. assert_raises(ValueError, empty.transpose, axes=0)
  1734. for dtype in self.checked_dtypes:
  1735. for j in range(len(matrices)):
  1736. check(dtype, j)
  1737. def test_add_dense(self):
  1738. def check(dtype):
  1739. dat = self.dat_dtypes[dtype]
  1740. datsp = self.datsp_dtypes[dtype]
  1741. # adding a dense matrix to a sparse matrix
  1742. sum1 = dat + datsp
  1743. assert_array_equal(sum1, dat + dat)
  1744. sum2 = datsp + dat
  1745. assert_array_equal(sum2, dat + dat)
  1746. for dtype in self.math_dtypes:
  1747. check(dtype)
  1748. def test_sub_dense(self):
  1749. # subtracting a dense matrix to/from a sparse matrix
  1750. def check(dtype):
  1751. dat = self.dat_dtypes[dtype]
  1752. datsp = self.datsp_dtypes[dtype]
  1753. # Behavior is different for bool.
  1754. if dat.dtype == bool:
  1755. sum1 = dat - datsp
  1756. assert_array_equal(sum1, dat - dat)
  1757. sum2 = datsp - dat
  1758. assert_array_equal(sum2, dat - dat)
  1759. else:
  1760. # Manually add to avoid upcasting from scalar
  1761. # multiplication.
  1762. sum1 = (dat + dat + dat) - datsp
  1763. assert_array_equal(sum1, dat + dat)
  1764. sum2 = (datsp + datsp + datsp) - dat
  1765. assert_array_equal(sum2, dat + dat)
  1766. for dtype in self.math_dtypes:
  1767. if dtype == np.dtype('bool'):
  1768. # boolean array subtraction deprecated in 1.9.0
  1769. continue
  1770. check(dtype)
  1771. def test_maximum_minimum(self):
  1772. A_dense = np.array([[1, 0, 3], [0, 4, 5], [0, 0, 0]])
  1773. B_dense = np.array([[1, 1, 2], [0, 3, 6], [1, -1, 0]])
  1774. A_dense_cpx = np.array([[1, 0, 3], [0, 4+2j, 5], [0, 1j, -1j]])
  1775. def check(dtype, dtype2, btype):
  1776. if np.issubdtype(dtype, np.complexfloating):
  1777. A = self.spcreator(A_dense_cpx.astype(dtype))
  1778. else:
  1779. A = self.spcreator(A_dense.astype(dtype))
  1780. if btype == 'scalar':
  1781. B = dtype2.type(1)
  1782. elif btype == 'scalar2':
  1783. B = dtype2.type(-1)
  1784. elif btype == 'dense':
  1785. B = B_dense.astype(dtype2)
  1786. elif btype == 'sparse':
  1787. B = self.spcreator(B_dense.astype(dtype2))
  1788. else:
  1789. raise ValueError()
  1790. with warnings.catch_warnings():
  1791. warnings.filterwarnings(
  1792. "ignore",
  1793. "Taking (maximum|minimum) with a (positive|negative) number "
  1794. "results in a dense matrix",
  1795. SparseEfficiencyWarning,
  1796. )
  1797. max_s = A.maximum(B)
  1798. min_s = A.minimum(B)
  1799. max_d = np.maximum(toarray(A), toarray(B))
  1800. assert_array_equal(toarray(max_s), max_d)
  1801. assert_equal(max_s.dtype, max_d.dtype)
  1802. min_d = np.minimum(toarray(A), toarray(B))
  1803. assert_array_equal(toarray(min_s), min_d)
  1804. assert_equal(min_s.dtype, min_d.dtype)
  1805. for dtype in self.math_dtypes:
  1806. for dtype2 in [np.int8, np.float64, np.complex128]:
  1807. for btype in ['scalar', 'scalar2', 'dense', 'sparse']:
  1808. check(np.dtype(dtype), np.dtype(dtype2), btype)
  1809. def test_copy(self):
  1810. # Check whether the copy=True and copy=False keywords work
  1811. A = self.datsp
  1812. # check that copy preserves format
  1813. assert_equal(A.copy().format, A.format)
  1814. assert_equal(A.__class__(A,copy=True).format, A.format)
  1815. assert_equal(A.__class__(A,copy=False).format, A.format)
  1816. assert_equal(A.copy().toarray(), A.toarray())
  1817. assert_equal(A.__class__(A, copy=True).toarray(), A.toarray())
  1818. assert_equal(A.__class__(A, copy=False).toarray(), A.toarray())
  1819. # check that XXX_array.toXXX() works
  1820. toself = getattr(A,'to' + A.format)
  1821. assert_(toself() is A)
  1822. assert_(toself(copy=False) is A)
  1823. assert_equal(toself(copy=True).format, A.format)
  1824. assert_equal(toself(copy=True).toarray(), A.toarray())
  1825. # check whether the data is copied?
  1826. assert_(not sparse_may_share_memory(A.copy(), A))
  1827. # test that __iter__ is compatible with NumPy matrix
  1828. def test_iterator(self):
  1829. B = self.asdense(np.arange(50).reshape(5, 10))
  1830. A = self.spcreator(B)
  1831. for x, y in zip(A, B):
  1832. assert_equal(x.toarray(), y)
  1833. def test_size_zero_matrix_arithmetic(self):
  1834. # Test basic matrix arithmetic with shapes like (0,0), (10,0),
  1835. # (0, 3), etc.
  1836. mat = array([])
  1837. a = mat.reshape((0, 0))
  1838. b = mat.reshape((0, 1))
  1839. c = mat.reshape((0, 5))
  1840. d = mat.reshape((1, 0))
  1841. e = mat.reshape((5, 0))
  1842. f = np.ones([5, 5])
  1843. asp = self.spcreator(a)
  1844. bsp = self.spcreator(b)
  1845. csp = self.spcreator(c)
  1846. dsp = self.spcreator(d)
  1847. esp = self.spcreator(e)
  1848. fsp = self.spcreator(f)
  1849. # matrix product.
  1850. assert_array_equal(asp.dot(asp).toarray(), np.dot(a, a))
  1851. assert_array_equal(bsp.dot(dsp).toarray(), np.dot(b, d))
  1852. assert_array_equal(dsp.dot(bsp).toarray(), np.dot(d, b))
  1853. assert_array_equal(csp.dot(esp).toarray(), np.dot(c, e))
  1854. assert_array_equal(csp.dot(fsp).toarray(), np.dot(c, f))
  1855. assert_array_equal(esp.dot(csp).toarray(), np.dot(e, c))
  1856. assert_array_equal(dsp.dot(csp).toarray(), np.dot(d, c))
  1857. assert_array_equal(fsp.dot(esp).toarray(), np.dot(f, e))
  1858. # bad matrix products
  1859. assert_raises(ValueError, dsp.dot, e)
  1860. assert_raises(ValueError, asp.dot, d)
  1861. # elemente-wise multiplication
  1862. assert_array_equal(asp.multiply(asp).toarray(), np.multiply(a, a))
  1863. assert_array_equal(bsp.multiply(bsp).toarray(), np.multiply(b, b))
  1864. assert_array_equal(dsp.multiply(dsp).toarray(), np.multiply(d, d))
  1865. assert_array_equal(asp.multiply(a).toarray(), np.multiply(a, a))
  1866. assert_array_equal(bsp.multiply(b).toarray(), np.multiply(b, b))
  1867. assert_array_equal(dsp.multiply(d).toarray(), np.multiply(d, d))
  1868. assert_array_equal(asp.multiply(6).toarray(), np.multiply(a, 6))
  1869. assert_array_equal(bsp.multiply(6).toarray(), np.multiply(b, 6))
  1870. assert_array_equal(dsp.multiply(6).toarray(), np.multiply(d, 6))
  1871. # bad element-wise multiplication
  1872. assert_raises(ValueError, asp.multiply, c)
  1873. assert_raises(ValueError, esp.multiply, c)
  1874. # Addition
  1875. assert_array_equal(asp.__add__(asp).toarray(), a.__add__(a))
  1876. assert_array_equal(bsp.__add__(bsp).toarray(), b.__add__(b))
  1877. assert_array_equal(dsp.__add__(dsp).toarray(), d.__add__(d))
  1878. # bad addition
  1879. assert_raises(ValueError, asp.__add__, dsp)
  1880. assert_raises(ValueError, bsp.__add__, asp)
  1881. def test_size_zero_conversions(self):
  1882. mat = array([])
  1883. a = mat.reshape((0, 0))
  1884. b = mat.reshape((0, 5))
  1885. c = mat.reshape((5, 0))
  1886. for m in [a, b, c]:
  1887. spm = self.spcreator(m)
  1888. assert_array_equal(spm.tocoo().toarray(), m)
  1889. assert_array_equal(spm.tocsr().toarray(), m)
  1890. assert_array_equal(spm.tocsc().toarray(), m)
  1891. assert_array_equal(spm.tolil().toarray(), m)
  1892. assert_array_equal(spm.todok().toarray(), m)
  1893. assert_array_equal(spm.tobsr().toarray(), m)
  1894. def test_dtype_check(self):
  1895. a = np.array([[3.5, 0, 1.1], [0, 0, 0]], dtype=np.float16)
  1896. with assert_raises(ValueError, match="does not support dtype"):
  1897. self.spcreator(a)
  1898. A32 = self.spcreator(a.astype(np.float32))
  1899. with assert_raises(ValueError, match="does not support dtype"):
  1900. self.spcreator(A32, dtype=np.float16)
  1901. def test_pickle(self):
  1902. import pickle
  1903. def check():
  1904. with warnings.catch_warnings():
  1905. warnings.simplefilter("ignore", SparseEfficiencyWarning)
  1906. datsp = self.datsp.copy()
  1907. for protocol in range(pickle.HIGHEST_PROTOCOL):
  1908. sploaded = pickle.loads(pickle.dumps(datsp, protocol=protocol))
  1909. assert_equal(datsp.shape, sploaded.shape)
  1910. assert_array_equal(datsp.toarray(), sploaded.toarray())
  1911. assert_equal(datsp.format, sploaded.format)
  1912. # Hacky check for class member equality. This assumes that
  1913. # all instance variables are one of:
  1914. # 1. Plain numpy ndarrays
  1915. # 2. Tuples of ndarrays
  1916. # 3. Types that support equality comparison with ==
  1917. for key, val in datsp.__dict__.items():
  1918. if isinstance(val, np.ndarray):
  1919. assert_array_equal(val, sploaded.__dict__[key])
  1920. elif (isinstance(val, tuple) and val
  1921. and isinstance(val[0], np.ndarray)):
  1922. assert_array_equal(val, sploaded.__dict__[key])
  1923. else:
  1924. assert_(val == sploaded.__dict__[key])
  1925. check()
  1926. def test_unary_ufunc_overrides(self):
  1927. def check(name):
  1928. if name == "sign":
  1929. pytest.skip("sign conflicts with comparison op "
  1930. "support on Numpy")
  1931. if self.datsp.format in ["dok", "lil"]:
  1932. pytest.skip("Unary ops not implemented for dok/lil")
  1933. ufunc = getattr(np, name)
  1934. X = self.spcreator(np.arange(20).reshape(4, 5) / 20.)
  1935. X0 = ufunc(X.toarray())
  1936. X2 = ufunc(X)
  1937. assert_array_equal(X2.toarray(), X0)
  1938. for name in ["sin", "tan", "arcsin", "arctan", "sinh", "tanh",
  1939. "arcsinh", "arctanh", "rint", "sign", "expm1", "log1p",
  1940. "deg2rad", "rad2deg", "floor", "ceil", "trunc", "sqrt",
  1941. "abs"]:
  1942. check(name)
  1943. def test_resize(self):
  1944. # resize(shape) resizes the matrix in-place
  1945. D = np.array([[1, 0, 3, 4],
  1946. [2, 0, 0, 0],
  1947. [3, 0, 0, 0]])
  1948. S = self.spcreator(D)
  1949. assert_(S.resize((3, 2)) is None)
  1950. assert_array_equal(S.toarray(), [[1, 0],
  1951. [2, 0],
  1952. [3, 0]])
  1953. S.resize((2, 2))
  1954. assert_array_equal(S.toarray(), [[1, 0],
  1955. [2, 0]])
  1956. S.resize((3, 2))
  1957. assert_array_equal(S.toarray(), [[1, 0],
  1958. [2, 0],
  1959. [0, 0]])
  1960. S.resize((3, 3))
  1961. assert_array_equal(S.toarray(), [[1, 0, 0],
  1962. [2, 0, 0],
  1963. [0, 0, 0]])
  1964. # test no-op
  1965. S.resize((3, 3))
  1966. assert_array_equal(S.toarray(), [[1, 0, 0],
  1967. [2, 0, 0],
  1968. [0, 0, 0]])
  1969. # test *args
  1970. S.resize(3, 2)
  1971. assert_array_equal(S.toarray(), [[1, 0],
  1972. [2, 0],
  1973. [0, 0]])
  1974. if self.is_array_test and S.format in ["coo", "csr"]:
  1975. S.resize(1)
  1976. else:
  1977. assert_raises((ValueError, NotImplementedError, IndexError), S.resize, 1)
  1978. for bad_shape in [(-1, 2), (2, -1), (1, 2, 3)]:
  1979. assert_raises(ValueError, S.resize, bad_shape)
  1980. def test_constructor1_base(self):
  1981. A = self.datsp
  1982. self_format = A.format
  1983. C = A.__class__(A, copy=False)
  1984. assert_array_equal_dtype(A.toarray(), C.toarray())
  1985. if self_format not in NON_ARRAY_BACKED_FORMATS:
  1986. assert_(sparse_may_share_memory(A, C))
  1987. C = A.__class__(A, dtype=A.dtype, copy=False)
  1988. assert_array_equal_dtype(A.toarray(), C.toarray())
  1989. if self_format not in NON_ARRAY_BACKED_FORMATS:
  1990. assert_(sparse_may_share_memory(A, C))
  1991. C = A.__class__(A, dtype=np.float32, copy=False)
  1992. assert_array_equal(A.toarray(), C.toarray())
  1993. C = A.__class__(A, copy=True)
  1994. assert_array_equal_dtype(A.toarray(), C.toarray())
  1995. assert_(not sparse_may_share_memory(A, C))
  1996. for other_format in ['csr', 'csc', 'coo', 'dia', 'dok', 'lil']:
  1997. if other_format == self_format:
  1998. continue
  1999. B = A.asformat(other_format)
  2000. C = A.__class__(B, copy=False)
  2001. assert_array_equal_dtype(A.toarray(), C.toarray())
  2002. C = A.__class__(B, copy=True)
  2003. assert_array_equal_dtype(A.toarray(), C.toarray())
  2004. assert_(not sparse_may_share_memory(B, C))
  2005. class _TestInplaceArithmetic:
  2006. def test_inplace_dense(self):
  2007. a = np.ones((3, 4))
  2008. b = self.spcreator(a)
  2009. x = a.copy()
  2010. y = a.copy()
  2011. x += a
  2012. y += b
  2013. assert_array_equal(x, y)
  2014. x = a.copy()
  2015. y = a.copy()
  2016. x -= a
  2017. y -= b
  2018. assert_array_equal(x, y)
  2019. if self.is_array_test:
  2020. # Elementwise multiply from sparray.__rmul__
  2021. x = a.copy()
  2022. y = a.copy()
  2023. with assert_raises(ValueError, match="inconsistent shapes"):
  2024. x *= b.T
  2025. x = x * a
  2026. y *= b
  2027. assert_array_equal(x, y.toarray())
  2028. else:
  2029. # Matrix multiply from spmatrix.__rmul__
  2030. x = a.copy()
  2031. y = a.copy()
  2032. with assert_raises(ValueError, match="dimension mismatch"):
  2033. x *= b
  2034. x = x.dot(a.T)
  2035. y *= b.T
  2036. assert_array_equal(x, y)
  2037. # Matrix multiply from __rmatmul__
  2038. y = a.copy()
  2039. y @= b.T
  2040. x = a.copy()
  2041. y = a.copy()
  2042. with assert_raises(ValueError, match="dimension mismatch"):
  2043. x @= b
  2044. x = x.dot(a.T)
  2045. y @= b.T
  2046. assert_array_equal(x, y)
  2047. # Floor division is not supported
  2048. with assert_raises(TypeError, match="unsupported operand"):
  2049. x //= b
  2050. def test_imul_scalar(self):
  2051. def check(dtype):
  2052. dat = self.dat_dtypes[dtype]
  2053. datsp = self.datsp_dtypes[dtype]
  2054. # Avoid implicit casting.
  2055. if np.can_cast(int, dtype, casting='same_kind'):
  2056. a = datsp.copy()
  2057. a *= 2
  2058. b = dat.copy()
  2059. b *= 2
  2060. assert_array_equal(b, a.toarray())
  2061. if np.can_cast(float, dtype, casting='same_kind'):
  2062. a = datsp.copy()
  2063. a *= 17.3
  2064. b = dat.copy()
  2065. b *= 17.3
  2066. assert_array_equal(b, a.toarray())
  2067. for dtype in self.math_dtypes:
  2068. check(dtype)
  2069. def test_idiv_scalar(self):
  2070. def check(dtype):
  2071. dat = self.dat_dtypes[dtype]
  2072. datsp = self.datsp_dtypes[dtype]
  2073. if np.can_cast(int, dtype, casting='same_kind'):
  2074. a = datsp.copy()
  2075. a /= 2
  2076. b = dat.copy()
  2077. b /= 2
  2078. assert_array_equal(b, a.toarray())
  2079. if np.can_cast(float, dtype, casting='same_kind'):
  2080. a = datsp.copy()
  2081. a /= 17.3
  2082. b = dat.copy()
  2083. b /= 17.3
  2084. assert_array_equal(b, a.toarray())
  2085. for dtype in self.math_dtypes:
  2086. # /= should only be used with float dtypes to avoid implicit
  2087. # casting.
  2088. if not np.can_cast(dtype, np.dtype(int)):
  2089. check(dtype)
  2090. def test_inplace_success(self):
  2091. # Inplace ops should work even if a specialized version is not
  2092. # implemented, falling back to x = x <op> y
  2093. a = self.spcreator(np.eye(5))
  2094. b = self.spcreator(np.eye(5))
  2095. bp = self.spcreator(np.eye(5))
  2096. b += a
  2097. bp = bp + a
  2098. assert_allclose(b.toarray(), bp.toarray())
  2099. if self.is_array_test:
  2100. b *= a
  2101. bp = bp * a
  2102. assert_allclose(b.toarray(), bp.toarray())
  2103. b @= a
  2104. bp = bp @ a
  2105. assert_allclose(b.toarray(), bp.toarray())
  2106. b -= a
  2107. bp = bp - a
  2108. assert_allclose(b.toarray(), bp.toarray())
  2109. with assert_raises(TypeError, match="unsupported operand"):
  2110. a //= b
  2111. class _TestGetSet:
  2112. def test_getelement(self):
  2113. def check(dtype):
  2114. D = array([[1,0,0],
  2115. [4,3,0],
  2116. [0,2,0],
  2117. [0,0,0]], dtype=dtype)
  2118. A = self.spcreator(D)
  2119. M,N = D.shape
  2120. for i in range(-M, M):
  2121. for j in range(-N, N):
  2122. assert_equal(A[i,j], D[i,j])
  2123. assert_equal(type(A[1,1]), dtype)
  2124. for ij in [(0,3),(-1,3),(4,0),(4,3),(4,-1), (1, 2, 3)]:
  2125. assert_raises((IndexError, TypeError), A.__getitem__, ij)
  2126. for dtype in supported_dtypes:
  2127. check(np.dtype(dtype))
  2128. def test_setelement(self):
  2129. def check(dtype, scalar_container):
  2130. A = self.spcreator((3, 4), dtype=dtype)
  2131. with warnings.catch_warnings():
  2132. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  2133. A[0, 0] = scalar_container(dtype.type(0)) # bug 870
  2134. A[1, 2] = scalar_container(dtype.type(4.0))
  2135. A[0, 1] = scalar_container(dtype.type(3))
  2136. A[2, 0] = scalar_container(dtype.type(2.0))
  2137. A[0, -1] = scalar_container(dtype.type(8))
  2138. A[-1, -2] = scalar_container(dtype.type(7))
  2139. A[0, 1] = scalar_container(dtype.type(5))
  2140. if dtype != np.bool_:
  2141. assert_array_equal(
  2142. A.toarray(), [[0, 5, 0, 8], [0, 0, 4, 0], [2, 0, 7, 0]]
  2143. )
  2144. for ij in [(0, 4), (-1, 4), (3, 0), (3, 4), (3, -1)]:
  2145. assert_raises(IndexError, A.__setitem__, ij, 123.0)
  2146. for v in [[1, 2, 3], array([1, 2, 3])]:
  2147. assert_raises(ValueError, A.__setitem__, (0, 0), v)
  2148. if not np.issubdtype(dtype, np.complexfloating) and dtype != np.bool_:
  2149. for v in [3j]:
  2150. assert_raises(TypeError, A.__setitem__, (0, 0), v)
  2151. scalar_containers = [
  2152. lambda x: csr_array(np.array([[x]])), np.array, lambda x: x
  2153. ]
  2154. for scalar_container in scalar_containers:
  2155. for dtype in supported_dtypes:
  2156. check(np.dtype(dtype), scalar_container)
  2157. def test_negative_index_assignment(self):
  2158. # Regression test for GitHub issue 4428.
  2159. def check(dtype):
  2160. A = self.spcreator((3, 10), dtype=dtype)
  2161. with warnings.catch_warnings():
  2162. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  2163. A[0, -4] = 1
  2164. assert_equal(A[0, -4], 1)
  2165. for dtype in self.math_dtypes:
  2166. check(np.dtype(dtype))
  2167. def test_scalar_assign_2(self):
  2168. n, m = (5, 10)
  2169. def _test_set(i, j, nitems):
  2170. msg = f"{i!r} ; {j!r} ; {nitems!r}"
  2171. A = self.spcreator((n, m))
  2172. with warnings.catch_warnings():
  2173. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  2174. A[i, j] = 1
  2175. assert_almost_equal(A.sum(), nitems, err_msg=msg)
  2176. assert_almost_equal(A[i, j], 1, err_msg=msg)
  2177. # [i,j]
  2178. for i, j in [(2, 3), (-1, 8), (-1, -2), (array(-1), -2), (-1, array(-2)),
  2179. (array(-1), array(-2))]:
  2180. _test_set(i, j, 1)
  2181. def test_index_scalar_assign(self):
  2182. A = self.spcreator((5, 5))
  2183. B = np.zeros((5, 5))
  2184. with warnings.catch_warnings():
  2185. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  2186. for C in [A, B]:
  2187. C[0,1] = 1
  2188. C[3,0] = 4
  2189. C[3,0] = 9
  2190. assert_array_equal(A.toarray(), B)
  2191. @pytest.mark.thread_unsafe(reason="fails in parallel")
  2192. class _TestSolve:
  2193. def test_solve(self):
  2194. # Test whether the lu_solve command segfaults, as reported by Nils
  2195. # Wagner for a 64-bit machine, 02 March 2005 (EJS)
  2196. n = 20
  2197. np.random.seed(0) # make tests repeatable
  2198. A = zeros((n,n), dtype=complex)
  2199. x = np.random.rand(n)
  2200. y = np.random.rand(n-1)+1j*np.random.rand(n-1)
  2201. r = np.random.rand(n)
  2202. for i in range(len(x)):
  2203. A[i,i] = x[i]
  2204. for i in range(len(y)):
  2205. A[i,i+1] = y[i]
  2206. A[i+1,i] = conjugate(y[i])
  2207. A = self.spcreator(A)
  2208. with warnings.catch_warnings():
  2209. warnings.filterwarnings(
  2210. "ignore", "splu converted its input to CSC format",
  2211. SparseEfficiencyWarning)
  2212. x = splu(A).solve(r)
  2213. assert_almost_equal(A @ x,r)
  2214. class _TestSlicing:
  2215. def test_dtype_preservation(self):
  2216. assert_equal(self.spcreator((1,10), dtype=np.int16)[0,1:5].dtype, np.int16)
  2217. assert_equal(self.spcreator((1,10), dtype=np.int32)[0,1:5].dtype, np.int32)
  2218. assert_equal(self.spcreator((1,10), dtype=np.float32)[0,1:5].dtype, np.float32)
  2219. assert_equal(self.spcreator((1,10), dtype=np.float64)[0,1:5].dtype, np.float64)
  2220. def test_dtype_preservation_empty_slice(self):
  2221. # This should be parametrized with pytest, but something in the parent
  2222. # class creation used in this file breaks pytest.mark.parametrize.
  2223. for dt in [np.int16, np.int32, np.float32, np.float64]:
  2224. A = self.spcreator((3, 2), dtype=dt)
  2225. assert_equal(A[:, 0:0:2].dtype, dt)
  2226. assert_equal(A[0:0:2, :].dtype, dt)
  2227. assert_equal(A[0, 0:0:2].dtype, dt)
  2228. assert_equal(A[0:0:2, 0].dtype, dt)
  2229. def test_get_horiz_slice(self):
  2230. B = self.asdense(arange(50.).reshape(5,10))
  2231. A = self.spcreator(B)
  2232. r0, r1, r2 = (0, 1, 2) if self.is_array_test else ([0], [1], [2])
  2233. assert_array_equal(B[r1, :], A[1, :].toarray())
  2234. assert_array_equal(B[r1, 2:5], A[1, 2:5].toarray())
  2235. C = self.asdense([[1, 2, 1], [4, 0, 6], [0, 0, 0], [0, 0, 1]])
  2236. D = self.spcreator(C)
  2237. assert_array_equal(C[r1, 1:3], D[1, 1:3].toarray())
  2238. # Now test slicing when a row contains only zeros
  2239. E = self.asdense([[1, 2, 1], [4, 0, 0], [0, 0, 0], [0, 0, 1]])
  2240. F = self.spcreator(E)
  2241. assert_array_equal(E[r1, 1:3], F[1, 1:3].toarray())
  2242. assert_array_equal(E[r2, -2:], F[2, -2:].toarray())
  2243. # The following should raise exceptions:
  2244. assert_raises(IndexError, A.__getitem__, (slice(None), 11))
  2245. assert_raises(IndexError, A.__getitem__, (6, slice(3, 7)))
  2246. def test_get_vert_slice(self):
  2247. B = arange(50.).reshape(5, 10)
  2248. A = self.spcreator(B)
  2249. c0, c1, c2 = (0, 1, 2) if self.is_array_test else ([0], [1], [2])
  2250. assert_array_equal(B[2:5, c0], A[2:5, 0].toarray())
  2251. assert_array_equal(B[:, c1], A[:, 1].toarray())
  2252. C = array([[1, 2, 1], [4, 0, 6], [0, 0, 0], [0, 0, 1]])
  2253. D = self.spcreator(C)
  2254. assert_array_equal(C[1:3, c1], D[1:3, 1].toarray())
  2255. assert_array_equal(C[:, c2], D[:, 2].toarray())
  2256. # Now test slicing when a column contains only zeros
  2257. E = array([[1, 0, 1], [4, 0, 0], [0, 0, 0], [0, 0, 1]])
  2258. F = self.spcreator(E)
  2259. assert_array_equal(E[:, c1], F[:, 1].toarray())
  2260. assert_array_equal(E[-2:, c2], F[-2:, 2].toarray())
  2261. # The following should raise exceptions:
  2262. assert_raises(IndexError, A.__getitem__, (slice(None), 11))
  2263. assert_raises(IndexError, A.__getitem__, (6, slice(3, 7)))
  2264. def test_get_slices(self):
  2265. B = arange(50.).reshape(5, 10)
  2266. A = self.spcreator(B)
  2267. assert_array_equal(A[2:5, 0:3].toarray(), B[2:5, 0:3])
  2268. assert_array_equal(A[1:, :-1].toarray(), B[1:, :-1])
  2269. assert_array_equal(A[:-1, 1:].toarray(), B[:-1, 1:])
  2270. # Now test slicing when a column contains only zeros
  2271. E = array([[1, 0, 1], [4, 0, 0], [0, 0, 0], [0, 0, 1]])
  2272. F = self.spcreator(E)
  2273. assert_array_equal(E[1:2, 1:2], F[1:2, 1:2].toarray())
  2274. assert_array_equal(E[:, 1:], F[:, 1:].toarray())
  2275. def test_non_unit_stride_2d_indexing(self):
  2276. # Regression test -- used to silently ignore the stride.
  2277. v0 = np.random.rand(50, 50)
  2278. try:
  2279. v = self.spcreator(v0)[0:25:2, 2:30:3]
  2280. except ValueError:
  2281. # if unsupported
  2282. raise pytest.skip("feature not implemented")
  2283. assert_array_equal(v.toarray(), v0[0:25:2, 2:30:3])
  2284. def test_slicing_2(self):
  2285. B = self.asdense(arange(50).reshape(5,10))
  2286. A = self.spcreator(B)
  2287. # [i,j]
  2288. assert_equal(A[2,3], B[2,3])
  2289. assert_equal(A[-1,8], B[-1,8])
  2290. assert_equal(A[-1,-2],B[-1,-2])
  2291. assert_equal(A[array(-1),-2],B[-1,-2])
  2292. assert_equal(A[-1,array(-2)],B[-1,-2])
  2293. assert_equal(A[array(-1),array(-2)],B[-1,-2])
  2294. # [i,1:2]
  2295. assert_equal(A[2, :].toarray(), B[2, :])
  2296. assert_equal(A[2, 5:-2].toarray(), B[2, 5:-2])
  2297. assert_equal(A[array(2), 5:-2].toarray(), B[2, 5:-2])
  2298. # [1:2,j]
  2299. assert_equal(A[:, 2].toarray(), B[:, 2])
  2300. assert_equal(A[3:4, 9].toarray(), B[3:4, 9])
  2301. assert_equal(A[1:4, -5].toarray(), B[1:4, -5])
  2302. assert_equal(A[2:-1, 3].toarray(), B[2:-1, 3])
  2303. assert_equal(A[2:-1, array(3)].toarray(), B[2:-1, 3])
  2304. # [1:2,1:2]
  2305. assert_equal(A[1:2, 1:2].toarray(), B[1:2, 1:2])
  2306. assert_equal(A[4:, 3:].toarray(), B[4:, 3:])
  2307. assert_equal(A[:4, :5].toarray(), B[:4, :5])
  2308. assert_equal(A[2:-1, :5].toarray(), B[2:-1, :5])
  2309. # [i]
  2310. assert_equal(A[1, :].toarray(), B[1, :])
  2311. assert_equal(A[-2, :].toarray(), B[-2, :])
  2312. assert_equal(A[array(-2), :].toarray(), B[-2, :])
  2313. # [1:2]
  2314. assert_equal(A[1:4].toarray(), B[1:4])
  2315. assert_equal(A[1:-2].toarray(), B[1:-2])
  2316. # Check bug reported by Robert Cimrman:
  2317. # http://thread.gmane.org/gmane.comp.python.scientific.devel/7986 (dead link)
  2318. s = slice(int8(2),int8(4),None)
  2319. assert_equal(A[s, :].toarray(), B[2:4, :])
  2320. assert_equal(A[:, s].toarray(), B[:, 2:4])
  2321. @pytest.mark.fail_slow(2)
  2322. def test_slicing_3(self):
  2323. B = self.asdense(arange(50).reshape(5,10))
  2324. A = self.spcreator(B)
  2325. s_ = np.s_
  2326. slices = [s_[:2], s_[1:2], s_[3:], s_[3::2],
  2327. s_[15:20], s_[3:2],
  2328. s_[8:3:-1], s_[4::-2], s_[:5:-1],
  2329. 0, 1, s_[:], s_[1:5], -1, -2, -5,
  2330. array(-1), np.int8(-3)]
  2331. def check_1(a):
  2332. x = A[a]
  2333. y = B[a]
  2334. if y.shape == ():
  2335. assert_equal(x, y, repr(a))
  2336. else:
  2337. if x.size == 0 and y.size == 0:
  2338. pass
  2339. else:
  2340. assert_array_equal(x.toarray(), y, repr(a))
  2341. for j, a in enumerate(slices):
  2342. check_1(a)
  2343. def check_2(a, b):
  2344. # Indexing np.matrix with 0-d arrays seems to be broken,
  2345. # as they seem not to be treated as scalars.
  2346. # https://github.com/numpy/numpy/issues/3110
  2347. if isinstance(a, np.ndarray):
  2348. ai = int(a)
  2349. else:
  2350. ai = a
  2351. if isinstance(b, np.ndarray):
  2352. bi = int(b)
  2353. else:
  2354. bi = b
  2355. x = A[a, b]
  2356. y = B[ai, bi]
  2357. if y.shape == ():
  2358. assert_equal(x, y, repr((a, b)))
  2359. else:
  2360. if x.size == 0 and y.size == 0:
  2361. pass
  2362. else:
  2363. assert_array_equal(x.toarray(), y, repr((a, b)))
  2364. for i, a in enumerate(slices):
  2365. for j, b in enumerate(slices):
  2366. check_2(a, b)
  2367. # Check out of bounds etc. systematically
  2368. extra_slices = []
  2369. for a, b, c in itertools.product(*([(None, 0, 1, 2, 5, 15,
  2370. -1, -2, 5, -15)]*3)):
  2371. if c == 0:
  2372. continue
  2373. extra_slices.append(slice(a, b, c))
  2374. for a in extra_slices:
  2375. check_2(a, a)
  2376. check_2(a, -2)
  2377. check_2(-2, a)
  2378. def test_None_slicing(self):
  2379. B = self.asdense(arange(50).reshape(5,10))
  2380. A = self.spcreator(B)
  2381. assert A[1, 2].ndim == 0
  2382. assert A[None, 1, 2:4].shape == (1, 2)
  2383. assert A[None, 1, 2, None].shape == (1, 1)
  2384. # see gh-22458
  2385. assert A[None, 1].shape == (1, 10)
  2386. assert A[1, None].shape == (1, 10)
  2387. assert A[None, 1, :].shape == (1, 10)
  2388. assert A[1, None, :].shape == (1, 10)
  2389. assert A[1, :, None].shape == (10, 1)
  2390. assert A[None, 1:3, 2].shape == B[None, 1:3, 2].shape == (1, 2)
  2391. assert A[1:3, None, 2].shape == B[1:3, None, 2].shape == (2, 1)
  2392. assert A[1:3, 2, None].shape == B[1:3, 2, None].shape == (2, 1)
  2393. assert A[None, 1, 2:4].shape == B[None, 1, 2:4].shape == (1, 2)
  2394. assert A[1, None, 2:4].shape == B[1, None, 2:4].shape == (1, 2)
  2395. assert A[1, 2:4, None].shape == B[1, 2:4, None].shape == (2, 1)
  2396. # different for spmatrix
  2397. if self.is_array_test:
  2398. assert A[1:3, 2].shape == B[1:3, 2].shape == (2,)
  2399. assert A[1, 2:4].shape == B[1, 2:4].shape == (2,)
  2400. assert A[None, 1, 2].shape == B[None, 1, 2].shape == (1,)
  2401. assert A[1, None, 2].shape == B[1, None, 2].shape == (1,)
  2402. assert A[1, 2, None].shape == B[1, 2, None].shape == (1,)
  2403. else:
  2404. assert A[1, 2:4].shape == B[1, 2:4].shape == (1, 2)
  2405. assert A[1:3, 2].shape == B[1:3, 2].shape == (2, 1)
  2406. assert A[None, 1, 2].shape == B[None, 1, 2].shape == (1, 1)
  2407. assert A[1, None, 2].shape == B[1, None, 2].shape == (1, 1)
  2408. assert A[1, 2, None].shape == B[1, 2, None].shape == (1, 1)
  2409. def test_ellipsis_slicing(self):
  2410. b = self.asdense(arange(50).reshape(5,10))
  2411. a = self.spcreator(b)
  2412. assert_array_equal(a[...].toarray(), b[...])
  2413. assert_array_equal(a[...,].toarray(), b[...,])
  2414. assert_array_equal(a[4, ...].toarray(), b[4, ...])
  2415. assert_array_equal(a[..., 4].toarray(), b[..., 4])
  2416. assert_array_equal(a[..., 5].toarray(), b[..., 5])
  2417. with pytest.raises(IndexError, match='index .5. out of range'):
  2418. a[5, ...]
  2419. with pytest.raises(IndexError, match='index .10. out of range'):
  2420. a[..., 10]
  2421. with pytest.raises(IndexError, match='index .5. out of range'):
  2422. a.T[..., 5]
  2423. assert_array_equal(a[1:, ...].toarray(), b[1:, ...])
  2424. assert_array_equal(a[..., 1:].toarray(), b[..., 1:])
  2425. assert_array_equal(a[:2, ...].toarray(), b[:2, ...])
  2426. assert_array_equal(a[..., :2].toarray(), b[..., :2])
  2427. # check slice limit outside range
  2428. assert_array_equal(a[:5, ...].toarray(), b[:5, ...])
  2429. assert_array_equal(a[..., :5].toarray(), b[..., :5])
  2430. assert_array_equal(a[5:, ...].toarray(), b[5:, ...])
  2431. assert_array_equal(a[..., 5:].toarray(), b[..., 5:])
  2432. assert_array_equal(a[10:, ...].toarray(), b[10:, ...])
  2433. assert_array_equal(a[..., 10:].toarray(), b[..., 10:])
  2434. # ellipsis should be ignored
  2435. assert_array_equal(a[1:, 1, ...].toarray(), b[1:, 1, ...])
  2436. assert_array_equal(a[1, ..., 1:].toarray(), b[1, ..., 1:])
  2437. assert_array_equal(a[..., 1, 1:].toarray(), b[1, ..., 1:])
  2438. assert_array_equal(a[:2, 1, ...].toarray(), b[:2, 1, ...])
  2439. assert_array_equal(a[1, ..., :2].toarray(), b[1, ..., :2])
  2440. assert_array_equal(a[..., 1, :2].toarray(), b[1, ..., :2])
  2441. # These return ints
  2442. assert_equal(a[1, 1, ...], b[1, 1, ...])
  2443. assert_equal(a[1, ..., 1], b[1, ..., 1])
  2444. def test_ellipsis_fancy_bool(self):
  2445. numpy_a = self.asdense(arange(50).reshape(5, 10))
  2446. a = self.spcreator(numpy_a)
  2447. ix5 = [True, False, True, False, True]
  2448. ix10 = [False] * 5 + ix5 # same number of True values as ix5
  2449. ix10_6True = ix5 + ix5 # not same number of True values as ix5
  2450. full_ix = [ix10] * 5
  2451. assert_array_equal(toarray(a[full_ix, ...]), numpy_a[full_ix, ...])
  2452. assert_array_equal(toarray(a[..., full_ix]), numpy_a[..., full_ix])
  2453. assert_array_equal(toarray(a[ix5, ...]), numpy_a[ix5, ...])
  2454. assert_array_equal(toarray(a[..., ix10]), numpy_a[..., ix10])
  2455. assert_array_equal(toarray(a[ix5, ..., ix10]), numpy_a[ix5, ..., ix10])
  2456. assert_array_equal(toarray(a[..., ix5, ix10]), numpy_a[..., ix5, ix10])
  2457. assert_array_equal(toarray(a[ix5, ix10, ...]), numpy_a[ix5, ix10, ...])
  2458. with assert_raises(IndexError, match="shape mismatch"):
  2459. a[ix5, ix10_6True]
  2460. def test_ellipsis_fancy_slicing(self):
  2461. b = self.asdense(arange(50).reshape(5, 10))
  2462. a = self.spcreator(b)
  2463. assert_array_equal(a[[4], ...].toarray(), b[[4], ...])
  2464. assert_array_equal(a[[2, 4], ...].toarray(), b[[2, 4], ...])
  2465. assert_array_equal(a[..., [4]].toarray(), b[..., [4]])
  2466. assert_array_equal(a[..., [2, 4]].toarray(), b[..., [2, 4]])
  2467. assert_array_equal(a[[4], 1, ...].toarray(), b[[4], 1, ...])
  2468. assert_array_equal(a[[2, 4], 1, ...].toarray(), b[[2, 4], 1, ...])
  2469. assert_array_equal(a[[4], ..., 1].toarray(), b[[4], ..., 1])
  2470. assert_array_equal(a[..., [4], 1].toarray(), b[..., [4], 1])
  2471. # fancy index gives dense
  2472. assert_array_equal(toarray(a[[2, 4], ..., [2, 4]]), b[[2, 4], ..., [2, 4]])
  2473. assert_array_equal(toarray(a[..., [2, 4], [2, 4]]), b[..., [2, 4], [2, 4]])
  2474. def test_multiple_ellipsis_slicing(self):
  2475. a = self.spcreator(arange(6).reshape(3, 2))
  2476. with pytest.raises(IndexError,
  2477. match='an index can only have a single ellipsis'):
  2478. a[..., ...]
  2479. with pytest.raises(IndexError,
  2480. match='an index can only have a single ellipsis'):
  2481. a[..., 1, ...]
  2482. class _TestSlicingAssign:
  2483. def test_slice_scalar_assign(self):
  2484. A = self.spcreator((5, 5))
  2485. B = np.zeros((5, 5))
  2486. with warnings.catch_warnings():
  2487. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  2488. for C in [A, B]:
  2489. C[0:1,1] = 1
  2490. C[3:0,0] = 4
  2491. C[3:4,0] = 9
  2492. C[0,4:] = 1
  2493. C[3::-1,4:] = 9
  2494. assert_array_equal(A.toarray(), B)
  2495. def test_slice_assign_2(self):
  2496. n, m = (5, 10)
  2497. def _test_set(i, j):
  2498. msg = f"i={i!r}; j={j!r}"
  2499. A = self.spcreator((n, m))
  2500. with warnings.catch_warnings():
  2501. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  2502. A[i, j] = 1
  2503. B = np.zeros((n, m))
  2504. B[i, j] = 1
  2505. assert_array_almost_equal(A.toarray(), B, err_msg=msg)
  2506. # [i,1:2]
  2507. for i, j in [(2, slice(3)), (2, slice(None, 10, 4)), (2, slice(5, -2)),
  2508. (array(2), slice(5, -2))]:
  2509. _test_set(i, j)
  2510. def test_self_self_assignment(self):
  2511. # Tests whether a row of one sparse array can be assigned to another.
  2512. B = self.spcreator((4,3))
  2513. with warnings.catch_warnings():
  2514. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  2515. B[0,0] = 2
  2516. B[1,2] = 7
  2517. B[2,1] = 3
  2518. B[3,0] = 10
  2519. A = B / 10
  2520. B[0,:] = A[0,:]
  2521. assert_array_equal(A[0,:].toarray(), B[0,:].toarray())
  2522. A = B / 10
  2523. B[:,:] = A[:1,:1]
  2524. assert_array_equal(np.zeros((4,3)) + A[0,0], B.toarray())
  2525. A = B / 10
  2526. B[:-1,0] = A[None,0,:].T
  2527. assert_array_equal(A[0,:].toarray().T, B[:-1,0].toarray())
  2528. def test_slice_assignment(self):
  2529. B = self.spcreator((4,3))
  2530. expected = array([[10,0,0],
  2531. [0,0,6],
  2532. [0,14,0],
  2533. [0,0,0]])
  2534. block = [[1,0],[0,4]]
  2535. with warnings.catch_warnings():
  2536. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  2537. B[0,0] = 5
  2538. B[1,2] = 3
  2539. B[2,1] = 7
  2540. B[:,:] = B+B
  2541. assert_array_equal(B.toarray(), expected)
  2542. B[:2,:2] = self.csc_container(array(block))
  2543. assert_array_equal(B.toarray()[:2, :2], block)
  2544. def test_sparsity_modifying_assignment(self):
  2545. B = self.spcreator((4,3))
  2546. with warnings.catch_warnings():
  2547. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  2548. B[0,0] = 5
  2549. B[1,2] = 3
  2550. B[2,1] = 7
  2551. B[3,0] = 10
  2552. B[:3] = self.csr_container(np.eye(3))
  2553. expected = array([[1,0,0],[0,1,0],[0,0,1],[10,0,0]])
  2554. assert_array_equal(B.toarray(), expected)
  2555. def test_set_slice(self):
  2556. A = self.spcreator((5,10))
  2557. B = array(zeros((5, 10), float))
  2558. s_ = np.s_
  2559. slices = [s_[:2], s_[1:2], s_[3:], s_[3::2],
  2560. s_[8:3:-1], s_[4::-2], s_[:5:-1],
  2561. 0, 1, s_[:], s_[1:5], -1, -2, -5,
  2562. array(-1), np.int8(-3)]
  2563. with warnings.catch_warnings():
  2564. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  2565. for j, a in enumerate(slices):
  2566. A[a] = j
  2567. B[a] = j
  2568. assert_array_equal(A.toarray(), B, repr(a))
  2569. for i, a in enumerate(slices):
  2570. for j, b in enumerate(slices):
  2571. A[a,b] = 10*i + 1000*(j+1)
  2572. B[a,b] = 10*i + 1000*(j+1)
  2573. assert_array_equal(A.toarray(), B, repr((a, b)))
  2574. A[0, 1:10:2] = range(1, 10, 2)
  2575. B[0, 1:10:2] = range(1, 10, 2)
  2576. assert_array_equal(A.toarray(), B)
  2577. A[1:5:2, 0] = np.arange(1, 5, 2)[:, None]
  2578. B[1:5:2, 0] = np.arange(1, 5, 2)[:]
  2579. assert_array_equal(A.toarray(), B)
  2580. # The next commands should raise exceptions
  2581. assert_raises(ValueError, A.__setitem__, (0, 0), list(range(100)))
  2582. assert_raises(ValueError, A.__setitem__, (0, 0), arange(100))
  2583. assert_raises(ValueError, A.__setitem__, (0, slice(None)),
  2584. list(range(100)))
  2585. assert_raises(ValueError, A.__setitem__, (slice(None), 1),
  2586. list(range(100)))
  2587. assert_raises(ValueError, A.__setitem__, (slice(None), 1), A.copy())
  2588. assert_raises(ValueError, A.__setitem__,
  2589. ([[1, 2, 3], [0, 3, 4]], [1, 2, 3]), [1, 2, 3, 4])
  2590. assert_raises(IndexError, A.__setitem__,
  2591. ([[1, 2, 3], [0, 3, 4], [4, 1, 3]],
  2592. [[1, 2, 4], [0, 1, 3]]), [2, 3, 4])
  2593. assert_raises(ValueError, A.__setitem__, (slice(4), 0),
  2594. [[1, 2], [3, 4]])
  2595. def test_assign_empty(self):
  2596. A = self.spcreator(np.ones((2, 3)))
  2597. B = self.spcreator((1, 2))
  2598. # Note: This is not like NumPy!! Incoming shape needs to be (2,) for NumPy
  2599. # we are more lenient to accommodate vectors in 2d format as input
  2600. A[1, :2] = B
  2601. assert_array_equal(A.toarray(), [[1, 1, 1], [0, 0, 1]])
  2602. def test_assign_1d_slice(self):
  2603. A = self.spcreator(np.ones((3, 3)))
  2604. x = np.zeros(3)
  2605. A[:, 0] = x
  2606. A[1, :] = x
  2607. assert_array_equal(A.toarray(), [[0, 1, 1], [0, 0, 0], [0, 1, 1]])
  2608. class _TestFancyIndexing:
  2609. """Tests fancy indexing features. The tests for any matrix formats
  2610. that implement these features should derive from this class.
  2611. """
  2612. def test_dtype_preservation_empty_index(self):
  2613. # This should be parametrized with pytest, but something in the parent
  2614. # class creation used in this file breaks pytest.mark.parametrize.
  2615. for dt in [np.int16, np.int32, np.float32, np.float64]:
  2616. A = self.spcreator((3, 2), dtype=dt)
  2617. assert_equal(A[:, [False, False]].dtype, dt)
  2618. assert_equal(A[[False, False, False], :].dtype, dt)
  2619. assert_equal(A[:, []].dtype, dt)
  2620. assert_equal(A[[], :].dtype, dt)
  2621. def test_bad_index(self):
  2622. A = self.spcreator(np.zeros([5, 5]))
  2623. assert_raises(IndexError, A.__getitem__, "foo").match('Index dimension')
  2624. assert_raises(IndexError, A.__getitem__, (2, "foo")).match('Index dimension')
  2625. idx = ([1, 2, 3], [1, 2, 3, 4])
  2626. assert_raises(IndexError, A.__getitem__, idx).match('shape mismatch')
  2627. def test_fancy_indexing(self):
  2628. B = self.asdense(arange(50).reshape(5,10))
  2629. A = self.spcreator(B)
  2630. # [i]
  2631. assert_equal(A[[3]].toarray(), B[[3]])
  2632. assert_equal(A[[1, 3]].toarray(), B[[1, 3]])
  2633. # [i,[1,2]]
  2634. assert_equal(A[3, [3]].toarray(), B[3, [3]])
  2635. assert_equal(A[3, [1, 3]].toarray(), B[3, [1, 3]])
  2636. assert_equal(A[-1, [2, -5]].toarray(), B[-1, [2, -5]])
  2637. assert_equal(A[array(-1), [2, -5]].toarray(), B[-1, [2, -5]])
  2638. assert_equal(A[-1, array([2, -5])].toarray(), B[-1, [2, -5]])
  2639. assert_equal(A[array(-1), array([2, -5])].toarray(), B[-1, [2, -5]])
  2640. # [1:2,[1,2]]
  2641. assert_equal(A[:, [2, 8, 3, -1]].toarray(), B[:, [2, 8, 3, -1]])
  2642. assert_equal(A[3:4, [9]].toarray(), B[3:4, [9]])
  2643. assert_equal(A[1:4, [-1, -5]].toarray(), B[1:4, [-1, -5]])
  2644. assert_equal(A[1:4, array([-1, -5])].toarray(), B[1:4, [-1, -5]])
  2645. # [[1,2],j]
  2646. assert_equal(A[[3], 3].toarray(), B[[3], 3])
  2647. assert_equal(A[[1, 3], 3].toarray(), B[[1, 3], 3])
  2648. assert_equal(A[[2, -5], -4].toarray(), B[[2, -5], -4])
  2649. assert_equal(A[array([2, -5]), -4].toarray(), B[[2, -5], -4])
  2650. assert_equal(A[[2, -5], array(-4)].toarray(), B[[2, -5], -4])
  2651. assert_equal(A[array([2, -5]), array(-4)].toarray(), B[[2, -5], -4])
  2652. # [[1,2],1:2]
  2653. assert_equal(A[[3], :].toarray(), B[[3], :])
  2654. assert_equal(A[[1, 3], :].toarray(), B[[1, 3], :])
  2655. assert_equal(A[[2, -5], 8:-1].toarray(), B[[2, -5], 8:-1])
  2656. assert_equal(A[array([2, -5]), 8:-1].toarray(), B[[2, -5], 8:-1])
  2657. # [[1,2],[1,2]]
  2658. assert_equal(toarray(A[[3], [4]]), B[[3], [4]])
  2659. assert_equal(toarray(A[[1, 3], [2, 4]]), B[[1, 3], [2, 4]])
  2660. assert_equal(toarray(A[[-1, -3], [2, -4]]), B[[-1, -3], [2, -4]])
  2661. assert_equal(
  2662. toarray(A[array([-1, -3]), [2, -4]]), B[[-1, -3], [2, -4]]
  2663. )
  2664. assert_equal(
  2665. toarray(A[[-1, -3], array([2, -4])]), B[[-1, -3], [2, -4]]
  2666. )
  2667. assert_equal(
  2668. toarray(A[array([-1, -3]), array([2, -4])]), B[[-1, -3], [2, -4]]
  2669. )
  2670. # [[[1],[2]],[1,2]]
  2671. assert_equal(A[[[1], [3]], [2, 4]].toarray(), B[[[1], [3]], [2, 4]])
  2672. assert_equal(
  2673. A[[[-1], [-3], [-2]], [2, -4]].toarray(),
  2674. B[[[-1], [-3], [-2]], [2, -4]]
  2675. )
  2676. assert_equal(
  2677. A[array([[-1], [-3], [-2]]), [2, -4]].toarray(),
  2678. B[[[-1], [-3], [-2]], [2, -4]]
  2679. )
  2680. assert_equal(
  2681. A[[[-1], [-3], [-2]], array([2, -4])].toarray(),
  2682. B[[[-1], [-3], [-2]], [2, -4]]
  2683. )
  2684. assert_equal(
  2685. A[array([[-1], [-3], [-2]]), array([2, -4])].toarray(),
  2686. B[[[-1], [-3], [-2]], [2, -4]]
  2687. )
  2688. # [[1,2]]
  2689. assert_equal(A[[1, 3]].toarray(), B[[1, 3]])
  2690. assert_equal(A[[-1, -3]].toarray(), B[[-1, -3]])
  2691. assert_equal(A[array([-1, -3])].toarray(), B[[-1, -3]])
  2692. # [[1,2],:][:,[1,2]]
  2693. assert_equal(A[[3], :][:, [4]].toarray(), B[[3], :][:, [4]])
  2694. assert_equal(
  2695. A[[1, 3], :][:, [2, 4]].toarray(), B[[1, 3], :][:, [2, 4]]
  2696. )
  2697. assert_equal(
  2698. A[[-1, -3], :][:, [2, -4]].toarray(), B[[-1, -3], :][:, [2, -4]]
  2699. )
  2700. assert_equal(
  2701. A[array([-1, -3]), :][:, array([2, -4])].toarray(),
  2702. B[[-1, -3], :][:, [2, -4]]
  2703. )
  2704. assert_equal(
  2705. A[1, [[1, 3]]][[[0, 0]], 1].toarray(), B[1, [[1, 3]]][[[0, 0]], 1]
  2706. )
  2707. assert_equal(
  2708. A[1, [[-1, -3]]][[[0, -1]], 1].toarray(), B[1, [[-1, -3]]][[[0, -1]], 1]
  2709. )
  2710. # leads to 3D result
  2711. if A.format == "coo":
  2712. assert_equal(A[:1, [[1, 3]]].toarray(), B[:1, [[1, 3]]])
  2713. assert_equal(A[[[0, 0]], :1].toarray(), B[[[0, 0]], :1])
  2714. else:
  2715. with pytest.raises(IndexError, match="Only 1D or 2D|>2D is not supported"):
  2716. A[:1, [[1, 3]]]
  2717. with pytest.raises(IndexError, match="Only 1D or 2D|>2D is not supported"):
  2718. A[[[0, 0]], :1]
  2719. assert_equal(
  2720. A[:, [1, 3]][[2, 4], :].toarray(), B[:, [1, 3]][[2, 4], :]
  2721. )
  2722. assert_equal(
  2723. A[:, [-1, -3]][[2, -4], :].toarray(), B[:, [-1, -3]][[2, -4], :]
  2724. )
  2725. assert_equal(
  2726. A[:, array([-1, -3])][array([2, -4]), :].toarray(),
  2727. B[:, [-1, -3]][[2, -4], :]
  2728. )
  2729. # Check bug reported by Robert Cimrman:
  2730. # http://thread.gmane.org/gmane.comp.python.scientific.devel/7986 (dead link)
  2731. s = slice(int8(2),int8(4),None)
  2732. assert_equal(A[s, :].toarray(), B[2:4, :])
  2733. assert_equal(A[:, s].toarray(), B[:, 2:4])
  2734. # Regression for gh-4917: index with tuple of 2D arrays
  2735. i = np.array([[1]], dtype=int)
  2736. assert_equal(A[i, i].toarray(), B[i, i])
  2737. # Regression for gh-4917: index with tuple of empty nested lists
  2738. assert_equal(A[[[]], [[]]].toarray(), B[[[]], [[]]])
  2739. def test_fancy_indexing_randomized(self):
  2740. np.random.seed(1234) # make runs repeatable
  2741. NUM_SAMPLES = 50
  2742. M = 6
  2743. N = 4
  2744. D = self.asdense(np.random.rand(M,N))
  2745. D = np.multiply(D, D > 0.5)
  2746. I = np.random.randint(-M + 1, M, size=NUM_SAMPLES)
  2747. J = np.random.randint(-N + 1, N, size=NUM_SAMPLES)
  2748. S = self.spcreator(D)
  2749. SIJ = S[I,J]
  2750. if issparse(SIJ):
  2751. SIJ = SIJ.toarray()
  2752. assert_equal(SIJ, D[I,J])
  2753. I_bad = I + M
  2754. J_bad = J - N
  2755. assert_raises(IndexError, S.__getitem__, (I_bad,J))
  2756. assert_raises(IndexError, S.__getitem__, (I,J_bad))
  2757. def test_missized_masking(self):
  2758. M, N = 5, 10
  2759. B = self.asdense(arange(M * N).reshape(M, N))
  2760. A = self.spcreator(B)
  2761. # Content of mask shouldn't matter, only its size
  2762. row_long = np.ones(M + 1, dtype=bool)
  2763. row_short = np.ones(M - 1, dtype=bool)
  2764. col_long = np.ones(N + 2, dtype=bool)
  2765. col_short = np.ones(N - 2, dtype=bool)
  2766. match="bool index .* has shape .* instead of .*"
  2767. for i, j in itertools.product(
  2768. (row_long, row_short, slice(None)),
  2769. (col_long, col_short, slice(None)),
  2770. ):
  2771. if isinstance(i, slice) and isinstance(j, slice):
  2772. continue
  2773. with pytest.raises(IndexError, match=match):
  2774. _ = A[i, j]
  2775. def test_fancy_indexing_boolean(self):
  2776. np.random.seed(1234) # make runs repeatable
  2777. B = self.asdense(arange(50).reshape(5,10))
  2778. A = self.spcreator(B)
  2779. I = np.array(np.random.randint(0, 2, size=5), dtype=bool)
  2780. J = np.array(np.random.randint(0, 2, size=10), dtype=bool)
  2781. X = np.array(np.random.randint(0, 2, size=(5, 10)), dtype=bool)
  2782. assert_equal(toarray(A[I]), B[I])
  2783. assert_equal(toarray(A[:, J]), B[:, J])
  2784. assert_equal(toarray(A[X]), B[X])
  2785. assert_equal(toarray(A[B > 9]), B[B > 9])
  2786. I = np.array([True, False, True, True, False])
  2787. J = np.array([False, True, True, False, True,
  2788. False, False, False, False, False])
  2789. assert_equal(toarray(A[I, J]), B[I, J])
  2790. Z1 = np.zeros((6, 11), dtype=bool)
  2791. Z2 = np.zeros((6, 11), dtype=bool)
  2792. Z2[0,-1] = True
  2793. Z3 = np.zeros((6, 11), dtype=bool)
  2794. Z3[-1,0] = True
  2795. assert_raises(IndexError, A.__getitem__, Z1)
  2796. assert_raises(IndexError, A.__getitem__, Z2)
  2797. assert_raises(IndexError, A.__getitem__, Z3)
  2798. assert_raises((IndexError, ValueError), A.__getitem__, (X, 1))
  2799. def test_fancy_indexing_sparse_boolean(self):
  2800. np.random.seed(1234) # make runs repeatable
  2801. B = self.asdense(arange(50).reshape(5,10))
  2802. A = self.spcreator(B)
  2803. X = np.array(np.random.randint(0, 2, size=(5, 10)), dtype=bool)
  2804. Xsp = self.csr_container(X)
  2805. assert_equal(toarray(A[Xsp]), B[X])
  2806. assert_equal(toarray(A[A > 9]), B[B > 9])
  2807. Z = np.array(np.random.randint(0, 2, size=(5, 11)), dtype=bool)
  2808. Y = np.array(np.random.randint(0, 2, size=(6, 10)), dtype=bool)
  2809. Zsp = self.csr_container(Z)
  2810. Ysp = self.csr_container(Y)
  2811. assert_raises(IndexError, A.__getitem__, Zsp)
  2812. assert_raises(IndexError, A.__getitem__, Ysp)
  2813. assert_raises((IndexError, ValueError), A.__getitem__, (Xsp, 1))
  2814. def test_fancy_indexing_regression_3087(self):
  2815. mat = self.spcreator(array([[1, 0, 0], [0,1,0], [1,0,0]]))
  2816. desired_cols = np.ravel(mat.sum(0)) > 0
  2817. assert_equal(mat[:, desired_cols].toarray(), [[1, 0], [0, 1], [1, 0]])
  2818. def test_fancy_indexing_seq_assign(self):
  2819. mat = self.spcreator(array([[1, 0], [0, 1]]))
  2820. assert_raises(ValueError, mat.__setitem__, (0, 0), np.array([1,2]))
  2821. def test_fancy_indexing_2d_assign(self):
  2822. # regression test for gh-10695
  2823. mat = self.spcreator(array([[1, 0], [2, 3]]))
  2824. with warnings.catch_warnings():
  2825. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  2826. mat[[0, 1], [1, 1]] = mat[[1, 0], [0, 0]]
  2827. assert_equal(toarray(mat), array([[1, 2], [2, 1]]))
  2828. def test_fancy_indexing_empty(self):
  2829. B = self.asdense(arange(50).reshape(5,10))
  2830. B[1,:] = 0
  2831. B[:,2] = 0
  2832. B[3,6] = 0
  2833. A = self.spcreator(B)
  2834. K = np.array([False, False, False, False, False])
  2835. assert_equal(toarray(A[K]), B[K])
  2836. K = np.array([], dtype=int)
  2837. assert_equal(toarray(A[K]), B[K])
  2838. assert_equal(toarray(A[K, K]), B[K, K])
  2839. J = np.array([0, 1, 2, 3, 4], dtype=int)[:,None]
  2840. assert_equal(toarray(A[K, J]), B[K, J])
  2841. assert_equal(toarray(A[J, K]), B[J, K])
  2842. @contextlib.contextmanager
  2843. def check_remains_sorted(X):
  2844. """Checks that sorted indices property is retained through an operation
  2845. """
  2846. if not hasattr(X, 'has_sorted_indices') or not X.has_sorted_indices:
  2847. yield
  2848. return
  2849. yield
  2850. indices = X.indices.copy()
  2851. X.has_sorted_indices = False
  2852. X.sort_indices()
  2853. assert_array_equal(indices, X.indices,
  2854. 'Expected sorted indices, found unsorted')
  2855. class _TestFancyIndexingAssign:
  2856. def test_bad_index_assign(self):
  2857. A = self.spcreator(np.zeros([5, 5]))
  2858. assert_raises((IndexError, ValueError, TypeError), A.__setitem__, "foo", 2)
  2859. assert_raises((IndexError, ValueError, TypeError), A.__setitem__, (2, "foo"), 5)
  2860. def test_fancy_indexing_set(self):
  2861. n, m = (5, 10)
  2862. def _test_set_slice(i, j):
  2863. A = self.spcreator((n, m))
  2864. B = self.asdense(np.zeros((n, m)))
  2865. with warnings.catch_warnings():
  2866. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  2867. B[i, j] = 1
  2868. with check_remains_sorted(A):
  2869. A[i, j] = 1
  2870. assert_array_almost_equal(A.toarray(), B)
  2871. # [1:2,1:2]
  2872. for i, j in [((2, 3, 4), slice(None, 10, 4)),
  2873. (np.arange(3), slice(5, -2)),
  2874. (slice(2, 5), slice(5, -2))]:
  2875. _test_set_slice(i, j)
  2876. for i, j in [(np.arange(3), np.arange(3)), ((0, 3, 4), (1, 2, 4))]:
  2877. _test_set_slice(i, j)
  2878. def test_fancy_assignment_dtypes(self):
  2879. def check(dtype):
  2880. A = self.spcreator((5, 5), dtype=dtype)
  2881. with warnings.catch_warnings():
  2882. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  2883. A[[0,1],[0,1]] = dtype.type(1)
  2884. assert_equal(A.sum(), dtype.type(1)*2)
  2885. A[0:2,0:2] = dtype.type(1.0)
  2886. assert_equal(A.sum(), dtype.type(1)*4)
  2887. A[2,2] = dtype.type(1.0)
  2888. assert_equal(A.sum(), dtype.type(1)*4 + dtype.type(1))
  2889. for dtype in supported_dtypes:
  2890. check(np.dtype(dtype))
  2891. def test_sequence_assignment(self):
  2892. A = self.spcreator((4,3))
  2893. B = self.spcreator(eye(3,4))
  2894. i0 = [0,1,2]
  2895. i1 = (0,1,2)
  2896. i2 = array(i0)
  2897. with warnings.catch_warnings():
  2898. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  2899. with check_remains_sorted(A):
  2900. A[0,i0] = B[i0,0].T
  2901. A[1,i1] = B[i1,1].T
  2902. A[2,i2] = B[i2,2].T
  2903. assert_array_equal(A.toarray(), B.T.toarray())
  2904. # column slice
  2905. A = self.spcreator((2,3))
  2906. with check_remains_sorted(A):
  2907. A[1,1:3] = [10,20]
  2908. assert_array_equal(A.toarray(), [[0, 0, 0], [0, 10, 20]])
  2909. # row slice
  2910. A = self.spcreator((3,2))
  2911. with check_remains_sorted(A):
  2912. A[1:3,1] = [[10],[20]]
  2913. assert_array_equal(A.toarray(), [[0, 0], [0, 10], [0, 20]])
  2914. # both slices
  2915. A = self.spcreator((3,3))
  2916. B = self.asdense(np.zeros((3,3)))
  2917. with check_remains_sorted(A):
  2918. for C in [A, B]:
  2919. C[[0,1,2], [0,1,2]] = [4,5,6]
  2920. assert_array_equal(A.toarray(), B)
  2921. # both slices (2)
  2922. A = self.spcreator((4, 3))
  2923. with check_remains_sorted(A):
  2924. A[(1, 2, 3), (0, 1, 2)] = [1, 2, 3]
  2925. assert_almost_equal(A.sum(), 6)
  2926. B = self.asdense(np.zeros((4, 3)))
  2927. B[(1, 2, 3), (0, 1, 2)] = [1, 2, 3]
  2928. assert_array_equal(A.toarray(), B)
  2929. def test_fancy_assign_empty(self):
  2930. B = self.asdense(arange(50).reshape(5,10))
  2931. B[1,:] = 0
  2932. B[:,2] = 0
  2933. B[3,6] = 0
  2934. A = self.spcreator(B)
  2935. K = np.array([False, False, False, False, False])
  2936. A[K] = 42
  2937. assert_equal(toarray(A), B)
  2938. K = np.array([], dtype=int)
  2939. A[K] = 42
  2940. assert_equal(toarray(A), B)
  2941. A[K,K] = 42
  2942. assert_equal(toarray(A), B)
  2943. J = np.array([0, 1, 2, 3, 4], dtype=int)[:,None]
  2944. A[K,J] = 42
  2945. assert_equal(toarray(A), B)
  2946. A[J,K] = 42
  2947. assert_equal(toarray(A), B)
  2948. class _TestFancyMultidim:
  2949. def test_fancy_indexing_ndarray(self):
  2950. IandJ = [
  2951. (np.array([[1], [2], [3]]), np.array([3, 4, 2])),
  2952. (np.array([[1], [2], [3]]), np.array([[3, 4, 2]])),
  2953. (np.array([[1, 2, 3]]), np.array([[3], [4], [2]])),
  2954. (np.array([1, 2, 3]), np.array([[3], [4], [2]])),
  2955. (np.array([[1, 2, 3], [3, 4, 2]]), np.array([[5, 6, 3], [2, 3, 1]])),
  2956. ]
  2957. np.random.seed(1234)
  2958. D = self.asdense(np.random.rand(5, 7))
  2959. S = self.spcreator(D)
  2960. # These inputs generate 3-D outputs
  2961. if S.format == 'coo':
  2962. IandJ.append(
  2963. (np.array([[[1], [2], [3]], [[3], [4], [2]]]),
  2964. np.array([[[5], [6], [3]], [[2], [3], [1]]]))
  2965. )
  2966. for I, J in IandJ:
  2967. SIJ = S[I, J]
  2968. DIJ = D[I, J]
  2969. assert_equal(toarray(SIJ), DIJ)
  2970. I_bad = I + 5
  2971. J_bad = J + 7
  2972. assert_raises(IndexError, S.__getitem__, (I_bad, J))
  2973. assert_raises(IndexError, S.__getitem__, (I, J_bad))
  2974. if S.format != 'coo':
  2975. assert_raises(IndexError, S.__getitem__, ([I, I], slice(None)))
  2976. assert_raises(IndexError, S.__getitem__, (slice(None), [J, J]))
  2977. else:
  2978. assert_equal(S[[I, I], :].toarray(), D[[I, I], :])
  2979. assert_equal(S[:, [J, J]].toarray(), D[:, [J, J]])
  2980. class _TestFancyMultidimAssign:
  2981. def test_fancy_assign_ndarray(self):
  2982. np.random.seed(1234)
  2983. D = self.asdense(np.random.rand(5, 7))
  2984. S = self.spcreator(D)
  2985. X = np.random.rand(2, 3)
  2986. I = np.array([[1, 2, 3], [3, 4, 2]])
  2987. J = np.array([[5, 6, 3], [2, 3, 1]])
  2988. with check_remains_sorted(S):
  2989. S[I,J] = X
  2990. D[I,J] = X
  2991. assert_equal(S.toarray(), D)
  2992. I_bad = I + 5
  2993. J_bad = J + 7
  2994. C = [1, 2, 3]
  2995. with check_remains_sorted(S):
  2996. S[I,J] = C
  2997. D[I,J] = C
  2998. assert_equal(S.toarray(), D)
  2999. with check_remains_sorted(S):
  3000. S[I,J] = 3
  3001. D[I,J] = 3
  3002. assert_equal(S.toarray(), D)
  3003. assert_raises(IndexError, S.__setitem__, (I_bad,J), C)
  3004. assert_raises(IndexError, S.__setitem__, (I,J_bad), C)
  3005. def test_fancy_indexing_multidim_set(self):
  3006. n, m = (5, 10)
  3007. def _test_set_slice(i, j):
  3008. A = self.spcreator((n, m))
  3009. with check_remains_sorted(A), warnings.catch_warnings():
  3010. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  3011. A[i, j] = 1
  3012. B = self.asdense(np.zeros((n, m)))
  3013. B[i, j] = 1
  3014. assert_array_almost_equal(A.toarray(), B)
  3015. # [[[1, 2], [1, 2]], [1, 2]]
  3016. for i, j in [(np.array([[1, 2], [1, 3]]), [1, 3]),
  3017. (np.array([0, 4]), [[0, 3], [1, 2]]),
  3018. ([[1, 2, 3], [0, 2, 4]], [[0, 4, 3], [4, 1, 2]])]:
  3019. _test_set_slice(i, j)
  3020. def test_fancy_assign_list(self):
  3021. np.random.seed(1234)
  3022. D = self.asdense(np.random.rand(5, 7))
  3023. S = self.spcreator(D)
  3024. X = np.random.rand(2, 3)
  3025. I = [[1, 2, 3], [3, 4, 2]]
  3026. J = [[5, 6, 3], [2, 3, 1]]
  3027. S[I,J] = X
  3028. D[I,J] = X
  3029. assert_equal(S.toarray(), D)
  3030. I_bad = [[ii + 5 for ii in i] for i in I]
  3031. J_bad = [[jj + 7 for jj in j] for j in J]
  3032. C = [1, 2, 3]
  3033. S[I,J] = C
  3034. D[I,J] = C
  3035. assert_equal(S.toarray(), D)
  3036. S[I,J] = 3
  3037. D[I,J] = 3
  3038. assert_equal(S.toarray(), D)
  3039. assert_raises(IndexError, S.__setitem__, (I_bad,J), C)
  3040. assert_raises(IndexError, S.__setitem__, (I,J_bad), C)
  3041. def test_fancy_assign_slice(self):
  3042. np.random.seed(1234)
  3043. D = self.asdense(np.random.rand(5, 7))
  3044. S = self.spcreator(D)
  3045. I = [1, 2, 3, 3, 4, 2]
  3046. J = [5, 6, 3, 2, 3, 1]
  3047. I_bad = [ii + 5 for ii in I]
  3048. J_bad = [jj + 7 for jj in J]
  3049. C1 = [1, 2, 3, 4, 5, 6, 7]
  3050. C2 = np.arange(5)[:, None]
  3051. assert_raises(IndexError, S.__setitem__, (I_bad, slice(None)), C1)
  3052. assert_raises(IndexError, S.__setitem__, (slice(None), J_bad), C2)
  3053. class _TestArithmetic:
  3054. """
  3055. Test real/complex arithmetic
  3056. """
  3057. def __arith_init(self):
  3058. # these can be represented exactly in FP (so arithmetic should be exact)
  3059. __A = array([[-1.5, 6.5, 0, 2.25, 0, 0],
  3060. [3.125, -7.875, 0.625, 0, 0, 0],
  3061. [0, 0, -0.125, 1.0, 0, 0],
  3062. [0, 0, 8.375, 0, 0, 0]], 'float64')
  3063. __B = array([[0.375, 0, 0, 0, -5, 2.5],
  3064. [14.25, -3.75, 0, 0, -0.125, 0],
  3065. [0, 7.25, 0, 0, 0, 0],
  3066. [18.5, -0.0625, 0, 0, 0, 0]], 'complex128')
  3067. __B.imag = array([[1.25, 0, 0, 0, 6, -3.875],
  3068. [2.25, 4.125, 0, 0, 0, 2.75],
  3069. [0, 4.125, 0, 0, 0, 0],
  3070. [-0.0625, 0, 0, 0, 0, 0]], 'float64')
  3071. # fractions are all x/16ths
  3072. assert_array_equal((__A*16).astype('int32'),16*__A)
  3073. assert_array_equal((__B.real*16).astype('int32'),16*__B.real)
  3074. assert_array_equal((__B.imag*16).astype('int32'),16*__B.imag)
  3075. __Asp = self.spcreator(__A)
  3076. __Bsp = self.spcreator(__B)
  3077. return __A, __B, __Asp, __Bsp
  3078. @pytest.mark.fail_slow(20)
  3079. def test_add_sub(self):
  3080. __A, __B, __Asp, __Bsp = self.__arith_init()
  3081. # basic tests
  3082. assert_array_equal(
  3083. (__Asp + __Bsp).toarray(), __A + __B
  3084. )
  3085. # check conversions
  3086. for x in supported_dtypes:
  3087. with np.errstate(invalid="ignore"):
  3088. A = __A.astype(x)
  3089. Asp = self.spcreator(A)
  3090. for y in supported_dtypes:
  3091. if not np.issubdtype(y, np.complexfloating):
  3092. with np.errstate(invalid="ignore"):
  3093. B = __B.real.astype(y)
  3094. else:
  3095. B = __B.astype(y)
  3096. Bsp = self.spcreator(B)
  3097. # addition
  3098. D1 = A + B
  3099. S1 = Asp + Bsp
  3100. assert_equal(S1.dtype,D1.dtype)
  3101. assert_array_equal(S1.toarray(), D1)
  3102. assert_array_equal(Asp + B,D1) # check sparse + dense
  3103. assert_array_equal(A + Bsp,D1) # check dense + sparse
  3104. # subtraction
  3105. if np.dtype('bool') in [x, y]:
  3106. # boolean array subtraction deprecated in 1.9.0
  3107. continue
  3108. D1 = A - B
  3109. S1 = Asp - Bsp
  3110. assert_equal(S1.dtype,D1.dtype)
  3111. assert_array_equal(S1.toarray(), D1)
  3112. assert_array_equal(Asp - B,D1) # check sparse - dense
  3113. assert_array_equal(A - Bsp,D1) # check dense - sparse
  3114. def test_mu(self):
  3115. __A, __B, __Asp, __Bsp = self.__arith_init()
  3116. # basic tests
  3117. assert_array_equal((__Asp @ __Bsp.T).toarray(),
  3118. __A @ __B.T)
  3119. for x in supported_dtypes:
  3120. with np.errstate(invalid="ignore"):
  3121. A = __A.astype(x)
  3122. Asp = self.spcreator(A)
  3123. for y in supported_dtypes:
  3124. if np.issubdtype(y, np.complexfloating):
  3125. B = __B.astype(y)
  3126. else:
  3127. with np.errstate(invalid="ignore"):
  3128. B = __B.real.astype(y)
  3129. Bsp = self.spcreator(B)
  3130. D1 = A @ B.T
  3131. S1 = Asp @ Bsp.T
  3132. assert_allclose(S1.toarray(), D1,
  3133. atol=1e-14*abs(D1).max())
  3134. assert_equal(S1.dtype,D1.dtype)
  3135. class _TestMinMax:
  3136. def test_minmax(self):
  3137. for dtype in [np.float32, np.float64, np.int32, np.int64, np.complex128]:
  3138. D = np.arange(20, dtype=dtype).reshape(5,4)
  3139. X = self.spcreator(D)
  3140. assert_equal(X.min(), 0)
  3141. assert_equal(X.max(), 19)
  3142. assert_equal(X.min().dtype, dtype)
  3143. assert_equal(X.max().dtype, dtype)
  3144. D *= -1
  3145. X = self.spcreator(D)
  3146. assert_equal(X.min(), -19)
  3147. assert_equal(X.max(), 0)
  3148. D += 5
  3149. X = self.spcreator(D)
  3150. assert_equal(X.min(), -14)
  3151. assert_equal(X.max(), 5)
  3152. # try a fully dense matrix
  3153. X = self.spcreator(np.arange(1, 10).reshape(3, 3))
  3154. assert_equal(X.min(), 1)
  3155. assert_equal(X.min().dtype, X.dtype)
  3156. assert_equal(X.min(explicit=True), 1)
  3157. X = -X
  3158. assert_equal(X.max(), -1)
  3159. assert_equal(X.max(explicit=True), -1)
  3160. # and a fully sparse matrix
  3161. Z = self.spcreator(np.zeros((1, 1)))
  3162. assert_equal(Z.min(), 0)
  3163. assert_equal(Z.max(), 0)
  3164. assert_equal(Z.max().dtype, Z.dtype)
  3165. # another test
  3166. D = np.arange(20, dtype=float).reshape(5,4)
  3167. D[0:2, :] = 0
  3168. X = self.spcreator(D)
  3169. assert_equal(X.min(), 0)
  3170. assert_equal(X.max(), 19)
  3171. # zero-size matrices
  3172. for D in [np.zeros((0, 0)), np.zeros((0, 10)), np.zeros((10, 0))]:
  3173. X = self.spcreator(D)
  3174. assert_raises(ValueError, X.min)
  3175. assert_raises(ValueError, X.max)
  3176. def test_minmax_axis(self):
  3177. keep = not self.is_array_test
  3178. D = np.arange(50).reshape(5, 10)
  3179. # completely empty rows, leaving some completely full:
  3180. D[1, :] = 0
  3181. # empty at end for reduceat:
  3182. D[:, 9] = 0
  3183. # partial rows/cols:
  3184. D[3, 3] = 0
  3185. # entries on either side of 0:
  3186. D[2, 2] = -1
  3187. X = self.spcreator(D)
  3188. axes_even = [0, -2]
  3189. axes_odd = [1, -1]
  3190. for axis in axes_odd + axes_even:
  3191. assert_array_equal(
  3192. X.max(axis=axis).toarray(), D.max(axis=axis, keepdims=keep)
  3193. )
  3194. assert_array_equal(
  3195. X.min(axis=axis).toarray(), D.min(axis=axis, keepdims=keep)
  3196. )
  3197. for axis in axes_even:
  3198. assert_equal(
  3199. X.max(axis=axis, explicit=True).toarray(),
  3200. self.asdense([40, 41, 42, 43, 44, 45, 46, 47, 48, 0])
  3201. )
  3202. if np.any(X.data == 0):
  3203. # Noncanonical case
  3204. expected = self.asdense([20, 1, -1, 3, 4, 5, 0, 7, 8, 0])
  3205. else:
  3206. expected = self.asdense([20, 1, -1, 3, 4, 5, 6, 7, 8, 0])
  3207. assert_equal(X.min(axis=axis, explicit=True).toarray(), expected)
  3208. for axis in axes_odd:
  3209. expected_max = np.array([8, 0, 28, 38, 48])
  3210. expected_min = np.array([1, 0, -1, 30, 40])
  3211. if not self.is_array_test:
  3212. expected_max = expected_max.reshape((5, 1))
  3213. expected_min = expected_min.reshape((5, 1))
  3214. assert_equal(X.max(axis=axis, explicit=True).toarray(), expected_max)
  3215. assert_equal(X.min(axis=axis, explicit=True).toarray(), expected_min)
  3216. # full matrix
  3217. D = np.arange(1, 51).reshape(10, 5)
  3218. X = self.spcreator(D)
  3219. for axis in axes_odd + axes_even:
  3220. assert_array_equal(
  3221. X.max(axis=axis).toarray(), D.max(axis=axis, keepdims=keep)
  3222. )
  3223. assert_array_equal(
  3224. X.min(axis=axis).toarray(), D.min(axis=axis, keepdims=keep)
  3225. )
  3226. assert_equal(X.max(axis=(0, 1)), D.max(axis=(0, 1), keepdims=keep))
  3227. for axis in axes_even:
  3228. expected_max = D[-1, :]
  3229. expected_min = D[0, :]
  3230. if not self.is_array_test:
  3231. expected_max = D[None, -1, :]
  3232. expected_min = D[None, 0, :]
  3233. assert_equal(X.max(axis=axis, explicit=True).toarray(), expected_max)
  3234. assert_equal(X.min(axis=axis, explicit=True).toarray(), expected_min)
  3235. for axis in axes_odd:
  3236. expected_max = D[:, -1]
  3237. expected_min = D[:, 0]
  3238. if not self.is_array_test:
  3239. expected_max = D[:, -1, None]
  3240. expected_min = D[:, 0, None]
  3241. assert_equal(X.max(axis=axis, explicit=True).toarray(), expected_max)
  3242. assert_equal(X.min(axis=axis, explicit=True).toarray(), expected_min)
  3243. # empty matrix
  3244. D = self.asdense(np.zeros((10, 5)))
  3245. X = self.spcreator(D)
  3246. for axis in axes_even + axes_odd:
  3247. assert_equal(X.max(axis=axis, explicit=True).toarray(), D.max(axis=axis))
  3248. assert_equal(X.min(axis=axis, explicit=True).toarray(), D.min(axis=axis))
  3249. # zero-size matrices
  3250. D = self.asdense(np.zeros((0, 10)))
  3251. X = self.spcreator(D)
  3252. explicit_values = [True, False]
  3253. even_explicit_pairs = list(itertools.product(axes_even, explicit_values))
  3254. odd_explicit_pairs = list(itertools.product(axes_odd, explicit_values))
  3255. for axis, ex in even_explicit_pairs:
  3256. assert_raises(ValueError, X.min, axis=axis, explicit=ex)
  3257. assert_raises(ValueError, X.max, axis=axis, explicit=ex)
  3258. for axis, ex in odd_explicit_pairs:
  3259. assert_equal(X.max(axis=axis, explicit=ex).toarray(), D.max(axis=axis))
  3260. assert_equal(X.min(axis=axis, explicit=ex).toarray(), D.min(axis=axis))
  3261. D = self.asdense(np.zeros((10, 0)))
  3262. X = self.spcreator(D)
  3263. for axis, ex in odd_explicit_pairs:
  3264. assert_raises(ValueError, X.min, axis=axis, explicit=ex)
  3265. assert_raises(ValueError, X.max, axis=axis, explicit=ex)
  3266. for axis, ex in even_explicit_pairs:
  3267. assert_equal(X.max(axis=axis, explicit=ex).toarray(), D.max(axis=axis))
  3268. assert_equal(X.min(axis=axis, explicit=ex).toarray(), D.min(axis=axis))
  3269. def test_minmax_container_type(self):
  3270. dat = array([[0, 1, 2],
  3271. [3, -4, 5],
  3272. [-6, 7, 9]])
  3273. datsp = self.spcreator(dat)
  3274. matrix_or_array = ndarray if self.is_array_test else np.matrix
  3275. spmatrix_or_sparray = sparray if self.is_array_test else spmatrix
  3276. assert isscalarlike(datsp.min())
  3277. assert isinstance(datsp.min(axis=0), spmatrix_or_sparray)
  3278. assert isinstance(datsp.min(axis=1), spmatrix_or_sparray)
  3279. assert isscalarlike(datsp.max())
  3280. assert isinstance(datsp.max(axis=0), spmatrix_or_sparray)
  3281. assert isinstance(datsp.max(axis=1), spmatrix_or_sparray)
  3282. assert isscalarlike(datsp.nanmin())
  3283. assert isinstance(datsp.nanmin(axis=0), spmatrix_or_sparray)
  3284. assert isinstance(datsp.nanmin(axis=1), spmatrix_or_sparray)
  3285. assert isscalarlike(datsp.nanmax())
  3286. assert isinstance(datsp.nanmax(axis=0), spmatrix_or_sparray)
  3287. assert isinstance(datsp.nanmax(axis=1), spmatrix_or_sparray)
  3288. assert isscalarlike(datsp.argmin())
  3289. assert isinstance(datsp.argmin(axis=0), matrix_or_array)
  3290. assert isinstance(datsp.argmin(axis=1), matrix_or_array)
  3291. assert isscalarlike(datsp.argmax())
  3292. assert isinstance(datsp.argmax(axis=0), matrix_or_array)
  3293. assert isinstance(datsp.argmax(axis=1), matrix_or_array)
  3294. def test_nanminmax(self):
  3295. D = self.asdense(np.arange(50).reshape(5,10), dtype=float)
  3296. D[1, :] = 0
  3297. D[:, 9] = 0
  3298. D[3, 3] = 0
  3299. D[2, 2] = -1
  3300. D[4, 2] = np.nan
  3301. D[1, 4] = np.nan
  3302. X = self.spcreator(D)
  3303. X_nan_maximum = X.nanmax()
  3304. assert np.isscalar(X_nan_maximum)
  3305. assert X_nan_maximum == np.nanmax(D)
  3306. X_nan_minimum = X.nanmin()
  3307. assert np.isscalar(X_nan_minimum)
  3308. assert X_nan_minimum == np.nanmin(D)
  3309. X_nan_minimum = X.nanmin(axis=(0, 1))
  3310. assert np.isscalar(X_nan_minimum)
  3311. assert X_nan_minimum == np.nanmin(D, axis=(0, 1))
  3312. axes = [-2, -1, 0, 1]
  3313. for axis in axes:
  3314. X_nan_maxima = X.nanmax(axis=axis)
  3315. assert_allclose(X_nan_maxima.toarray(), np.nanmax(D, axis=axis))
  3316. assert isinstance(X_nan_maxima, self.coo_container)
  3317. X_nan_minima = X.nanmin(axis=axis)
  3318. assert_allclose(X_nan_minima.toarray(), np.nanmin(D, axis=axis))
  3319. assert isinstance(X_nan_minima, self.coo_container)
  3320. def test_minmax_invalid_params(self):
  3321. dat = array([[0, 1, 2],
  3322. [3, -4, 5],
  3323. [-6, 7, 9]])
  3324. datsp = self.spcreator(dat)
  3325. for fname in ('min', 'max'):
  3326. datfunc = getattr(dat, fname)
  3327. func = getattr(datsp, fname)
  3328. assert_raises(ValueError, func, axis=3)
  3329. assert_raises(TypeError, func, axis=1.5)
  3330. assert_raises(ValueError, func, axis=1, out=1)
  3331. assert_equal(func(axis=(0, 1)), datfunc(axis=(0, 1)))
  3332. def test_numpy_minmax(self):
  3333. # See gh-5987
  3334. # xref gh-7460 in 'numpy'
  3335. from scipy.sparse import _data
  3336. dat = array([[0, 1, 2],
  3337. [3, -4, 5],
  3338. [-6, 7, 9]])
  3339. datsp = self.spcreator(dat)
  3340. # We are only testing sparse matrices who have
  3341. # implemented 'min' and 'max' because they are
  3342. # the ones with the compatibility issues with
  3343. # the 'numpy' implementation.
  3344. if isinstance(datsp, _data._minmax_mixin):
  3345. assert_array_equal(np.min(datsp), np.min(dat))
  3346. assert_array_equal(np.max(datsp), np.max(dat))
  3347. def test_argmax(self):
  3348. from scipy.sparse import _data
  3349. D1 = np.array([
  3350. [-1, 5, 2, 3],
  3351. [0, 0, -1, -2],
  3352. [-1, -2, -3, -4],
  3353. [1, 2, 3, 4],
  3354. [1, 2, 0, 0],
  3355. ])
  3356. D2 = D1.transpose()
  3357. # Non-regression test cases for gh-16929.
  3358. D3 = np.array([[4, 3], [7, 5]])
  3359. D4 = np.array([[4, 3], [7, 0]])
  3360. D5 = np.array([[5, 5, 3], [4, 9, 10], [3, 4, 9]])
  3361. for D in [D1, D2, D3, D4, D5]:
  3362. D = self.asdense(D)
  3363. mat = self.spcreator(D)
  3364. if not isinstance(mat, _data._minmax_mixin):
  3365. continue
  3366. assert_equal(mat.argmax(), np.argmax(D))
  3367. assert_equal(mat.argmin(), np.argmin(D))
  3368. assert_equal(mat.argmax(axis=0), np.argmax(D, axis=0))
  3369. assert_equal(mat.argmin(axis=0), np.argmin(D, axis=0))
  3370. assert_equal(mat.argmax(axis=1), np.argmax(D, axis=1))
  3371. assert_equal(mat.argmin(axis=1), np.argmin(D, axis=1))
  3372. # full matrix with explicit=True
  3373. mat = self.spcreator(self.asdense(D5))
  3374. assert_equal(mat.argmax(explicit=True), 5)
  3375. assert_equal((-mat).argmax(explicit=True), 2)
  3376. assert_equal(mat.argmin(explicit=True), 2)
  3377. assert_equal((-mat).argmin(explicit=True), 5)
  3378. # zero-size matrices
  3379. D6 = self.spcreator(np.empty((0, 5)))
  3380. D7 = self.spcreator(np.empty((5, 0)))
  3381. explicits = [True, False]
  3382. for mat, axis, ex in itertools.product([D6, D7], [None, 0, 1], explicits):
  3383. if axis is None or mat.shape[axis] == 0:
  3384. with pytest.raises(ValueError, match="Cannot apply"):
  3385. mat.argmax(axis=axis, explicit=ex)
  3386. with pytest.raises(ValueError, match="Cannot apply"):
  3387. mat.argmin(axis=axis, explicit=ex)
  3388. else:
  3389. if self.is_array_test:
  3390. expected = np.zeros(0)
  3391. else:
  3392. expected = np.zeros((0, 1) if axis == 1 else (1, 0))
  3393. assert_equal(mat.argmin(axis=axis, explicit=ex), expected)
  3394. assert_equal(mat.argmax(axis=axis, explicit=ex), expected)
  3395. mat = self.spcreator(D1)
  3396. assert_equal(mat.argmax(axis=0, explicit=True), self.asdense([3, 0, 3, 3]))
  3397. assert_equal(mat.argmin(axis=0, explicit=True), self.asdense([0, 2, 2, 2]))
  3398. expected_max = np.array([1, 2, 0, 3, 1])
  3399. expected_min = np.array([0, 3, 3, 0, 0])
  3400. if mat.nnz != 16:
  3401. # Noncanonical case
  3402. expected_min[-1] = 2
  3403. if not self.is_array_test:
  3404. expected_max = expected_max.reshape((5, 1))
  3405. expected_min = expected_min.reshape((5, 1))
  3406. assert_equal(mat.argmax(axis=1, explicit=True), expected_max)
  3407. assert_equal(asarray(mat.argmin(axis=1, explicit=True)), expected_min)
  3408. # all zeros
  3409. D = np.zeros((2, 2))
  3410. mat = self.spcreator(D)
  3411. if mat.nnz != 0:
  3412. # Noncanonical case
  3413. assert_equal(mat.argmin(axis=None, explicit=True), 0)
  3414. assert_equal(mat.argmax(axis=None, explicit=True), 0)
  3415. else:
  3416. # Canonical case
  3417. with pytest.raises(ValueError, match="Cannot apply"):
  3418. mat.argmin(axis=None, explicit=True)
  3419. with pytest.raises(ValueError, match="Cannot apply"):
  3420. mat.argmax(axis=None, explicit=True)
  3421. class _TestGetNnzAxis:
  3422. def test_getnnz_axis(self):
  3423. dat = array([[0, 2],
  3424. [3, 5],
  3425. [-6, 9]])
  3426. bool_dat = dat.astype(bool)
  3427. datsp = self.spcreator(dat)
  3428. accepted_return_dtypes = (np.int32, np.int64)
  3429. getnnz = datsp.count_nonzero if self.is_array_test else datsp.getnnz
  3430. assert_array_equal(bool_dat.sum(axis=None), getnnz(axis=None))
  3431. assert_array_equal(bool_dat.sum(), getnnz())
  3432. assert_array_equal(bool_dat.sum(axis=0), getnnz(axis=0))
  3433. assert_in(getnnz(axis=0).dtype, accepted_return_dtypes)
  3434. assert_array_equal(bool_dat.sum(axis=1), getnnz(axis=1))
  3435. assert_in(getnnz(axis=1).dtype, accepted_return_dtypes)
  3436. assert_array_equal(bool_dat.sum(axis=-2), getnnz(axis=-2))
  3437. assert_in(getnnz(axis=-2).dtype, accepted_return_dtypes)
  3438. assert_array_equal(bool_dat.sum(axis=-1), getnnz(axis=-1))
  3439. assert_in(getnnz(axis=-1).dtype, accepted_return_dtypes)
  3440. assert_raises(ValueError, getnnz, axis=2)
  3441. #------------------------------------------------------------------------------
  3442. # Tailored base class for generic tests
  3443. #------------------------------------------------------------------------------
  3444. def _possibly_unimplemented(cls, require=True):
  3445. """
  3446. Construct a class that either runs tests as usual (require=True),
  3447. or each method skips if it encounters a common error.
  3448. """
  3449. if require:
  3450. return cls
  3451. else:
  3452. def wrap(fc):
  3453. @functools.wraps(fc)
  3454. def wrapper(*a, **kw):
  3455. try:
  3456. return fc(*a, **kw)
  3457. except (NotImplementedError, TypeError, ValueError,
  3458. IndexError, AttributeError):
  3459. raise pytest.skip("feature not implemented")
  3460. return wrapper
  3461. new_dict = dict(cls.__dict__)
  3462. for name, func in cls.__dict__.items():
  3463. if name.startswith('test_'):
  3464. new_dict[name] = wrap(func)
  3465. return type(cls.__name__ + "NotImplemented",
  3466. cls.__bases__,
  3467. new_dict)
  3468. def sparse_test_class(getset=True, slicing=True, slicing_assign=True,
  3469. fancy_indexing=True, fancy_assign=True,
  3470. fancy_multidim_indexing=True, fancy_multidim_assign=True,
  3471. minmax=True, nnz_axis=True):
  3472. """
  3473. Construct a base class, optionally converting some of the tests in
  3474. the suite to check that the feature is not implemented.
  3475. """
  3476. bases = (_TestCommon,
  3477. _possibly_unimplemented(_TestGetSet, getset),
  3478. _TestSolve,
  3479. _TestInplaceArithmetic,
  3480. _TestArithmetic,
  3481. _possibly_unimplemented(_TestSlicing, slicing),
  3482. _possibly_unimplemented(_TestSlicingAssign, slicing_assign),
  3483. _possibly_unimplemented(_TestFancyIndexing, fancy_indexing),
  3484. _possibly_unimplemented(_TestFancyIndexingAssign,
  3485. fancy_assign),
  3486. _possibly_unimplemented(_TestFancyMultidim,
  3487. fancy_indexing and fancy_multidim_indexing),
  3488. _possibly_unimplemented(_TestFancyMultidimAssign,
  3489. fancy_multidim_assign and fancy_assign),
  3490. _possibly_unimplemented(_TestMinMax, minmax),
  3491. _possibly_unimplemented(_TestGetNnzAxis, nnz_axis))
  3492. # check that test names do not clash
  3493. names = {}
  3494. for cls in bases:
  3495. for name in cls.__dict__:
  3496. if not name.startswith('test_'):
  3497. continue
  3498. old_cls = names.get(name)
  3499. if old_cls is not None:
  3500. raise ValueError(f"Test class {cls.__name__} overloads test "
  3501. f"{name} defined in {old_cls.__name__}")
  3502. names[name] = cls
  3503. return type("TestBase", bases, {})
  3504. #------------------------------------------------------------------------------
  3505. # Matrix class based tests
  3506. #------------------------------------------------------------------------------
  3507. class _CompressedMixin:
  3508. def _test_setdiag_sorted(self, D):
  3509. A = self.spcreator(D)
  3510. # Force sorted indices
  3511. A.has_sorted_indices = False
  3512. A.sort_indices()
  3513. assert A.has_sorted_indices
  3514. # Set the diagonal (only 1 new entry / 1002, so _insert_many is used)
  3515. with check_remains_sorted(A):
  3516. A.setdiag(5)
  3517. assert np.all(A.diagonal() == 5)
  3518. def test_setdiag_noconvert(self):
  3519. # Test small ratio of new elements
  3520. # see gh-21791 setting mixture of existing and not when new_values < 0.001*nnz
  3521. # see gh-23644
  3522. # Create off-main-diagonal elements so that we have multiple elements
  3523. # per column to see if the indices are sorted or not
  3524. N = 1002
  3525. vals = np.arange(1, N + 1)
  3526. diags = np.c_[[-1, 2, 1]] * vals # rows are diagonal entries
  3527. # Remove a small number of diagonal elements so we have a small ratio
  3528. # of new ones to force _cs_matrix._setdiag to remain in CSC/CSR format
  3529. N_new = 3
  3530. diags[1, -N_new:] = 0.0
  3531. offsets = [-1, 0, 1]
  3532. D = self.dia_container((diags, offsets), shape=(N, N))
  3533. return self._test_setdiag_sorted(D)
  3534. def test_setdiag_cooconvert(self):
  3535. # Test large ratio of new elements
  3536. # see gh-23644
  3537. # Create off-main-diagonal elements so that we have multiple elements
  3538. # per column to see if the indices are sorted or not
  3539. N = 1002
  3540. vals = np.arange(1, N + 1) # only a few non-zeros
  3541. diags = np.c_[[-1, 2, 1]] * vals
  3542. # Remove many entries so we have a large ratio of new entries
  3543. diags[1, 5:] = 0.0
  3544. offsets = [-1, 0, 1]
  3545. D = self.dia_container((diags, offsets), shape=(N, N))
  3546. return self._test_setdiag_sorted(D)
  3547. class TestCSR(_CompressedMixin, sparse_test_class()):
  3548. @classmethod
  3549. def spcreator(cls, *args, **kwargs):
  3550. with warnings.catch_warnings():
  3551. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  3552. return csr_array(*args, **kwargs)
  3553. math_dtypes = [np.bool_, np.int_, np.float64, np.complex128]
  3554. def test_constructor1(self):
  3555. b = array([[0, 4, 0],
  3556. [3, 0, 0],
  3557. [0, 2, 0]], 'd')
  3558. bsp = self.csr_container(b)
  3559. assert_array_almost_equal(bsp.data,[4,3,2])
  3560. assert_array_equal(bsp.indices,[1,0,1])
  3561. assert_array_equal(bsp.indptr,[0,1,2,3])
  3562. assert_equal(bsp.nnz,3)
  3563. assert_equal(bsp.format,'csr')
  3564. assert_array_equal(bsp.toarray(), b)
  3565. def test_constructor2(self):
  3566. b = zeros((6,6),'d')
  3567. b[3,4] = 5
  3568. bsp = self.csr_container(b)
  3569. assert_array_almost_equal(bsp.data,[5])
  3570. assert_array_equal(bsp.indices,[4])
  3571. assert_array_equal(bsp.indptr,[0,0,0,0,1,1,1])
  3572. assert_array_almost_equal(bsp.toarray(), b)
  3573. def test_constructor3(self):
  3574. b = array([[1, 0],
  3575. [0, 2],
  3576. [3, 0]], 'd')
  3577. bsp = self.csr_container(b)
  3578. assert_array_almost_equal(bsp.data,[1,2,3])
  3579. assert_array_equal(bsp.indices,[0,1,0])
  3580. assert_array_equal(bsp.indptr,[0,1,2,3])
  3581. assert_array_almost_equal(bsp.toarray(), b)
  3582. def test_constructor4(self):
  3583. # using (data, ij) format
  3584. row = array([2, 3, 1, 3, 0, 1, 3, 0, 2, 1, 2])
  3585. col = array([0, 1, 0, 0, 1, 1, 2, 2, 2, 2, 1])
  3586. data = array([6., 10., 3., 9., 1., 4.,
  3587. 11., 2., 8., 5., 7.])
  3588. ij = vstack((row,col))
  3589. csr = self.csr_container((data,ij),(4,3))
  3590. assert_array_equal(arange(12).reshape(4, 3), csr.toarray())
  3591. # using Python lists and a specified dtype
  3592. csr = self.csr_container(([2**63 + 1, 1], ([0, 1], [0, 1])), dtype=np.uint64)
  3593. dense = array([[2**63 + 1, 0], [0, 1]], dtype=np.uint64)
  3594. assert_array_equal(dense, csr.toarray())
  3595. # with duplicates (should sum the duplicates)
  3596. csr = self.csr_container(([1,1,1,1], ([0,2,2,0], [0,1,1,0])))
  3597. assert csr.nnz == 2
  3598. def test_constructor5(self):
  3599. # infer dimensions from arrays
  3600. indptr = array([0,1,3,3])
  3601. indices = array([0,5,1,2])
  3602. data = array([1,2,3,4])
  3603. csr = self.csr_container((data, indices, indptr))
  3604. assert_array_equal(csr.shape,(3,6))
  3605. def test_constructor6(self):
  3606. # infer dimensions and dtype from lists
  3607. indptr = [0, 1, 3, 3]
  3608. indices = [0, 5, 1, 2]
  3609. data = [1, 2, 3, 4]
  3610. csr = self.csr_container((data, indices, indptr))
  3611. assert_array_equal(csr.shape, (3,6))
  3612. assert_(np.issubdtype(csr.dtype, np.signedinteger))
  3613. def test_constructor_smallcol(self):
  3614. # int64 indices not required
  3615. data = arange(6) + 1
  3616. col = array([1, 2, 1, 0, 0, 2], dtype=np.int64)
  3617. ptr = array([0, 2, 4, 6], dtype=np.int64)
  3618. a = self.csr_container((data, col, ptr), shape=(3, 3))
  3619. b = array([[0, 1, 2],
  3620. [4, 3, 0],
  3621. [5, 0, 6]], 'd')
  3622. # sparray is less aggressive in downcasting indices to int32 than spmatrix
  3623. expected_dtype = np.dtype(np.int64 if self.is_array_test else np.int32)
  3624. assert_equal(a.indptr.dtype, expected_dtype)
  3625. assert_equal(a.indices.dtype, expected_dtype)
  3626. assert_array_equal(a.toarray(), b)
  3627. def test_constructor_largecol(self):
  3628. # int64 indices required
  3629. data = arange(6) + 1
  3630. large = np.iinfo(np.int32).max + 100
  3631. col = array([0, 1, 2, large, large+1, large+2], dtype=np.int64)
  3632. ptr = array([0, 2, 4, 6], dtype=np.int64)
  3633. a = self.csr_container((data, col, ptr))
  3634. assert_equal(a.indptr.dtype, np.dtype(np.int64))
  3635. assert_equal(a.indices.dtype, np.dtype(np.int64))
  3636. assert_array_equal(a.shape, (3, max(col)+1))
  3637. def test_sort_indices(self):
  3638. data = arange(5)
  3639. indices = array([7, 2, 1, 5, 4])
  3640. indptr = array([0, 3, 5])
  3641. asp = self.csr_container((data, indices, indptr), shape=(2,10))
  3642. bsp = asp.copy()
  3643. asp.sort_indices()
  3644. assert_array_equal(asp.indices,[1, 2, 7, 4, 5])
  3645. assert_array_equal(asp.toarray(), bsp.toarray())
  3646. def test_eliminate_zeros(self):
  3647. data = array([1, 0, 0, 0, 2, 0, 3, 0])
  3648. indices = array([1, 2, 3, 4, 5, 6, 7, 8])
  3649. indptr = array([0, 3, 8])
  3650. asp = self.csr_container((data, indices, indptr), shape=(2,10))
  3651. bsp = asp.copy()
  3652. asp.eliminate_zeros()
  3653. assert_array_equal(asp.nnz, 3)
  3654. assert_array_equal(asp.data,[1, 2, 3])
  3655. assert_array_equal(asp.toarray(), bsp.toarray())
  3656. def test_ufuncs(self):
  3657. X = self.csr_container(np.arange(20).reshape(4, 5) / 20.)
  3658. for f in ["sin", "tan", "arcsin", "arctan", "sinh", "tanh",
  3659. "arcsinh", "arctanh", "rint", "sign", "expm1", "log1p",
  3660. "deg2rad", "rad2deg", "floor", "ceil", "trunc", "sqrt"]:
  3661. assert_equal(hasattr(self.datsp, f), True)
  3662. X2 = getattr(X, f)()
  3663. assert_equal(X.shape, X2.shape)
  3664. assert_array_equal(X.indices, X2.indices)
  3665. assert_array_equal(X.indptr, X2.indptr)
  3666. assert_array_equal(X2.toarray(), getattr(np, f)(X.toarray()))
  3667. def test_unsorted_arithmetic(self):
  3668. data = arange(5)
  3669. indices = array([7, 2, 1, 5, 4])
  3670. indptr = array([0, 3, 5])
  3671. asp = self.csr_container((data, indices, indptr), shape=(2,10))
  3672. data = arange(6)
  3673. indices = array([8, 1, 5, 7, 2, 4])
  3674. indptr = array([0, 2, 6])
  3675. bsp = self.csr_container((data, indices, indptr), shape=(2,10))
  3676. assert_equal((asp + bsp).toarray(), asp.toarray() + bsp.toarray())
  3677. def test_fancy_indexing_broadcast(self):
  3678. # broadcasting indexing mode is supported
  3679. I = np.array([[1], [2], [3]])
  3680. J = np.array([3, 4, 2])
  3681. np.random.seed(1234)
  3682. D = self.asdense(np.random.rand(5, 7))
  3683. S = self.spcreator(D)
  3684. SIJ = S[I,J]
  3685. if issparse(SIJ):
  3686. SIJ = SIJ.toarray()
  3687. assert_equal(SIJ, D[I,J])
  3688. def test_has_sorted_indices(self):
  3689. "Ensure has_sorted_indices memoizes sorted state for sort_indices"
  3690. sorted_inds = np.array([0, 1])
  3691. unsorted_inds = np.array([1, 0])
  3692. data = np.array([1, 1])
  3693. indptr = np.array([0, 2])
  3694. M = self.csr_container((data, sorted_inds, indptr)).copy()
  3695. assert_equal(True, M.has_sorted_indices)
  3696. assert isinstance(M.has_sorted_indices, bool)
  3697. M = self.csr_container((data, unsorted_inds, indptr)).copy()
  3698. assert_equal(False, M.has_sorted_indices)
  3699. # set by sorting
  3700. M.sort_indices()
  3701. assert_equal(True, M.has_sorted_indices)
  3702. assert_array_equal(M.indices, sorted_inds)
  3703. M = self.csr_container((data, unsorted_inds, indptr)).copy()
  3704. # set manually (although underlyingly unsorted)
  3705. M.has_sorted_indices = True
  3706. assert_equal(True, M.has_sorted_indices)
  3707. assert_array_equal(M.indices, unsorted_inds)
  3708. # ensure sort bypassed when has_sorted_indices == True
  3709. M.sort_indices()
  3710. assert_array_equal(M.indices, unsorted_inds)
  3711. def test_has_canonical_format(self):
  3712. "Ensure has_canonical_format memoizes state for sum_duplicates"
  3713. info_no_dups = (np.array([2]), np.array([0]), np.array([0, 1]))
  3714. info_with_dups = (np.array([1, 1]), np.array([0, 0]), np.array([0, 2]))
  3715. M = self.csr_container(info_no_dups)
  3716. assert_equal(True, M.has_canonical_format)
  3717. M = self.csr_container(info_with_dups).copy()
  3718. assert_equal(False, M.has_canonical_format)
  3719. assert isinstance(M.has_canonical_format, bool)
  3720. # set flag by deduplicating
  3721. M.sum_duplicates()
  3722. assert_equal(True, M.has_canonical_format)
  3723. assert_equal(1, len(M.indices))
  3724. # manually set flag True (although underlyingly duplicated)
  3725. M = self.csr_container(info_with_dups).copy()
  3726. M.has_canonical_format = True
  3727. assert_equal(True, M.has_canonical_format)
  3728. assert_equal(2, len(M.indices)) # unaffected content
  3729. # ensure deduplication bypassed when has_canonical_format == True
  3730. M.sum_duplicates()
  3731. assert_equal(2, len(M.indices)) # still has duplicates!!!!
  3732. # ensure deduplication reenabled when has_canonical_format == False
  3733. M.has_canonical_format = False
  3734. M.sum_duplicates()
  3735. assert_equal(1, len(M.indices))
  3736. assert_equal(True, M.has_canonical_format)
  3737. # manually set flag False (although underlyingly canonical)
  3738. M.has_canonical_format = False
  3739. assert_equal(False, M.has_canonical_format)
  3740. Mcheck = self.csr_container((M.data, M.indices, M.indptr))
  3741. assert_equal(True, Mcheck.has_canonical_format)
  3742. # sum_duplicates does not complain when no work to do
  3743. M.sum_duplicates()
  3744. assert_equal(True, M.has_canonical_format)
  3745. # check assignments maintain canonical format
  3746. M = self.csr_container((np.array([2]), np.array([2]), np.array([0, 1, 1, 1])))
  3747. assert_equal(M.shape, (3, 3))
  3748. with warnings.catch_warnings():
  3749. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  3750. M[0, 1] = 2
  3751. M[1, :] *= 5
  3752. M[0, 2] = 3
  3753. assert_equal(True, M.has_canonical_format)
  3754. Mcheck = self.csr_container((M.data, M.indices, M.indptr))
  3755. assert_equal(True, Mcheck.has_canonical_format)
  3756. # resetting index arrays before accessing M.has_canonical_format is OK
  3757. M = self.csr_container(info_no_dups)
  3758. M.data, M.indices, M.indptr = info_with_dups
  3759. assert_equal(False, M.has_canonical_format)
  3760. assert_equal(2, len(M.indices)) # dups and has_canonical_format is False
  3761. # but reset after accessing M.has_canonical_format can break flag
  3762. M = self.csr_container(info_no_dups)
  3763. M.has_canonical_format # underlying attr is set here
  3764. M.data, M.indices, M.indptr = info_with_dups
  3765. assert_equal(True, M.has_canonical_format)
  3766. assert_equal(2, len(M.indices)) # dups but has_canonical_format is True
  3767. M.sum_duplicates()
  3768. assert_equal(2, len(M.indices)) # still has duplicates!!!!
  3769. def test_scalar_idx_dtype(self):
  3770. # Check that index dtype takes into account all parameters
  3771. # passed to sparsetools, including the scalar ones
  3772. indptr = np.zeros(2, dtype=np.int32)
  3773. indices = np.zeros(0, dtype=np.int32)
  3774. vals = np.zeros(0)
  3775. a = self.csr_container((vals, indices, indptr), shape=(1, 2**31-1))
  3776. b = self.csr_container((vals, indices, indptr), shape=(1, 2**31))
  3777. ij = np.zeros((2, 0), dtype=np.int32)
  3778. c = self.csr_container((vals, ij), shape=(1, 2**31-1))
  3779. d = self.csr_container((vals, ij), shape=(1, 2**31))
  3780. e = self.csr_container((1, 2**31-1))
  3781. f = self.csr_container((1, 2**31))
  3782. assert_equal(a.indptr.dtype, np.int32)
  3783. assert_equal(b.indptr.dtype, np.int64)
  3784. assert_equal(c.indptr.dtype, np.int32)
  3785. assert_equal(d.indptr.dtype, np.int64)
  3786. assert_equal(e.indptr.dtype, np.int32)
  3787. assert_equal(f.indptr.dtype, np.int64)
  3788. # These shouldn't fail
  3789. for x in [a, b, c, d, e, f]:
  3790. x + x
  3791. def test_binop_explicit_zeros(self):
  3792. # Check that binary ops don't introduce spurious explicit zeros.
  3793. # See gh-9619 for context.
  3794. a = self.csr_container([[0, 1, 0]])
  3795. b = self.csr_container([[1, 1, 0]])
  3796. assert (a + b).nnz == 2
  3797. assert a.multiply(b).nnz == 1
  3798. TestCSR.init_class()
  3799. class TestCSRMatrix(_MatrixMixin, TestCSR):
  3800. @classmethod
  3801. def spcreator(cls, *args, **kwargs):
  3802. with warnings.catch_warnings():
  3803. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  3804. return csr_matrix(*args, **kwargs)
  3805. def test_spmatrix_subscriptable():
  3806. result = csr_matrix[np.int8]
  3807. assert isinstance(result, GenericAlias)
  3808. assert result.__origin__ is csr_matrix
  3809. assert result.__args__ == (np.int8,)
  3810. TestCSRMatrix.init_class()
  3811. class TestCSC(_CompressedMixin, sparse_test_class()):
  3812. @classmethod
  3813. def spcreator(cls, *args, **kwargs):
  3814. with warnings.catch_warnings():
  3815. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  3816. return csc_array(*args, **kwargs)
  3817. math_dtypes = [np.bool_, np.int_, np.float64, np.complex128]
  3818. def test_constructor1(self):
  3819. b = array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 2, 0, 3]], 'd')
  3820. bsp = self.csc_container(b)
  3821. assert_array_almost_equal(bsp.data,[1,2,1,3])
  3822. assert_array_equal(bsp.indices,[0,2,1,2])
  3823. assert_array_equal(bsp.indptr,[0,1,2,3,4])
  3824. assert_equal(bsp.nnz,4)
  3825. assert_equal(bsp.shape,b.shape)
  3826. assert_equal(bsp.format,'csc')
  3827. def test_constructor2(self):
  3828. b = zeros((6,6),'d')
  3829. b[2,4] = 5
  3830. bsp = self.csc_container(b)
  3831. assert_array_almost_equal(bsp.data,[5])
  3832. assert_array_equal(bsp.indices,[2])
  3833. assert_array_equal(bsp.indptr,[0,0,0,0,0,1,1])
  3834. def test_constructor3(self):
  3835. b = array([[1, 0], [0, 0], [0, 2]], 'd')
  3836. bsp = self.csc_container(b)
  3837. assert_array_almost_equal(bsp.data,[1,2])
  3838. assert_array_equal(bsp.indices,[0,2])
  3839. assert_array_equal(bsp.indptr,[0,1,2])
  3840. def test_constructor4(self):
  3841. # using (data, ij) format
  3842. row = array([2, 3, 1, 3, 0, 1, 3, 0, 2, 1, 2])
  3843. col = array([0, 1, 0, 0, 1, 1, 2, 2, 2, 2, 1])
  3844. data = array([6., 10., 3., 9., 1., 4., 11., 2., 8., 5., 7.])
  3845. ij = vstack((row,col))
  3846. csc = self.csc_container((data,ij),(4,3))
  3847. assert_array_equal(arange(12).reshape(4, 3), csc.toarray())
  3848. # with duplicates (should sum the duplicates)
  3849. csc = self.csc_container(([1,1,1,1], ([0,2,2,0], [0,1,1,0])))
  3850. assert csc.nnz == 2
  3851. def test_constructor5(self):
  3852. # infer dimensions from arrays
  3853. indptr = array([0,1,3,3])
  3854. indices = array([0,5,1,2])
  3855. data = array([1,2,3,4])
  3856. csc = self.csc_container((data, indices, indptr))
  3857. assert_array_equal(csc.shape,(6,3))
  3858. def test_constructor6(self):
  3859. # infer dimensions and dtype from lists
  3860. indptr = [0, 1, 3, 3]
  3861. indices = [0, 5, 1, 2]
  3862. data = [1, 2, 3, 4]
  3863. csc = self.csc_container((data, indices, indptr))
  3864. assert_array_equal(csc.shape,(6,3))
  3865. assert_(np.issubdtype(csc.dtype, np.signedinteger))
  3866. def test_eliminate_zeros(self):
  3867. data = array([1, 0, 0, 0, 2, 0, 3, 0])
  3868. indices = array([1, 2, 3, 4, 5, 6, 7, 8])
  3869. indptr = array([0, 3, 8])
  3870. asp = self.csc_container((data, indices, indptr), shape=(10,2))
  3871. bsp = asp.copy()
  3872. asp.eliminate_zeros()
  3873. assert_array_equal(asp.nnz, 3)
  3874. assert_array_equal(asp.data,[1, 2, 3])
  3875. assert_array_equal(asp.toarray(), bsp.toarray())
  3876. def test_sort_indices(self):
  3877. data = arange(5)
  3878. row = array([7, 2, 1, 5, 4])
  3879. ptr = [0, 3, 5]
  3880. asp = self.csc_container((data, row, ptr), shape=(10,2))
  3881. bsp = asp.copy()
  3882. asp.sort_indices()
  3883. assert_array_equal(asp.indices,[1, 2, 7, 4, 5])
  3884. assert_array_equal(asp.toarray(), bsp.toarray())
  3885. def test_ufuncs(self):
  3886. X = self.csc_container(np.arange(21).reshape(7, 3) / 21.)
  3887. for f in ["sin", "tan", "arcsin", "arctan", "sinh", "tanh",
  3888. "arcsinh", "arctanh", "rint", "sign", "expm1", "log1p",
  3889. "deg2rad", "rad2deg", "floor", "ceil", "trunc", "sqrt"]:
  3890. assert_equal(hasattr(self.datsp, f), True)
  3891. X2 = getattr(X, f)()
  3892. assert_equal(X.shape, X2.shape)
  3893. assert_array_equal(X.indices, X2.indices)
  3894. assert_array_equal(X.indptr, X2.indptr)
  3895. assert_array_equal(X2.toarray(), getattr(np, f)(X.toarray()))
  3896. def test_unsorted_arithmetic(self):
  3897. data = arange(5)
  3898. indices = array([7, 2, 1, 5, 4])
  3899. indptr = array([0, 3, 5])
  3900. asp = self.csc_container((data, indices, indptr), shape=(10,2))
  3901. data = arange(6)
  3902. indices = array([8, 1, 5, 7, 2, 4])
  3903. indptr = array([0, 2, 6])
  3904. bsp = self.csc_container((data, indices, indptr), shape=(10,2))
  3905. assert_equal((asp + bsp).toarray(), asp.toarray() + bsp.toarray())
  3906. def test_fancy_indexing_broadcast(self):
  3907. # broadcasting indexing mode is supported
  3908. I = np.array([[1], [2], [3]])
  3909. J = np.array([3, 4, 2])
  3910. np.random.seed(1234)
  3911. D = self.asdense(np.random.rand(5, 7))
  3912. S = self.spcreator(D)
  3913. SIJ = S[I,J]
  3914. if issparse(SIJ):
  3915. SIJ = SIJ.toarray()
  3916. assert_equal(SIJ, D[I,J])
  3917. def test_scalar_idx_dtype(self):
  3918. # Check that index dtype takes into account all parameters
  3919. # passed to sparsetools, including the scalar ones
  3920. indptr = np.zeros(2, dtype=np.int32)
  3921. indices = np.zeros(0, dtype=np.int32)
  3922. vals = np.zeros(0)
  3923. a = self.csc_container((vals, indices, indptr), shape=(2**31-1, 1))
  3924. b = self.csc_container((vals, indices, indptr), shape=(2**31, 1))
  3925. ij = np.zeros((2, 0), dtype=np.int32)
  3926. c = self.csc_container((vals, ij), shape=(2**31-1, 1))
  3927. d = self.csc_container((vals, ij), shape=(2**31, 1))
  3928. e = self.csr_container((1, 2**31-1))
  3929. f = self.csr_container((1, 2**31))
  3930. assert_equal(a.indptr.dtype, np.int32)
  3931. assert_equal(b.indptr.dtype, np.int64)
  3932. assert_equal(c.indptr.dtype, np.int32)
  3933. assert_equal(d.indptr.dtype, np.int64)
  3934. assert_equal(e.indptr.dtype, np.int32)
  3935. assert_equal(f.indptr.dtype, np.int64)
  3936. # These shouldn't fail
  3937. for x in [a, b, c, d, e, f]:
  3938. x + x
  3939. TestCSC.init_class()
  3940. class TestCSCMatrix(_MatrixMixin, TestCSC):
  3941. @classmethod
  3942. def spcreator(cls, *args, **kwargs):
  3943. with warnings.catch_warnings():
  3944. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  3945. return csc_matrix(*args, **kwargs)
  3946. TestCSCMatrix.init_class()
  3947. class TestDOK(sparse_test_class(minmax=False, nnz_axis=False)):
  3948. spcreator = dok_array
  3949. math_dtypes = [np.int_, np.float64, np.complex128]
  3950. def test_mult(self):
  3951. A = self.dok_container((10, 12))
  3952. A[0, 3] = 10
  3953. A[5, 6] = 20
  3954. D = A @ A.T
  3955. E = A @ A.T.conjugate()
  3956. assert_array_equal(D.toarray(), E.toarray())
  3957. def test_add_nonzero(self):
  3958. A = self.spcreator((3,2))
  3959. A[0,1] = -10
  3960. A[2,0] = 20
  3961. A = A + 10
  3962. B = array([[10, 0], [10, 10], [30, 10]])
  3963. assert_array_equal(A.toarray(), B)
  3964. A = A + 1j
  3965. B = B + 1j
  3966. assert_array_equal(A.toarray(), B)
  3967. def test_dok_divide_scalar(self):
  3968. A = self.spcreator((3,2))
  3969. A[0,1] = -10
  3970. A[2,0] = 20
  3971. assert_array_equal((A/1j).toarray(), A.toarray()/1j)
  3972. assert_array_equal((A/9).toarray(), A.toarray()/9)
  3973. def test_convert(self):
  3974. # Test provided by Andrew Straw. Fails in SciPy <= r1477.
  3975. (m, n) = (6, 7)
  3976. a = self.dok_container((m, n))
  3977. # set a few elements, but none in the last column
  3978. a[2,1] = 1
  3979. a[0,2] = 2
  3980. a[3,1] = 3
  3981. a[1,5] = 4
  3982. a[4,3] = 5
  3983. a[4,2] = 6
  3984. # assert that the last column is all zeros
  3985. assert_array_equal(a.toarray()[:,n-1], zeros(m,))
  3986. # make sure it still works for CSC format
  3987. csc = a.tocsc()
  3988. assert_array_equal(csc.toarray()[:,n-1], zeros(m,))
  3989. # now test CSR
  3990. (m, n) = (n, m)
  3991. b = a.transpose()
  3992. assert_equal(b.shape, (m, n))
  3993. # assert that the last row is all zeros
  3994. assert_array_equal(b.toarray()[m-1,:], zeros(n,))
  3995. # make sure it still works for CSR format
  3996. csr = b.tocsr()
  3997. assert_array_equal(csr.toarray()[m-1,:], zeros(n,))
  3998. def test_ctor(self):
  3999. # Empty ctor
  4000. assert_raises(TypeError, self.dok_container)
  4001. # Dense ctor
  4002. b = array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 2, 0, 3]], 'd')
  4003. A = self.dok_container(b)
  4004. assert_equal(b.dtype, A.dtype)
  4005. assert_equal(A.toarray(), b)
  4006. # Sparse ctor
  4007. c = self.csr_container(b)
  4008. assert_equal(A.toarray(), c.toarray())
  4009. data = [[0, 1, 2], [3, 0, 0]]
  4010. d = self.dok_container(data, dtype=np.float32)
  4011. assert_equal(d.dtype, np.float32)
  4012. da = d.toarray()
  4013. assert_equal(da.dtype, np.float32)
  4014. assert_array_equal(da, data)
  4015. def test_ticket1160(self):
  4016. # Regression test for ticket #1160.
  4017. a = self.dok_container((3,3))
  4018. a[0,0] = 0
  4019. # This assert would fail, because the above assignment would
  4020. # incorrectly call __set_item__ even though the value was 0.
  4021. assert_((0,0) not in a.keys(), "Unexpected entry (0,0) in keys")
  4022. # Slice assignments were also affected.
  4023. b = self.dok_container((3,3))
  4024. b[:,0] = 0
  4025. assert_(len(b.keys()) == 0, "Unexpected entries in keys")
  4026. class TestDOKMatrix(_MatrixMixin, TestDOK):
  4027. spcreator = dok_matrix
  4028. TestDOK.init_class()
  4029. TestDOKMatrix.init_class()
  4030. class TestLIL(sparse_test_class(minmax=False)):
  4031. spcreator = lil_array
  4032. math_dtypes = [np.int_, np.float64, np.complex128]
  4033. def test_dot(self):
  4034. A = zeros((10, 10), np.complex128)
  4035. A[0, 3] = 10
  4036. A[5, 6] = 20j
  4037. B = self.lil_container((10, 10), dtype=np.complex128)
  4038. B[0, 3] = 10
  4039. B[5, 6] = 20j
  4040. # TODO: properly handle this assertion on ppc64le
  4041. if platform.machine() != 'ppc64le':
  4042. assert_array_equal(A @ A.T, (B @ B.T).toarray())
  4043. assert_array_equal(A @ A.conjugate().T, (B @ B.conjugate().T).toarray())
  4044. def test_scalar_mul(self):
  4045. x = self.lil_container((3, 3))
  4046. x[0, 0] = 2
  4047. x = x*2
  4048. assert_equal(x[0, 0], 4)
  4049. x = x*0
  4050. assert_equal(x[0, 0], 0)
  4051. def test_truediv_scalar(self):
  4052. A = self.spcreator((3, 2))
  4053. A[0, 1] = -10
  4054. A[2, 0] = 20
  4055. assert_array_equal((A / 1j).toarray(), A.toarray() / 1j)
  4056. assert_array_equal((A / 9).toarray(), A.toarray() / 9)
  4057. def test_inplace_ops(self):
  4058. A = self.lil_container([[0, 2, 3], [4, 0, 6]])
  4059. B = self.lil_container([[0, 1, 0], [0, 2, 3]])
  4060. data = {'add': (B, A + B),
  4061. 'sub': (B, A - B),
  4062. 'mul': (3, A * 3)}
  4063. for op, (other, expected) in data.items():
  4064. result = A.copy()
  4065. getattr(result, f'__i{op}__')(other)
  4066. assert_array_equal(result.toarray(), expected.toarray())
  4067. # Ticket 1604.
  4068. A = self.lil_container((1, 3), dtype=np.dtype('float64'))
  4069. B = self.asdense([0.1, 0.1, 0.1])
  4070. A[0, :] += B
  4071. assert_array_equal(A[0, :].toarray(), B)
  4072. def test_lil_iteration(self):
  4073. row_data = [[1, 2, 3], [4, 5, 6]]
  4074. B = self.lil_container(array(row_data))
  4075. for r, row in enumerate(B):
  4076. assert_array_equal(row.toarray(), array(row_data[r], ndmin=row.ndim))
  4077. def test_lil_from_csr(self):
  4078. # Tests whether a LIL can be constructed from a CSR.
  4079. B = self.lil_container((10, 10))
  4080. B[0, 3] = 10
  4081. B[5, 6] = 20
  4082. B[8, 3] = 30
  4083. B[3, 8] = 40
  4084. B[8, 9] = 50
  4085. C = B.tocsr()
  4086. D = self.lil_container(C)
  4087. assert_array_equal(C.toarray(), D.toarray())
  4088. def test_fancy_indexing_lil(self):
  4089. M = self.asdense(arange(25).reshape(5, 5))
  4090. A = self.lil_container(M)
  4091. assert_equal(A[array([1, 2, 3]), 2:3].toarray(),
  4092. M[array([1, 2, 3]), 2:3])
  4093. def test_point_wise_multiply(self):
  4094. l = self.lil_container((4, 3))
  4095. l[0, 0] = 1
  4096. l[1, 1] = 2
  4097. l[2, 2] = 3
  4098. l[3, 1] = 4
  4099. m = self.lil_container((4, 3))
  4100. m[0, 0] = 1
  4101. m[0, 1] = 2
  4102. m[2, 2] = 3
  4103. m[3, 1] = 4
  4104. m[3, 2] = 4
  4105. assert_array_equal(l.multiply(m).toarray(),
  4106. m.multiply(l).toarray())
  4107. assert_array_equal(l.multiply(m).toarray(),
  4108. [[1, 0, 0],
  4109. [0, 0, 0],
  4110. [0, 0, 9],
  4111. [0, 16, 0]])
  4112. def test_lil_multiply_removal(self):
  4113. # Ticket #1427.
  4114. a = self.lil_container(np.ones((3, 3)))
  4115. a *= 2.
  4116. a[0, :] = 0
  4117. class TestLILMatrix(_MatrixMixin, TestLIL):
  4118. spcreator = lil_matrix
  4119. TestLIL.init_class()
  4120. TestLILMatrix.init_class()
  4121. class BaseTestCOO:
  4122. math_dtypes = [np.int_, np.float64, np.complex128]
  4123. def test_constructor1(self):
  4124. # unsorted triplet format
  4125. row = array([2, 3, 1, 3, 0, 1, 3, 0, 2, 1, 2])
  4126. col = array([0, 1, 0, 0, 1, 1, 2, 2, 2, 2, 1])
  4127. data = array([6., 10., 3., 9., 1., 4., 11., 2., 8., 5., 7.])
  4128. coo = self.coo_container((data,(row,col)),(4,3))
  4129. assert_array_equal(arange(12).reshape(4, 3), coo.toarray())
  4130. # using Python lists and a specified dtype
  4131. coo = self.coo_container(([2**63 + 1, 1], ([0, 1], [0, 1])), dtype=np.uint64)
  4132. dense = array([[2**63 + 1, 0], [0, 1]], dtype=np.uint64)
  4133. assert_array_equal(dense, coo.toarray())
  4134. def test_constructor2(self):
  4135. # unsorted triplet format with duplicates (which are summed)
  4136. row = array([0,1,2,2,2,2,0,0,2,2])
  4137. col = array([0,2,0,2,1,1,1,0,0,2])
  4138. data = array([2,9,-4,5,7,0,-1,2,1,-5])
  4139. coo = self.coo_container((data,(row,col)),(3,3))
  4140. mat = array([[4, -1, 0], [0, 0, 9], [-3, 7, 0]])
  4141. assert_array_equal(mat, coo.toarray())
  4142. def test_constructor3(self):
  4143. # empty matrix
  4144. coo = self.coo_container((4,3))
  4145. assert_array_equal(coo.shape,(4,3))
  4146. assert_array_equal(coo.row,[])
  4147. assert_array_equal(coo.col,[])
  4148. assert_array_equal(coo.data,[])
  4149. assert_array_equal(coo.toarray(), zeros((4, 3)))
  4150. def test_constructor4(self):
  4151. # from dense matrix
  4152. mat = array([[0,1,0,0],
  4153. [7,0,3,0],
  4154. [0,4,0,0]])
  4155. coo = self.coo_container(mat)
  4156. assert_array_equal(coo.toarray(), mat)
  4157. # upgrade rank 1 arrays to row matrix
  4158. mat = array([0,1,0,0])
  4159. coo = self.coo_container(mat)
  4160. expected = mat if self.is_array_test else mat.reshape(1, -1)
  4161. assert_array_equal(coo.toarray(), expected)
  4162. # error if second arg interpreted as shape (gh-9919)
  4163. with pytest.raises(TypeError, match=r'object cannot be interpreted'):
  4164. self.coo_container([0, 11, 22, 33], ([0, 1, 2, 3], [0, 0, 0, 0]))
  4165. # error if explicit shape arg doesn't match the dense matrix
  4166. with pytest.raises(ValueError, match=r'inconsistent shapes'):
  4167. self.coo_container([0, 11, 22, 33], shape=(4, 4))
  4168. def test_constructor_data_ij_dtypeNone(self):
  4169. data = [1]
  4170. coo = self.coo_container((data, ([0], [0])), dtype=None)
  4171. assert coo.dtype == np.array(data).dtype
  4172. @pytest.mark.xfail(run=False, reason='COO does not have a __getitem__')
  4173. def test_iterator(self):
  4174. pass
  4175. def test_todia_all_zeros(self):
  4176. zeros = [[0, 0]]
  4177. dia = self.coo_container(zeros).todia()
  4178. assert_array_equal(dia.toarray(), zeros)
  4179. def test_sum_duplicates(self):
  4180. coo = self.coo_container((4,3))
  4181. coo.sum_duplicates()
  4182. coo = self.coo_container(([1,2], ([1,0], [1,0])))
  4183. coo.sum_duplicates()
  4184. assert_array_equal(coo.toarray(), [[2,0],[0,1]])
  4185. coo = self.coo_container(([1,2], ([1,1], [1,1])))
  4186. coo.sum_duplicates()
  4187. assert_array_equal(coo.toarray(), [[0,0],[0,3]])
  4188. assert_array_equal(coo.row, [1])
  4189. assert_array_equal(coo.col, [1])
  4190. assert_array_equal(coo.data, [3])
  4191. def test_todok_duplicates(self):
  4192. coo = self.coo_container(([1,1,1,1], ([0,2,2,0], [0,1,1,0])))
  4193. dok = coo.todok()
  4194. assert_array_equal(dok.toarray(), coo.toarray())
  4195. def test_tocompressed_duplicates(self):
  4196. coo = self.coo_container(([1,1,1,1], ([0,2,2,0], [0,1,1,0])))
  4197. csr = coo.tocsr()
  4198. assert_equal(csr.nnz + 2, coo.nnz)
  4199. csc = coo.tocsc()
  4200. assert_equal(csc.nnz + 2, coo.nnz)
  4201. def test_has_canonical_format(self):
  4202. "Ensure has_canonical_format memoizes state for sum_duplicates"
  4203. A = self.coo_container((2, 3))
  4204. assert_equal(A.has_canonical_format, True)
  4205. A_array = np.array([[0, 2, 0]])
  4206. A_coords_form = (np.array([2]), (np.array([0]), np.array([1])))
  4207. A_coords_dups = (np.array([1, 1]), (np.array([0, 0]), np.array([1, 1])))
  4208. A = self.coo_container(A_array)
  4209. assert A.has_canonical_format is True
  4210. A = self.coo_container(A_coords_form)
  4211. assert A.has_canonical_format is False
  4212. A.sum_duplicates()
  4213. assert A.has_canonical_format is True
  4214. A = self.coo_container(A, copy=True)
  4215. assert A.has_canonical_format is True
  4216. A = self.coo_container(A, copy=False)
  4217. assert A.has_canonical_format is False
  4218. A.sum_duplicates()
  4219. assert A.has_canonical_format is True
  4220. A = self.coo_container(A_coords_dups)
  4221. assert A.has_canonical_format is False
  4222. assert_equal(A.nnz, 2) # duplicates
  4223. A.sum_duplicates()
  4224. assert A.has_canonical_format is True
  4225. assert_equal(A.nnz, 1)
  4226. # manually set
  4227. A.has_canonical_format = False
  4228. assert_equal(A.has_canonical_format, False)
  4229. assert_equal(A.nnz, 1) # incorrectly False
  4230. A.sum_duplicates() # check flag updated
  4231. assert_equal(A.has_canonical_format, True)
  4232. A = self.coo_container(A_coords_dups)
  4233. A.has_canonical_format = True
  4234. assert_equal(A.has_canonical_format, True)
  4235. assert_equal(A.nnz, 2) # incorrectly True
  4236. A.sum_duplicates() # check dups not removed due to flag
  4237. assert_equal(A.nnz, 2) # still has duplicates!!!!
  4238. def test_eliminate_zeros(self):
  4239. data = array([1, 0, 0, 0, 2, 0, 3, 0])
  4240. row = array([0, 0, 0, 1, 1, 1, 1, 1])
  4241. col = array([1, 2, 3, 4, 5, 6, 7, 8])
  4242. asp = self.coo_container((data, (row, col)), shape=(2,10))
  4243. bsp = asp.copy()
  4244. asp.eliminate_zeros()
  4245. assert_((asp.data != 0).all())
  4246. assert_array_equal(asp.toarray(), bsp.toarray())
  4247. def test_reshape_copy(self):
  4248. arr = [[0, 10, 0, 0], [0, 0, 0, 0], [0, 20, 30, 40]]
  4249. new_shape = (2, 6)
  4250. x = self.coo_container(arr)
  4251. y = x.reshape(new_shape)
  4252. assert_(y.data is x.data)
  4253. y = x.reshape(new_shape, copy=False)
  4254. assert_(y.data is x.data)
  4255. y = x.reshape(new_shape, copy=True)
  4256. assert_(not np.may_share_memory(y.data, x.data))
  4257. def test_large_dimensions_reshape(self):
  4258. # Test that reshape is immune to integer overflow when number of elements
  4259. # exceeds 2^31-1
  4260. mat1 = self.coo_container(([1], ([3000000], [1000])), (3000001, 1001))
  4261. mat2 = self.coo_container(([1], ([1000], [3000000])), (1001, 3000001))
  4262. # assert_array_equal is slow for big matrices because it expects dense
  4263. # Using __ne__ and nnz instead
  4264. assert_((mat1.reshape((1001, 3000001), order='C') != mat2).nnz == 0)
  4265. assert_((mat2.reshape((3000001, 1001), order='F') != mat1).nnz == 0)
  4266. class TestCOO(BaseTestCOO,
  4267. sparse_test_class(getset=True,
  4268. slicing=True, slicing_assign=True,
  4269. fancy_indexing=True, fancy_assign=True)):
  4270. spcreator = coo_array
  4271. class TestCOOMatrix(_MatrixMixin,
  4272. BaseTestCOO,
  4273. sparse_test_class(getset=False,
  4274. slicing=False, slicing_assign=False,
  4275. fancy_indexing=False, fancy_assign=False)):
  4276. spcreator = coo_matrix
  4277. TestCOO.init_class()
  4278. TestCOOMatrix.init_class()
  4279. def test_sparray_subscriptable():
  4280. result = coo_array[np.int8, tuple[int]]
  4281. assert isinstance(result, GenericAlias)
  4282. assert result.__origin__ is coo_array
  4283. assert result.__args__ == (np.int8, tuple[int])
  4284. result = coo_array[np.int8]
  4285. assert isinstance(result, GenericAlias)
  4286. assert result.__origin__ is coo_array
  4287. assert result.__args__ == (np.int8,)
  4288. class TestDIA(sparse_test_class(getset=False, slicing=False, slicing_assign=False,
  4289. fancy_indexing=False, fancy_assign=False,
  4290. minmax=False, nnz_axis=False)):
  4291. spcreator = dia_array
  4292. math_dtypes = [np.int_, np.float64, np.complex128]
  4293. def test_constructor1(self):
  4294. D = array([[1, 0, 3, 0],
  4295. [1, 2, 0, 4],
  4296. [0, 2, 3, 0],
  4297. [0, 0, 3, 4]])
  4298. data = np.array([[1,2,3,4]]).repeat(3,axis=0)
  4299. offsets = np.array([0,-1,2])
  4300. assert_equal(self.dia_container((data, offsets), shape=(4, 4)).toarray(), D)
  4301. @pytest.mark.xfail(run=False, reason='DIA does not have a __getitem__')
  4302. def test_iterator(self):
  4303. pass
  4304. @with_64bit_maxval_limit(3)
  4305. def test_setdiag_dtype(self):
  4306. m = self.dia_container(np.eye(3))
  4307. assert_equal(m.offsets.dtype, np.int32)
  4308. m.setdiag((3,), k=2)
  4309. assert_equal(m.offsets.dtype, np.int32)
  4310. m = self.dia_container(np.eye(4))
  4311. assert_equal(m.offsets.dtype, np.int64)
  4312. m.setdiag((3,), k=3)
  4313. assert_equal(m.offsets.dtype, np.int64)
  4314. def ill_cases(self):
  4315. # Ill-formed inputs and reference 2 x 2 outputs for testing _getnnz()
  4316. # and tocsr(): list of tuples
  4317. # (data, offsets, nnz, dense array, case description)
  4318. d1 = [[1]] # diagonal shorter than width
  4319. d3 = [[1, 2, 3]] # diagonal longer than width
  4320. return [(d1, [-1], 1, [[0, 0], [1, 0]],
  4321. 'shorter diagonal within'),
  4322. (d1, [1], 0, [[0, 0], [0, 0]],
  4323. 'shorter diagonal above (but within if full)'),
  4324. (d1, [3], 0, [[0, 0], [0, 0]],
  4325. 'shorter diagonal, all elements above'),
  4326. (d1, [-3], 0, [[0, 0], [0, 0]],
  4327. 'shorter diagonal, all elements below'),
  4328. (d3, [-1], 1, [[0, 0], [1, 0]],
  4329. 'longer diagonal within (only head)'),
  4330. (d3, [1], 1, [[0, 2], [0, 0]],
  4331. 'longer diagonal within (only tail)'),
  4332. (d3, [3], 0, [[0, 0], [0, 0]],
  4333. 'longer diagonal, all elements above'),
  4334. (d3, [-3], 0, [[0, 0], [0, 0]],
  4335. 'longer diagonal, all elements below'),
  4336. (None, None, 0, [[0, 0], [0, 0]],
  4337. 'empty input'),
  4338. ([[0, 0]], [0], 2, [[0, 0], [0, 0]],
  4339. 'explicit zeros'),
  4340. (np.arange(1, 1 + 7).reshape((7, 1)),
  4341. [0, 1, 2, 3, -1, -2, -3],
  4342. 2, [[1, 0], [5, 0]],
  4343. 'overfilled shorter-diagonal, out of order'),
  4344. (np.arange(1, 1 + 7 * 3).reshape((7, 3)),
  4345. [0, 1, 2, 3, -1, -2, -3],
  4346. 4, [[1, 5], [13, 2]],
  4347. 'overfilled longer-diagonal, out of order')]
  4348. def test_getnnz(self):
  4349. for data, ofsets, nnz, ref, case in self.ill_cases():
  4350. for shape in [(2, 2), (0, 2), (2, 0)]:
  4351. if data is None:
  4352. A = self.dia_container(shape)
  4353. else:
  4354. A = self.dia_container((data, ofsets), shape=shape)
  4355. if 0 in shape:
  4356. nnz = 0
  4357. assert A._getnnz() == nnz, 'case: ' + case
  4358. @pytest.mark.skip(reason='DIA stores extra zeros')
  4359. def test_getnnz_axis(self):
  4360. pass
  4361. def test_tocsr(self):
  4362. # test bound checks (other pathological cases are tested by
  4363. # TestConstructUtils::test_spdiags, and normal operation is ensured by
  4364. # many other tests here using .toarray())
  4365. for data, ofsets, _, r, case in self.ill_cases():
  4366. for shape in [(2, 2), (0, 2), (2, 0)]:
  4367. if data is None:
  4368. A = self.dia_container(shape)
  4369. else:
  4370. A = self.dia_container((data, ofsets), shape=shape)
  4371. B = A.tocsr()
  4372. ref = np.array(r)[:shape[0], :shape[1]]
  4373. nnz = np.count_nonzero(ref)
  4374. assert B.nnz == nnz
  4375. assert_array_equal(B.toarray(), ref, err_msg='case: ' + case)
  4376. def test_convert_gh14555(self):
  4377. # regression test for gh-14555
  4378. m = self.dia_container(([[1, 1, 0]], [-1]), shape=(4, 2))
  4379. expected = m.toarray()
  4380. assert_array_equal(m.tocsc().toarray(), expected)
  4381. assert_array_equal(m.tocsr().toarray(), expected)
  4382. def test_tocoo_gh10050(self):
  4383. # regression test for gh-10050
  4384. m = self.dia_container([[1, 2], [3, 4]]).tocoo()
  4385. flat_inds = np.ravel_multi_index((m.row, m.col), m.shape)
  4386. inds_are_sorted = np.all(np.diff(flat_inds) > 0)
  4387. assert m.has_canonical_format == inds_are_sorted
  4388. def test_tocoo_tocsr_tocsc_gh19245(self):
  4389. # test index_dtype with tocoo, tocsr, tocsc
  4390. data = np.array([[1, 2, 3, 4]]).repeat(3, axis=0)
  4391. offsets = np.array([0, -1, 2], dtype=np.int32)
  4392. dia = sparse.dia_array((data, offsets), shape=(4, 4))
  4393. coo = dia.tocoo()
  4394. assert coo.col.dtype == np.int32
  4395. csr = dia.tocsr()
  4396. assert csr.indices.dtype == np.int32
  4397. csc = dia.tocsc()
  4398. assert csc.indices.dtype == np.int32
  4399. def test_add_sparse(self):
  4400. # test format and cases not covered by common add tests
  4401. A = diag([1, 2])
  4402. B = A + diag([3], 1)
  4403. Asp = self.dia_container(A)
  4404. Bsp = self.dia_container(B)
  4405. Csp = Asp + Bsp
  4406. assert isinstance(Csp, self.dia_container)
  4407. assert_array_equal(Csp.toarray(), A + B)
  4408. Csp = Bsp + Asp
  4409. assert isinstance(Csp, self.dia_container)
  4410. assert_array_equal(Csp.toarray(), B + A)
  4411. def test_sub_sparse(self):
  4412. # test format and cases not covered by common sub tests
  4413. A = diag([1, 2])
  4414. B = A + diag([3], 1)
  4415. Asp = self.dia_container(A)
  4416. Bsp = self.dia_container(B)
  4417. Csp = Asp - Bsp
  4418. assert isinstance(Csp, self.dia_container)
  4419. assert_array_equal(Csp.toarray(), A - B)
  4420. Csp = Bsp - Asp
  4421. assert isinstance(Csp, self.dia_container)
  4422. assert_array_equal(Csp.toarray(), B - A)
  4423. Bsp = Bsp.asformat('csr')
  4424. assert_array_equal((Asp - Bsp).toarray(), A - B)
  4425. assert_array_equal((Bsp - Asp).toarray(), B - A)
  4426. def test_mul_scalar(self):
  4427. # repro for gh-20434
  4428. m = self.dia_container([[1, 2], [0, 4]])
  4429. res = m * 3
  4430. assert isinstance(res, m.__class__)
  4431. assert_array_equal(res.toarray(), [[3, 6], [0, 12]])
  4432. res2 = m.multiply(3)
  4433. assert isinstance(res2, m.__class__)
  4434. assert_array_equal(res2.toarray(), [[3, 6], [0, 12]])
  4435. def test_matmul_dia(self):
  4436. # test DIA structure of DIA @ DIA:
  4437. # that all and only needed elements are used and produced
  4438. A = array([[1, 2, 3],
  4439. [4, 5, 6]])
  4440. B = array([[11, 12],
  4441. [13, 14],
  4442. [15, 16]])
  4443. Asp = self.dia_container(A)
  4444. Bsp = self.dia_container(B)
  4445. Asp.data[Asp.data == 0] = -1 # poison outside elements
  4446. Bsp.data[Bsp.data == 0] = -1
  4447. assert_array_equal(Asp.toarray(), A)
  4448. assert_array_equal(Bsp.toarray(), B)
  4449. C = A @ B
  4450. Csp = Asp @ Bsp
  4451. assert isinstance(Csp, self.dia_container)
  4452. assert_array_equal(Csp.toarray(), C)
  4453. assert_array_equal(Csp.offsets, [-1, 0, 1])
  4454. assert_array_equal(Csp.data, self.dia_container(C).data)
  4455. C = B @ A
  4456. Csp = Bsp @ Asp
  4457. assert isinstance(Csp, self.dia_container)
  4458. assert_array_equal(Csp.toarray(), C)
  4459. assert_array_equal(Csp.offsets, [-2, -1, 0, 1, 2])
  4460. assert_array_equal(Csp.data, self.dia_container(C).data)
  4461. # short data and that order of input offsets doesn't matter
  4462. Asp = self.dia_container(([[0., 1., 2.], [3., 4., 5.]], [1, -2]), (5, 5))
  4463. Bsp = self.dia_container(([[6., 7., 8.], [0., 0., 9.]], [-1, 2]), (5, 5))
  4464. Csp = Asp @ Bsp
  4465. assert_array_equal(Csp.offsets, array([-3, 0]))
  4466. assert_array_equal(Csp.data, [[24., 35., 0.],
  4467. [6., 14., 27.]])
  4468. Csp = Bsp @ Asp
  4469. assert_array_equal(Csp.offsets, array([-3, 0]))
  4470. assert_array_equal(Csp.data, [[24., 0., 0.],
  4471. [27., 6., 14.]])
  4472. class TestDIAMatrix(_MatrixMixin, TestDIA):
  4473. spcreator = dia_matrix
  4474. TestDIA.init_class()
  4475. TestDIAMatrix.init_class()
  4476. class TestBSR(sparse_test_class(getset=False,
  4477. slicing=False, slicing_assign=False,
  4478. fancy_indexing=False, fancy_assign=False,
  4479. nnz_axis=False)):
  4480. spcreator = bsr_array
  4481. math_dtypes = [np.int_, np.float64, np.complex128]
  4482. def test_constructor1(self):
  4483. # check native BSR format constructor
  4484. indptr = array([0,2,2,4])
  4485. indices = array([0,2,2,3])
  4486. data = zeros((4,2,3))
  4487. data[0] = array([[0, 1, 2],
  4488. [3, 0, 5]])
  4489. data[1] = array([[0, 2, 4],
  4490. [6, 0, 10]])
  4491. data[2] = array([[0, 4, 8],
  4492. [12, 0, 20]])
  4493. data[3] = array([[0, 5, 10],
  4494. [15, 0, 25]])
  4495. A = kron([[1,0,2,0],[0,0,0,0],[0,0,4,5]], [[0,1,2],[3,0,5]])
  4496. Asp = self.bsr_container((data,indices,indptr),shape=(6,12))
  4497. assert_equal(Asp.toarray(), A)
  4498. # infer shape from arrays
  4499. Asp = self.bsr_container((data,indices,indptr))
  4500. assert_equal(Asp.toarray(), A)
  4501. def test_constructor2(self):
  4502. # construct from dense
  4503. # test zero mats
  4504. for shape in [(1,1), (5,1), (1,10), (10,4), (3,7), (2,1)]:
  4505. A = zeros(shape)
  4506. assert_equal(self.bsr_container(A).toarray(), A)
  4507. A = zeros((4,6))
  4508. assert_equal(self.bsr_container(A, blocksize=(2, 2)).toarray(), A)
  4509. assert_equal(self.bsr_container(A, blocksize=(2, 3)).toarray(), A)
  4510. A = kron([[1,0,2,0],[0,0,0,0],[0,0,4,5]], [[0,1,2],[3,0,5]])
  4511. assert_equal(self.bsr_container(A).toarray(), A)
  4512. assert_equal(self.bsr_container(A, shape=(6, 12)).toarray(), A)
  4513. assert_equal(self.bsr_container(A, blocksize=(1, 1)).toarray(), A)
  4514. assert_equal(self.bsr_container(A, blocksize=(2, 3)).toarray(), A)
  4515. assert_equal(self.bsr_container(A, blocksize=(2, 6)).toarray(), A)
  4516. assert_equal(self.bsr_container(A, blocksize=(2, 12)).toarray(), A)
  4517. assert_equal(self.bsr_container(A, blocksize=(3, 12)).toarray(), A)
  4518. assert_equal(self.bsr_container(A, blocksize=(6, 12)).toarray(), A)
  4519. A = kron([[1,0,2,0],[0,1,0,0],[0,0,0,0]], [[0,1,2],[3,0,5]])
  4520. assert_equal(self.bsr_container(A, blocksize=(2, 3)).toarray(), A)
  4521. def test_constructor3(self):
  4522. # construct from coo-like (data,(row,col)) format
  4523. arg = ([1,2,3], ([0,1,1], [0,0,1]))
  4524. A = array([[1,0],[2,3]])
  4525. assert_equal(self.bsr_container(arg, blocksize=(2, 2)).toarray(), A)
  4526. def test_constructor4(self):
  4527. # regression test for gh-6292: self.bsr_matrix((data, indices, indptr)) was
  4528. # trying to compare an int to a None
  4529. n = 8
  4530. data = np.ones((n, n, 1), dtype=np.int8)
  4531. indptr = np.array([0, n], dtype=np.int32)
  4532. indices = np.arange(n, dtype=np.int32)
  4533. self.bsr_container((data, indices, indptr), blocksize=(n, 1), copy=False)
  4534. def test_constructor5(self):
  4535. # check for validations introduced in gh-13400
  4536. n = 8
  4537. data_1dim = np.ones(n)
  4538. data = np.ones((n, n, n))
  4539. indptr = np.array([0, n])
  4540. indices = np.arange(n)
  4541. with assert_raises(ValueError):
  4542. # data ndim check
  4543. self.bsr_container((data_1dim, indices, indptr))
  4544. with assert_raises(ValueError):
  4545. # invalid blocksize
  4546. self.bsr_container((data, indices, indptr), blocksize=(1, 1, 1))
  4547. with assert_raises(ValueError):
  4548. # mismatching blocksize
  4549. self.bsr_container((data, indices, indptr), blocksize=(1, 1))
  4550. def test_default_dtype(self):
  4551. # As a numpy array, `values` has shape (2, 2, 1).
  4552. values = [[[1], [1]], [[1], [1]]]
  4553. indptr = np.array([0, 2], dtype=np.int32)
  4554. indices = np.array([0, 1], dtype=np.int32)
  4555. b = self.bsr_container((values, indices, indptr), blocksize=(2, 1))
  4556. assert b.dtype == np.array(values).dtype
  4557. def test_bsr_tocsr(self):
  4558. # check native conversion from BSR to CSR
  4559. indptr = array([0, 2, 2, 4])
  4560. indices = array([0, 2, 2, 3])
  4561. data = zeros((4, 2, 3))
  4562. data[0] = array([[0, 1, 2],
  4563. [3, 0, 5]])
  4564. data[1] = array([[0, 2, 4],
  4565. [6, 0, 10]])
  4566. data[2] = array([[0, 4, 8],
  4567. [12, 0, 20]])
  4568. data[3] = array([[0, 5, 10],
  4569. [15, 0, 25]])
  4570. A = kron([[1, 0, 2, 0], [0, 0, 0, 0], [0, 0, 4, 5]],
  4571. [[0, 1, 2], [3, 0, 5]])
  4572. Absr = self.bsr_container((data, indices, indptr), shape=(6, 12))
  4573. Acsr = Absr.tocsr()
  4574. Acsr_via_coo = Absr.tocoo().tocsr()
  4575. assert_equal(Acsr.toarray(), A)
  4576. assert_equal(Acsr.toarray(), Acsr_via_coo.toarray())
  4577. def test_eliminate_zeros(self):
  4578. data = kron([1, 0, 0, 0, 2, 0, 3, 0], [[1,1],[1,1]]).T
  4579. data = data.reshape(-1,2,2)
  4580. indices = array([1, 2, 3, 4, 5, 6, 7, 8])
  4581. indptr = array([0, 3, 8])
  4582. asp = self.bsr_container((data, indices, indptr), shape=(4,20))
  4583. bsp = asp.copy()
  4584. asp.eliminate_zeros()
  4585. assert_array_equal(asp.nnz, 3*4)
  4586. assert_array_equal(asp.toarray(), bsp.toarray())
  4587. # GitHub issue #9687
  4588. def test_eliminate_zeros_all_zero(self):
  4589. np.random.seed(0)
  4590. m = self.bsr_container(np.random.random((12, 12)), blocksize=(2, 3))
  4591. # eliminate some blocks, but not all
  4592. m.data[m.data <= 0.9] = 0
  4593. m.eliminate_zeros()
  4594. assert_equal(m.nnz, 66)
  4595. assert_array_equal(m.data.shape, (11, 2, 3))
  4596. # eliminate all remaining blocks
  4597. m.data[m.data <= 1.0] = 0
  4598. m.eliminate_zeros()
  4599. assert_equal(m.nnz, 0)
  4600. assert_array_equal(m.data.shape, (0, 2, 3))
  4601. assert_array_equal(m.toarray(), np.zeros((12, 12)))
  4602. # test fast path
  4603. m.eliminate_zeros()
  4604. assert_equal(m.nnz, 0)
  4605. assert_array_equal(m.data.shape, (0, 2, 3))
  4606. assert_array_equal(m.toarray(), np.zeros((12, 12)))
  4607. def test_has_canonical_format(self):
  4608. "Ensure has_canonical_format memoizes state for sum_duplicates"
  4609. A = np.array([[2, 3, 2], [0, 2, 1], [-4, 0, 2]])
  4610. M = self.bsr_container(A)
  4611. assert_equal(True, M.has_canonical_format)
  4612. indices = np.array([0, 0]) # contains duplicate
  4613. data = np.array([A, A*0])
  4614. indptr = np.array([0, 2])
  4615. M = self.bsr_container((data, indices, indptr)).copy()
  4616. assert_equal(False, M.has_canonical_format)
  4617. assert isinstance(M.has_canonical_format, bool)
  4618. # set flag by deduplicating
  4619. M.sum_duplicates()
  4620. assert_equal(True, M.has_canonical_format)
  4621. assert_equal(1, len(M.indices))
  4622. # manually set flag True (although underlyingly duplicated)
  4623. M = self.bsr_container((data, indices, indptr)).copy()
  4624. M.has_canonical_format = True
  4625. assert_equal(True, M.has_canonical_format)
  4626. assert_equal(2, len(M.indices)) # unaffected content
  4627. # ensure deduplication bypassed when has_canonical_format == True
  4628. M.sum_duplicates()
  4629. assert_equal(2, len(M.indices)) # still has duplicates!!!!
  4630. # ensure deduplication reenabled when has_canonical_format == False
  4631. M.has_canonical_format = False
  4632. M.sum_duplicates()
  4633. assert_equal(1, len(M.indices))
  4634. assert_equal(True, M.has_canonical_format)
  4635. # manually set flag False (although underlyingly canonical)
  4636. M = self.bsr_container(A)
  4637. M.has_canonical_format = False
  4638. assert_equal(False, M.has_canonical_format)
  4639. assert_equal(1, len(M.indices))
  4640. # sum_duplicates does not complain when no work to do
  4641. M.sum_duplicates()
  4642. assert_equal(True, M.has_canonical_format)
  4643. # manually reset index arrays before accessing M.has_canonical_format is OK
  4644. M = self.bsr_container(A)
  4645. M.data, M.indices, M.indptr = data, indices, indptr
  4646. assert_equal(False, M.has_canonical_format)
  4647. assert_equal(2, len(M.indices)) # dups and has_canonical_format is False
  4648. # but reset after accessing M.has_canonical_format can break flag
  4649. M = self.bsr_container(A)
  4650. M.has_canonical_format # underlying attr is set here
  4651. M.data, M.indices, M.indptr = data, indices, indptr
  4652. assert_equal(True, M.has_canonical_format)
  4653. assert_equal(2, len(M.indices)) # dups but has_canonical_format is True
  4654. M.sum_duplicates()
  4655. assert_equal(2, len(M.indices)) # still has duplicates!!!!
  4656. def test_bsr_matvec(self):
  4657. A = self.bsr_container(arange(2*3*4*5).reshape(2*4,3*5), blocksize=(4,5))
  4658. x = arange(A.shape[1]).reshape(-1,1)
  4659. assert_equal(A @ x, A.toarray() @ x)
  4660. def test_bsr_matvecs(self):
  4661. A = self.bsr_container(arange(2*3*4*5).reshape(2*4,3*5), blocksize=(4,5))
  4662. x = arange(A.shape[1]*6).reshape(-1,6)
  4663. assert_equal(A @ x, A.toarray() @ x)
  4664. @pytest.mark.xfail(run=False, reason='BSR does not have a __getitem__')
  4665. def test_iterator(self):
  4666. pass
  4667. @pytest.mark.xfail(run=False, reason='BSR does not have a __setitem__')
  4668. def test_setdiag(self):
  4669. pass
  4670. def test_resize_blocked(self):
  4671. # test resize() with non-(1,1) blocksize
  4672. D = np.array([[1, 0, 3, 4],
  4673. [2, 0, 0, 0],
  4674. [3, 0, 0, 0]])
  4675. S = self.spcreator(D, blocksize=(1, 2))
  4676. assert_(S.resize((3, 2)) is None)
  4677. assert_array_equal(S.toarray(), [[1, 0],
  4678. [2, 0],
  4679. [3, 0]])
  4680. S.resize((2, 2))
  4681. assert_array_equal(S.toarray(), [[1, 0],
  4682. [2, 0]])
  4683. S.resize((3, 2))
  4684. assert_array_equal(S.toarray(), [[1, 0],
  4685. [2, 0],
  4686. [0, 0]])
  4687. S.resize((3, 4))
  4688. assert_array_equal(S.toarray(), [[1, 0, 0, 0],
  4689. [2, 0, 0, 0],
  4690. [0, 0, 0, 0]])
  4691. assert_raises(ValueError, S.resize, (2, 3))
  4692. @pytest.mark.xfail(run=False, reason='BSR does not have a __setitem__')
  4693. def test_setdiag_comprehensive(self):
  4694. pass
  4695. @pytest.mark.skipif(IS_COLAB, reason="exceeds memory limit")
  4696. def test_scalar_idx_dtype(self):
  4697. # Check that index dtype takes into account all parameters
  4698. # passed to sparsetools, including the scalar ones
  4699. indptr = np.zeros(2, dtype=np.int32)
  4700. indices = np.zeros(0, dtype=np.int32)
  4701. vals = np.zeros((0, 1, 1))
  4702. a = self.bsr_container((vals, indices, indptr), shape=(1, 2**31-1))
  4703. b = self.bsr_container((vals, indices, indptr), shape=(1, 2**31))
  4704. c = self.bsr_container((1, 2**31-1))
  4705. d = self.bsr_container((1, 2**31))
  4706. assert_equal(a.indptr.dtype, np.int32)
  4707. assert_equal(b.indptr.dtype, np.int64)
  4708. assert_equal(c.indptr.dtype, np.int32)
  4709. assert_equal(d.indptr.dtype, np.int64)
  4710. try:
  4711. vals2 = np.zeros((0, 1, 2**31-1))
  4712. vals3 = np.zeros((0, 1, 2**31))
  4713. e = self.bsr_container((vals2, indices, indptr), shape=(1, 2**31-1))
  4714. f = self.bsr_container((vals3, indices, indptr), shape=(1, 2**31))
  4715. assert_equal(e.indptr.dtype, np.int32)
  4716. assert_equal(f.indptr.dtype, np.int64)
  4717. except (MemoryError, ValueError):
  4718. # May fail on 32-bit Python
  4719. e = 0
  4720. f = 0
  4721. # These shouldn't fail
  4722. for x in [a, b, c, d, e, f]:
  4723. x + x
  4724. class TestBSRMatrix(_MatrixMixin, TestBSR):
  4725. spcreator = bsr_matrix
  4726. TestBSR.init_class()
  4727. TestBSRMatrix.init_class()
  4728. #------------------------------------------------------------------------------
  4729. # Tests for non-canonical representations (with duplicates, unsorted indices)
  4730. #------------------------------------------------------------------------------
  4731. def _same_sum_duplicate(data, *inds, **kwargs):
  4732. """Duplicates entries to produce the same matrix"""
  4733. indptr = kwargs.pop('indptr', None)
  4734. if np.issubdtype(data.dtype, np.bool_) or \
  4735. np.issubdtype(data.dtype, np.unsignedinteger):
  4736. if indptr is None:
  4737. return (data,) + inds
  4738. else:
  4739. return (data,) + inds + (indptr,)
  4740. zeros_pos = (data == 0).nonzero()
  4741. # duplicate data
  4742. data = data.repeat(2, axis=0)
  4743. data[::2] -= 1
  4744. data[1::2] = 1
  4745. # don't spoil all explicit zeros
  4746. if zeros_pos[0].size > 0:
  4747. pos = tuple(p[0] for p in zeros_pos)
  4748. pos1 = (2*pos[0],) + pos[1:]
  4749. pos2 = (2*pos[0]+1,) + pos[1:]
  4750. data[pos1] = 0
  4751. data[pos2] = 0
  4752. inds = tuple(indices.repeat(2) for indices in inds)
  4753. if indptr is None:
  4754. return (data,) + inds
  4755. else:
  4756. return (data,) + inds + (indptr * 2,)
  4757. class _NonCanonicalMixin:
  4758. def spcreator(self, D, *args, sorted_indices=False, **kwargs):
  4759. """Replace D with a non-canonical equivalent: containing
  4760. duplicate elements and explicit zeros"""
  4761. construct = super().spcreator
  4762. M = construct(D, *args, **kwargs)
  4763. zero_pos = (M.toarray() == 0).nonzero()
  4764. has_zeros = (zero_pos[0].size > 0)
  4765. if has_zeros:
  4766. k = zero_pos[0].size//2
  4767. with warnings.catch_warnings():
  4768. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  4769. M = self._insert_explicit_zero(M, zero_pos[0][k], zero_pos[1][k])
  4770. arg1 = self._arg1_for_noncanonical(M, sorted_indices)
  4771. if 'shape' not in kwargs:
  4772. kwargs['shape'] = M.shape
  4773. NC = construct(arg1, **kwargs)
  4774. # check that result is valid
  4775. if NC.dtype in [np.float32, np.complex64]:
  4776. # For single-precision floats, the differences between M and NC
  4777. # that are introduced by the extra operations involved in the
  4778. # construction of NC necessitate a more lenient tolerance level
  4779. # than the default.
  4780. rtol = 1e-05
  4781. else:
  4782. rtol = 1e-07
  4783. assert_allclose(NC.toarray(), M.toarray(), rtol=rtol)
  4784. # check that at least one explicit zero
  4785. if has_zeros:
  4786. assert_((NC.data == 0).any())
  4787. # TODO check that NC has duplicates (which are not explicit zeros)
  4788. return NC
  4789. @pytest.mark.skip(reason='bool(matrix) counts explicit zeros')
  4790. def test_bool(self):
  4791. pass
  4792. @pytest.mark.skip(reason='getnnz-axis counts explicit zeros')
  4793. def test_getnnz_axis(self):
  4794. pass
  4795. @pytest.mark.skip(reason='nnz counts explicit zeros')
  4796. def test_empty(self):
  4797. pass
  4798. class _NonCanonicalCompressedMixin(_NonCanonicalMixin):
  4799. def _arg1_for_noncanonical(self, M, sorted_indices=False):
  4800. """Return non-canonical constructor arg1 equivalent to M"""
  4801. data, indices, indptr = _same_sum_duplicate(M.data, M.indices,
  4802. indptr=M.indptr)
  4803. if not sorted_indices:
  4804. for start, stop in zip(indptr, indptr[1:]):
  4805. indices[start:stop] = indices[start:stop][::-1].copy()
  4806. data[start:stop] = data[start:stop][::-1].copy()
  4807. return data, indices, indptr
  4808. def _insert_explicit_zero(self, M, i, j):
  4809. M[i,j] = 0
  4810. return M
  4811. class _NonCanonicalCSMixin(_NonCanonicalCompressedMixin):
  4812. def test_getelement(self):
  4813. def check(dtype, sorted_indices):
  4814. D = array([[1,0,0],
  4815. [4,3,0],
  4816. [0,2,0],
  4817. [0,0,0]], dtype=dtype)
  4818. A = self.spcreator(D, sorted_indices=sorted_indices)
  4819. M,N = D.shape
  4820. for i in range(-M, M):
  4821. for j in range(-N, N):
  4822. assert_equal(A[i,j], D[i,j])
  4823. for ij in [(0,3),(-1,3),(4,0),(4,3),(4,-1), (1, 2, 3)]:
  4824. assert_raises((IndexError, TypeError), A.__getitem__, ij)
  4825. for dtype in supported_dtypes:
  4826. for sorted_indices in [False, True]:
  4827. check(np.dtype(dtype), sorted_indices)
  4828. def test_setitem_sparse(self):
  4829. D = np.eye(3)
  4830. A = self.spcreator(D)
  4831. B = self.spcreator([[1,2,3]])
  4832. D[1,:] = B.toarray()
  4833. with warnings.catch_warnings():
  4834. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  4835. A[1,:] = B
  4836. assert_array_equal(A.toarray(), D)
  4837. D[:,2] = B.toarray().ravel()
  4838. with warnings.catch_warnings():
  4839. warnings.filterwarnings("ignore", WMSG, SparseEfficiencyWarning)
  4840. A[:,2] = B.T
  4841. assert_array_equal(A.toarray(), D)
  4842. @pytest.mark.xfail(run=False, reason='inverse broken with non-canonical matrix')
  4843. def test_inv(self):
  4844. pass
  4845. @pytest.mark.xfail(run=False, reason='solve broken with non-canonical matrix')
  4846. def test_solve(self):
  4847. pass
  4848. class TestCSRNonCanonical(_NonCanonicalCSMixin, TestCSR):
  4849. pass
  4850. class TestCSRNonCanonicalMatrix(TestCSRNonCanonical, TestCSRMatrix):
  4851. pass
  4852. class TestCSCNonCanonical(_NonCanonicalCSMixin, TestCSC):
  4853. pass
  4854. class TestCSCNonCanonicalMatrix(TestCSCNonCanonical, TestCSCMatrix):
  4855. pass
  4856. class TestBSRNonCanonical(_NonCanonicalCompressedMixin, TestBSR):
  4857. def _insert_explicit_zero(self, M, i, j):
  4858. x = M.tocsr()
  4859. x[i,j] = 0
  4860. return x.tobsr(blocksize=M.blocksize)
  4861. @pytest.mark.xfail(run=False, reason='diagonal broken with non-canonical BSR')
  4862. def test_diagonal(self):
  4863. pass
  4864. @pytest.mark.xfail(run=False, reason='expm broken with non-canonical BSR')
  4865. def test_expm(self):
  4866. pass
  4867. class TestBSRNonCanonicalMatrix(TestBSRNonCanonical, TestBSRMatrix):
  4868. pass
  4869. class COONonCanonicalMixin(_NonCanonicalMixin):
  4870. def _arg1_for_noncanonical(self, M, sorted_indices=None):
  4871. """Return non-canonical constructor arg1 equivalent to M"""
  4872. data, row, col = _same_sum_duplicate(M.data, M.row, M.col)
  4873. return data, (row, col)
  4874. def _insert_explicit_zero(self, M, i, j):
  4875. M.data = np.r_[M.data.dtype.type(0), M.data]
  4876. M.row = np.r_[M.row.dtype.type(i), M.row]
  4877. M.col = np.r_[M.col.dtype.type(j), M.col]
  4878. return M
  4879. def test_setdiag_noncanonical(self):
  4880. m = self.spcreator(np.eye(3))
  4881. m.sum_duplicates()
  4882. m.setdiag([3, 2], k=1)
  4883. m.sum_duplicates()
  4884. assert_(np.all(np.diff(m.col) >= 0))
  4885. class TestCOONonCanonical(COONonCanonicalMixin, TestCOO):
  4886. pass
  4887. class TestCOONonCanonicalMatrix(COONonCanonicalMixin, TestCOOMatrix):
  4888. pass
  4889. def test_broadcast_to():
  4890. a = np.array([[1, 0, 2]])
  4891. b = np.array([[1], [0], [2]])
  4892. c = np.array([[1, 0, 2], [0, 3, 0]])
  4893. d = np.array([[7]])
  4894. e = np.array([[0]])
  4895. f = np.array([[0,0,0,0]])
  4896. for container in (csc_matrix, csc_array, csr_matrix, csr_array):
  4897. res_a = container(a)._broadcast_to((2,3))
  4898. res_b = container(b)._broadcast_to((3,4))
  4899. res_c = container(c)._broadcast_to((2,3))
  4900. res_d = container(d)._broadcast_to((4,4))
  4901. res_e = container(e)._broadcast_to((5,6))
  4902. res_f = container(f)._broadcast_to((2,4))
  4903. assert_array_equal(res_a.toarray(), np.broadcast_to(a, (2,3)))
  4904. assert_array_equal(res_b.toarray(), np.broadcast_to(b, (3,4)))
  4905. assert_array_equal(res_c.toarray(), c)
  4906. assert_array_equal(res_d.toarray(), np.broadcast_to(d, (4,4)))
  4907. assert_array_equal(res_e.toarray(), np.broadcast_to(e, (5,6)))
  4908. assert_array_equal(res_f.toarray(), np.broadcast_to(f, (2,4)))
  4909. with pytest.raises(ValueError, match="cannot be broadcast"):
  4910. container([[1, 2, 0], [3, 0, 1]])._broadcast_to(shape=(2, 1))
  4911. with pytest.raises(ValueError, match="cannot be broadcast"):
  4912. container([[0, 1, 2]])._broadcast_to(shape=(3, 2))