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