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