test_mmio.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. from tempfile import mkdtemp
  2. import os
  3. import io
  4. import shutil
  5. import textwrap
  6. import numpy as np
  7. from numpy import array, transpose, pi
  8. from numpy.testing import (assert_equal, assert_allclose,
  9. assert_array_equal, assert_array_almost_equal)
  10. import pytest
  11. from pytest import raises as assert_raises
  12. import scipy.sparse
  13. from scipy.io import mminfo, mmread, mmwrite
  14. parametrize_args = [('integer', 'int'),
  15. ('unsigned-integer', 'uint')]
  16. class TestMMIOArray:
  17. def setup_method(self):
  18. self.tmpdir = mkdtemp()
  19. self.fn = os.path.join(self.tmpdir, 'testfile.mtx')
  20. def teardown_method(self):
  21. shutil.rmtree(self.tmpdir)
  22. def check(self, a, info):
  23. mmwrite(self.fn, a)
  24. assert_equal(mminfo(self.fn), info)
  25. b = mmread(self.fn)
  26. assert_array_almost_equal(a, b)
  27. def check_exact(self, a, info):
  28. mmwrite(self.fn, a)
  29. assert_equal(mminfo(self.fn), info)
  30. b = mmread(self.fn)
  31. assert_equal(a, b)
  32. @pytest.mark.parametrize('typeval, dtype', parametrize_args)
  33. def test_simple_integer(self, typeval, dtype):
  34. self.check_exact(array([[1, 2], [3, 4]], dtype=dtype),
  35. (2, 2, 4, 'array', typeval, 'general'))
  36. @pytest.mark.parametrize('typeval, dtype', parametrize_args)
  37. def test_32bit_integer(self, typeval, dtype):
  38. a = array([[2**31-1, 2**31-2], [2**31-3, 2**31-4]], dtype=dtype)
  39. self.check_exact(a, (2, 2, 4, 'array', typeval, 'general'))
  40. def test_64bit_integer(self):
  41. a = array([[2**31, 2**32], [2**63-2, 2**63-1]], dtype=np.int64)
  42. if (np.intp(0).itemsize < 8):
  43. assert_raises(OverflowError, mmwrite, self.fn, a)
  44. else:
  45. self.check_exact(a, (2, 2, 4, 'array', 'integer', 'general'))
  46. def test_64bit_unsigned_integer(self):
  47. a = array([[2**31, 2**32], [2**64-2, 2**64-1]], dtype=np.uint64)
  48. self.check_exact(a, (2, 2, 4, 'array', 'unsigned-integer', 'general'))
  49. @pytest.mark.parametrize('typeval, dtype', parametrize_args)
  50. def test_simple_upper_triangle_integer(self, typeval, dtype):
  51. self.check_exact(array([[0, 1], [0, 0]], dtype=dtype),
  52. (2, 2, 4, 'array', typeval, 'general'))
  53. @pytest.mark.parametrize('typeval, dtype', parametrize_args)
  54. def test_simple_lower_triangle_integer(self, typeval, dtype):
  55. self.check_exact(array([[0, 0], [1, 0]], dtype=dtype),
  56. (2, 2, 4, 'array', typeval, 'general'))
  57. @pytest.mark.parametrize('typeval, dtype', parametrize_args)
  58. def test_simple_rectangular_integer(self, typeval, dtype):
  59. self.check_exact(array([[1, 2, 3], [4, 5, 6]], dtype=dtype),
  60. (2, 3, 6, 'array', typeval, 'general'))
  61. def test_simple_rectangular_float(self):
  62. self.check([[1, 2], [3.5, 4], [5, 6]],
  63. (3, 2, 6, 'array', 'real', 'general'))
  64. def test_simple_float(self):
  65. self.check([[1, 2], [3, 4.0]],
  66. (2, 2, 4, 'array', 'real', 'general'))
  67. def test_simple_complex(self):
  68. self.check([[1, 2], [3, 4j]],
  69. (2, 2, 4, 'array', 'complex', 'general'))
  70. @pytest.mark.parametrize('typeval, dtype', parametrize_args)
  71. def test_simple_symmetric_integer(self, typeval, dtype):
  72. self.check_exact(array([[1, 2], [2, 4]], dtype=dtype),
  73. (2, 2, 4, 'array', typeval, 'symmetric'))
  74. def test_simple_skew_symmetric_integer(self):
  75. self.check_exact([[0, 2], [-2, 0]],
  76. (2, 2, 4, 'array', 'integer', 'skew-symmetric'))
  77. def test_simple_skew_symmetric_float(self):
  78. self.check(array([[0, 2], [-2.0, 0.0]], 'f'),
  79. (2, 2, 4, 'array', 'real', 'skew-symmetric'))
  80. def test_simple_hermitian_complex(self):
  81. self.check([[1, 2+3j], [2-3j, 4]],
  82. (2, 2, 4, 'array', 'complex', 'hermitian'))
  83. def test_random_symmetric_float(self):
  84. sz = (20, 20)
  85. a = np.random.random(sz)
  86. a = a + transpose(a)
  87. self.check(a, (20, 20, 400, 'array', 'real', 'symmetric'))
  88. def test_random_rectangular_float(self):
  89. sz = (20, 15)
  90. a = np.random.random(sz)
  91. self.check(a, (20, 15, 300, 'array', 'real', 'general'))
  92. def test_bad_number_of_array_header_fields(self):
  93. s = """\
  94. %%MatrixMarket matrix array real general
  95. 3 3 999
  96. 1.0
  97. 2.0
  98. 3.0
  99. 4.0
  100. 5.0
  101. 6.0
  102. 7.0
  103. 8.0
  104. 9.0
  105. """
  106. text = textwrap.dedent(s).encode('ascii')
  107. with pytest.raises(ValueError, match='not of length 2'):
  108. scipy.io.mmread(io.BytesIO(text))
  109. def test_gh13634_non_skew_symmetric_int(self):
  110. self.check_exact(array([[1, 2], [-2, 99]], dtype=np.int32),
  111. (2, 2, 4, 'array', 'integer', 'general'))
  112. def test_gh13634_non_skew_symmetric_float(self):
  113. self.check(array([[1, 2], [-2, 99.]], dtype=np.float32),
  114. (2, 2, 4, 'array', 'real', 'general'))
  115. class TestMMIOSparseCSR(TestMMIOArray):
  116. def setup_method(self):
  117. self.tmpdir = mkdtemp()
  118. self.fn = os.path.join(self.tmpdir, 'testfile.mtx')
  119. def teardown_method(self):
  120. shutil.rmtree(self.tmpdir)
  121. def check(self, a, info):
  122. mmwrite(self.fn, a)
  123. assert_equal(mminfo(self.fn), info)
  124. b = mmread(self.fn)
  125. assert_array_almost_equal(a.toarray(), b.toarray())
  126. def check_exact(self, a, info):
  127. mmwrite(self.fn, a)
  128. assert_equal(mminfo(self.fn), info)
  129. b = mmread(self.fn)
  130. assert_equal(a.toarray(), b.toarray())
  131. @pytest.mark.parametrize('typeval, dtype', parametrize_args)
  132. def test_simple_integer(self, typeval, dtype):
  133. self.check_exact(scipy.sparse.csr_matrix([[1, 2], [3, 4]], dtype=dtype),
  134. (2, 2, 4, 'coordinate', typeval, 'general'))
  135. def test_32bit_integer(self):
  136. a = scipy.sparse.csr_matrix(array([[2**31-1, -2**31+2],
  137. [2**31-3, 2**31-4]],
  138. dtype=np.int32))
  139. self.check_exact(a, (2, 2, 4, 'coordinate', 'integer', 'general'))
  140. def test_64bit_integer(self):
  141. a = scipy.sparse.csr_matrix(array([[2**32+1, 2**32+1],
  142. [-2**63+2, 2**63-2]],
  143. dtype=np.int64))
  144. if (np.intp(0).itemsize < 8):
  145. assert_raises(OverflowError, mmwrite, self.fn, a)
  146. else:
  147. self.check_exact(a, (2, 2, 4, 'coordinate', 'integer', 'general'))
  148. def test_32bit_unsigned_integer(self):
  149. a = scipy.sparse.csr_matrix(array([[2**31-1, 2**31-2],
  150. [2**31-3, 2**31-4]],
  151. dtype=np.uint32))
  152. self.check_exact(a, (2, 2, 4, 'coordinate', 'unsigned-integer', 'general'))
  153. def test_64bit_unsigned_integer(self):
  154. a = scipy.sparse.csr_matrix(array([[2**32+1, 2**32+1],
  155. [2**64-2, 2**64-1]],
  156. dtype=np.uint64))
  157. self.check_exact(a, (2, 2, 4, 'coordinate', 'unsigned-integer', 'general'))
  158. @pytest.mark.parametrize('typeval, dtype', parametrize_args)
  159. def test_simple_upper_triangle_integer(self, typeval, dtype):
  160. self.check_exact(scipy.sparse.csr_matrix([[0, 1], [0, 0]], dtype=dtype),
  161. (2, 2, 1, 'coordinate', typeval, 'general'))
  162. @pytest.mark.parametrize('typeval, dtype', parametrize_args)
  163. def test_simple_lower_triangle_integer(self, typeval, dtype):
  164. self.check_exact(scipy.sparse.csr_matrix([[0, 0], [1, 0]], dtype=dtype),
  165. (2, 2, 1, 'coordinate', typeval, 'general'))
  166. @pytest.mark.parametrize('typeval, dtype', parametrize_args)
  167. def test_simple_rectangular_integer(self, typeval, dtype):
  168. self.check_exact(scipy.sparse.csr_matrix([[1, 2, 3], [4, 5, 6]], dtype=dtype),
  169. (2, 3, 6, 'coordinate', typeval, 'general'))
  170. def test_simple_rectangular_float(self):
  171. self.check(scipy.sparse.csr_matrix([[1, 2], [3.5, 4], [5, 6]]),
  172. (3, 2, 6, 'coordinate', 'real', 'general'))
  173. def test_simple_float(self):
  174. self.check(scipy.sparse.csr_matrix([[1, 2], [3, 4.0]]),
  175. (2, 2, 4, 'coordinate', 'real', 'general'))
  176. def test_simple_complex(self):
  177. self.check(scipy.sparse.csr_matrix([[1, 2], [3, 4j]]),
  178. (2, 2, 4, 'coordinate', 'complex', 'general'))
  179. @pytest.mark.parametrize('typeval, dtype', parametrize_args)
  180. def test_simple_symmetric_integer(self, typeval, dtype):
  181. self.check_exact(scipy.sparse.csr_matrix([[1, 2], [2, 4]], dtype=dtype),
  182. (2, 2, 3, 'coordinate', typeval, 'symmetric'))
  183. def test_simple_skew_symmetric_integer(self):
  184. self.check_exact(scipy.sparse.csr_matrix([[0, 2], [-2, 0]]),
  185. (2, 2, 1, 'coordinate', 'integer', 'skew-symmetric'))
  186. def test_simple_skew_symmetric_float(self):
  187. self.check(scipy.sparse.csr_matrix(array([[0, 2], [-2.0, 0]], 'f')),
  188. (2, 2, 1, 'coordinate', 'real', 'skew-symmetric'))
  189. def test_simple_hermitian_complex(self):
  190. self.check(scipy.sparse.csr_matrix([[1, 2+3j], [2-3j, 4]]),
  191. (2, 2, 3, 'coordinate', 'complex', 'hermitian'))
  192. def test_random_symmetric_float(self):
  193. sz = (20, 20)
  194. a = np.random.random(sz)
  195. a = a + transpose(a)
  196. a = scipy.sparse.csr_matrix(a)
  197. self.check(a, (20, 20, 210, 'coordinate', 'real', 'symmetric'))
  198. def test_random_rectangular_float(self):
  199. sz = (20, 15)
  200. a = np.random.random(sz)
  201. a = scipy.sparse.csr_matrix(a)
  202. self.check(a, (20, 15, 300, 'coordinate', 'real', 'general'))
  203. def test_simple_pattern(self):
  204. a = scipy.sparse.csr_matrix([[0, 1.5], [3.0, 2.5]])
  205. p = np.zeros_like(a.toarray())
  206. p[a.toarray() > 0] = 1
  207. info = (2, 2, 3, 'coordinate', 'pattern', 'general')
  208. mmwrite(self.fn, a, field='pattern')
  209. assert_equal(mminfo(self.fn), info)
  210. b = mmread(self.fn)
  211. assert_array_almost_equal(p, b.toarray())
  212. def test_gh13634_non_skew_symmetric_int(self):
  213. a = scipy.sparse.csr_matrix([[1, 2], [-2, 99]], dtype=np.int32)
  214. self.check_exact(a, (2, 2, 4, 'coordinate', 'integer', 'general'))
  215. def test_gh13634_non_skew_symmetric_float(self):
  216. a = scipy.sparse.csr_matrix([[1, 2], [-2, 99.]], dtype=np.float32)
  217. self.check(a, (2, 2, 4, 'coordinate', 'real', 'general'))
  218. _32bit_integer_dense_example = '''\
  219. %%MatrixMarket matrix array integer general
  220. 2 2
  221. 2147483647
  222. 2147483646
  223. 2147483647
  224. 2147483646
  225. '''
  226. _32bit_integer_sparse_example = '''\
  227. %%MatrixMarket matrix coordinate integer symmetric
  228. 2 2 2
  229. 1 1 2147483647
  230. 2 2 2147483646
  231. '''
  232. _64bit_integer_dense_example = '''\
  233. %%MatrixMarket matrix array integer general
  234. 2 2
  235. 2147483648
  236. -9223372036854775806
  237. -2147483648
  238. 9223372036854775807
  239. '''
  240. _64bit_integer_sparse_general_example = '''\
  241. %%MatrixMarket matrix coordinate integer general
  242. 2 2 3
  243. 1 1 2147483648
  244. 1 2 9223372036854775807
  245. 2 2 9223372036854775807
  246. '''
  247. _64bit_integer_sparse_symmetric_example = '''\
  248. %%MatrixMarket matrix coordinate integer symmetric
  249. 2 2 3
  250. 1 1 2147483648
  251. 1 2 -9223372036854775807
  252. 2 2 9223372036854775807
  253. '''
  254. _64bit_integer_sparse_skew_example = '''\
  255. %%MatrixMarket matrix coordinate integer skew-symmetric
  256. 2 2 3
  257. 1 1 2147483648
  258. 1 2 -9223372036854775807
  259. 2 2 9223372036854775807
  260. '''
  261. _over64bit_integer_dense_example = '''\
  262. %%MatrixMarket matrix array integer general
  263. 2 2
  264. 2147483648
  265. 9223372036854775807
  266. 2147483648
  267. 9223372036854775808
  268. '''
  269. _over64bit_integer_sparse_example = '''\
  270. %%MatrixMarket matrix coordinate integer symmetric
  271. 2 2 2
  272. 1 1 2147483648
  273. 2 2 19223372036854775808
  274. '''
  275. class TestMMIOReadLargeIntegers:
  276. def setup_method(self):
  277. self.tmpdir = mkdtemp()
  278. self.fn = os.path.join(self.tmpdir, 'testfile.mtx')
  279. def teardown_method(self):
  280. shutil.rmtree(self.tmpdir)
  281. def check_read(self, example, a, info, dense, over32, over64):
  282. with open(self.fn, 'w') as f:
  283. f.write(example)
  284. assert_equal(mminfo(self.fn), info)
  285. if (over32 and (np.intp(0).itemsize < 8)) or over64:
  286. assert_raises(OverflowError, mmread, self.fn)
  287. else:
  288. b = mmread(self.fn)
  289. if not dense:
  290. b = b.toarray()
  291. assert_equal(a, b)
  292. def test_read_32bit_integer_dense(self):
  293. a = array([[2**31-1, 2**31-1],
  294. [2**31-2, 2**31-2]], dtype=np.int64)
  295. self.check_read(_32bit_integer_dense_example,
  296. a,
  297. (2, 2, 4, 'array', 'integer', 'general'),
  298. dense=True,
  299. over32=False,
  300. over64=False)
  301. def test_read_32bit_integer_sparse(self):
  302. a = array([[2**31-1, 0],
  303. [0, 2**31-2]], dtype=np.int64)
  304. self.check_read(_32bit_integer_sparse_example,
  305. a,
  306. (2, 2, 2, 'coordinate', 'integer', 'symmetric'),
  307. dense=False,
  308. over32=False,
  309. over64=False)
  310. def test_read_64bit_integer_dense(self):
  311. a = array([[2**31, -2**31],
  312. [-2**63+2, 2**63-1]], dtype=np.int64)
  313. self.check_read(_64bit_integer_dense_example,
  314. a,
  315. (2, 2, 4, 'array', 'integer', 'general'),
  316. dense=True,
  317. over32=True,
  318. over64=False)
  319. def test_read_64bit_integer_sparse_general(self):
  320. a = array([[2**31, 2**63-1],
  321. [0, 2**63-1]], dtype=np.int64)
  322. self.check_read(_64bit_integer_sparse_general_example,
  323. a,
  324. (2, 2, 3, 'coordinate', 'integer', 'general'),
  325. dense=False,
  326. over32=True,
  327. over64=False)
  328. def test_read_64bit_integer_sparse_symmetric(self):
  329. a = array([[2**31, -2**63+1],
  330. [-2**63+1, 2**63-1]], dtype=np.int64)
  331. self.check_read(_64bit_integer_sparse_symmetric_example,
  332. a,
  333. (2, 2, 3, 'coordinate', 'integer', 'symmetric'),
  334. dense=False,
  335. over32=True,
  336. over64=False)
  337. def test_read_64bit_integer_sparse_skew(self):
  338. a = array([[2**31, -2**63+1],
  339. [2**63-1, 2**63-1]], dtype=np.int64)
  340. self.check_read(_64bit_integer_sparse_skew_example,
  341. a,
  342. (2, 2, 3, 'coordinate', 'integer', 'skew-symmetric'),
  343. dense=False,
  344. over32=True,
  345. over64=False)
  346. def test_read_over64bit_integer_dense(self):
  347. self.check_read(_over64bit_integer_dense_example,
  348. None,
  349. (2, 2, 4, 'array', 'integer', 'general'),
  350. dense=True,
  351. over32=True,
  352. over64=True)
  353. def test_read_over64bit_integer_sparse(self):
  354. self.check_read(_over64bit_integer_sparse_example,
  355. None,
  356. (2, 2, 2, 'coordinate', 'integer', 'symmetric'),
  357. dense=False,
  358. over32=True,
  359. over64=True)
  360. _general_example = '''\
  361. %%MatrixMarket matrix coordinate real general
  362. %=================================================================================
  363. %
  364. % This ASCII file represents a sparse MxN matrix with L
  365. % nonzeros in the following Matrix Market format:
  366. %
  367. % +----------------------------------------------+
  368. % |%%MatrixMarket matrix coordinate real general | <--- header line
  369. % |% | <--+
  370. % |% comments | |-- 0 or more comment lines
  371. % |% | <--+
  372. % | M N L | <--- rows, columns, entries
  373. % | I1 J1 A(I1, J1) | <--+
  374. % | I2 J2 A(I2, J2) | |
  375. % | I3 J3 A(I3, J3) | |-- L lines
  376. % | . . . | |
  377. % | IL JL A(IL, JL) | <--+
  378. % +----------------------------------------------+
  379. %
  380. % Indices are 1-based, i.e. A(1,1) is the first element.
  381. %
  382. %=================================================================================
  383. 5 5 8
  384. 1 1 1.000e+00
  385. 2 2 1.050e+01
  386. 3 3 1.500e-02
  387. 1 4 6.000e+00
  388. 4 2 2.505e+02
  389. 4 4 -2.800e+02
  390. 4 5 3.332e+01
  391. 5 5 1.200e+01
  392. '''
  393. _hermitian_example = '''\
  394. %%MatrixMarket matrix coordinate complex hermitian
  395. 5 5 7
  396. 1 1 1.0 0
  397. 2 2 10.5 0
  398. 4 2 250.5 22.22
  399. 3 3 1.5e-2 0
  400. 4 4 -2.8e2 0
  401. 5 5 12. 0
  402. 5 4 0 33.32
  403. '''
  404. _skew_example = '''\
  405. %%MatrixMarket matrix coordinate real skew-symmetric
  406. 5 5 7
  407. 1 1 1.0
  408. 2 2 10.5
  409. 4 2 250.5
  410. 3 3 1.5e-2
  411. 4 4 -2.8e2
  412. 5 5 12.
  413. 5 4 0
  414. '''
  415. _symmetric_example = '''\
  416. %%MatrixMarket matrix coordinate real symmetric
  417. 5 5 7
  418. 1 1 1.0
  419. 2 2 10.5
  420. 4 2 250.5
  421. 3 3 1.5e-2
  422. 4 4 -2.8e2
  423. 5 5 12.
  424. 5 4 8
  425. '''
  426. _symmetric_pattern_example = '''\
  427. %%MatrixMarket matrix coordinate pattern symmetric
  428. 5 5 7
  429. 1 1
  430. 2 2
  431. 4 2
  432. 3 3
  433. 4 4
  434. 5 5
  435. 5 4
  436. '''
  437. # example (without comment lines) from Figure 1 in
  438. # https://math.nist.gov/MatrixMarket/reports/MMformat.ps
  439. _empty_lines_example = '''\
  440. %%MatrixMarket MATRIX Coordinate Real General
  441. 5 5 8
  442. 1 1 1.0
  443. 2 2 10.5
  444. 3 3 1.5e-2
  445. 4 4 -2.8E2
  446. 5 5 12.
  447. 1 4 6
  448. 4 2 250.5
  449. 4 5 33.32
  450. '''
  451. class TestMMIOCoordinate:
  452. def setup_method(self):
  453. self.tmpdir = mkdtemp()
  454. self.fn = os.path.join(self.tmpdir, 'testfile.mtx')
  455. def teardown_method(self):
  456. shutil.rmtree(self.tmpdir)
  457. def check_read(self, example, a, info):
  458. f = open(self.fn, 'w')
  459. f.write(example)
  460. f.close()
  461. assert_equal(mminfo(self.fn), info)
  462. b = mmread(self.fn).toarray()
  463. assert_array_almost_equal(a, b)
  464. def test_read_general(self):
  465. a = [[1, 0, 0, 6, 0],
  466. [0, 10.5, 0, 0, 0],
  467. [0, 0, .015, 0, 0],
  468. [0, 250.5, 0, -280, 33.32],
  469. [0, 0, 0, 0, 12]]
  470. self.check_read(_general_example, a,
  471. (5, 5, 8, 'coordinate', 'real', 'general'))
  472. def test_read_hermitian(self):
  473. a = [[1, 0, 0, 0, 0],
  474. [0, 10.5, 0, 250.5 - 22.22j, 0],
  475. [0, 0, .015, 0, 0],
  476. [0, 250.5 + 22.22j, 0, -280, -33.32j],
  477. [0, 0, 0, 33.32j, 12]]
  478. self.check_read(_hermitian_example, a,
  479. (5, 5, 7, 'coordinate', 'complex', 'hermitian'))
  480. def test_read_skew(self):
  481. a = [[1, 0, 0, 0, 0],
  482. [0, 10.5, 0, -250.5, 0],
  483. [0, 0, .015, 0, 0],
  484. [0, 250.5, 0, -280, 0],
  485. [0, 0, 0, 0, 12]]
  486. self.check_read(_skew_example, a,
  487. (5, 5, 7, 'coordinate', 'real', 'skew-symmetric'))
  488. def test_read_symmetric(self):
  489. a = [[1, 0, 0, 0, 0],
  490. [0, 10.5, 0, 250.5, 0],
  491. [0, 0, .015, 0, 0],
  492. [0, 250.5, 0, -280, 8],
  493. [0, 0, 0, 8, 12]]
  494. self.check_read(_symmetric_example, a,
  495. (5, 5, 7, 'coordinate', 'real', 'symmetric'))
  496. def test_read_symmetric_pattern(self):
  497. a = [[1, 0, 0, 0, 0],
  498. [0, 1, 0, 1, 0],
  499. [0, 0, 1, 0, 0],
  500. [0, 1, 0, 1, 1],
  501. [0, 0, 0, 1, 1]]
  502. self.check_read(_symmetric_pattern_example, a,
  503. (5, 5, 7, 'coordinate', 'pattern', 'symmetric'))
  504. def test_read_empty_lines(self):
  505. a = [[1, 0, 0, 6, 0],
  506. [0, 10.5, 0, 0, 0],
  507. [0, 0, .015, 0, 0],
  508. [0, 250.5, 0, -280, 33.32],
  509. [0, 0, 0, 0, 12]]
  510. self.check_read(_empty_lines_example, a,
  511. (5, 5, 8, 'coordinate', 'real', 'general'))
  512. def test_empty_write_read(self):
  513. # https://github.com/scipy/scipy/issues/1410 (Trac #883)
  514. b = scipy.sparse.coo_matrix((10, 10))
  515. mmwrite(self.fn, b)
  516. assert_equal(mminfo(self.fn),
  517. (10, 10, 0, 'coordinate', 'real', 'symmetric'))
  518. a = b.toarray()
  519. b = mmread(self.fn).toarray()
  520. assert_array_almost_equal(a, b)
  521. def test_bzip2_py3(self):
  522. # test if fix for #2152 works
  523. try:
  524. # bz2 module isn't always built when building Python.
  525. import bz2
  526. except ImportError:
  527. return
  528. I = array([0, 0, 1, 2, 3, 3, 3, 4])
  529. J = array([0, 3, 1, 2, 1, 3, 4, 4])
  530. V = array([1.0, 6.0, 10.5, 0.015, 250.5, -280.0, 33.32, 12.0])
  531. b = scipy.sparse.coo_matrix((V, (I, J)), shape=(5, 5))
  532. mmwrite(self.fn, b)
  533. fn_bzip2 = "%s.bz2" % self.fn
  534. with open(self.fn, 'rb') as f_in:
  535. f_out = bz2.BZ2File(fn_bzip2, 'wb')
  536. f_out.write(f_in.read())
  537. f_out.close()
  538. a = mmread(fn_bzip2).toarray()
  539. assert_array_almost_equal(a, b.toarray())
  540. def test_gzip_py3(self):
  541. # test if fix for #2152 works
  542. try:
  543. # gzip module can be missing from Python installation
  544. import gzip
  545. except ImportError:
  546. return
  547. I = array([0, 0, 1, 2, 3, 3, 3, 4])
  548. J = array([0, 3, 1, 2, 1, 3, 4, 4])
  549. V = array([1.0, 6.0, 10.5, 0.015, 250.5, -280.0, 33.32, 12.0])
  550. b = scipy.sparse.coo_matrix((V, (I, J)), shape=(5, 5))
  551. mmwrite(self.fn, b)
  552. fn_gzip = "%s.gz" % self.fn
  553. with open(self.fn, 'rb') as f_in:
  554. f_out = gzip.open(fn_gzip, 'wb')
  555. f_out.write(f_in.read())
  556. f_out.close()
  557. a = mmread(fn_gzip).toarray()
  558. assert_array_almost_equal(a, b.toarray())
  559. def test_real_write_read(self):
  560. I = array([0, 0, 1, 2, 3, 3, 3, 4])
  561. J = array([0, 3, 1, 2, 1, 3, 4, 4])
  562. V = array([1.0, 6.0, 10.5, 0.015, 250.5, -280.0, 33.32, 12.0])
  563. b = scipy.sparse.coo_matrix((V, (I, J)), shape=(5, 5))
  564. mmwrite(self.fn, b)
  565. assert_equal(mminfo(self.fn),
  566. (5, 5, 8, 'coordinate', 'real', 'general'))
  567. a = b.toarray()
  568. b = mmread(self.fn).toarray()
  569. assert_array_almost_equal(a, b)
  570. def test_complex_write_read(self):
  571. I = array([0, 0, 1, 2, 3, 3, 3, 4])
  572. J = array([0, 3, 1, 2, 1, 3, 4, 4])
  573. V = array([1.0 + 3j, 6.0 + 2j, 10.50 + 0.9j, 0.015 + -4.4j,
  574. 250.5 + 0j, -280.0 + 5j, 33.32 + 6.4j, 12.00 + 0.8j])
  575. b = scipy.sparse.coo_matrix((V, (I, J)), shape=(5, 5))
  576. mmwrite(self.fn, b)
  577. assert_equal(mminfo(self.fn),
  578. (5, 5, 8, 'coordinate', 'complex', 'general'))
  579. a = b.toarray()
  580. b = mmread(self.fn).toarray()
  581. assert_array_almost_equal(a, b)
  582. def test_sparse_formats(self, tmp_path):
  583. # Note: `tmp_path` is a pytest fixture, it handles cleanup
  584. tmpdir = tmp_path / 'sparse_formats'
  585. tmpdir.mkdir()
  586. mats = []
  587. I = array([0, 0, 1, 2, 3, 3, 3, 4])
  588. J = array([0, 3, 1, 2, 1, 3, 4, 4])
  589. V = array([1.0, 6.0, 10.5, 0.015, 250.5, -280.0, 33.32, 12.0])
  590. mats.append(scipy.sparse.coo_matrix((V, (I, J)), shape=(5, 5)))
  591. V = array([1.0 + 3j, 6.0 + 2j, 10.50 + 0.9j, 0.015 + -4.4j,
  592. 250.5 + 0j, -280.0 + 5j, 33.32 + 6.4j, 12.00 + 0.8j])
  593. mats.append(scipy.sparse.coo_matrix((V, (I, J)), shape=(5, 5)))
  594. for mat in mats:
  595. expected = mat.toarray()
  596. for fmt in ['csr', 'csc', 'coo']:
  597. fname = tmpdir / (fmt + '.mtx')
  598. mmwrite(fname, mat.asformat(fmt))
  599. result = mmread(fname).toarray()
  600. assert_array_almost_equal(result, expected)
  601. def test_precision(self):
  602. test_values = [pi] + [10**(i) for i in range(0, -10, -1)]
  603. test_precisions = range(1, 10)
  604. for value in test_values:
  605. for precision in test_precisions:
  606. # construct sparse matrix with test value at last main diagonal
  607. n = 10**precision + 1
  608. A = scipy.sparse.dok_matrix((n, n))
  609. A[n-1, n-1] = value
  610. # write matrix with test precision and read again
  611. mmwrite(self.fn, A, precision=precision)
  612. A = scipy.io.mmread(self.fn)
  613. # check for right entries in matrix
  614. assert_array_equal(A.row, [n-1])
  615. assert_array_equal(A.col, [n-1])
  616. assert_allclose(A.data, [float('%%.%dg' % precision % value)])
  617. def test_bad_number_of_coordinate_header_fields(self):
  618. s = """\
  619. %%MatrixMarket matrix coordinate real general
  620. 5 5 8 999
  621. 1 1 1.000e+00
  622. 2 2 1.050e+01
  623. 3 3 1.500e-02
  624. 1 4 6.000e+00
  625. 4 2 2.505e+02
  626. 4 4 -2.800e+02
  627. 4 5 3.332e+01
  628. 5 5 1.200e+01
  629. """
  630. text = textwrap.dedent(s).encode('ascii')
  631. with pytest.raises(ValueError, match='not of length 3'):
  632. scipy.io.mmread(io.BytesIO(text))
  633. def test_gh11389():
  634. mmread(io.StringIO("%%MatrixMarket matrix coordinate complex symmetric\n"
  635. " 1 1 1\n"
  636. "1 1 -2.1846000000000e+02 0.0000000000000e+00"))