test_construct.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. """test sparse matrix construction functions"""
  2. from __future__ import division, print_function, absolute_import
  3. import numpy as np
  4. from numpy import array, matrix
  5. from numpy.testing import (assert_equal, assert_,
  6. assert_array_equal, assert_array_almost_equal_nulp)
  7. import pytest
  8. from pytest import raises as assert_raises
  9. from scipy._lib._testutils import check_free_memory
  10. from scipy.sparse import csr_matrix, coo_matrix
  11. from scipy.sparse import construct
  12. from scipy.sparse.construct import rand as sprand
  13. sparse_formats = ['csr','csc','coo','bsr','dia','lil','dok']
  14. #TODO check whether format=XXX is respected
  15. def _sprandn(m, n, density=0.01, format="coo", dtype=None, random_state=None):
  16. # Helper function for testing.
  17. if random_state is None:
  18. random_state = np.random
  19. elif isinstance(random_state, (int, np.integer)):
  20. random_state = np.random.RandomState(random_state)
  21. data_rvs = random_state.randn
  22. return construct.random(m, n, density, format, dtype,
  23. random_state, data_rvs)
  24. class TestConstructUtils(object):
  25. def test_spdiags(self):
  26. diags1 = array([[1, 2, 3, 4, 5]])
  27. diags2 = array([[1, 2, 3, 4, 5],
  28. [6, 7, 8, 9,10]])
  29. diags3 = array([[1, 2, 3, 4, 5],
  30. [6, 7, 8, 9,10],
  31. [11,12,13,14,15]])
  32. cases = []
  33. cases.append((diags1, 0, 1, 1, [[1]]))
  34. cases.append((diags1, [0], 1, 1, [[1]]))
  35. cases.append((diags1, [0], 2, 1, [[1],[0]]))
  36. cases.append((diags1, [0], 1, 2, [[1,0]]))
  37. cases.append((diags1, [1], 1, 2, [[0,2]]))
  38. cases.append((diags1,[-1], 1, 2, [[0,0]]))
  39. cases.append((diags1, [0], 2, 2, [[1,0],[0,2]]))
  40. cases.append((diags1,[-1], 2, 2, [[0,0],[1,0]]))
  41. cases.append((diags1, [3], 2, 2, [[0,0],[0,0]]))
  42. cases.append((diags1, [0], 3, 4, [[1,0,0,0],[0,2,0,0],[0,0,3,0]]))
  43. cases.append((diags1, [1], 3, 4, [[0,2,0,0],[0,0,3,0],[0,0,0,4]]))
  44. cases.append((diags1, [2], 3, 5, [[0,0,3,0,0],[0,0,0,4,0],[0,0,0,0,5]]))
  45. cases.append((diags2, [0,2], 3, 3, [[1,0,8],[0,2,0],[0,0,3]]))
  46. cases.append((diags2, [-1,0], 3, 4, [[6,0,0,0],[1,7,0,0],[0,2,8,0]]))
  47. cases.append((diags2, [2,-3], 6, 6, [[0,0,3,0,0,0],
  48. [0,0,0,4,0,0],
  49. [0,0,0,0,5,0],
  50. [6,0,0,0,0,0],
  51. [0,7,0,0,0,0],
  52. [0,0,8,0,0,0]]))
  53. cases.append((diags3, [-1,0,1], 6, 6, [[6,12, 0, 0, 0, 0],
  54. [1, 7,13, 0, 0, 0],
  55. [0, 2, 8,14, 0, 0],
  56. [0, 0, 3, 9,15, 0],
  57. [0, 0, 0, 4,10, 0],
  58. [0, 0, 0, 0, 5, 0]]))
  59. cases.append((diags3, [-4,2,-1], 6, 5, [[0, 0, 8, 0, 0],
  60. [11, 0, 0, 9, 0],
  61. [0,12, 0, 0,10],
  62. [0, 0,13, 0, 0],
  63. [1, 0, 0,14, 0],
  64. [0, 2, 0, 0,15]]))
  65. for d,o,m,n,result in cases:
  66. assert_equal(construct.spdiags(d,o,m,n).todense(), result)
  67. def test_diags(self):
  68. a = array([1, 2, 3, 4, 5])
  69. b = array([6, 7, 8, 9, 10])
  70. c = array([11, 12, 13, 14, 15])
  71. cases = []
  72. cases.append((a[:1], 0, (1, 1), [[1]]))
  73. cases.append(([a[:1]], [0], (1, 1), [[1]]))
  74. cases.append(([a[:1]], [0], (2, 1), [[1],[0]]))
  75. cases.append(([a[:1]], [0], (1, 2), [[1,0]]))
  76. cases.append(([a[:1]], [1], (1, 2), [[0,1]]))
  77. cases.append(([a[:2]], [0], (2, 2), [[1,0],[0,2]]))
  78. cases.append(([a[:1]],[-1], (2, 2), [[0,0],[1,0]]))
  79. cases.append(([a[:3]], [0], (3, 4), [[1,0,0,0],[0,2,0,0],[0,0,3,0]]))
  80. cases.append(([a[:3]], [1], (3, 4), [[0,1,0,0],[0,0,2,0],[0,0,0,3]]))
  81. cases.append(([a[:1]], [-2], (3, 5), [[0,0,0,0,0],[0,0,0,0,0],[1,0,0,0,0]]))
  82. cases.append(([a[:2]], [-1], (3, 5), [[0,0,0,0,0],[1,0,0,0,0],[0,2,0,0,0]]))
  83. cases.append(([a[:3]], [0], (3, 5), [[1,0,0,0,0],[0,2,0,0,0],[0,0,3,0,0]]))
  84. cases.append(([a[:3]], [1], (3, 5), [[0,1,0,0,0],[0,0,2,0,0],[0,0,0,3,0]]))
  85. cases.append(([a[:3]], [2], (3, 5), [[0,0,1,0,0],[0,0,0,2,0],[0,0,0,0,3]]))
  86. cases.append(([a[:2]], [3], (3, 5), [[0,0,0,1,0],[0,0,0,0,2],[0,0,0,0,0]]))
  87. cases.append(([a[:1]], [4], (3, 5), [[0,0,0,0,1],[0,0,0,0,0],[0,0,0,0,0]]))
  88. cases.append(([a[:1]], [-4], (5, 3), [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[1,0,0]]))
  89. cases.append(([a[:2]], [-3], (5, 3), [[0,0,0],[0,0,0],[0,0,0],[1,0,0],[0,2,0]]))
  90. cases.append(([a[:3]], [-2], (5, 3), [[0,0,0],[0,0,0],[1,0,0],[0,2,0],[0,0,3]]))
  91. cases.append(([a[:3]], [-1], (5, 3), [[0,0,0],[1,0,0],[0,2,0],[0,0,3],[0,0,0]]))
  92. cases.append(([a[:3]], [0], (5, 3), [[1,0,0],[0,2,0],[0,0,3],[0,0,0],[0,0,0]]))
  93. cases.append(([a[:2]], [1], (5, 3), [[0,1,0],[0,0,2],[0,0,0],[0,0,0],[0,0,0]]))
  94. cases.append(([a[:1]], [2], (5, 3), [[0,0,1],[0,0,0],[0,0,0],[0,0,0],[0,0,0]]))
  95. cases.append(([a[:3],b[:1]], [0,2], (3, 3), [[1,0,6],[0,2,0],[0,0,3]]))
  96. cases.append(([a[:2],b[:3]], [-1,0], (3, 4), [[6,0,0,0],[1,7,0,0],[0,2,8,0]]))
  97. cases.append(([a[:4],b[:3]], [2,-3], (6, 6), [[0,0,1,0,0,0],
  98. [0,0,0,2,0,0],
  99. [0,0,0,0,3,0],
  100. [6,0,0,0,0,4],
  101. [0,7,0,0,0,0],
  102. [0,0,8,0,0,0]]))
  103. cases.append(([a[:4],b,c[:4]], [-1,0,1], (5, 5), [[6,11, 0, 0, 0],
  104. [1, 7,12, 0, 0],
  105. [0, 2, 8,13, 0],
  106. [0, 0, 3, 9,14],
  107. [0, 0, 0, 4,10]]))
  108. cases.append(([a[:2],b[:3],c], [-4,2,-1], (6, 5), [[0, 0, 6, 0, 0],
  109. [11, 0, 0, 7, 0],
  110. [0,12, 0, 0, 8],
  111. [0, 0,13, 0, 0],
  112. [1, 0, 0,14, 0],
  113. [0, 2, 0, 0,15]]))
  114. # too long arrays are OK
  115. cases.append(([a], [0], (1, 1), [[1]]))
  116. cases.append(([a[:3],b], [0,2], (3, 3), [[1, 0, 6], [0, 2, 0], [0, 0, 3]]))
  117. cases.append((np.array([[1, 2, 3], [4, 5, 6]]), [0,-1], (3, 3), [[1, 0, 0], [4, 2, 0], [0, 5, 3]]))
  118. # scalar case: broadcasting
  119. cases.append(([1,-2,1], [1,0,-1], (3, 3), [[-2, 1, 0],
  120. [1, -2, 1],
  121. [0, 1, -2]]))
  122. for d, o, shape, result in cases:
  123. err_msg = "%r %r %r %r" % (d, o, shape, result)
  124. assert_equal(construct.diags(d, o, shape=shape).todense(),
  125. result, err_msg=err_msg)
  126. if shape[0] == shape[1] and hasattr(d[0], '__len__') and len(d[0]) <= max(shape):
  127. # should be able to find the shape automatically
  128. assert_equal(construct.diags(d, o).todense(), result,
  129. err_msg=err_msg)
  130. def test_diags_default(self):
  131. a = array([1, 2, 3, 4, 5])
  132. assert_equal(construct.diags(a).todense(), np.diag(a))
  133. def test_diags_default_bad(self):
  134. a = array([[1, 2, 3, 4, 5], [2, 3, 4, 5, 6]])
  135. assert_raises(ValueError, construct.diags, a)
  136. def test_diags_bad(self):
  137. a = array([1, 2, 3, 4, 5])
  138. b = array([6, 7, 8, 9, 10])
  139. c = array([11, 12, 13, 14, 15])
  140. cases = []
  141. cases.append(([a[:0]], 0, (1, 1)))
  142. cases.append(([a[:4],b,c[:3]], [-1,0,1], (5, 5)))
  143. cases.append(([a[:2],c,b[:3]], [-4,2,-1], (6, 5)))
  144. cases.append(([a[:2],c,b[:3]], [-4,2,-1], None))
  145. cases.append(([], [-4,2,-1], None))
  146. cases.append(([1], [-5], (4, 4)))
  147. cases.append(([a], 0, None))
  148. for d, o, shape in cases:
  149. assert_raises(ValueError, construct.diags, d, o, shape)
  150. assert_raises(TypeError, construct.diags, [[None]], [0])
  151. def test_diags_vs_diag(self):
  152. # Check that
  153. #
  154. # diags([a, b, ...], [i, j, ...]) == diag(a, i) + diag(b, j) + ...
  155. #
  156. np.random.seed(1234)
  157. for n_diags in [1, 2, 3, 4, 5, 10]:
  158. n = 1 + n_diags//2 + np.random.randint(0, 10)
  159. offsets = np.arange(-n+1, n-1)
  160. np.random.shuffle(offsets)
  161. offsets = offsets[:n_diags]
  162. diagonals = [np.random.rand(n - abs(q)) for q in offsets]
  163. mat = construct.diags(diagonals, offsets)
  164. dense_mat = sum([np.diag(x, j) for x, j in zip(diagonals, offsets)])
  165. assert_array_almost_equal_nulp(mat.todense(), dense_mat)
  166. if len(offsets) == 1:
  167. mat = construct.diags(diagonals[0], offsets[0])
  168. dense_mat = np.diag(diagonals[0], offsets[0])
  169. assert_array_almost_equal_nulp(mat.todense(), dense_mat)
  170. def test_diags_dtype(self):
  171. x = construct.diags([2.2], [0], shape=(2, 2), dtype=int)
  172. assert_equal(x.dtype, int)
  173. assert_equal(x.todense(), [[2, 0], [0, 2]])
  174. def test_diags_one_diagonal(self):
  175. d = list(range(5))
  176. for k in range(-5, 6):
  177. assert_equal(construct.diags(d, k).toarray(),
  178. construct.diags([d], [k]).toarray())
  179. def test_diags_empty(self):
  180. x = construct.diags([])
  181. assert_equal(x.shape, (0, 0))
  182. def test_identity(self):
  183. assert_equal(construct.identity(1).toarray(), [[1]])
  184. assert_equal(construct.identity(2).toarray(), [[1,0],[0,1]])
  185. I = construct.identity(3, dtype='int8', format='dia')
  186. assert_equal(I.dtype, np.dtype('int8'))
  187. assert_equal(I.format, 'dia')
  188. for fmt in sparse_formats:
  189. I = construct.identity(3, format=fmt)
  190. assert_equal(I.format, fmt)
  191. assert_equal(I.toarray(), [[1,0,0],[0,1,0],[0,0,1]])
  192. def test_eye(self):
  193. assert_equal(construct.eye(1,1).toarray(), [[1]])
  194. assert_equal(construct.eye(2,3).toarray(), [[1,0,0],[0,1,0]])
  195. assert_equal(construct.eye(3,2).toarray(), [[1,0],[0,1],[0,0]])
  196. assert_equal(construct.eye(3,3).toarray(), [[1,0,0],[0,1,0],[0,0,1]])
  197. assert_equal(construct.eye(3,3,dtype='int16').dtype, np.dtype('int16'))
  198. for m in [3, 5]:
  199. for n in [3, 5]:
  200. for k in range(-5,6):
  201. assert_equal(construct.eye(m, n, k=k).toarray(), np.eye(m, n, k=k))
  202. if m == n:
  203. assert_equal(construct.eye(m, k=k).toarray(), np.eye(m, n, k=k))
  204. def test_eye_one(self):
  205. assert_equal(construct.eye(1).toarray(), [[1]])
  206. assert_equal(construct.eye(2).toarray(), [[1,0],[0,1]])
  207. I = construct.eye(3, dtype='int8', format='dia')
  208. assert_equal(I.dtype, np.dtype('int8'))
  209. assert_equal(I.format, 'dia')
  210. for fmt in sparse_formats:
  211. I = construct.eye(3, format=fmt)
  212. assert_equal(I.format, fmt)
  213. assert_equal(I.toarray(), [[1,0,0],[0,1,0],[0,0,1]])
  214. def test_kron(self):
  215. cases = []
  216. cases.append(array([[0]]))
  217. cases.append(array([[-1]]))
  218. cases.append(array([[4]]))
  219. cases.append(array([[10]]))
  220. cases.append(array([[0],[0]]))
  221. cases.append(array([[0,0]]))
  222. cases.append(array([[1,2],[3,4]]))
  223. cases.append(array([[0,2],[5,0]]))
  224. cases.append(array([[0,2,-6],[8,0,14]]))
  225. cases.append(array([[5,4],[0,0],[6,0]]))
  226. cases.append(array([[5,4,4],[1,0,0],[6,0,8]]))
  227. cases.append(array([[0,1,0,2,0,5,8]]))
  228. cases.append(array([[0.5,0.125,0,3.25],[0,2.5,0,0]]))
  229. for a in cases:
  230. for b in cases:
  231. result = construct.kron(csr_matrix(a),csr_matrix(b)).todense()
  232. expected = np.kron(a,b)
  233. assert_array_equal(result,expected)
  234. def test_kronsum(self):
  235. cases = []
  236. cases.append(array([[0]]))
  237. cases.append(array([[-1]]))
  238. cases.append(array([[4]]))
  239. cases.append(array([[10]]))
  240. cases.append(array([[1,2],[3,4]]))
  241. cases.append(array([[0,2],[5,0]]))
  242. cases.append(array([[0,2,-6],[8,0,14],[0,3,0]]))
  243. cases.append(array([[1,0,0],[0,5,-1],[4,-2,8]]))
  244. for a in cases:
  245. for b in cases:
  246. result = construct.kronsum(csr_matrix(a),csr_matrix(b)).todense()
  247. expected = np.kron(np.eye(len(b)), a) + \
  248. np.kron(b, np.eye(len(a)))
  249. assert_array_equal(result,expected)
  250. def test_vstack(self):
  251. A = coo_matrix([[1,2],[3,4]])
  252. B = coo_matrix([[5,6]])
  253. expected = matrix([[1, 2],
  254. [3, 4],
  255. [5, 6]])
  256. assert_equal(construct.vstack([A,B]).todense(), expected)
  257. assert_equal(construct.vstack([A,B], dtype=np.float32).dtype, np.float32)
  258. assert_equal(construct.vstack([A.tocsr(),B.tocsr()]).todense(),
  259. expected)
  260. assert_equal(construct.vstack([A.tocsr(),B.tocsr()], dtype=np.float32).dtype,
  261. np.float32)
  262. assert_equal(construct.vstack([A.tocsr(),B.tocsr()],
  263. dtype=np.float32).indices.dtype, np.int32)
  264. assert_equal(construct.vstack([A.tocsr(),B.tocsr()],
  265. dtype=np.float32).indptr.dtype, np.int32)
  266. def test_hstack(self):
  267. A = coo_matrix([[1,2],[3,4]])
  268. B = coo_matrix([[5],[6]])
  269. expected = matrix([[1, 2, 5],
  270. [3, 4, 6]])
  271. assert_equal(construct.hstack([A,B]).todense(), expected)
  272. assert_equal(construct.hstack([A,B], dtype=np.float32).dtype, np.float32)
  273. assert_equal(construct.hstack([A.tocsc(),B.tocsc()]).todense(),
  274. expected)
  275. assert_equal(construct.hstack([A.tocsc(),B.tocsc()], dtype=np.float32).dtype,
  276. np.float32)
  277. def test_bmat(self):
  278. A = coo_matrix([[1,2],[3,4]])
  279. B = coo_matrix([[5],[6]])
  280. C = coo_matrix([[7]])
  281. D = coo_matrix((0,0))
  282. expected = matrix([[1, 2, 5],
  283. [3, 4, 6],
  284. [0, 0, 7]])
  285. assert_equal(construct.bmat([[A,B],[None,C]]).todense(), expected)
  286. expected = matrix([[1, 2, 0],
  287. [3, 4, 0],
  288. [0, 0, 7]])
  289. assert_equal(construct.bmat([[A,None],[None,C]]).todense(), expected)
  290. expected = matrix([[0, 5],
  291. [0, 6],
  292. [7, 0]])
  293. assert_equal(construct.bmat([[None,B],[C,None]]).todense(), expected)
  294. expected = matrix(np.empty((0,0)))
  295. assert_equal(construct.bmat([[None,None]]).todense(), expected)
  296. assert_equal(construct.bmat([[None,D],[D,None]]).todense(), expected)
  297. # test bug reported in gh-5976
  298. expected = matrix([[7]])
  299. assert_equal(construct.bmat([[None,D],[C,None]]).todense(), expected)
  300. # test failure cases
  301. with assert_raises(ValueError) as excinfo:
  302. construct.bmat([[A], [B]])
  303. excinfo.match(r'Got blocks\[1,0\]\.shape\[1\] == 1, expected 2')
  304. with assert_raises(ValueError) as excinfo:
  305. construct.bmat([[A, C]])
  306. excinfo.match(r'Got blocks\[0,1\]\.shape\[0\] == 1, expected 2')
  307. @pytest.mark.slow
  308. def test_concatenate_int32_overflow(self):
  309. """ test for indptr overflow when concatenating matrices """
  310. check_free_memory(30000)
  311. n = 33000
  312. A = csr_matrix(np.ones((n, n), dtype=bool))
  313. B = A.copy()
  314. C = construct._compressed_sparse_stack((A,B), 0)
  315. assert_(np.all(np.equal(np.diff(C.indptr), n)))
  316. assert_equal(C.indices.dtype, np.int64)
  317. assert_equal(C.indptr.dtype, np.int64)
  318. def test_block_diag_basic(self):
  319. """ basic test for block_diag """
  320. A = coo_matrix([[1,2],[3,4]])
  321. B = coo_matrix([[5],[6]])
  322. C = coo_matrix([[7]])
  323. expected = matrix([[1, 2, 0, 0],
  324. [3, 4, 0, 0],
  325. [0, 0, 5, 0],
  326. [0, 0, 6, 0],
  327. [0, 0, 0, 7]])
  328. assert_equal(construct.block_diag((A, B, C)).todense(), expected)
  329. def test_block_diag_scalar_1d_args(self):
  330. """ block_diag with scalar and 1d arguments """
  331. # one 1d matrix and a scalar
  332. assert_array_equal(construct.block_diag([[2,3], 4]).toarray(),
  333. [[2, 3, 0], [0, 0, 4]])
  334. def test_block_diag_1(self):
  335. """ block_diag with one matrix """
  336. assert_equal(construct.block_diag([[1, 0]]).todense(),
  337. matrix([[1, 0]]))
  338. assert_equal(construct.block_diag([[[1, 0]]]).todense(),
  339. matrix([[1, 0]]))
  340. assert_equal(construct.block_diag([[[1], [0]]]).todense(),
  341. matrix([[1], [0]]))
  342. # just on scalar
  343. assert_equal(construct.block_diag([1]).todense(),
  344. matrix([[1]]))
  345. def test_random_sampling(self):
  346. # Simple sanity checks for sparse random sampling.
  347. for f in sprand, _sprandn:
  348. for t in [np.float32, np.float64, np.longdouble,
  349. np.int32, np.int64, np.complex64, np.complex128]:
  350. x = f(5, 10, density=0.1, dtype=t)
  351. assert_equal(x.dtype, t)
  352. assert_equal(x.shape, (5, 10))
  353. assert_equal(x.nnz, 5)
  354. x1 = f(5, 10, density=0.1, random_state=4321)
  355. assert_equal(x1.dtype, np.double)
  356. x2 = f(5, 10, density=0.1,
  357. random_state=np.random.RandomState(4321))
  358. assert_array_equal(x1.data, x2.data)
  359. assert_array_equal(x1.row, x2.row)
  360. assert_array_equal(x1.col, x2.col)
  361. for density in [0.0, 0.1, 0.5, 1.0]:
  362. x = f(5, 10, density=density)
  363. assert_equal(x.nnz, int(density * np.prod(x.shape)))
  364. for fmt in ['coo', 'csc', 'csr', 'lil']:
  365. x = f(5, 10, format=fmt)
  366. assert_equal(x.format, fmt)
  367. assert_raises(ValueError, lambda: f(5, 10, 1.1))
  368. assert_raises(ValueError, lambda: f(5, 10, -0.1))
  369. def test_rand(self):
  370. # Simple distributional checks for sparse.rand.
  371. for random_state in None, 4321, np.random.RandomState():
  372. x = sprand(10, 20, density=0.5, dtype=np.float64,
  373. random_state=random_state)
  374. assert_(np.all(np.less_equal(0, x.data)))
  375. assert_(np.all(np.less_equal(x.data, 1)))
  376. def test_randn(self):
  377. # Simple distributional checks for sparse.randn.
  378. # Statistically, some of these should be negative
  379. # and some should be greater than 1.
  380. for random_state in None, 4321, np.random.RandomState():
  381. x = _sprandn(10, 20, density=0.5, dtype=np.float64,
  382. random_state=random_state)
  383. assert_(np.any(np.less(x.data, 0)))
  384. assert_(np.any(np.less(1, x.data)))
  385. def test_random_accept_str_dtype(self):
  386. # anything that np.dtype can convert to a dtype should be accepted
  387. # for the dtype
  388. a = construct.random(10, 10, dtype='d')