test_coo.py 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387
  1. import math
  2. import warnings
  3. import numpy as np
  4. from numpy.testing import assert_equal, assert_allclose
  5. import pytest
  6. from scipy.linalg import block_diag
  7. from scipy.sparse import coo_array, random_array, SparseEfficiencyWarning
  8. from scipy.sparse._csr import csr_array
  9. from .._coo import _block_diag, _extract_block_diag
  10. def test_shape_constructor():
  11. empty1d = coo_array((3,))
  12. assert empty1d.shape == (3,)
  13. assert_equal(empty1d.toarray(), np.zeros((3,)))
  14. empty2d = coo_array((3, 2))
  15. assert empty2d.shape == (3, 2)
  16. assert_equal(empty2d.toarray(), np.zeros((3, 2)))
  17. empty_nd = coo_array((2,3,4,6,7))
  18. assert empty_nd.shape == (2,3,4,6,7)
  19. assert_equal(empty_nd.toarray(), np.zeros((2,3,4,6,7)))
  20. def test_dense_constructor():
  21. # 1d
  22. res1d = coo_array([1, 2, 3])
  23. assert res1d.shape == (3,)
  24. assert_equal(res1d.toarray(), np.array([1, 2, 3]))
  25. # 2d
  26. res2d = coo_array([[1, 2, 3], [4, 5, 6]])
  27. assert res2d.shape == (2, 3)
  28. assert_equal(res2d.toarray(), np.array([[1, 2, 3], [4, 5, 6]]))
  29. # 4d
  30. arr4d = np.array([[[[3, 7], [1, 0]], [[6, 5], [9, 2]]],
  31. [[[4, 3], [2, 8]], [[7, 5], [1, 6]]],
  32. [[[0, 9], [4, 3]], [[2, 1], [7, 8]]]])
  33. res4d = coo_array(arr4d)
  34. assert res4d.shape == (3, 2, 2, 2)
  35. assert_equal(res4d.toarray(), arr4d)
  36. # 9d
  37. np.random.seed(12)
  38. arr9d = np.random.randn(2,3,4,7,6,5,3,2,4)
  39. res9d = coo_array(arr9d)
  40. assert res9d.shape == (2,3,4,7,6,5,3,2,4)
  41. assert_equal(res9d.toarray(), arr9d)
  42. # storing nan as element of sparse array
  43. nan_3d = coo_array([[[1, np.nan]], [[3, 4]], [[5, 6]]])
  44. assert nan_3d.shape == (3, 1, 2)
  45. assert_equal(nan_3d.toarray(), np.array([[[1, np.nan]], [[3, 4]], [[5, 6]]]))
  46. def test_dense_constructor_with_shape():
  47. res1d = coo_array([1, 2, 3], shape=(3,))
  48. assert res1d.shape == (3,)
  49. assert_equal(res1d.toarray(), np.array([1, 2, 3]))
  50. res2d = coo_array([[1, 2, 3], [4, 5, 6]], shape=(2, 3))
  51. assert res2d.shape == (2, 3)
  52. assert_equal(res2d.toarray(), np.array([[1, 2, 3], [4, 5, 6]]))
  53. res3d = coo_array([[[3]], [[4]]], shape=(2, 1, 1))
  54. assert res3d.shape == (2, 1, 1)
  55. assert_equal(res3d.toarray(), np.array([[[3]], [[4]]]))
  56. np.random.seed(12)
  57. arr7d = np.random.randn(2,4,1,6,5,3,2)
  58. res7d = coo_array((arr7d), shape=(2,4,1,6,5,3,2))
  59. assert res7d.shape == (2,4,1,6,5,3,2)
  60. assert_equal(res7d.toarray(), arr7d)
  61. def test_dense_constructor_with_inconsistent_shape():
  62. with pytest.raises(ValueError, match='inconsistent shapes'):
  63. coo_array([1, 2, 3], shape=(4,))
  64. with pytest.raises(ValueError, match='inconsistent shapes'):
  65. coo_array([1, 2, 3], shape=(3, 1))
  66. with pytest.raises(ValueError, match='inconsistent shapes'):
  67. coo_array([[1, 2, 3]], shape=(3,))
  68. with pytest.raises(ValueError, match='inconsistent shapes'):
  69. coo_array([[[3]], [[4]]], shape=(1, 1, 1))
  70. with pytest.raises(ValueError,
  71. match='axis 0 index 2 exceeds matrix dimension 2'):
  72. coo_array(([1], ([2],)), shape=(2,))
  73. with pytest.raises(ValueError,
  74. match='axis 1 index 3 exceeds matrix dimension 3'):
  75. coo_array(([1,3], ([0, 1], [0, 3], [1, 1])), shape=(2, 3, 2))
  76. with pytest.raises(ValueError, match='negative axis 0 index: -1'):
  77. coo_array(([1], ([-1],)))
  78. with pytest.raises(ValueError, match='negative axis 2 index: -1'):
  79. coo_array(([1], ([0], [2], [-1])))
  80. def test_1d_sparse_constructor():
  81. empty1d = coo_array((3,))
  82. res = coo_array(empty1d)
  83. assert res.shape == (3,)
  84. assert_equal(res.toarray(), np.zeros((3,)))
  85. def test_1d_tuple_constructor():
  86. res = coo_array(([9,8], ([1,2],)))
  87. assert res.shape == (3,)
  88. assert_equal(res.toarray(), np.array([0, 9, 8]))
  89. def test_1d_tuple_constructor_with_shape():
  90. res = coo_array(([9,8], ([1,2],)), shape=(4,))
  91. assert res.shape == (4,)
  92. assert_equal(res.toarray(), np.array([0, 9, 8, 0]))
  93. def test_reshape_overflow():
  94. # see gh-22353 : new idx_dtype can need to be int64 instead of int32
  95. M, N = (1045507, 523266)
  96. coords = (np.array([M - 1], dtype='int32'), np.array([N - 1], dtype='int32'))
  97. A = coo_array(([3.3], coords), shape=(M, N))
  98. # need new idx_dtype to not overflow
  99. B = A.reshape((M * N, 1))
  100. assert B.coords[0].dtype == np.dtype('int64')
  101. assert B.coords[0][0] == (M * N) - 1
  102. # need idx_dtype to stay int32 if before and after can be int32
  103. C = A.reshape(N, M)
  104. assert C.coords[0].dtype == np.dtype('int32')
  105. assert C.coords[0][0] == N - 1
  106. def test_reshape():
  107. arr1d = coo_array([1, 0, 3])
  108. assert arr1d.shape == (3,)
  109. col_vec = arr1d.reshape((3, 1))
  110. assert col_vec.shape == (3, 1)
  111. assert_equal(col_vec.toarray(), np.array([[1], [0], [3]]))
  112. row_vec = arr1d.reshape((1, 3))
  113. assert row_vec.shape == (1, 3)
  114. assert_equal(row_vec.toarray(), np.array([[1, 0, 3]]))
  115. # attempting invalid reshape
  116. with pytest.raises(ValueError, match="cannot reshape array"):
  117. arr1d.reshape((3,3))
  118. # attempting reshape with a size 0 dimension
  119. with pytest.raises(ValueError, match="cannot reshape array"):
  120. arr1d.reshape((3,0))
  121. arr2d = coo_array([[1, 2, 0], [0, 0, 3]])
  122. assert arr2d.shape == (2, 3)
  123. flat = arr2d.reshape((6,))
  124. assert flat.shape == (6,)
  125. assert_equal(flat.toarray(), np.array([1, 2, 0, 0, 0, 3]))
  126. # 2d to 3d
  127. to_3d_arr = arr2d.reshape((2, 3, 1))
  128. assert to_3d_arr.shape == (2, 3, 1)
  129. assert_equal(to_3d_arr.toarray(), np.array([[[1], [2], [0]], [[0], [0], [3]]]))
  130. # attempting invalid reshape
  131. with pytest.raises(ValueError, match="cannot reshape array"):
  132. arr2d.reshape((1,3))
  133. def test_nnz():
  134. arr1d = coo_array([1, 0, 3])
  135. assert arr1d.shape == (3,)
  136. assert arr1d.nnz == 2
  137. arr2d = coo_array([[1, 2, 0], [0, 0, 3]])
  138. assert arr2d.shape == (2, 3)
  139. assert arr2d.nnz == 3
  140. def test_transpose():
  141. arr1d = coo_array([1, 0, 3]).T
  142. assert arr1d.shape == (3,)
  143. assert_equal(arr1d.toarray(), np.array([1, 0, 3]))
  144. arr2d = coo_array([[1, 2, 0], [0, 0, 3]]).T
  145. assert arr2d.shape == (3, 2)
  146. assert_equal(arr2d.toarray(), np.array([[1, 0], [2, 0], [0, 3]]))
  147. def test_transpose_with_axis():
  148. arr1d = coo_array([1, 0, 3]).transpose(axes=(0,))
  149. assert arr1d.shape == (3,)
  150. assert_equal(arr1d.toarray(), np.array([1, 0, 3]))
  151. arr2d = coo_array([[1, 2, 0], [0, 0, 3]]).transpose(axes=(0, 1))
  152. assert arr2d.shape == (2, 3)
  153. assert_equal(arr2d.toarray(), np.array([[1, 2, 0], [0, 0, 3]]))
  154. with pytest.raises(ValueError, match="axes don't match matrix dimensions"):
  155. coo_array([1, 0, 3]).transpose(axes=(0, 1))
  156. with pytest.raises(ValueError, match="repeated axis in transpose"):
  157. coo_array([[1, 2, 0], [0, 0, 3]]).transpose(axes=(1, 1))
  158. def test_1d_row_and_col():
  159. res = coo_array([1, -2, -3])
  160. assert_equal(res.col, np.array([0, 1, 2]))
  161. assert_equal(res.row, np.zeros_like(res.col))
  162. assert res.row.dtype == res.col.dtype
  163. assert res.row.flags.writeable is False
  164. res.col = [1, 2, 3]
  165. assert len(res.coords) == 1
  166. assert_equal(res.col, np.array([1, 2, 3]))
  167. assert res.row.dtype == res.col.dtype
  168. with pytest.raises(ValueError, match="cannot set row attribute"):
  169. res.row = [1, 2, 3]
  170. def test_1d_toformats():
  171. res = coo_array([1, -2, -3])
  172. for f in [res.tobsr, res.tocsc, res.todia, res.tolil]:
  173. with pytest.raises(ValueError, match='Cannot convert'):
  174. f()
  175. for f in [res.tocoo, res.tocsr, res.todok]:
  176. assert_equal(f().toarray(), res.toarray())
  177. @pytest.mark.parametrize('arg', [1, 2, 4, 5, 8])
  178. def test_1d_resize(arg: int):
  179. den = np.array([1, -2, -3])
  180. res = coo_array(den)
  181. den.resize(arg, refcheck=False)
  182. res.resize(arg)
  183. assert res.shape == den.shape
  184. assert_equal(res.toarray(), den)
  185. @pytest.mark.parametrize('arg', zip([1, 2, 3, 4], [1, 2, 3, 4]))
  186. def test_1d_to_2d_resize(arg: tuple[int, int]):
  187. den = np.array([1, 0, 3])
  188. res = coo_array(den)
  189. den.resize(arg, refcheck=False)
  190. res.resize(arg)
  191. assert res.shape == den.shape
  192. assert_equal(res.toarray(), den)
  193. @pytest.mark.parametrize('arg', [1, 4, 6, 8])
  194. def test_2d_to_1d_resize(arg: int):
  195. den = np.array([[1, 0, 3], [4, 0, 0]])
  196. res = coo_array(den)
  197. den.resize(arg, refcheck=False)
  198. res.resize(arg)
  199. assert res.shape == den.shape
  200. assert_equal(res.toarray(), den)
  201. def test_sum_duplicates():
  202. # 1d case
  203. arr1d = coo_array(([2, 2, 2], ([1, 0, 1],)))
  204. assert arr1d.nnz == 3
  205. assert_equal(arr1d.toarray(), np.array([2, 4]))
  206. arr1d.sum_duplicates()
  207. assert arr1d.nnz == 2
  208. assert_equal(arr1d.toarray(), np.array([2, 4]))
  209. # 4d case
  210. arr4d = coo_array(([2, 3, 7], ([1, 0, 1], [0, 2, 0], [1, 2, 1], [1, 0, 1])))
  211. assert arr4d.nnz == 3
  212. expected = np.array( # noqa: E501
  213. [[[[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [3, 0]]],
  214. [[[0, 0], [0, 9], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]]]
  215. )
  216. assert_equal(arr4d.toarray(), expected)
  217. arr4d.sum_duplicates()
  218. assert arr4d.nnz == 2
  219. assert_equal(arr4d.toarray(), expected)
  220. # when there are no duplicates
  221. arr_nodups = coo_array(([1, 2, 3, 4], ([0, 1, 2, 3],)))
  222. assert arr_nodups.nnz == 4
  223. arr_nodups.sum_duplicates()
  224. assert arr_nodups.nnz == 4
  225. def test_eliminate_zeros():
  226. arr1d = coo_array(([0, 0, 1], ([1, 0, 1],)))
  227. assert arr1d.nnz == 3
  228. assert arr1d.count_nonzero() == 1
  229. assert_equal(arr1d.toarray(), np.array([0, 1]))
  230. arr1d.eliminate_zeros()
  231. assert arr1d.nnz == 1
  232. assert arr1d.count_nonzero() == 1
  233. assert_equal(arr1d.toarray(), np.array([0, 1]))
  234. assert_equal(arr1d.col, np.array([1]))
  235. assert_equal(arr1d.row, np.array([0]))
  236. def test_1d_add_dense():
  237. den_a = np.array([0, -2, -3, 0])
  238. den_b = np.array([0, 1, 2, 3])
  239. exp = den_a + den_b
  240. res = coo_array(den_a) + den_b
  241. assert type(res) is type(exp)
  242. assert_equal(res, exp)
  243. def test_1d_add_sparse():
  244. den_a = np.array([0, -2, -3, 0])
  245. den_b = np.array([0, 1, 2, 3])
  246. dense_sum = den_a + den_b
  247. # this routes through CSR format
  248. sparse_sum = coo_array(den_a) + coo_array(den_b)
  249. assert_equal(dense_sum, sparse_sum.toarray())
  250. def test_1d_matmul_vector():
  251. den_a = np.array([0, -2, -3, 0])
  252. den_b = np.array([0, 1, 2, 3])
  253. exp = den_a @ den_b
  254. res = coo_array(den_a) @ den_b
  255. assert np.ndim(res) == 0
  256. assert_equal(res, exp)
  257. def test_1d_matmul_multivector():
  258. den = np.array([0, -2, -3, 0])
  259. other = np.array([[0, 1, 2, 3], [3, 2, 1, 0]]).T
  260. exp = den @ other
  261. res = coo_array(den) @ other
  262. assert type(res) is type(exp)
  263. assert_equal(res, exp)
  264. def test_2d_matmul_multivector():
  265. # sparse-sparse matmul
  266. den = np.array([[0, 1, 2, 3], [3, 2, 1, 0]])
  267. arr2d = coo_array(den)
  268. exp = den @ den.T
  269. res = arr2d @ arr2d.T
  270. assert_equal(res.toarray(), exp)
  271. # sparse-dense matmul for self.ndim = 2
  272. den = np.array([[0, 4, 3, 0, 5], [1, 0, 7, 3, 4]])
  273. arr2d = coo_array(den)
  274. exp = den @ den.T
  275. res = arr2d @ den.T
  276. assert_equal(res, exp)
  277. # sparse-dense matmul for self.ndim = 1
  278. den_a = np.array([[0, 4, 3, 0, 5], [1, 0, 7, 3, 4]])
  279. den_b = np.array([0, 1, 6, 0, 4])
  280. arr1d = coo_array(den_b)
  281. exp = den_b @ den_a.T
  282. res = arr1d @ den_a.T
  283. assert_equal(res, exp)
  284. # sparse-dense matmul for self.ndim = 1 and other.ndim = 2
  285. den_a = np.array([1, 0, 2])
  286. den_b = np.array([[3], [4], [0]])
  287. exp = den_a @ den_b
  288. res = coo_array(den_a) @ den_b
  289. assert_equal(res, exp)
  290. res = coo_array(den_a) @ list(den_b)
  291. assert_equal(res, exp)
  292. def test_1d_diagonal():
  293. den = np.array([0, -2, -3, 0])
  294. with pytest.raises(ValueError, match='diagonal requires two dimensions'):
  295. coo_array(den).diagonal()
  296. @pytest.mark.parametrize('shape', [(0,), (7,), (4,7), (0,0,0), (3,6,2),
  297. (1,0,3), (7,9,3,2,4,5)])
  298. def test_nd_todense(shape):
  299. np.random.seed(12)
  300. arr = np.random.randint(low=0, high=5, size=shape)
  301. assert_equal(coo_array(arr).todense(), arr)
  302. @pytest.mark.parametrize('shape', [(0,), (7,), (4,7), (0,0,0), (3,6,2),
  303. (1,0,3), (7,9,3,2,4,5)])
  304. def test_nd_sparse_constructor(shape):
  305. empty_arr = coo_array(shape)
  306. res = coo_array(empty_arr)
  307. assert res.shape == (shape)
  308. assert_equal(res.toarray(), np.zeros(shape))
  309. @pytest.mark.parametrize('shape', [(0,), (7,), (4,7), (0,0,0), (3,6,2),
  310. (1,0,3), (7,9,3,2,4,5)])
  311. def test_nd_tuple_constructor(shape):
  312. np.random.seed(12)
  313. arr = np.random.randn(*shape)
  314. res = coo_array(arr)
  315. assert res.shape == shape
  316. assert_equal(res.toarray(), arr)
  317. @pytest.mark.parametrize('shape', [(0,), (7,), (4,7), (0,0,0), (3,6,2),
  318. (1,0,3), (7,9,3,2,4,5)])
  319. def test_nd_tuple_constructor_with_shape(shape):
  320. np.random.seed(12)
  321. arr = np.random.randn(*shape)
  322. res = coo_array(arr, shape=shape)
  323. assert res.shape == shape
  324. assert_equal(res.toarray(), arr)
  325. def test_tuple_constructor_for_dim_size_zero():
  326. # arrays with a dimension of size 0
  327. with pytest.raises(ValueError, match='exceeds matrix dimension'):
  328. coo_array(([9, 8], ([1, 2], [1, 0], [2, 1])), shape=(3,4,0))
  329. empty_arr = coo_array(([], ([], [], [], [])), shape=(4,0,2,3))
  330. assert_equal(empty_arr.toarray(), np.empty((4,0,2,3)))
  331. @pytest.mark.parametrize(('shape', 'new_shape'), [((4,9,6,5), (3,6,15,4)),
  332. ((4,9,6,5), (36,30)),
  333. ((4,9,6,5), (1080,)),
  334. ((4,9,6,5), (2,3,2,2,3,5,3)),])
  335. def test_nd_reshape(shape, new_shape):
  336. # reshaping a 4d sparse array
  337. rng = np.random.default_rng(23409823)
  338. arr4d = random_array(shape, density=0.6, rng=rng, dtype=int)
  339. assert arr4d.shape == shape
  340. den4d = arr4d.toarray()
  341. exp_arr = den4d.reshape(new_shape)
  342. res_arr = arr4d.reshape(new_shape)
  343. assert res_arr.shape == new_shape
  344. assert_equal(res_arr.toarray(), exp_arr)
  345. @pytest.mark.parametrize('shape', [(0,), (7,), (4,7), (0,0,0), (3,6,2),
  346. (1,0,3), (7,9,3,2,4,5)])
  347. def test_nd_nnz(shape):
  348. rng = np.random.default_rng(23409823)
  349. arr = random_array(shape, density=0.6, rng=rng, dtype=int)
  350. assert arr.nnz == np.count_nonzero(arr.toarray())
  351. @pytest.mark.parametrize('shape', [(0,), (7,), (4,7), (0,0,0), (3,6,2),
  352. (1,0,3), (7,9,3,2,4,5)])
  353. def test_nd_transpose(shape):
  354. rng = np.random.default_rng(23409823)
  355. arr = random_array(shape, density=0.6, rng=rng, dtype=int)
  356. exp_arr = arr.toarray().T
  357. trans_arr = arr.transpose()
  358. assert trans_arr.shape == shape[::-1]
  359. assert_equal(exp_arr, trans_arr.toarray())
  360. @pytest.mark.parametrize(('shape', 'axis_perm'), [((3,), (0,)),
  361. ((2,3), (0,1)),
  362. ((2,4,3,6,5,3), (1,2,0,5,3,4)),])
  363. def test_nd_transpose_with_axis(shape, axis_perm):
  364. rng = np.random.default_rng(23409823)
  365. arr = random_array(shape, density=0.6, rng=rng, dtype=int)
  366. trans_arr = arr.transpose(axes=axis_perm)
  367. assert_equal(trans_arr.toarray(), np.transpose(arr.toarray(), axes=axis_perm))
  368. def test_transpose_with_inconsistent_axis():
  369. with pytest.raises(ValueError, match="axes don't match matrix dimensions"):
  370. coo_array([1, 0, 3]).transpose(axes=(0, 1))
  371. with pytest.raises(ValueError, match="repeated axis in transpose"):
  372. coo_array([[1, 2, 0], [0, 0, 3]]).transpose(axes=(1, 1))
  373. def test_nd_eliminate_zeros():
  374. # for 3d sparse arrays
  375. arr3d = coo_array(([1, 0, 0, 4], ([0, 1, 1, 2], [0, 1, 0, 1], [1, 1, 2, 0])))
  376. assert arr3d.nnz == 4
  377. assert arr3d.count_nonzero() == 2
  378. assert_equal(arr3d.toarray(), np.array([[[0, 1, 0], [0, 0, 0]],
  379. [[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [4, 0, 0]]]))
  380. arr3d.eliminate_zeros()
  381. assert arr3d.nnz == 2
  382. assert arr3d.count_nonzero() == 2
  383. assert_equal(arr3d.toarray(), np.array([[[0, 1, 0], [0, 0, 0]],
  384. [[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [4, 0, 0]]]))
  385. # for a 5d sparse array when all elements of data array are 0
  386. coords = ([0, 1, 1, 2], [0, 1, 0, 1], [1, 1, 2, 0], [0, 0, 2, 3], [1, 0, 0, 2])
  387. arr5d = coo_array(([0, 0, 0, 0], coords))
  388. assert arr5d.nnz == 4
  389. assert arr5d.count_nonzero() == 0
  390. arr5d.eliminate_zeros()
  391. assert arr5d.nnz == 0
  392. assert arr5d.count_nonzero() == 0
  393. assert_equal(arr5d.col, np.array([]))
  394. assert_equal(arr5d.row, np.array([]))
  395. assert_equal(arr5d.coords, ([], [], [], [], []))
  396. @pytest.mark.parametrize('shape', [(0,), (7,), (4,7), (0,0,0), (3,6,2),
  397. (1,0,3), (7,9,3,2,4,5)])
  398. def test_nd_add_dense(shape):
  399. rng = np.random.default_rng(23409823)
  400. sp_x = random_array(shape, density=0.6, rng=rng, dtype=int)
  401. sp_y = random_array(shape, density=0.6, rng=rng, dtype=int)
  402. den_x, den_y = sp_x.toarray(), sp_y.toarray()
  403. exp = den_x + den_y
  404. res = sp_x + den_y
  405. assert type(res) is type(exp)
  406. assert_equal(res, exp)
  407. @pytest.mark.parametrize('shape', [(0,), (7,), (4,7), (0,0,0), (3,6,2),
  408. (1,0,3), (7,9,3,2,4,5)])
  409. def test_nd_add_sparse(shape):
  410. rng = np.random.default_rng(23409823)
  411. sp_x = random_array((shape), density=0.6, rng=rng, dtype=int)
  412. sp_y = random_array((shape), density=0.6, rng=rng, dtype=int)
  413. den_x, den_y = sp_x.toarray(), sp_y.toarray()
  414. dense_sum = den_x + den_y
  415. sparse_sum = sp_x + sp_y
  416. assert_equal(dense_sum, sparse_sum.toarray())
  417. def test_add_sparse_with_inf():
  418. # addition of sparse arrays with an inf element
  419. den_a = np.array([[[0], [np.inf]], [[-3], [0]]])
  420. den_b = np.array([[[0], [1]], [[2], [3]]])
  421. dense_sum = den_a + den_b
  422. sparse_sum = coo_array(den_a) + coo_array(den_b)
  423. assert_equal(dense_sum, sparse_sum.toarray())
  424. @pytest.mark.parametrize(('a_shape', 'b_shape'), [((7,), (12,)),
  425. ((6,4), (6,5)),
  426. ((5,9,3,2), (9,5,2,3)),])
  427. def test_nd_add_sparse_with_inconsistent_shapes(a_shape, b_shape):
  428. rng = np.random.default_rng(23409823)
  429. arr_a = random_array((a_shape), density=0.6, rng=rng, dtype=int)
  430. arr_b = random_array((b_shape), density=0.6, rng=rng, dtype=int)
  431. with pytest.raises(ValueError, match="inconsistent shapes"):
  432. arr_a + arr_b
  433. @pytest.mark.parametrize('shape', [(0,), (7,), (4,7), (0,0,0), (3,6,2),
  434. (1,0,3), (7,9,3,2,4,5)])
  435. def test_nd_sub_dense(shape):
  436. rng = np.random.default_rng(23409823)
  437. sp_x = random_array(shape, density=0.6, rng=rng, dtype=int)
  438. sp_y = random_array(shape, density=0.6, rng=rng, dtype=int)
  439. den_x, den_y = sp_x.toarray(), sp_y.toarray()
  440. exp = den_x - den_y
  441. res = sp_x - den_y
  442. assert type(res) is type(exp)
  443. assert_equal(res, exp)
  444. @pytest.mark.parametrize('shape', [(0,), (7,), (4,7), (0,0,0), (3,6,2),
  445. (1,0,3), (7,9,3,2,4,5)])
  446. def test_nd_sub_sparse(shape):
  447. rng = np.random.default_rng(23409823)
  448. sp_x = random_array(shape, density=0.6, rng=rng, dtype=int)
  449. sp_y = random_array(shape, density=0.6, rng=rng, dtype=int)
  450. den_x, den_y = sp_x.toarray(), sp_y.toarray()
  451. dense_sum = den_x - den_y
  452. sparse_sum = sp_x - sp_y
  453. assert_equal(dense_sum, sparse_sum.toarray())
  454. def test_nd_sub_sparse_with_nan():
  455. # subtraction of sparse arrays with a nan element
  456. den_a = np.array([[[0], [np.nan]], [[-3], [0]]])
  457. den_b = np.array([[[0], [1]], [[2], [3]]])
  458. dense_sum = den_a - den_b
  459. sparse_sum = coo_array(den_a) - coo_array(den_b)
  460. assert_equal(dense_sum, sparse_sum.toarray())
  461. @pytest.mark.parametrize(('a_shape', 'b_shape'), [((7,), (12,)),
  462. ((6,4), (6,5)),
  463. ((5,9,3,2), (9,5,2,3)),])
  464. def test_nd_sub_sparse_with_inconsistent_shapes(a_shape, b_shape):
  465. rng = np.random.default_rng(23409823)
  466. arr_a = random_array((a_shape), density=0.6, rng=rng, dtype=int)
  467. arr_b = random_array((b_shape), density=0.6, rng=rng, dtype=int)
  468. with pytest.raises(ValueError, match="inconsistent shapes"):
  469. arr_a - arr_b
  470. mat_vec_shapes = [
  471. ((2, 3, 4, 5), (5,)),
  472. ((0, 0), (0,)),
  473. ((2, 3, 4, 7, 8), (8,)),
  474. ((4, 4, 2, 0), (0,)),
  475. ((6, 5, 3, 2, 4), (4, 1)),
  476. ((2,5), (5,)),
  477. ((2, 5), (5, 1)),
  478. ((3,), (3, 1)),
  479. ((4,), (4,))
  480. ]
  481. @pytest.mark.parametrize(('mat_shape', 'vec_shape'), mat_vec_shapes)
  482. def test_nd_matmul_vector(mat_shape, vec_shape):
  483. rng = np.random.default_rng(23409823)
  484. sp_x = random_array(mat_shape, density=0.6, rng=rng, dtype=int)
  485. sp_y = random_array(vec_shape, density=0.6, rng=rng, dtype=int)
  486. den_x, den_y = sp_x.toarray(), sp_y.toarray()
  487. exp = den_x @ den_y
  488. res = sp_x @ den_y
  489. assert_equal(res,exp)
  490. res = sp_x @ list(den_y)
  491. assert_equal(res,exp)
  492. mat_mat_shapes = [
  493. ((2, 3, 4, 5), (2, 3, 5, 7)),
  494. ((0, 0), (0,)),
  495. ((4, 4, 2, 0), (0,)),
  496. ((7, 8, 3), (3,)),
  497. ((7, 8, 3), (3, 1)),
  498. ((6, 5, 3, 2, 4), (4, 3)),
  499. ((1, 3, 2, 4), (6, 5, 1, 4, 3)),
  500. ((6, 1, 1, 2, 4), (1, 3, 4, 3)),
  501. ((4,), (2, 4, 3)),
  502. ((3,), (5, 6, 7, 3, 2)),
  503. ((4,), (4, 3)),
  504. ((2, 5), (5, 1)),
  505. ]
  506. @pytest.mark.parametrize(('mat_shape1', 'mat_shape2'), mat_mat_shapes)
  507. def test_nd_matmul(mat_shape1, mat_shape2):
  508. rng = np.random.default_rng(23409823)
  509. sp_x = random_array(mat_shape1, density=0.6, random_state=rng, dtype=int)
  510. sp_y = random_array(mat_shape2, density=0.6, random_state=rng, dtype=int)
  511. den_x, den_y = sp_x.toarray(), sp_y.toarray()
  512. exp = den_x @ den_y
  513. # sparse-sparse
  514. res = sp_x @ sp_y
  515. assert_equal(res.toarray(), exp)
  516. # sparse-dense
  517. res = sp_x @ den_y
  518. assert_equal(res, exp)
  519. res = sp_x @ list(den_y)
  520. assert_equal(res, exp)
  521. # dense-sparse
  522. res = den_x @ sp_y
  523. assert_equal(res, exp)
  524. def test_nd_matmul_sparse_with_inconsistent_arrays():
  525. rng = np.random.default_rng(23409823)
  526. sp_x = random_array((4,5,7,6,3), density=0.6, random_state=rng, dtype=int)
  527. sp_y = random_array((1,5,3,2,5), density=0.6, random_state=rng, dtype=int)
  528. with pytest.raises(ValueError, match="matmul: dimension mismatch with signature"):
  529. sp_x @ sp_y
  530. with pytest.raises(ValueError, match="matmul: dimension mismatch with signature"):
  531. sp_x @ (sp_y.toarray())
  532. sp_z = random_array((1,5,3,2), density=0.6, random_state=rng, dtype=int)
  533. with pytest.raises(ValueError, match="Batch dimensions are not broadcastable"):
  534. sp_x @ sp_z
  535. with pytest.raises(ValueError, match="Batch dimensions are not broadcastable"):
  536. sp_x @ (sp_z.toarray())
  537. def test_dot_1d_1d(): # 1-D inner product
  538. a = coo_array([1,2,3])
  539. b = coo_array([4,5,6])
  540. exp = np.dot(a.toarray(), b.toarray())
  541. res = a.dot(b)
  542. assert_equal(res, exp)
  543. res = a.dot(b.toarray())
  544. assert_equal(res, exp)
  545. def test_dot_sparse_scalar():
  546. a = coo_array([[1, 2], [3, 4], [5, 6]])
  547. b = 3
  548. res = a.dot(b)
  549. exp = np.dot(a.toarray(), b)
  550. assert_equal(res.toarray(), exp)
  551. def test_dot_with_inconsistent_shapes():
  552. arr_a = coo_array([[[1, 2]], [[3, 4]]])
  553. arr_b = coo_array([4, 5, 6])
  554. with pytest.raises(ValueError, match="not aligned for n-D dot"):
  555. arr_a.dot(arr_b)
  556. def test_matmul_dot_not_implemented():
  557. arr_a = coo_array([[1, 2], [3, 4]])
  558. with pytest.raises(TypeError, match="argument not supported type"):
  559. arr_a.dot(None)
  560. with pytest.raises(TypeError, match="arg not supported type"):
  561. arr_a.tensordot(None)
  562. with pytest.raises(TypeError, match="unsupported operand type"):
  563. arr_a @ None
  564. with pytest.raises(TypeError, match="unsupported operand type"):
  565. None @ arr_a
  566. dot_shapes = [
  567. ((3,3), (3,3)), ((4,6), (6,7)), ((1,4), (4,1)), # matrix multiplication 2-D
  568. ((3,2,4,7), (7,)), ((5,), (6,3,5,2)), # dot of n-D and 1-D arrays
  569. ((3,2,4,7), (7,1)), ((1,5,), (6,3,5,2)),
  570. ((4,6), (3,2,6,4)), ((2,8,7), (4,5,7,7,2)), # dot of n-D and m-D arrays
  571. ((4,5,7,6), (3,2,6,4)),
  572. ]
  573. @pytest.mark.parametrize(('a_shape', 'b_shape'), dot_shapes)
  574. def test_dot_nd(a_shape, b_shape):
  575. rng = np.random.default_rng(23409823)
  576. arr_a = random_array(a_shape, density=0.6, random_state=rng, dtype=int)
  577. arr_b = random_array(b_shape, density=0.6, random_state=rng, dtype=int)
  578. exp = np.dot(arr_a.toarray(), arr_b.toarray())
  579. # sparse-dense
  580. res = arr_a.dot(arr_b.toarray())
  581. assert_equal(res, exp)
  582. res = arr_a.dot(list(arr_b.toarray()))
  583. assert_equal(res, exp)
  584. # sparse-sparse
  585. res = arr_a.dot(arr_b)
  586. assert_equal(res.toarray(), exp)
  587. tensordot_shapes_and_axes = [
  588. ((4,6), (6,7), ([1], [0])),
  589. ((3,2,4,7), (7,), ([3], [0])),
  590. ((5,), (6,3,5,2), ([0], [2])),
  591. ((4,5,7,6), (3,2,6,4), ([0, 3], [3, 2])),
  592. ((2,8,7), (4,5,7,8,2), ([0, 1, 2], [4, 3, 2])),
  593. ((4,5,3,2,6), (3,2,6,7,8), 3),
  594. ((4,5,7), (7,3,7), 1),
  595. ((2,3,4), (2,3,4), ([0, 1, 2], [0, 1, 2])),
  596. ]
  597. @pytest.mark.parametrize(('a_shape', 'b_shape', 'axes'), tensordot_shapes_and_axes)
  598. def test_tensordot(a_shape, b_shape, axes):
  599. rng = np.random.default_rng(23409823)
  600. arr_a = random_array(a_shape, density=0.6, random_state=rng, dtype=int)
  601. arr_b = random_array(b_shape, density=0.6, random_state=rng, dtype=int)
  602. exp = np.tensordot(arr_a.toarray(), arr_b.toarray(), axes=axes)
  603. # sparse-dense
  604. res = arr_a.tensordot(arr_b.toarray(), axes=axes)
  605. assert_equal(res, exp)
  606. res = arr_a.tensordot(list(arr_b.toarray()), axes=axes)
  607. assert_equal(res, exp)
  608. # sparse-sparse
  609. res = arr_a.tensordot(arr_b, axes=axes)
  610. if type(res) is coo_array:
  611. assert_equal(res.toarray(), exp)
  612. else:
  613. assert_equal(res, exp)
  614. def test_tensordot_with_invalid_args():
  615. rng = np.random.default_rng(23409823)
  616. arr_a = random_array((3,4,5), density=0.6, random_state=rng, dtype=int)
  617. arr_b = random_array((3,4,6), density=0.6, random_state=rng, dtype=int)
  618. axes = ([2], [2]) # sizes of 2nd axes of both shapes do not match
  619. with pytest.raises(ValueError, match="sizes of the corresponding axes must match"):
  620. arr_a.tensordot(arr_b, axes=axes)
  621. arr_a = random_array((5,4,2,3,7), density=0.6, random_state=rng, dtype=int)
  622. arr_b = random_array((4,6,3,2), density=0.6, random_state=rng, dtype=int)
  623. axes = ([2,0,1], [1,3]) # lists have different lengths
  624. with pytest.raises(ValueError, match="axes lists/tuples must be of the"
  625. " same length"):
  626. arr_a.tensordot(arr_b, axes=axes)
  627. @pytest.mark.parametrize(('actual_shape', 'broadcast_shape'),
  628. [((1,3,5,4), (2,3,5,4)), ((2,1,5,4), (6,2,3,5,4)),
  629. ((1,1,7,8,9), (4,5,6,7,8,9)), ((1,3), (4,5,3)),
  630. ((7,8,1), (7,8,5)), ((3,1), (3,4)), ((1,), (5,)),
  631. ((1,1,1), (4,5,6)), ((1,3,1,5,4), (8,2,3,9,5,4)),])
  632. def test_broadcast_to(actual_shape, broadcast_shape):
  633. rng = np.random.default_rng(23409823)
  634. arr = random_array(actual_shape, density=0.6, random_state=rng, dtype=int)
  635. res = arr._broadcast_to(broadcast_shape)
  636. exp = np.broadcast_to(arr.toarray(), broadcast_shape)
  637. assert_equal(res.toarray(), exp)
  638. @pytest.mark.parametrize(('shape'), [(4,5,6,7,8), (6,4),
  639. (5,9,3,2), (9,5,2,3,4),])
  640. def test_block_diag(shape):
  641. rng = np.random.default_rng(23409823)
  642. sp_x = random_array(shape, density=0.6, random_state=rng, dtype=int)
  643. den_x = sp_x.toarray()
  644. # converting n-d numpy array to an array of slices of 2-D matrices,
  645. # to pass as argument into scipy.linalg.block_diag
  646. num_slices = int(np.prod(den_x.shape[:-2]))
  647. reshaped_array = den_x.reshape((num_slices,) + den_x.shape[-2:])
  648. matrices = [reshaped_array[i, :, :] for i in range(num_slices)]
  649. exp = block_diag(*matrices)
  650. res = _block_diag(sp_x)
  651. assert_equal(res.toarray(), exp)
  652. @pytest.mark.parametrize(('shape'), [(4,5,6,7,8), (6,4),
  653. (5,9,3,2), (9,5,2,3,4),])
  654. def test_extract_block_diag(shape):
  655. rng = np.random.default_rng(23409823)
  656. sp_x = random_array(shape, density=0.6, random_state=rng, dtype=int)
  657. res = _extract_block_diag(_block_diag(sp_x), shape)
  658. assert_equal(res.toarray(), sp_x.toarray())
  659. add_sub_shapes = [
  660. ((3,4), (3,4)), ((3,4,6), (3,4,6)), ((3,7,5), (3,7,5))
  661. ]
  662. @pytest.mark.parametrize(('a_shape', 'b_shape'), add_sub_shapes)
  663. def test_add_no_broadcasting(a_shape, b_shape):
  664. rng = np.random.default_rng(23409823)
  665. a = random_array(a_shape, density=0.6, random_state=rng, dtype=int)
  666. b = random_array(b_shape, density=0.6, random_state=rng, dtype=int)
  667. res = a + b
  668. exp = np.add(a.toarray(), b.toarray())
  669. assert_equal(res.toarray(), exp)
  670. res = a + b.toarray()
  671. assert_equal(res, exp)
  672. @pytest.mark.parametrize(('a_shape', 'b_shape'), add_sub_shapes)
  673. def test_sub_no_broadcasting(a_shape, b_shape):
  674. rng = np.random.default_rng(23409823)
  675. a = random_array(a_shape, density=0.6, random_state=rng, dtype=int)
  676. b = random_array(b_shape, density=0.6, random_state=rng, dtype=int)
  677. res = a - b
  678. exp = np.subtract(a.toarray(), b.toarray())
  679. assert_equal(res.toarray(), exp)
  680. res = a - b.toarray()
  681. assert_equal(res, exp)
  682. argmax_argmin_shapes_axis = [
  683. ((3,), None), ((3,), 0),
  684. ((4,6), 1), ((7,3), 0), ((3,5), None),
  685. ((2,8,7), 2), ((2,8,7), 0),
  686. ((2,0), 0), ((3,0,0,2), 0),
  687. ((3,2,4,7), None), ((3,2,4,7), 1), ((3,2,4,7), 0), ((3,2,4,7), 2),
  688. ((3,2,4,7), -2), ((4,5,7,8,2), 4), ((4,5,7,8,2), -3),
  689. ]
  690. @pytest.mark.parametrize(('shape', 'axis'), argmax_argmin_shapes_axis)
  691. def test_argmax_argmin(shape, axis):
  692. rng = np.random.default_rng(23409823)
  693. a = random_array(shape, density=0.6, random_state=rng, dtype=int)
  694. res = a.argmax(axis=axis)
  695. exp = np.argmax(a.toarray(), axis=axis)
  696. assert_equal(res, exp)
  697. res = a.argmin(axis=axis)
  698. exp = np.argmin(a.toarray(), axis=axis)
  699. assert_equal(res, exp)
  700. max_min_shapes_axis = [
  701. ((3,), None), ((3,), 0),
  702. ((4,6), 1), ((7,3), 0), ((3,5), None),
  703. ((2,8,7), 2), ((2,8,7), 0),
  704. ((3,2,4,7), None), ((3,2,4,7), 1), ((3,2,4,7), 0), ((3,2,4,7), 2),
  705. ((4,5,7,8,2), 4), ((4,5,8,1), 3), ((4,6), (0,)), ((4,6), (0,1)),
  706. ((3,0,2), 2), ((3,0,2), (0,2)), ((3,0), 0),
  707. ((3,7,8,5), (0,1)), ((3,7,8,5), (2,1)), ((3,7,8,5), (2,0)),
  708. ((3,7,8,5), (0,-2)), ((3,7,8,5), (-1,2)), ((3,7,8,5), (3)),
  709. ((3,7,8,5), (0,1,2)), ((3,7,8,5), (0,1,2,3)),
  710. ]
  711. @pytest.mark.parametrize(('shape', 'axis'), max_min_shapes_axis)
  712. def test_min_max(shape, axis):
  713. rng = np.random.default_rng(23409823)
  714. a = random_array(shape, density=0.6, random_state=rng, dtype=int)
  715. res_min = a.min(axis=axis)
  716. exp_min = np.min(a.toarray(), axis=axis)
  717. res_max = a.max(axis=axis)
  718. exp_max = np.max(a.toarray(), axis=axis)
  719. res_nanmin = a.nanmin(axis=axis)
  720. exp_nanmin = np.nanmin(a.toarray(), axis=axis)
  721. res_nanmax = a.nanmax(axis=axis)
  722. exp_nanmax = np.nanmax(a.toarray(), axis=axis)
  723. for res, exp in [(res_min, exp_min), (res_max, exp_max),
  724. (res_nanmin, exp_nanmin), (res_nanmax, exp_nanmax)]:
  725. if np.issubdtype(type(res), np.number):
  726. assert_equal(res, exp)
  727. else:
  728. assert_equal(res.toarray(), exp)
  729. def test_min_max_full():
  730. for a in (coo_array([[[1, 2, 3, 4]]]), coo_array([[1, 2, 3, 4]])):
  731. assert a.min() == 1
  732. assert (-a).max() == -1
  733. sum_mean_params = [
  734. ((3,), None, None), ((3,), 0, None),
  735. ((4,6), 1, None), ((7,3), 0, None), ((3,5), None, None),
  736. ((2,8,7), 2, None), ((2,8,7), 0, np.zeros((8,7))),
  737. ((3,2,4,7), None, None), ((3,2,4,7), 1, np.zeros((3,4,7))),
  738. ((3,2,4,7), 0, None), ((4,5,7,8,2), 4, None),
  739. ((4,5,8,1), 3, None), ((4,6), (0,), None), ((4,6), (0,1), None),
  740. ((3,0,2), 2, None), ((3,0,2), (0,2), None), ((3,0), 0, None),
  741. ((3,7,8,5), (0,1), np.zeros((8,5))), ((3,7,8,5), (2,1), None),
  742. ((3,7,8,5), (0,-2), None), ((3,7,8,5), (-1,2), np.zeros((3,7))),
  743. ((3,7,8,5), (3), None), ((3,7,8,5), (0,1,2), np.zeros((5,))),
  744. ((3,7,8,5), (0,1,2,3), None),
  745. ]
  746. @pytest.mark.parametrize(('shape', 'axis', 'out'), sum_mean_params)
  747. def test_sum(shape, axis, out):
  748. rng = np.random.default_rng(23409823)
  749. a = random_array(shape, density=0.6, random_state=rng, dtype=int)
  750. res = a.sum(axis=axis, out=out)
  751. exp = np.sum(a.toarray(), axis=axis)
  752. assert_equal(res, exp)
  753. if out is not None:
  754. assert_equal(out, exp)
  755. assert id(res) == id(out)
  756. @pytest.mark.parametrize(('shape', 'axis', 'out'), sum_mean_params)
  757. def test_mean(shape, axis, out):
  758. rng = np.random.default_rng(23409823)
  759. a = random_array(shape, density=0.6, random_state=rng, dtype=int)
  760. res = a.mean(axis=axis, out=out)
  761. exp = np.mean(a.toarray(), axis=axis)
  762. assert_allclose(res, exp)
  763. if out is not None:
  764. assert id(res) == id(out)
  765. assert_allclose(out, exp)
  766. def test_pow_abs_round():
  767. rng = np.random.default_rng(23409823)
  768. a = random_array((3,6,5,2,4), density=0.6, random_state=rng, dtype=int)
  769. assert_allclose((a**3).toarray(), np.power(a.toarray(), 3))
  770. assert_allclose((a**7).toarray(), np.power(a.toarray(), 7))
  771. assert_allclose(round(a).toarray(), np.round(a.toarray()))
  772. assert_allclose(abs(a).toarray(), np.abs(a.toarray()))
  773. #bitwise_op_and_compare_broadcast_shapes = [
  774. # ((3,4), (3,4)), ((1,4), (2,1)), ((3,5), (1,)), ((1,), (7,8)),
  775. # ((3,4,6), (3,4,6)), ((4,3), (2,1,3)), ((2,1,3), (4,3)),
  776. # ((3,5,4), (1,)), ((1,), (7,8,4)), ((16,1,6), (2,6)), ((3,7,5), (3,7,5)),
  777. # ((16,2,6), (1,2,6)), ((7,8), (5,7,8)), ((4,5,1), (5,1)),
  778. # ((6,8,3), (4,1,1,3)), ((1,1,1), (3,4,2)), ((3,4,2), (1,1,1,1,1)),
  779. bitwise_op_and_compare_shapes = [
  780. ((3,4), (3,4)), ((3,4,6), (3,4,6)), ((3,7,5), (3,7,5)),
  781. ]
  782. @pytest.mark.parametrize(('a_shape', 'b_shape'), bitwise_op_and_compare_shapes)
  783. def test_boolean_comparisons(a_shape, b_shape):
  784. rng = np.random.default_rng(23409823)
  785. a = random_array(a_shape, density=0.6, random_state=rng, dtype=int)
  786. b = random_array(b_shape, density=0.6, random_state=rng, dtype=int)
  787. with warnings.catch_warnings():
  788. warnings.simplefilter("ignore", SparseEfficiencyWarning)
  789. assert_equal((a==b).toarray(), a.toarray()==b.toarray())
  790. assert_equal((a!=b).toarray(), a.toarray()!=b.toarray())
  791. assert_equal((a>=b).toarray(), a.toarray()>=b.toarray())
  792. assert_equal((a<=b).toarray(), a.toarray()<=b.toarray())
  793. assert_equal((a>b).toarray(), a.toarray()>b.toarray())
  794. assert_equal((a<b).toarray(), a.toarray()<b.toarray())
  795. assert_equal((a==b).toarray(), np.bitwise_not((a!=b).toarray()))
  796. assert_equal((a>=b).toarray(), np.bitwise_not((a<b).toarray()))
  797. assert_equal((a<=b).toarray(), np.bitwise_not((a>b).toarray()))
  798. def test_boolean_comparisons_with_scalar():
  799. rng = np.random.default_rng(23409823)
  800. a = random_array((5,4,8,7), density=0.6, random_state=rng, dtype=int)
  801. with warnings.catch_warnings():
  802. warnings.simplefilter("ignore", SparseEfficiencyWarning)
  803. assert_equal((a==0).toarray(), a.toarray()==0)
  804. assert_equal((a!=0).toarray(), a.toarray()!=0)
  805. assert_equal((a>=1).toarray(), a.toarray()>=1)
  806. assert_equal((a<=1).toarray(), a.toarray()<=1)
  807. assert_equal((a>0).toarray(), a.toarray()>0)
  808. assert_equal((a<0).toarray(), a.toarray()<0)
  809. @pytest.mark.parametrize(('a_shape', 'b_shape'), bitwise_op_and_compare_shapes)
  810. def test_multiply(a_shape, b_shape):
  811. rng = np.random.default_rng(23409823)
  812. a = random_array(a_shape, density=0.6, random_state=rng, dtype=int)
  813. b = random_array(b_shape, density=0.6, random_state=rng, dtype=int)
  814. res = a * b
  815. exp = np.multiply(a.toarray(), b.toarray())
  816. assert_equal(res.toarray(), exp)
  817. def test_multiply_with_scalar():
  818. rng = np.random.default_rng(23409823)
  819. a = random_array((3,5,4), density=0.6, random_state=rng, dtype=int)
  820. res = a * 7
  821. exp = np.multiply(a.toarray(), 7)
  822. assert_equal(res.toarray(), exp)
  823. @pytest.mark.parametrize(('a_shape', 'b_shape'), bitwise_op_and_compare_shapes)
  824. def test_divide(a_shape, b_shape):
  825. rng = np.random.default_rng(23409823)
  826. a = random_array(a_shape, density=0.6, random_state=rng, dtype=int)
  827. b = np.arange(1, 1 + math.prod(b_shape)).reshape(b_shape)
  828. res = a / b
  829. exp = a.toarray() / b
  830. assert_allclose(res.toarray(), exp)
  831. res = a / b
  832. assert_allclose(res.toarray(), exp)
  833. def test_divide_with_scalar():
  834. rng = np.random.default_rng(23409823)
  835. a = random_array((3,5,4), density=0.6, random_state=rng, dtype=int)
  836. res = a / 7
  837. exp = a.toarray() / 7
  838. assert_allclose(res.toarray(), exp)
  839. @pytest.mark.parametrize(('a_shape', 'b_shape'), bitwise_op_and_compare_shapes)
  840. def test_maximum(a_shape, b_shape):
  841. rng = np.random.default_rng(23409823)
  842. a = random_array(a_shape, density=0.6, random_state=rng, dtype=int)
  843. b = random_array(b_shape, density=0.6, random_state=rng, dtype=int)
  844. with warnings.catch_warnings():
  845. warnings.simplefilter("ignore", SparseEfficiencyWarning)
  846. res = a.maximum(b)
  847. exp = np.maximum(a.toarray(), b.toarray())
  848. assert_equal(res.toarray(), exp)
  849. @pytest.mark.parametrize(('a_shape', 'b_shape'), bitwise_op_and_compare_shapes)
  850. def test_minimum(a_shape, b_shape):
  851. rng = np.random.default_rng(23409823)
  852. a = random_array(a_shape, density=0.6, random_state=rng, dtype=int)
  853. b = random_array(b_shape, density=0.6, random_state=rng, dtype=int)
  854. with warnings.catch_warnings():
  855. warnings.simplefilter("ignore", SparseEfficiencyWarning)
  856. res = a.minimum(b)
  857. exp = np.minimum(a.toarray(), b.toarray())
  858. assert_equal(res.toarray(), exp)
  859. def test_maximum_with_scalar():
  860. a = coo_array([0,1,6])
  861. b = coo_array([[15, 0], [14, 5], [0, -12]])
  862. c = coo_array([[[[3,0], [2,4]], [[8,9], [-3,12]]],
  863. [[[5,2], [3,0]], [[0,7], [0,-6]]]])
  864. with warnings.catch_warnings():
  865. warnings.simplefilter("ignore", SparseEfficiencyWarning)
  866. assert_equal(a.maximum(5).toarray(), np.maximum(a.toarray(), 5))
  867. assert_equal(b.maximum(9).toarray(), np.maximum(b.toarray(), 9))
  868. assert_equal(c.maximum(5).toarray(), np.maximum(c.toarray(), 5))
  869. def test_minimum_with_scalar():
  870. a = coo_array([0,1,6])
  871. b = coo_array([[15, 0], [14, 5], [0, -12]])
  872. c = coo_array([[[[3,0], [2,4]], [[8,9], [-3,12]]],
  873. [[[5,2], [3,0]], [[0,7], [0,-6]]]])
  874. with warnings.catch_warnings():
  875. warnings.simplefilter("ignore", SparseEfficiencyWarning)
  876. assert_equal(a.minimum(5).toarray(), np.minimum(a.toarray(), 5))
  877. assert_equal(b.minimum(9).toarray(), np.minimum(b.toarray(), 9))
  878. assert_equal(c.minimum(5).toarray(), np.minimum(c.toarray(), 5))
  879. def test_1d_coo_get():
  880. B = coo_array(np.arange(9))
  881. assert B[0] == 0
  882. assert B[4] == 4
  883. assert_equal(B[1:3].toarray(), B.toarray()[1:3])
  884. assert_equal(B[:3].toarray(), B.toarray()[:3])
  885. assert_equal(B[1:].toarray(), B.toarray()[1:])
  886. assert_equal(B[1:5:2].toarray(), B.toarray()[1:5:2])
  887. assert_equal(B[[1, 3, 4]].toarray(), B.toarray()[[1, 3, 4]])
  888. assert_equal(B[[3, 4, 1]].toarray(), B.toarray()[[3, 4, 1]])
  889. def test_2d_coo_get():
  890. B = coo_array(np.arange(4 * 5).reshape((4, 5)))
  891. assert B[0, 0] == 0
  892. assert B[3, 4] == 19
  893. assert_equal(B[1:3, 0].toarray(), B.toarray()[1:3, 0])
  894. assert_equal(B[2, 1:3].toarray(), B.toarray()[2, 1:3])
  895. assert_equal(B[:2, 1:5:3].toarray(), B.toarray()[:2, 1:5:3])
  896. assert_equal(B[[1, 3], 0].toarray(), B.toarray()[[1,3], 0])
  897. assert_equal(B[2:, [1, 3]].toarray(), B.toarray()[2:, [1,3]])
  898. assert_equal(B[np.array([1, 3]), 0].toarray(), B.toarray()[[1,3], 0])
  899. assert_equal(B[2:, np.array([1, 3])].toarray(), B.toarray()[2:, [1,3]])
  900. assert_equal(B[:, 0].toarray(), B.toarray()[:, 0])
  901. assert_equal(B[0, :].toarray(), B.toarray()[0, :])
  902. def test_3d_coo_get():
  903. A = coo_array(np.arange(4 * 5 * 6).reshape((4, 5, 6)))
  904. assert A[0, 0, 0] == 0
  905. assert A[3, 4, 5] == 119
  906. assert_equal(A[0, 1:3, 0].toarray(), A.toarray()[0, 1:3, 0])
  907. assert_equal(A[0, 1:3, 3].toarray(), A.toarray()[0, 1:3, 3])
  908. assert_equal(A[:3, 1:5:2, 2:].toarray(), A.toarray()[:3, 1:5:2, 2:])
  909. assert_equal(A[[1, 3], 0, 0].toarray(), A.toarray()[[1, 3], 0, 0])
  910. assert_equal(A[:2, 1:3, [1, 3]].toarray(), A.toarray()[:2, 1:3, [1, 3]])
  911. assert_equal(A[0, :, 0].toarray(), A.toarray()[0, :, 0])
  912. assert_equal(A[:, :, 0].toarray(), A.toarray()[:, :, 0])
  913. def test_newaxis_get():
  914. A = coo_array(np.arange(4 * 5 * 6).reshape((4, 5, 6)))
  915. D = A.toarray()
  916. assert_equal(A[:5, 3:, 1].toarray(), D[:5, 3:, 1])
  917. assert_equal(A[None, :5, 1:3, None, 1].toarray(), D[None, :5, 1:3, None, 1])
  918. assert_equal(A[None, :5, 3:, 1, None].toarray(), D[None, :5, 3:, 1, None])
  919. assert_equal(A[None, :5, ..., None].toarray(), D[None, :5, ..., None])
  920. def test_newaxis_set():
  921. D = np.arange(4 * 5 * 6).reshape((4, 5, 6))
  922. A = coo_array(D)
  923. A[None, 3:, 1] = D[None, 3:, 1] = 5
  924. assert_equal(A.toarray(), D)
  925. A[3:, 1, None] = D[3:, 1, None] = 7
  926. assert_equal(A.toarray(), D)
  927. A[3:, None, 1] = D[3:, None, 1] = 3
  928. assert_equal(A.toarray(), D)
  929. def test_1d_coo_set():
  930. D = np.arange(9)
  931. A = coo_array(D)
  932. A[0] = D[0] = -1
  933. assert_equal(A.toarray(), D)
  934. A[4] = D[4] = -2
  935. assert_equal(A.toarray(), D)
  936. A[1:3] = D[1:3] = [-2, -3]
  937. assert_equal(A.toarray(), D)
  938. A[:3] = D[:3] = [-7, -8, -9]
  939. assert_equal(A.toarray(), D)
  940. A[1:] = D[1:] = -D[1:]
  941. assert_equal(A.toarray(), D)
  942. A[1:5:2] = D[1:5:2] = -D[1:5:2]
  943. assert_equal(A.toarray(), D)
  944. A[[1, 3, 4]] = D[[1, 3, 4]] = -D[[1, 3, 4]]
  945. assert_equal(A.toarray(), D)
  946. A[[3, 4, 1]] = D[[3, 4, 1]] = -D[[1, 2, 3]]
  947. assert_equal(A.toarray(), D)
  948. D = np.arange(4 * 5).reshape((4, 5))
  949. A = coo_array(D)
  950. keys = [
  951. # all int
  952. (1, 3),
  953. (-1, -3),
  954. # slices and ints
  955. (slice(1, 3, None), 0),
  956. (2, slice(1, 3, None)),
  957. (slice(1, 3, None), slice(1, 5, 3)),
  958. (slice(None, None, -1), 2),
  959. (1, slice(None)),
  960. (Ellipsis,),
  961. # array indexing
  962. ([1, 3], 0),
  963. (2, [1, 2]),
  964. (np.array([1, 3]), slice(1, None)),
  965. (slice(2), np.array([1, 2, 3])),
  966. # fancy array indexing
  967. (np.array([1, 3]), np.array([0, 2])),
  968. ]
  969. @pytest.mark.parametrize(["A", "D", "idx"], [(A, D, idx) for idx in keys])
  970. @pytest.mark.thread_unsafe
  971. def test_2d_coo_set(A, D, idx):
  972. D[idx] = A[idx] = -D[idx]
  973. assert_equal(A.toarray(), D)
  974. D = np.arange(4 * 5 * 6).reshape((4, 5, 6))
  975. A = coo_array(D)
  976. keys = [
  977. # all ints
  978. (0, 0, 0),
  979. (3, -4, 5),
  980. # slices and ints
  981. (0, slice(1, 3), 0),
  982. (slice(3, None), 3, slice(2)),
  983. (slice(2), slice(1, 5, 2), slice(1, None)),
  984. (slice(None, None, -1), slice(None), slice(1, 5, 2)),
  985. (Ellipsis),
  986. # array indexing
  987. (2, [1, 2], slice(3)),
  988. (np.array([1, 3]), slice(1, None), 0),
  989. (np.array([1, 3]), slice(1, None), [0]),
  990. # fancy array indexing
  991. (np.array([1, 3]), slice(1, None), np.array([2, 4])),
  992. (2, np.array([1, 3]), np.array([2, 4])),
  993. (np.array([1, 3]), np.array([2, 4]), 1),
  994. (np.array([1, 3]), np.array([2, 4]), [2]),
  995. ]
  996. @pytest.mark.parametrize(["A", "D", "idx"], [(A, D, idx) for idx in keys])
  997. @pytest.mark.thread_unsafe
  998. def test_3d_coo_set(A, D, idx):
  999. D[idx] = A[idx] = -99
  1000. assert_equal(A.toarray(), D)
  1001. @pytest.mark.parametrize(
  1002. "scalar_container",
  1003. [lambda x: csr_array(np.array([[x]])), np.array, lambda x: x],
  1004. ids=["sparse", "dense", "scalar"],
  1005. )
  1006. @pytest.mark.thread_unsafe(reason="fails in parallel")
  1007. def test_3d_coo_singleton(scalar_container):
  1008. A[(0, 0, 0)] = scalar_container(-99)
  1009. D[(0, 0, 0)] = -99
  1010. assert_equal(A.toarray(), D)
  1011. #D = np.arange(4 * 5 * 6 * 4 * 6).reshape((4, 5, 6, 4, 6))
  1012. D = np.arange(4 * 6 * 6 * 3 * 4).reshape((4, 6, 6, 3, 4))
  1013. A = coo_array(D)
  1014. keys = [
  1015. # multidimensional
  1016. ("all-ints", (1, 2, 1)),
  1017. ("ellipsis-first", (..., 0)),
  1018. ("ellipsis-last", (1, ...)),
  1019. ("ellipsis-middle", (1, ..., 0)),
  1020. # slices and ints
  1021. ("split-ints", (slice(None, 4, None), 2, 1, slice(None, None, None), 1)),
  1022. ("contiguous-ints-last", (slice(4, None, None), slice(None, None, None), 2, 1, 1)),
  1023. ("contiguous-ints-first", (2, 1, 1, slice(4, None, None), slice(None, None, None))),
  1024. ("empty-slice", (slice(4, 4, None), slice(None, None, None), 2, 1, 1)),
  1025. # slices and arrays and ints
  1026. ("split-2d-arrays-and-ints",
  1027. (slice(None, 4, None), [[2, 1, 1], [2, 1, 2]], [[2, 1, 0], [3, 4, 0]],
  1028. slice(None, None, None), 0)
  1029. ),
  1030. ("contiguous-2d-arrays-and-ints",
  1031. (slice(None, 4, None), [[2, 1, 0], [2, 1, 2]], [[2, 1, 0], [3, 4, 0]],
  1032. 1, slice(None, None, None))
  1033. ),
  1034. ("split-1d-arrays-and-ints",
  1035. (slice(None, 4, None), [2, 1, 0], [2, 1, 0], slice(None, None, None), 1)
  1036. ),
  1037. ("split-ints-broadcast-arrays-slice-step-not-1",
  1038. (0, slice(1, 4, 2), 1, [[2, 1, 0]], [[2], [1], [0]])
  1039. ),
  1040. ("contiguous-broadcast-arrays",
  1041. (slice(None, 3, None), slice(1, 4, 2), 1, [[2, 1, 0]], [[2], [1], [0]])
  1042. ),
  1043. ("contiguous-arrays-first",
  1044. ([[2, 1, 0]], [[2], [1], [0]], 0, slice(1, 4, 2), slice(None, 3, None))
  1045. ),
  1046. ("split-arrays-some-first-some-last",
  1047. ([[2, 1, 0]], slice(1, 4, 2), slice(None, 3, None), 0, [[2], [1], [0]])
  1048. ),
  1049. # test we are not creating duplicate entries for duplicate values in array index
  1050. ("duplicate-array-entries-split-arrays",
  1051. (slice(None, 4, None), [[2, 1, 0], [2, 1, 1]], [[2, 1, 0], [3, 4, 4]],
  1052. slice(None, None, None), 1)
  1053. ),
  1054. ("duplicate-array-entries-contiguous-broadcast-arrays",
  1055. (slice(1, 4, 2), 0, 1, [[2, 1, 1]], [[2], [1], [1]])
  1056. ),
  1057. ]
  1058. @pytest.mark.parametrize(["A", "D", "ix", "msg"], [(A, D, ix, msg) for msg, ix in keys])
  1059. @pytest.mark.thread_unsafe
  1060. def test_5d_coo_set(A, D, ix, msg):
  1061. D[ix] = A[ix] = -99
  1062. assert_equal(A.toarray(), D, err_msg=f"\nTest of: {msg}\n")
  1063. def test_bool_get():
  1064. D = np.arange(4 * 6 * 6 * 3 * 4).reshape((4, 6, 6, 3, 4))
  1065. A = coo_array(D)
  1066. assert_equal(A[D > 500].toarray(), D[D > 500])
  1067. assert_equal(A[D > 5000].toarray(), D[D > 5000])
  1068. assert_equal(A[D > -1].toarray(), D[D > -1])
  1069. assert_equal(A[A > 500].toarray(), D[D > 500])
  1070. assert_equal(A[A > 5000].toarray(), D[D > 5000])
  1071. assert_equal(A[A < -1].toarray(), D[D < -1])
  1072. bi0 = A[:, 0, 0, 0, 0] > 50
  1073. bi1 = A[0, :, 0, 0, 0] > 50
  1074. idx = (bi0, slice(2, 3, None), [1], slice(None, 2, 2), bi0)
  1075. idxnp = (bi0.toarray(), slice(2, 3, 1), [1], slice(0, 2, 2), bi0.toarray())
  1076. result = D[idxnp]
  1077. assert_equal(A[idx].toarray(), result)
  1078. assert_equal(A[idxnp].toarray(), result)
  1079. idx = (slice(2, 3, None), bi1, bi1, slice(None, 2, 2), [1])
  1080. idxnp = (slice(2, 3, None), bi1.toarray(), bi1.toarray(), slice(None, 2, 2), [1])
  1081. result = D[idxnp]
  1082. assert_equal(A[idx].toarray(), result)
  1083. def test_bool_set():
  1084. D_orig = np.arange(4 * 6 * 6 * 3 * 4).reshape((4, 6, 6, 3, 4))
  1085. A_orig = coo_array(D_orig)
  1086. A, D = A_orig.copy(), D_orig.copy()
  1087. D[D > 500] = A[A > 500] = -33
  1088. assert_equal(A.toarray(), D)
  1089. A, D = A_orig.copy(), D_orig.copy()
  1090. D[D > 500] = A[A > 500] = -77
  1091. assert_equal(A.toarray(), D)
  1092. A, D = A_orig.copy(), D_orig.copy()
  1093. bool0 = A[:, 0, 0, 0, 0] > 50
  1094. idx = (bool0, slice(2, 3, None), [1], slice(None, 2, 2), bool0)
  1095. idxnp = (bool0.toarray(), slice(2, 3, 1), [1], slice(0, 2, 2), bool0.toarray())
  1096. D[idxnp] = A[idx] = -55
  1097. assert_equal(A.toarray(), D)
  1098. A, D = A_orig.copy(), D_orig.copy()
  1099. D[idxnp] = A[idxnp] = -88
  1100. assert_equal(A.toarray(), D)