|
|
|
|
|
|
|
""" Test functions for sparse matrices. Each class in the "Matrix class |
|
based tests" section become subclasses of the classes in the "Generic |
|
tests" section. This is done by the functions in the "Tailored base |
|
class for generic tests" section. |
|
|
|
""" |
|
|
|
|
|
import contextlib |
|
import functools |
|
import operator |
|
import platform |
|
import itertools |
|
import sys |
|
|
|
import pytest |
|
from pytest import raises as assert_raises |
|
|
|
import numpy as np |
|
from numpy import (arange, zeros, array, dot, asarray, |
|
vstack, ndarray, transpose, diag, kron, inf, conjugate, |
|
int8) |
|
|
|
import random |
|
from numpy.testing import (assert_equal, assert_array_equal, |
|
assert_array_almost_equal, assert_almost_equal, assert_, |
|
assert_allclose, suppress_warnings) |
|
|
|
import scipy.linalg |
|
|
|
import scipy.sparse as sparse |
|
from scipy.sparse import (csc_matrix, csr_matrix, dok_matrix, |
|
coo_matrix, lil_matrix, dia_matrix, bsr_matrix, |
|
csc_array, csr_array, dok_array, |
|
coo_array, lil_array, dia_array, bsr_array, |
|
eye, issparse, SparseEfficiencyWarning, sparray) |
|
from scipy.sparse._base import _formats |
|
from scipy.sparse._sputils import (supported_dtypes, isscalarlike, |
|
get_index_dtype, asmatrix, matrix) |
|
from scipy.sparse.linalg import splu, expm, inv |
|
|
|
from scipy._lib.decorator import decorator |
|
from scipy._lib._util import ComplexWarning |
|
|
|
IS_COLAB = ('google.colab' in sys.modules) |
|
|
|
|
|
def assert_in(member, collection, msg=None): |
|
message = msg if msg is not None else f"{member!r} not found in {collection!r}" |
|
assert_(member in collection, msg=message) |
|
|
|
|
|
def assert_array_equal_dtype(x, y, **kwargs): |
|
assert_(x.dtype == y.dtype) |
|
assert_array_equal(x, y, **kwargs) |
|
|
|
|
|
NON_ARRAY_BACKED_FORMATS = frozenset(['dok']) |
|
|
|
def sparse_may_share_memory(A, B): |
|
|
|
|
|
def _underlying_arrays(x): |
|
|
|
|
|
|
|
arrays = [] |
|
for a in x.__dict__.values(): |
|
if isinstance(a, np.ndarray | np.generic): |
|
arrays.append(a) |
|
return arrays |
|
|
|
for a in _underlying_arrays(A): |
|
for b in _underlying_arrays(B): |
|
if np.may_share_memory(a, b): |
|
return True |
|
return False |
|
|
|
|
|
sup_complex = suppress_warnings() |
|
sup_complex.filter(ComplexWarning) |
|
|
|
|
|
def with_64bit_maxval_limit(maxval_limit=None, random=False, fixed_dtype=None, |
|
downcast_maxval=None, assert_32bit=False): |
|
""" |
|
Monkeypatch the maxval threshold at which scipy.sparse switches to |
|
64-bit index arrays, or make it (pseudo-)random. |
|
|
|
""" |
|
if maxval_limit is None: |
|
maxval_limit = np.int64(10) |
|
else: |
|
|
|
|
|
maxval_limit = np.int64(maxval_limit) |
|
|
|
if assert_32bit: |
|
def new_get_index_dtype(arrays=(), maxval=None, check_contents=False): |
|
tp = get_index_dtype(arrays, maxval, check_contents) |
|
assert_equal(np.iinfo(tp).max, np.iinfo(np.int32).max) |
|
assert_(tp == np.int32 or tp == np.intc) |
|
return tp |
|
elif fixed_dtype is not None: |
|
def new_get_index_dtype(arrays=(), maxval=None, check_contents=False): |
|
return fixed_dtype |
|
elif random: |
|
counter = np.random.RandomState(seed=1234) |
|
|
|
def new_get_index_dtype(arrays=(), maxval=None, check_contents=False): |
|
return (np.int32, np.int64)[counter.randint(2)] |
|
else: |
|
def new_get_index_dtype(arrays=(), maxval=None, check_contents=False): |
|
dtype = np.int32 |
|
if maxval is not None: |
|
if maxval > maxval_limit: |
|
dtype = np.int64 |
|
for arr in arrays: |
|
arr = np.asarray(arr) |
|
if arr.dtype > np.int32: |
|
if check_contents: |
|
if arr.size == 0: |
|
|
|
continue |
|
elif np.issubdtype(arr.dtype, np.integer): |
|
maxval = arr.max() |
|
minval = arr.min() |
|
if minval >= -maxval_limit and maxval <= maxval_limit: |
|
|
|
continue |
|
dtype = np.int64 |
|
return dtype |
|
|
|
if downcast_maxval is not None: |
|
def new_downcast_intp_index(arr): |
|
if arr.max() > downcast_maxval: |
|
raise AssertionError("downcast limited") |
|
return arr.astype(np.intp) |
|
|
|
@decorator |
|
def deco(func, *a, **kw): |
|
backup = [] |
|
modules = [scipy.sparse._bsr, scipy.sparse._coo, scipy.sparse._csc, |
|
scipy.sparse._csr, scipy.sparse._dia, scipy.sparse._dok, |
|
scipy.sparse._lil, scipy.sparse._sputils, |
|
scipy.sparse._compressed, scipy.sparse._construct] |
|
try: |
|
for mod in modules: |
|
backup.append((mod, 'get_index_dtype', |
|
getattr(mod, 'get_index_dtype', None))) |
|
setattr(mod, 'get_index_dtype', new_get_index_dtype) |
|
if downcast_maxval is not None: |
|
backup.append((mod, 'downcast_intp_index', |
|
getattr(mod, 'downcast_intp_index', None))) |
|
setattr(mod, 'downcast_intp_index', new_downcast_intp_index) |
|
return func(*a, **kw) |
|
finally: |
|
for mod, name, oldfunc in backup: |
|
if oldfunc is not None: |
|
setattr(mod, name, oldfunc) |
|
|
|
return deco |
|
|
|
|
|
def toarray(a): |
|
if isinstance(a, np.ndarray) or isscalarlike(a): |
|
return a |
|
return a.toarray() |
|
|
|
|
|
class BinopTester: |
|
|
|
|
|
def __add__(self, mat): |
|
return "matrix on the right" |
|
|
|
def __mul__(self, mat): |
|
return "matrix on the right" |
|
|
|
def __sub__(self, mat): |
|
return "matrix on the right" |
|
|
|
def __radd__(self, mat): |
|
return "matrix on the left" |
|
|
|
def __rmul__(self, mat): |
|
return "matrix on the left" |
|
|
|
def __rsub__(self, mat): |
|
return "matrix on the left" |
|
|
|
def __matmul__(self, mat): |
|
return "matrix on the right" |
|
|
|
def __rmatmul__(self, mat): |
|
return "matrix on the left" |
|
|
|
class BinopTester_with_shape: |
|
|
|
|
|
def __init__(self,shape): |
|
self._shape = shape |
|
|
|
def shape(self): |
|
return self._shape |
|
|
|
def ndim(self): |
|
return len(self._shape) |
|
|
|
def __add__(self, mat): |
|
return "matrix on the right" |
|
|
|
def __mul__(self, mat): |
|
return "matrix on the right" |
|
|
|
def __sub__(self, mat): |
|
return "matrix on the right" |
|
|
|
def __radd__(self, mat): |
|
return "matrix on the left" |
|
|
|
def __rmul__(self, mat): |
|
return "matrix on the left" |
|
|
|
def __rsub__(self, mat): |
|
return "matrix on the left" |
|
|
|
def __matmul__(self, mat): |
|
return "matrix on the right" |
|
|
|
def __rmatmul__(self, mat): |
|
return "matrix on the left" |
|
|
|
class ComparisonTester: |
|
|
|
def __eq__(self, other): |
|
return "eq" |
|
|
|
def __ne__(self, other): |
|
return "ne" |
|
|
|
def __lt__(self, other): |
|
return "lt" |
|
|
|
def __le__(self, other): |
|
return "le" |
|
|
|
def __gt__(self, other): |
|
return "gt" |
|
|
|
def __ge__(self, other): |
|
return "ge" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _MatrixMixin: |
|
"""mixin to easily allow tests of both sparray and spmatrix""" |
|
bsr_container = bsr_matrix |
|
coo_container = coo_matrix |
|
csc_container = csc_matrix |
|
csr_container = csr_matrix |
|
dia_container = dia_matrix |
|
dok_container = dok_matrix |
|
lil_container = lil_matrix |
|
asdense = staticmethod(asmatrix) |
|
|
|
def test_getrow(self): |
|
assert_array_equal(self.datsp.getrow(1).toarray(), self.dat[[1], :]) |
|
assert_array_equal(self.datsp.getrow(-1).toarray(), self.dat[[-1], :]) |
|
|
|
def test_getcol(self): |
|
assert_array_equal(self.datsp.getcol(1).toarray(), self.dat[:, [1]]) |
|
assert_array_equal(self.datsp.getcol(-1).toarray(), self.dat[:, [-1]]) |
|
|
|
def test_asfptype(self): |
|
A = self.spcreator(arange(6,dtype='int32').reshape(2,3)) |
|
|
|
assert_equal(A.asfptype().dtype, np.dtype('float64')) |
|
assert_equal(A.asfptype().format, A.format) |
|
assert_equal(A.astype('int16').asfptype().dtype, np.dtype('float32')) |
|
assert_equal(A.astype('complex128').asfptype().dtype, np.dtype('complex128')) |
|
|
|
B = A.asfptype() |
|
C = B.asfptype() |
|
assert_(B is C) |
|
|
|
|
|
|
|
|
|
class _TestCommon: |
|
"""test common functionality shared by all sparse formats""" |
|
math_dtypes = supported_dtypes |
|
|
|
bsr_container = bsr_array |
|
coo_container = coo_array |
|
csc_container = csc_array |
|
csr_container = csr_array |
|
dia_container = dia_array |
|
dok_container = dok_array |
|
lil_container = lil_array |
|
asdense = array |
|
|
|
@classmethod |
|
def init_class(cls): |
|
|
|
cls.dat = array([[1, 0, 0, 2], [3, 0, 1, 0], [0, 2, 0, 0]], 'd') |
|
cls.datsp = cls.spcreator(cls.dat) |
|
|
|
|
|
|
|
|
|
cls.checked_dtypes = set(supported_dtypes).union(cls.math_dtypes) |
|
cls.dat_dtypes = {} |
|
cls.datsp_dtypes = {} |
|
for dtype in cls.checked_dtypes: |
|
cls.dat_dtypes[dtype] = cls.dat.astype(dtype) |
|
cls.datsp_dtypes[dtype] = cls.spcreator(cls.dat.astype(dtype)) |
|
|
|
|
|
|
|
assert_equal(cls.dat, cls.dat_dtypes[np.float64]) |
|
assert_equal(cls.datsp.toarray(), |
|
cls.datsp_dtypes[np.float64].toarray()) |
|
|
|
cls.is_array_test = isinstance(cls.datsp, sparray) |
|
|
|
def test_bool(self): |
|
def check(dtype): |
|
datsp = self.datsp_dtypes[dtype] |
|
|
|
assert_raises(ValueError, bool, datsp) |
|
assert_(self.spcreator([[1]])) |
|
assert_(not self.spcreator([[0]])) |
|
|
|
if isinstance(self, TestDOK): |
|
pytest.skip("Cannot create a rank <= 2 DOK matrix.") |
|
for dtype in self.checked_dtypes: |
|
check(dtype) |
|
|
|
def test_bool_rollover(self): |
|
|
|
|
|
dat = array([[True, False]]) |
|
datsp = self.spcreator(dat) |
|
|
|
for _ in range(10): |
|
datsp = datsp + datsp |
|
dat = dat + dat |
|
assert_array_equal(dat, datsp.toarray()) |
|
|
|
def test_eq(self): |
|
sup = suppress_warnings() |
|
sup.filter(SparseEfficiencyWarning) |
|
|
|
@sup |
|
@sup_complex |
|
def check(dtype): |
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
dat2 = dat.copy() |
|
dat2[:,0] = 0 |
|
datsp2 = self.spcreator(dat2) |
|
datbsr = self.bsr_container(dat) |
|
datcsr = self.csr_container(dat) |
|
datcsc = self.csc_container(dat) |
|
datlil = self.lil_container(dat) |
|
|
|
|
|
assert_array_equal_dtype(dat == dat2, (datsp == datsp2).toarray()) |
|
|
|
assert_array_equal_dtype(dat == dat2, (datbsr == datsp2).toarray()) |
|
assert_array_equal_dtype(dat == dat2, (datcsr == datsp2).toarray()) |
|
assert_array_equal_dtype(dat == dat2, (datcsc == datsp2).toarray()) |
|
assert_array_equal_dtype(dat == dat2, (datlil == datsp2).toarray()) |
|
|
|
assert_array_equal_dtype(dat == datsp2, datsp2 == dat) |
|
|
|
assert_array_equal_dtype(dat == 0, (datsp == 0).toarray()) |
|
assert_array_equal_dtype(dat == 1, (datsp == 1).toarray()) |
|
assert_array_equal_dtype(dat == np.nan, |
|
(datsp == np.nan).toarray()) |
|
|
|
if self.datsp.format not in ['bsr', 'csc', 'csr']: |
|
pytest.skip("Bool comparisons only implemented for BSR, CSC, and CSR.") |
|
for dtype in self.checked_dtypes: |
|
check(dtype) |
|
|
|
def test_ne(self): |
|
sup = suppress_warnings() |
|
sup.filter(SparseEfficiencyWarning) |
|
|
|
@sup |
|
@sup_complex |
|
def check(dtype): |
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
dat2 = dat.copy() |
|
dat2[:,0] = 0 |
|
datsp2 = self.spcreator(dat2) |
|
datbsr = self.bsr_container(dat) |
|
datcsc = self.csc_container(dat) |
|
datcsr = self.csr_container(dat) |
|
datlil = self.lil_container(dat) |
|
|
|
|
|
assert_array_equal_dtype(dat != dat2, (datsp != datsp2).toarray()) |
|
|
|
assert_array_equal_dtype(dat != dat2, (datbsr != datsp2).toarray()) |
|
assert_array_equal_dtype(dat != dat2, (datcsc != datsp2).toarray()) |
|
assert_array_equal_dtype(dat != dat2, (datcsr != datsp2).toarray()) |
|
assert_array_equal_dtype(dat != dat2, (datlil != datsp2).toarray()) |
|
|
|
assert_array_equal_dtype(dat != datsp2, datsp2 != dat) |
|
|
|
assert_array_equal_dtype(dat != 0, (datsp != 0).toarray()) |
|
assert_array_equal_dtype(dat != 1, (datsp != 1).toarray()) |
|
assert_array_equal_dtype(0 != dat, (0 != datsp).toarray()) |
|
assert_array_equal_dtype(1 != dat, (1 != datsp).toarray()) |
|
assert_array_equal_dtype(dat != np.nan, |
|
(datsp != np.nan).toarray()) |
|
|
|
if self.datsp.format not in ['bsr', 'csc', 'csr']: |
|
pytest.skip("Bool comparisons only implemented for BSR, CSC, and CSR.") |
|
for dtype in self.checked_dtypes: |
|
check(dtype) |
|
|
|
def test_lt(self): |
|
sup = suppress_warnings() |
|
sup.filter(SparseEfficiencyWarning) |
|
|
|
@sup |
|
@sup_complex |
|
def check(dtype): |
|
|
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
dat2 = dat.copy() |
|
dat2[:,0] = 0 |
|
datsp2 = self.spcreator(dat2) |
|
datcomplex = dat.astype(complex) |
|
datcomplex[:,0] = 1 + 1j |
|
datspcomplex = self.spcreator(datcomplex) |
|
datbsr = self.bsr_container(dat) |
|
datcsc = self.csc_container(dat) |
|
datcsr = self.csr_container(dat) |
|
datlil = self.lil_container(dat) |
|
|
|
|
|
assert_array_equal_dtype(dat < dat2, (datsp < datsp2).toarray()) |
|
assert_array_equal_dtype(datcomplex < dat2, |
|
(datspcomplex < datsp2).toarray()) |
|
|
|
assert_array_equal_dtype(dat < dat2, (datbsr < datsp2).toarray()) |
|
assert_array_equal_dtype(dat < dat2, (datcsc < datsp2).toarray()) |
|
assert_array_equal_dtype(dat < dat2, (datcsr < datsp2).toarray()) |
|
assert_array_equal_dtype(dat < dat2, (datlil < datsp2).toarray()) |
|
|
|
assert_array_equal_dtype(dat2 < dat, (datsp2 < datbsr).toarray()) |
|
assert_array_equal_dtype(dat2 < dat, (datsp2 < datcsc).toarray()) |
|
assert_array_equal_dtype(dat2 < dat, (datsp2 < datcsr).toarray()) |
|
assert_array_equal_dtype(dat2 < dat, (datsp2 < datlil).toarray()) |
|
|
|
assert_array_equal_dtype(dat < dat2, datsp < dat2) |
|
assert_array_equal_dtype(datcomplex < dat2, datspcomplex < dat2) |
|
|
|
for val in [2, 1, 0, -1, -2]: |
|
val = np.int64(val) |
|
assert_array_equal_dtype((datsp < val).toarray(), dat < val) |
|
assert_array_equal_dtype((val < datsp).toarray(), val < dat) |
|
|
|
with np.errstate(invalid='ignore'): |
|
assert_array_equal_dtype((datsp < np.nan).toarray(), |
|
dat < np.nan) |
|
|
|
|
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
dat2 = dat.copy() |
|
dat2[:,0] = 0 |
|
datsp2 = self.spcreator(dat2) |
|
|
|
|
|
assert_array_equal_dtype(dat < datsp2, datsp < dat2) |
|
|
|
if self.datsp.format not in ['bsr', 'csc', 'csr']: |
|
pytest.skip("Bool comparisons only implemented for BSR, CSC, and CSR.") |
|
for dtype in self.checked_dtypes: |
|
check(dtype) |
|
|
|
def test_gt(self): |
|
sup = suppress_warnings() |
|
sup.filter(SparseEfficiencyWarning) |
|
|
|
@sup |
|
@sup_complex |
|
def check(dtype): |
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
dat2 = dat.copy() |
|
dat2[:,0] = 0 |
|
datsp2 = self.spcreator(dat2) |
|
datcomplex = dat.astype(complex) |
|
datcomplex[:,0] = 1 + 1j |
|
datspcomplex = self.spcreator(datcomplex) |
|
datbsr = self.bsr_container(dat) |
|
datcsc = self.csc_container(dat) |
|
datcsr = self.csr_container(dat) |
|
datlil = self.lil_container(dat) |
|
|
|
|
|
assert_array_equal_dtype(dat > dat2, (datsp > datsp2).toarray()) |
|
assert_array_equal_dtype(datcomplex > dat2, |
|
(datspcomplex > datsp2).toarray()) |
|
|
|
assert_array_equal_dtype(dat > dat2, (datbsr > datsp2).toarray()) |
|
assert_array_equal_dtype(dat > dat2, (datcsc > datsp2).toarray()) |
|
assert_array_equal_dtype(dat > dat2, (datcsr > datsp2).toarray()) |
|
assert_array_equal_dtype(dat > dat2, (datlil > datsp2).toarray()) |
|
|
|
assert_array_equal_dtype(dat2 > dat, (datsp2 > datbsr).toarray()) |
|
assert_array_equal_dtype(dat2 > dat, (datsp2 > datcsc).toarray()) |
|
assert_array_equal_dtype(dat2 > dat, (datsp2 > datcsr).toarray()) |
|
assert_array_equal_dtype(dat2 > dat, (datsp2 > datlil).toarray()) |
|
|
|
assert_array_equal_dtype(dat > dat2, datsp > dat2) |
|
assert_array_equal_dtype(datcomplex > dat2, datspcomplex > dat2) |
|
|
|
for val in [2, 1, 0, -1, -2]: |
|
val = np.int64(val) |
|
assert_array_equal_dtype((datsp > val).toarray(), dat > val) |
|
assert_array_equal_dtype((val > datsp).toarray(), val > dat) |
|
|
|
with np.errstate(invalid='ignore'): |
|
assert_array_equal_dtype((datsp > np.nan).toarray(), |
|
dat > np.nan) |
|
|
|
|
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
dat2 = dat.copy() |
|
dat2[:,0] = 0 |
|
datsp2 = self.spcreator(dat2) |
|
|
|
|
|
assert_array_equal_dtype(dat > datsp2, datsp > dat2) |
|
|
|
if self.datsp.format not in ['bsr', 'csc', 'csr']: |
|
pytest.skip("Bool comparisons only implemented for BSR, CSC, and CSR.") |
|
for dtype in self.checked_dtypes: |
|
check(dtype) |
|
|
|
def test_le(self): |
|
sup = suppress_warnings() |
|
sup.filter(SparseEfficiencyWarning) |
|
|
|
@sup |
|
@sup_complex |
|
def check(dtype): |
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
dat2 = dat.copy() |
|
dat2[:,0] = 0 |
|
datsp2 = self.spcreator(dat2) |
|
datcomplex = dat.astype(complex) |
|
datcomplex[:,0] = 1 + 1j |
|
datspcomplex = self.spcreator(datcomplex) |
|
datbsr = self.bsr_container(dat) |
|
datcsc = self.csc_container(dat) |
|
datcsr = self.csr_container(dat) |
|
datlil = self.lil_container(dat) |
|
|
|
|
|
assert_array_equal_dtype(dat <= dat2, (datsp <= datsp2).toarray()) |
|
assert_array_equal_dtype(datcomplex <= dat2, |
|
(datspcomplex <= datsp2).toarray()) |
|
|
|
assert_array_equal_dtype((datbsr <= datsp2).toarray(), dat <= dat2) |
|
assert_array_equal_dtype((datcsc <= datsp2).toarray(), dat <= dat2) |
|
assert_array_equal_dtype((datcsr <= datsp2).toarray(), dat <= dat2) |
|
assert_array_equal_dtype((datlil <= datsp2).toarray(), dat <= dat2) |
|
|
|
assert_array_equal_dtype((datsp2 <= datbsr).toarray(), dat2 <= dat) |
|
assert_array_equal_dtype((datsp2 <= datcsc).toarray(), dat2 <= dat) |
|
assert_array_equal_dtype((datsp2 <= datcsr).toarray(), dat2 <= dat) |
|
assert_array_equal_dtype((datsp2 <= datlil).toarray(), dat2 <= dat) |
|
|
|
assert_array_equal_dtype(datsp <= dat2, dat <= dat2) |
|
assert_array_equal_dtype(datspcomplex <= dat2, datcomplex <= dat2) |
|
|
|
for val in [2, 1, -1, -2]: |
|
val = np.int64(val) |
|
assert_array_equal_dtype((datsp <= val).toarray(), dat <= val) |
|
assert_array_equal_dtype((val <= datsp).toarray(), val <= dat) |
|
|
|
|
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
dat2 = dat.copy() |
|
dat2[:,0] = 0 |
|
datsp2 = self.spcreator(dat2) |
|
|
|
|
|
assert_array_equal_dtype(dat <= datsp2, datsp <= dat2) |
|
|
|
if self.datsp.format not in ['bsr', 'csc', 'csr']: |
|
pytest.skip("Bool comparisons only implemented for BSR, CSC, and CSR.") |
|
for dtype in self.checked_dtypes: |
|
check(dtype) |
|
|
|
def test_ge(self): |
|
sup = suppress_warnings() |
|
sup.filter(SparseEfficiencyWarning) |
|
|
|
@sup |
|
@sup_complex |
|
def check(dtype): |
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
dat2 = dat.copy() |
|
dat2[:,0] = 0 |
|
datsp2 = self.spcreator(dat2) |
|
datcomplex = dat.astype(complex) |
|
datcomplex[:,0] = 1 + 1j |
|
datspcomplex = self.spcreator(datcomplex) |
|
datbsr = self.bsr_container(dat) |
|
datcsc = self.csc_container(dat) |
|
datcsr = self.csr_container(dat) |
|
datlil = self.lil_container(dat) |
|
|
|
|
|
assert_array_equal_dtype(dat >= dat2, (datsp >= datsp2).toarray()) |
|
assert_array_equal_dtype(datcomplex >= dat2, |
|
(datspcomplex >= datsp2).toarray()) |
|
|
|
assert_array_equal_dtype((datbsr >= datsp2).toarray(), dat >= dat2) |
|
assert_array_equal_dtype((datcsc >= datsp2).toarray(), dat >= dat2) |
|
assert_array_equal_dtype((datcsr >= datsp2).toarray(), dat >= dat2) |
|
assert_array_equal_dtype((datlil >= datsp2).toarray(), dat >= dat2) |
|
|
|
assert_array_equal_dtype((datsp2 >= datbsr).toarray(), dat2 >= dat) |
|
assert_array_equal_dtype((datsp2 >= datcsc).toarray(), dat2 >= dat) |
|
assert_array_equal_dtype((datsp2 >= datcsr).toarray(), dat2 >= dat) |
|
assert_array_equal_dtype((datsp2 >= datlil).toarray(), dat2 >= dat) |
|
|
|
assert_array_equal_dtype(datsp >= dat2, dat >= dat2) |
|
assert_array_equal_dtype(datspcomplex >= dat2, datcomplex >= dat2) |
|
|
|
for val in [2, 1, -1, -2]: |
|
val = np.int64(val) |
|
assert_array_equal_dtype((datsp >= val).toarray(), dat >= val) |
|
assert_array_equal_dtype((val >= datsp).toarray(), val >= dat) |
|
|
|
|
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
dat2 = dat.copy() |
|
dat2[:,0] = 0 |
|
datsp2 = self.spcreator(dat2) |
|
|
|
|
|
assert_array_equal_dtype(dat >= datsp2, datsp >= dat2) |
|
|
|
if self.datsp.format not in ['bsr', 'csc', 'csr']: |
|
pytest.skip("Bool comparisons only implemented for BSR, CSC, and CSR.") |
|
for dtype in self.checked_dtypes: |
|
check(dtype) |
|
|
|
def test_empty(self): |
|
|
|
assert_equal(self.spcreator((3, 3)).toarray(), zeros((3, 3))) |
|
assert_equal(self.spcreator((3, 3)).nnz, 0) |
|
assert_equal(self.spcreator((3, 3)).count_nonzero(), 0) |
|
if self.datsp.format in ["coo", "csr", "csc", "lil"]: |
|
assert_equal(self.spcreator((3, 3)).count_nonzero(axis=0), array([0, 0, 0])) |
|
|
|
def test_count_nonzero(self): |
|
axis_support = self.datsp.format in ["coo", "csr", "csc", "lil"] |
|
axes = [None, 0, 1, -1, -2] if axis_support else [None] |
|
|
|
for A in (self.datsp, self.datsp.T): |
|
for ax in axes: |
|
expected = np.count_nonzero(A.toarray(), axis=ax) |
|
assert_equal(A.count_nonzero(axis=ax), expected) |
|
|
|
if not axis_support: |
|
with assert_raises(NotImplementedError, match="not implemented .* format"): |
|
self.datsp.count_nonzero(axis=0) |
|
|
|
def test_invalid_shapes(self): |
|
assert_raises(ValueError, self.spcreator, (-1,3)) |
|
assert_raises(ValueError, self.spcreator, (3,-1)) |
|
assert_raises(ValueError, self.spcreator, (-1,-1)) |
|
|
|
def test_repr(self): |
|
datsp = self.spcreator([[1, 0, 0], [0, 0, 0], [0, 0, -2]]) |
|
extra = ( |
|
"(1 diagonals) " if datsp.format == "dia" |
|
else "(blocksize=1x1) " if datsp.format == "bsr" |
|
else "" |
|
) |
|
_, fmt = _formats[datsp.format] |
|
sparse_cls = "array" if self.is_array_test else "matrix" |
|
expected = ( |
|
f"<{fmt} sparse {sparse_cls} of dtype '{datsp.dtype}'\n" |
|
f"\twith {datsp.nnz} stored elements {extra}and shape {datsp.shape}>" |
|
) |
|
assert repr(datsp) == expected |
|
|
|
def test_str_maxprint(self): |
|
datsp = self.spcreator(np.arange(75).reshape(5, 15)) |
|
assert datsp.maxprint == 50 |
|
assert len(str(datsp).split('\n')) == 51 + 3 |
|
|
|
dat = np.arange(15).reshape(5,3) |
|
datsp = self.spcreator(dat) |
|
|
|
nnz_small = 14 if datsp.format == 'dia' else datsp.nnz |
|
datsp_mp6 = self.spcreator(dat, maxprint=6) |
|
|
|
assert len(str(datsp).split('\n')) == nnz_small + 3 |
|
assert len(str(datsp_mp6).split('\n')) == 6 + 4 |
|
|
|
|
|
datsp = self.spcreator(dat, shape=(5, 3), dtype='i', copy=False, maxprint=4) |
|
datsp = self.spcreator(dat, (5, 3), 'i', False, maxprint=4) |
|
with pytest.raises(TypeError, match="positional argument|unpack non-iterable"): |
|
self.spcreator(dat, (5, 3), 'i', False, 4) |
|
|
|
def test_str(self): |
|
datsp = self.spcreator([[1, 0, 0], [0, 0, 0], [0, 0, -2]]) |
|
if datsp.nnz != 2: |
|
return |
|
extra = ( |
|
"(1 diagonals) " if datsp.format == "dia" |
|
else "(blocksize=1x1) " if datsp.format == "bsr" |
|
else "" |
|
) |
|
_, fmt = _formats[datsp.format] |
|
sparse_cls = "array" if self.is_array_test else "matrix" |
|
expected = ( |
|
f"<{fmt} sparse {sparse_cls} of dtype '{datsp.dtype}'\n" |
|
f"\twith {datsp.nnz} stored elements {extra}and shape {datsp.shape}>" |
|
"\n Coords\tValues" |
|
"\n (0, 0)\t1" |
|
"\n (2, 2)\t-2" |
|
) |
|
assert str(datsp) == expected |
|
|
|
def test_empty_arithmetic(self): |
|
|
|
shape = (5, 5) |
|
for mytype in [np.dtype('int32'), np.dtype('float32'), |
|
np.dtype('float64'), np.dtype('complex64'), |
|
np.dtype('complex128')]: |
|
a = self.spcreator(shape, dtype=mytype) |
|
b = a + a |
|
c = 2 * a |
|
d = a @ a.tocsc() |
|
e = a @ a.tocsr() |
|
f = a @ a.tocoo() |
|
for m in [a,b,c,d,e,f]: |
|
assert_equal(m.toarray(), a.toarray()@a.toarray()) |
|
|
|
assert_equal(m.dtype,mytype) |
|
assert_equal(m.toarray().dtype,mytype) |
|
|
|
def test_abs(self): |
|
A = array([[-1, 0, 17], [0, -5, 0], [1, -4, 0], [0, 0, 0]], 'd') |
|
assert_equal(abs(A), abs(self.spcreator(A)).toarray()) |
|
|
|
def test_round(self): |
|
decimal = 1 |
|
A = array([[-1.35, 0.56], [17.25, -5.98]], 'd') |
|
assert_equal(np.around(A, decimals=decimal), |
|
round(self.spcreator(A), ndigits=decimal).toarray()) |
|
|
|
def test_elementwise_power(self): |
|
A = array([[-4, -3, -2], [-1, 0, 1], [2, 3, 4]], 'd') |
|
assert_equal(np.power(A, 2), self.spcreator(A).power(2).toarray()) |
|
|
|
|
|
assert_raises(NotImplementedError, self.spcreator(A).power, A) |
|
|
|
def test_neg(self): |
|
A = array([[-1, 0, 17], [0, -5, 0], [1, -4, 0], [0, 0, 0]], 'd') |
|
assert_equal(-A, (-self.spcreator(A)).toarray()) |
|
|
|
|
|
A = array([[True, False, False], [False, False, True]]) |
|
assert_raises(NotImplementedError, self.spcreator(A).__neg__) |
|
|
|
def test_real(self): |
|
D = array([[1 + 3j, 2 - 4j]]) |
|
A = self.spcreator(D) |
|
assert_equal(A.real.toarray(), D.real) |
|
|
|
def test_imag(self): |
|
D = array([[1 + 3j, 2 - 4j]]) |
|
A = self.spcreator(D) |
|
assert_equal(A.imag.toarray(), D.imag) |
|
|
|
def test_diagonal(self): |
|
|
|
mats = [] |
|
mats.append([[1,0,2]]) |
|
mats.append([[1],[0],[2]]) |
|
mats.append([[0,1],[0,2],[0,3]]) |
|
mats.append([[0,0,1],[0,0,2],[0,3,0]]) |
|
mats.append([[1,0],[0,0]]) |
|
|
|
mats.append(kron(mats[0],[[1,2]])) |
|
mats.append(kron(mats[0],[[1],[2]])) |
|
mats.append(kron(mats[1],[[1,2],[3,4]])) |
|
mats.append(kron(mats[2],[[1,2],[3,4]])) |
|
mats.append(kron(mats[3],[[1,2],[3,4]])) |
|
mats.append(kron(mats[3],[[1,2,3,4]])) |
|
|
|
for m in mats: |
|
rows, cols = array(m).shape |
|
sparse_mat = self.spcreator(m) |
|
for k in range(-rows-1, cols+2): |
|
assert_equal(sparse_mat.diagonal(k=k), diag(m, k=k)) |
|
|
|
assert_equal(sparse_mat.diagonal(k=10), diag(m, k=10)) |
|
assert_equal(sparse_mat.diagonal(k=-99), diag(m, k=-99)) |
|
|
|
|
|
assert_equal(self.spcreator((40, 16130)).diagonal(), np.zeros(40)) |
|
|
|
|
|
assert_equal(self.spcreator((0, 0)).diagonal(), np.empty(0)) |
|
assert_equal(self.spcreator((15, 0)).diagonal(), np.empty(0)) |
|
assert_equal(self.spcreator((0, 5)).diagonal(10), np.empty(0)) |
|
|
|
def test_trace(self): |
|
|
|
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) |
|
B = self.spcreator(A) |
|
for k in range(-2, 3): |
|
assert_equal(A.trace(offset=k), B.trace(offset=k)) |
|
|
|
|
|
A = np.array([[1, 2, 3], [4, 5, 6]]) |
|
B = self.spcreator(A) |
|
for k in range(-1, 3): |
|
assert_equal(A.trace(offset=k), B.trace(offset=k)) |
|
|
|
def test_reshape(self): |
|
x = self.spcreator([[1, 0, 7], [0, 0, 0], [0, 3, 0], [0, 0, 5]]) |
|
for order in ['C', 'F']: |
|
for s in [(12, 1), (1, 12)]: |
|
assert_array_equal(x.reshape(s, order=order).toarray(), |
|
x.toarray().reshape(s, order=order)) |
|
|
|
|
|
|
|
x = self.spcreator([[0, 10, 0, 0], [0, 0, 0, 0], [0, 20, 30, 40]]) |
|
y = x.reshape((2, 6)) |
|
desired = [[0, 10, 0, 0, 0, 0], [0, 0, 0, 20, 30, 40]] |
|
assert_array_equal(y.toarray(), desired) |
|
|
|
|
|
y = x.reshape((2, -1)) |
|
assert_array_equal(y.toarray(), desired) |
|
y = x.reshape((-1, 6)) |
|
assert_array_equal(y.toarray(), desired) |
|
assert_raises(ValueError, x.reshape, (-1, -1)) |
|
|
|
|
|
y = x.reshape(2, 6) |
|
assert_array_equal(y.toarray(), desired) |
|
assert_raises(TypeError, x.reshape, 2, 6, not_an_arg=1) |
|
|
|
|
|
y = x.reshape((3, 4)) |
|
assert_(y is x) |
|
y = x.reshape((3, 4), copy=True) |
|
assert_(y is not x) |
|
|
|
|
|
assert_array_equal(x.shape, (3, 4)) |
|
|
|
if self.is_array_test: |
|
with assert_raises(AttributeError, match="has no setter|n't set attribute"): |
|
x.shape = (2, 6) |
|
else: |
|
|
|
x.shape = (2, 6) |
|
assert_array_equal(x.toarray(), desired) |
|
|
|
|
|
assert_raises(ValueError, x.reshape, (x.size,)) |
|
assert_raises(ValueError, x.reshape, (1, x.size, 1)) |
|
|
|
@pytest.mark.slow |
|
def test_setdiag_comprehensive(self): |
|
def dense_setdiag(a, v, k): |
|
v = np.asarray(v) |
|
if k >= 0: |
|
n = min(a.shape[0], a.shape[1] - k) |
|
if v.ndim != 0: |
|
n = min(n, len(v)) |
|
v = v[:n] |
|
i = np.arange(0, n) |
|
j = np.arange(k, k + n) |
|
a[i,j] = v |
|
elif k < 0: |
|
dense_setdiag(a.T, v, -k) |
|
|
|
def check_setdiag(a, b, k): |
|
|
|
|
|
for r in [-1, len(np.diag(a, k)), 2, 30]: |
|
if r < 0: |
|
v = np.random.choice(range(1, 20)) |
|
else: |
|
v = np.random.randint(1, 20, size=r) |
|
|
|
dense_setdiag(a, v, k) |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structu") |
|
b.setdiag(v, k) |
|
|
|
|
|
d = np.diag(a, k) |
|
if np.asarray(v).ndim == 0: |
|
assert_array_equal(d, v, err_msg="{msg} {r}") |
|
else: |
|
n = min(len(d), len(v)) |
|
assert_array_equal(d[:n], v[:n], err_msg="{msg} {r}") |
|
|
|
assert_array_equal(b.toarray(), a, err_msg="{msg} {r}") |
|
|
|
|
|
np.random.seed(1234) |
|
shapes = [(0,5), (5,0), (1,5), (5,1), (5,5)] |
|
for dtype in [np.int8, np.float64]: |
|
for m,n in shapes: |
|
ks = np.arange(-m+1, n-1) |
|
for k in ks: |
|
a = np.zeros((m, n), dtype=dtype) |
|
b = self.spcreator((m, n), dtype=dtype) |
|
|
|
check_setdiag(a, b, k) |
|
|
|
|
|
for k2 in np.random.choice(ks, size=min(len(ks), 5)): |
|
check_setdiag(a, b, k2) |
|
|
|
def test_setdiag(self): |
|
|
|
m = self.spcreator(np.eye(3)) |
|
m2 = self.spcreator((4, 4)) |
|
values = [3, 2, 1] |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
assert_raises(ValueError, m.setdiag, values, k=4) |
|
m.setdiag(values) |
|
assert_array_equal(m.diagonal(), values) |
|
m.setdiag(values, k=1) |
|
assert_array_equal(m.toarray(), np.array([[3, 3, 0], |
|
[0, 2, 2], |
|
[0, 0, 1]])) |
|
m.setdiag(values, k=-2) |
|
assert_array_equal(m.toarray(), np.array([[3, 3, 0], |
|
[0, 2, 2], |
|
[3, 0, 1]])) |
|
m.setdiag((9,), k=2) |
|
assert_array_equal(m.toarray()[0,2], 9) |
|
m.setdiag((9,), k=-2) |
|
assert_array_equal(m.toarray()[2,0], 9) |
|
|
|
m2.setdiag([1], k=2) |
|
assert_array_equal(m2.toarray()[0], [0, 0, 1, 0]) |
|
|
|
m2.setdiag([1, 1], k=2) |
|
assert_array_equal(m2.toarray()[:2], [[0, 0, 1, 0], |
|
[0, 0, 0, 1]]) |
|
|
|
def test_nonzero(self): |
|
A = array([[1, 0, 1],[0, 1, 1],[0, 0, 1]]) |
|
Asp = self.spcreator(A) |
|
|
|
A_nz = {tuple(ij) for ij in transpose(A.nonzero())} |
|
Asp_nz = {tuple(ij) for ij in transpose(Asp.nonzero())} |
|
|
|
assert_equal(A_nz, Asp_nz) |
|
|
|
def test_numpy_nonzero(self): |
|
|
|
A = array([[1, 0, 1], [0, 1, 1], [0, 0, 1]]) |
|
Asp = self.spcreator(A) |
|
|
|
A_nz = {tuple(ij) for ij in transpose(np.nonzero(A))} |
|
Asp_nz = {tuple(ij) for ij in transpose(np.nonzero(Asp))} |
|
|
|
assert_equal(A_nz, Asp_nz) |
|
|
|
def test_sum(self): |
|
np.random.seed(1234) |
|
dat_1 = np.array([[0, 1, 2], |
|
[3, -4, 5], |
|
[-6, 7, 9]]) |
|
dat_2 = np.random.rand(5, 5) |
|
dat_3 = np.array([[]]) |
|
dat_4 = np.zeros((40, 40)) |
|
dat_5 = sparse.rand(5, 5, density=1e-2).toarray() |
|
matrices = [dat_1, dat_2, dat_3, dat_4, dat_5] |
|
|
|
def check(dtype, j): |
|
dat = self.asdense(matrices[j], dtype=dtype) |
|
datsp = self.spcreator(dat, dtype=dtype) |
|
with np.errstate(over='ignore'): |
|
assert_array_almost_equal(dat.sum(), datsp.sum()) |
|
assert_equal(dat.sum().dtype, datsp.sum().dtype) |
|
assert_(np.isscalar(datsp.sum(axis=None))) |
|
assert_array_almost_equal(dat.sum(axis=None), |
|
datsp.sum(axis=None)) |
|
assert_equal(dat.sum(axis=None).dtype, |
|
datsp.sum(axis=None).dtype) |
|
assert_array_almost_equal(dat.sum(axis=0), datsp.sum(axis=0)) |
|
assert_equal(dat.sum(axis=0).dtype, datsp.sum(axis=0).dtype) |
|
assert_array_almost_equal(dat.sum(axis=1), datsp.sum(axis=1)) |
|
assert_equal(dat.sum(axis=1).dtype, datsp.sum(axis=1).dtype) |
|
assert_array_almost_equal(dat.sum(axis=-2), datsp.sum(axis=-2)) |
|
assert_equal(dat.sum(axis=-2).dtype, datsp.sum(axis=-2).dtype) |
|
assert_array_almost_equal(dat.sum(axis=-1), datsp.sum(axis=-1)) |
|
assert_equal(dat.sum(axis=-1).dtype, datsp.sum(axis=-1).dtype) |
|
|
|
for dtype in self.checked_dtypes: |
|
for j in range(len(matrices)): |
|
check(dtype, j) |
|
|
|
def test_sum_invalid_params(self): |
|
out = np.zeros((1, 3)) |
|
dat = array([[0, 1, 2], |
|
[3, -4, 5], |
|
[-6, 7, 9]]) |
|
datsp = self.spcreator(dat) |
|
|
|
assert_raises(ValueError, datsp.sum, axis=3) |
|
assert_raises(TypeError, datsp.sum, axis=(0, 1)) |
|
assert_raises(TypeError, datsp.sum, axis=1.5) |
|
assert_raises(ValueError, datsp.sum, axis=1, out=out) |
|
|
|
def test_sum_dtype(self): |
|
dat = array([[0, 1, 2], |
|
[3, -4, 5], |
|
[-6, 7, 9]]) |
|
datsp = self.spcreator(dat) |
|
|
|
def check(dtype): |
|
dat_sum = dat.sum(dtype=dtype) |
|
datsp_sum = datsp.sum(dtype=dtype) |
|
|
|
assert_array_almost_equal(dat_sum, datsp_sum) |
|
assert_equal(dat_sum.dtype, datsp_sum.dtype) |
|
|
|
for dtype in self.checked_dtypes: |
|
check(dtype) |
|
|
|
def test_sum_out(self): |
|
keep = not self.is_array_test |
|
dat = array([[0, 1, 2], |
|
[3, -4, 5], |
|
[-6, 7, 9]]) |
|
datsp = self.spcreator(dat) |
|
|
|
dat_out = array(0) if self.is_array_test else array([[0]]) |
|
datsp_out = array(0) if self.is_array_test else matrix([[0]]) |
|
|
|
dat.sum(out=dat_out, keepdims=keep) |
|
datsp.sum(out=datsp_out) |
|
assert_array_almost_equal(dat_out, datsp_out) |
|
|
|
dat_out = np.zeros((3,)) if self.is_array_test else np.zeros((3, 1)) |
|
datsp_out = np.zeros((3,)) if self.is_array_test else matrix(np.zeros((3, 1))) |
|
|
|
dat.sum(axis=1, out=dat_out, keepdims=keep) |
|
datsp.sum(axis=1, out=datsp_out) |
|
assert_array_almost_equal(dat_out, datsp_out) |
|
|
|
def test_numpy_sum(self): |
|
|
|
dat = array([[0, 1, 2], |
|
[3, -4, 5], |
|
[-6, 7, 9]]) |
|
datsp = self.spcreator(dat) |
|
|
|
dat_sum = np.sum(dat) |
|
datsp_sum = np.sum(datsp) |
|
|
|
assert_array_almost_equal(dat_sum, datsp_sum) |
|
assert_equal(dat_sum.dtype, datsp_sum.dtype) |
|
|
|
def test_mean(self): |
|
keep = not self.is_array_test |
|
def check(dtype): |
|
dat = array([[0, 1, 2], |
|
[3, 4, 5], |
|
[6, 7, 9]], dtype=dtype) |
|
datsp = self.spcreator(dat, dtype=dtype) |
|
|
|
assert_array_almost_equal(dat.mean(), datsp.mean()) |
|
assert_equal(dat.mean().dtype, datsp.mean().dtype) |
|
assert_(np.isscalar(datsp.mean(axis=None))) |
|
assert_array_almost_equal( |
|
dat.mean(axis=None, keepdims=keep), datsp.mean(axis=None) |
|
) |
|
assert_equal(dat.mean(axis=None).dtype, datsp.mean(axis=None).dtype) |
|
assert_array_almost_equal( |
|
dat.mean(axis=0, keepdims=keep), datsp.mean(axis=0) |
|
) |
|
assert_equal(dat.mean(axis=0).dtype, datsp.mean(axis=0).dtype) |
|
assert_array_almost_equal( |
|
dat.mean(axis=1, keepdims=keep), datsp.mean(axis=1) |
|
) |
|
assert_equal(dat.mean(axis=1).dtype, datsp.mean(axis=1).dtype) |
|
assert_array_almost_equal( |
|
dat.mean(axis=-2, keepdims=keep), datsp.mean(axis=-2) |
|
) |
|
assert_equal(dat.mean(axis=-2).dtype, datsp.mean(axis=-2).dtype) |
|
assert_array_almost_equal( |
|
dat.mean(axis=-1, keepdims=keep), datsp.mean(axis=-1) |
|
) |
|
assert_equal(dat.mean(axis=-1).dtype, datsp.mean(axis=-1).dtype) |
|
|
|
for dtype in self.checked_dtypes: |
|
check(dtype) |
|
|
|
def test_mean_invalid_params(self): |
|
out = self.asdense(np.zeros((1, 3))) |
|
dat = array([[0, 1, 2], |
|
[3, -4, 5], |
|
[-6, 7, 9]]) |
|
datsp = self.spcreator(dat) |
|
|
|
assert_raises(ValueError, datsp.mean, axis=3) |
|
assert_raises(TypeError, datsp.mean, axis=(0, 1)) |
|
assert_raises(TypeError, datsp.mean, axis=1.5) |
|
assert_raises(ValueError, datsp.mean, axis=1, out=out) |
|
|
|
def test_mean_dtype(self): |
|
dat = array([[0, 1, 2], |
|
[3, -4, 5], |
|
[-6, 7, 9]]) |
|
datsp = self.spcreator(dat) |
|
|
|
def check(dtype): |
|
dat_mean = dat.mean(dtype=dtype) |
|
datsp_mean = datsp.mean(dtype=dtype) |
|
|
|
assert_array_almost_equal(dat_mean, datsp_mean) |
|
assert_equal(dat_mean.dtype, datsp_mean.dtype) |
|
|
|
for dtype in self.checked_dtypes: |
|
check(dtype) |
|
|
|
def test_mean_out(self): |
|
keep = not self.is_array_test |
|
dat = array([[0, 1, 2], |
|
[3, -4, 5], |
|
[-6, 7, 9]]) |
|
datsp = self.spcreator(dat) |
|
|
|
dat_out = array(0) if self.is_array_test else array([[0]]) |
|
datsp_out = array(0) if self.is_array_test else matrix([[0]]) |
|
|
|
dat.mean(out=dat_out, keepdims=keep) |
|
datsp.mean(out=datsp_out) |
|
assert_array_almost_equal(dat_out, datsp_out) |
|
|
|
dat_out = np.zeros((3,)) if self.is_array_test else np.zeros((3, 1)) |
|
datsp_out = np.zeros((3,)) if self.is_array_test else matrix(np.zeros((3, 1))) |
|
|
|
dat.mean(axis=1, out=dat_out, keepdims=keep) |
|
datsp.mean(axis=1, out=datsp_out) |
|
assert_array_almost_equal(dat_out, datsp_out) |
|
|
|
def test_numpy_mean(self): |
|
|
|
dat = array([[0, 1, 2], |
|
[3, -4, 5], |
|
[-6, 7, 9]]) |
|
datsp = self.spcreator(dat) |
|
|
|
dat_mean = np.mean(dat) |
|
datsp_mean = np.mean(datsp) |
|
|
|
assert_array_almost_equal(dat_mean, datsp_mean) |
|
assert_equal(dat_mean.dtype, datsp_mean.dtype) |
|
|
|
def test_expm(self): |
|
M = array([[1, 0, 2], [0, 0, 3], [-4, 5, 6]], float) |
|
sM = self.spcreator(M, shape=(3,3), dtype=float) |
|
Mexp = scipy.linalg.expm(M) |
|
|
|
N = array([[3., 0., 1.], [0., 2., 0.], [0., 0., 0.]]) |
|
sN = self.spcreator(N, shape=(3,3), dtype=float) |
|
Nexp = scipy.linalg.expm(N) |
|
|
|
with suppress_warnings() as sup: |
|
sup.filter( |
|
SparseEfficiencyWarning, |
|
"splu converted its input to CSC format", |
|
) |
|
sup.filter( |
|
SparseEfficiencyWarning, |
|
"spsolve is more efficient when sparse b is in the CSC matrix format", |
|
) |
|
sup.filter( |
|
SparseEfficiencyWarning, |
|
"spsolve requires A be CSC or CSR matrix format", |
|
) |
|
sMexp = expm(sM).toarray() |
|
sNexp = expm(sN).toarray() |
|
|
|
assert_array_almost_equal((sMexp - Mexp), zeros((3, 3))) |
|
assert_array_almost_equal((sNexp - Nexp), zeros((3, 3))) |
|
|
|
def test_inv(self): |
|
def check(dtype): |
|
M = array([[1, 0, 2], [0, 0, 3], [-4, 5, 6]], dtype) |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, |
|
"spsolve requires A be CSC or CSR matrix format",) |
|
sup.filter(SparseEfficiencyWarning, |
|
"spsolve is more efficient when sparse b " |
|
"is in the CSC matrix format",) |
|
sup.filter(SparseEfficiencyWarning, |
|
"splu converted its input to CSC format",) |
|
sM = self.spcreator(M, shape=(3,3), dtype=dtype) |
|
sMinv = inv(sM) |
|
assert_array_almost_equal(sMinv.dot(sM).toarray(), np.eye(3)) |
|
assert_raises(TypeError, inv, M) |
|
for dtype in [float]: |
|
check(dtype) |
|
|
|
@sup_complex |
|
def test_from_array(self): |
|
A = array([[1,0,0],[2,3,4],[0,5,0],[0,0,0]]) |
|
assert_array_equal(self.spcreator(A).toarray(), A) |
|
|
|
A = array([[1.0 + 3j, 0, 0], |
|
[0, 2.0 + 5, 0], |
|
[0, 0, 0]]) |
|
assert_array_equal(self.spcreator(A).toarray(), A) |
|
assert_array_equal(self.spcreator(A, dtype='int16').toarray(),A.astype('int16')) |
|
|
|
@sup_complex |
|
def test_from_matrix(self): |
|
A = self.asdense([[1, 0, 0], [2, 3, 4], [0, 5, 0], [0, 0, 0]]) |
|
assert_array_equal(self.spcreator(A).todense(), A) |
|
|
|
A = self.asdense([[1.0 + 3j, 0, 0], |
|
[0, 2.0 + 5, 0], |
|
[0, 0, 0]]) |
|
assert_array_equal(self.spcreator(A).todense(), A) |
|
assert_array_equal( |
|
self.spcreator(A, dtype='int16').todense(), A.astype('int16') |
|
) |
|
|
|
@sup_complex |
|
def test_from_list(self): |
|
A = [[1,0,0],[2,3,4],[0,5,0],[0,0,0]] |
|
assert_array_equal(self.spcreator(A).toarray(), A) |
|
|
|
A = [[1.0 + 3j, 0, 0], |
|
[0, 2.0 + 5, 0], |
|
[0, 0, 0]] |
|
assert_array_equal(self.spcreator(A).toarray(), array(A)) |
|
assert_array_equal( |
|
self.spcreator(A, dtype='int16').toarray(), array(A).astype('int16') |
|
) |
|
|
|
@sup_complex |
|
def test_from_sparse(self): |
|
D = array([[1,0,0],[2,3,4],[0,5,0],[0,0,0]]) |
|
S = self.csr_container(D) |
|
assert_array_equal(self.spcreator(S).toarray(), D) |
|
S = self.spcreator(D) |
|
assert_array_equal(self.spcreator(S).toarray(), D) |
|
|
|
D = array([[1.0 + 3j, 0, 0], |
|
[0, 2.0 + 5, 0], |
|
[0, 0, 0]]) |
|
S = self.csr_container(D) |
|
assert_array_equal(self.spcreator(S).toarray(), D) |
|
assert_array_equal(self.spcreator(S, dtype='int16').toarray(), |
|
D.astype('int16')) |
|
S = self.spcreator(D) |
|
assert_array_equal(self.spcreator(S).toarray(), D) |
|
assert_array_equal(self.spcreator(S, dtype='int16').toarray(), |
|
D.astype('int16')) |
|
|
|
|
|
|
|
|
|
|
|
def test_todense(self): |
|
|
|
chk = self.datsp.todense() |
|
assert isinstance(chk, np.ndarray if self.is_array_test else np.matrix) |
|
assert_array_equal(chk, self.dat) |
|
assert_(chk.flags.c_contiguous != chk.flags.f_contiguous) |
|
|
|
chk = self.datsp.todense(order='C') |
|
assert_array_equal(chk, self.dat) |
|
assert_(chk.flags.c_contiguous) |
|
assert_(not chk.flags.f_contiguous) |
|
|
|
chk = self.datsp.todense(order='F') |
|
assert_array_equal(chk, self.dat) |
|
assert_(not chk.flags.c_contiguous) |
|
assert_(chk.flags.f_contiguous) |
|
|
|
out = np.zeros(self.datsp.shape, dtype=self.datsp.dtype) |
|
chk = self.datsp.todense(out=out) |
|
assert_array_equal(self.dat, out) |
|
assert_array_equal(self.dat, chk) |
|
assert np.may_share_memory(chk, out) |
|
|
|
out = self.asdense(np.zeros(self.datsp.shape, dtype=self.datsp.dtype)) |
|
chk = self.datsp.todense(out=out) |
|
assert_array_equal(self.dat, out) |
|
assert_array_equal(self.dat, chk) |
|
assert np.may_share_memory(chk, out) |
|
a = array([[1.,2.,3.]]) |
|
dense_dot_dense = a @ self.dat |
|
check = a @ self.datsp.todense() |
|
assert_array_equal(dense_dot_dense, check) |
|
b = array([[1.,2.,3.,4.]]).T |
|
dense_dot_dense = self.dat @ b |
|
check2 = self.datsp.todense() @ b |
|
assert_array_equal(dense_dot_dense, check2) |
|
|
|
spbool = self.spcreator(self.dat, dtype=bool) |
|
matbool = self.dat.astype(bool) |
|
assert_array_equal(spbool.todense(), matbool) |
|
|
|
def test_toarray(self): |
|
|
|
dat = asarray(self.dat) |
|
chk = self.datsp.toarray() |
|
assert_array_equal(chk, dat) |
|
assert_(chk.flags.c_contiguous != chk.flags.f_contiguous) |
|
|
|
chk = self.datsp.toarray(order='C') |
|
assert_array_equal(chk, dat) |
|
assert_(chk.flags.c_contiguous) |
|
assert_(not chk.flags.f_contiguous) |
|
|
|
chk = self.datsp.toarray(order='F') |
|
assert_array_equal(chk, dat) |
|
assert_(not chk.flags.c_contiguous) |
|
assert_(chk.flags.f_contiguous) |
|
|
|
out = np.zeros(self.datsp.shape, dtype=self.datsp.dtype) |
|
self.datsp.toarray(out=out) |
|
assert_array_equal(chk, dat) |
|
|
|
out[...] = 1. |
|
self.datsp.toarray(out=out) |
|
assert_array_equal(chk, dat) |
|
a = array([1.,2.,3.]) |
|
dense_dot_dense = dot(a, dat) |
|
check = dot(a, self.datsp.toarray()) |
|
assert_array_equal(dense_dot_dense, check) |
|
b = array([1.,2.,3.,4.]) |
|
dense_dot_dense = dot(dat, b) |
|
check2 = dot(self.datsp.toarray(), b) |
|
assert_array_equal(dense_dot_dense, check2) |
|
|
|
spbool = self.spcreator(self.dat, dtype=bool) |
|
arrbool = dat.astype(bool) |
|
assert_array_equal(spbool.toarray(), arrbool) |
|
|
|
@sup_complex |
|
def test_astype(self): |
|
D = array([[2.0 + 3j, 0, 0], |
|
[0, 4.0 + 5j, 0], |
|
[0, 0, 0]]) |
|
S = self.spcreator(D) |
|
|
|
for x in supported_dtypes: |
|
|
|
D_casted = D.astype(x) |
|
for copy in (True, False): |
|
S_casted = S.astype(x, copy=copy) |
|
assert_equal(S_casted.dtype, D_casted.dtype) |
|
assert_equal(S_casted.toarray(), D_casted) |
|
assert_equal(S_casted.format, S.format) |
|
|
|
assert_(S_casted.astype(x, copy=False) is S_casted) |
|
S_copied = S_casted.astype(x, copy=True) |
|
assert_(S_copied is not S_casted) |
|
|
|
def check_equal_but_not_same_array_attribute(attribute): |
|
a = getattr(S_casted, attribute) |
|
b = getattr(S_copied, attribute) |
|
assert_array_equal(a, b) |
|
assert_(a is not b) |
|
i = (0,) * b.ndim |
|
b_i = b[i] |
|
b[i] = not b[i] |
|
assert_(a[i] != b[i]) |
|
b[i] = b_i |
|
|
|
if S_casted.format in ('csr', 'csc', 'bsr'): |
|
for attribute in ('indices', 'indptr', 'data'): |
|
check_equal_but_not_same_array_attribute(attribute) |
|
elif S_casted.format == 'coo': |
|
for attribute in ('row', 'col', 'data'): |
|
check_equal_but_not_same_array_attribute(attribute) |
|
elif S_casted.format == 'dia': |
|
for attribute in ('offsets', 'data'): |
|
check_equal_but_not_same_array_attribute(attribute) |
|
|
|
@sup_complex |
|
def test_astype_immutable(self): |
|
D = array([[2.0 + 3j, 0, 0], |
|
[0, 4.0 + 5j, 0], |
|
[0, 0, 0]]) |
|
S = self.spcreator(D) |
|
if hasattr(S, 'data'): |
|
S.data.flags.writeable = False |
|
if S.format in ('csr', 'csc', 'bsr'): |
|
S.indptr.flags.writeable = False |
|
S.indices.flags.writeable = False |
|
for x in supported_dtypes: |
|
D_casted = D.astype(x) |
|
S_casted = S.astype(x) |
|
assert_equal(S_casted.dtype, D_casted.dtype) |
|
|
|
def test_mul_scalar(self): |
|
def check(dtype): |
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
|
|
assert_array_equal(dat*2, (datsp*2).toarray()) |
|
assert_array_equal(dat*17.3, (datsp*17.3).toarray()) |
|
|
|
for dtype in self.math_dtypes: |
|
check(dtype) |
|
|
|
def test_rmul_scalar(self): |
|
def check(dtype): |
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
|
|
assert_array_equal(2*dat, (2*datsp).toarray()) |
|
assert_array_equal(17.3*dat, (17.3*datsp).toarray()) |
|
|
|
for dtype in self.math_dtypes: |
|
check(dtype) |
|
|
|
|
|
def test_rmul_scalar_type_error(self): |
|
datsp = self.datsp_dtypes[np.float64] |
|
with assert_raises(TypeError): |
|
None * datsp |
|
|
|
def test_add(self): |
|
def check(dtype): |
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
|
|
a = dat.copy() |
|
a[0,2] = 2.0 |
|
b = datsp |
|
c = b + a |
|
assert_array_equal(c, b.toarray() + a) |
|
|
|
c = b + b.tocsr() |
|
assert_array_equal(c.toarray(), |
|
b.toarray() + b.toarray()) |
|
|
|
|
|
c = b + a[0] |
|
assert_array_equal(c, b.toarray() + a[0]) |
|
|
|
for dtype in self.math_dtypes: |
|
check(dtype) |
|
|
|
def test_radd(self): |
|
def check(dtype): |
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
|
|
a = dat.copy() |
|
a[0,2] = 2.0 |
|
b = datsp |
|
c = a + b |
|
assert_array_equal(c, a + b.toarray()) |
|
|
|
for dtype in self.math_dtypes: |
|
check(dtype) |
|
|
|
def test_sub(self): |
|
def check(dtype): |
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
|
|
assert_array_equal((datsp - datsp).toarray(), np.zeros((3, 4))) |
|
assert_array_equal((datsp - 0).toarray(), dat) |
|
|
|
A = self.spcreator( |
|
np.array([[1, 0, 0, 4], [-1, 0, 0, 0], [0, 8, 0, -5]], 'd') |
|
) |
|
assert_array_equal((datsp - A).toarray(), dat - A.toarray()) |
|
assert_array_equal((A - datsp).toarray(), A.toarray() - dat) |
|
|
|
|
|
assert_array_equal(datsp - dat[0], dat - dat[0]) |
|
|
|
for dtype in self.math_dtypes: |
|
if dtype == np.dtype('bool'): |
|
|
|
continue |
|
|
|
check(dtype) |
|
|
|
def test_rsub(self): |
|
def check(dtype): |
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
|
|
assert_array_equal((dat - datsp),[[0,0,0,0],[0,0,0,0],[0,0,0,0]]) |
|
assert_array_equal((datsp - dat),[[0,0,0,0],[0,0,0,0],[0,0,0,0]]) |
|
assert_array_equal((0 - datsp).toarray(), -dat) |
|
|
|
A = self.spcreator([[1,0,0,4],[-1,0,0,0],[0,8,0,-5]],dtype='d') |
|
assert_array_equal((dat - A), dat - A.toarray()) |
|
assert_array_equal((A - dat), A.toarray() - dat) |
|
assert_array_equal(A.toarray() - datsp, A.toarray() - dat) |
|
assert_array_equal(datsp - A.toarray(), dat - A.toarray()) |
|
|
|
|
|
assert_array_equal(dat[0] - datsp, dat[0] - dat) |
|
|
|
for dtype in self.math_dtypes: |
|
if dtype == np.dtype('bool'): |
|
|
|
continue |
|
|
|
check(dtype) |
|
|
|
def test_add0(self): |
|
def check(dtype): |
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
|
|
|
|
assert_array_equal((datsp + 0).toarray(), dat) |
|
|
|
sumS = sum([k * datsp for k in range(1, 3)]) |
|
sumD = sum([k * dat for k in range(1, 3)]) |
|
assert_almost_equal(sumS.toarray(), sumD) |
|
|
|
for dtype in self.math_dtypes: |
|
check(dtype) |
|
|
|
def test_elementwise_multiply(self): |
|
|
|
A = array([[4,0,9],[2,-3,5]]) |
|
B = array([[0,7,0],[0,-4,0]]) |
|
Asp = self.spcreator(A) |
|
Bsp = self.spcreator(B) |
|
assert_almost_equal(Asp.multiply(Bsp).toarray(), A*B) |
|
assert_almost_equal(Asp.multiply(B).toarray(), A*B) |
|
|
|
|
|
C = array([[1-2j,0+5j,-1+0j],[4-3j,-3+6j,5]]) |
|
D = array([[5+2j,7-3j,-2+1j],[0-1j,-4+2j,9]]) |
|
Csp = self.spcreator(C) |
|
Dsp = self.spcreator(D) |
|
assert_almost_equal(Csp.multiply(Dsp).toarray(), C*D) |
|
assert_almost_equal(Csp.multiply(D).toarray(), C*D) |
|
|
|
|
|
assert_almost_equal(Asp.multiply(Dsp).toarray(), A*D) |
|
assert_almost_equal(Asp.multiply(D).toarray(), A*D) |
|
|
|
def test_elementwise_multiply_broadcast(self): |
|
A = array([4]) |
|
B = array([[-9]]) |
|
C = array([1,-1,0]) |
|
D = array([[7,9,-9]]) |
|
E = array([[3],[2],[1]]) |
|
F = array([[8,6,3],[-4,3,2],[6,6,6]]) |
|
G = [1, 2, 3] |
|
H = np.ones((3, 4)) |
|
J = H.T |
|
K = array([[0]]) |
|
L = array([[[1,2],[0,1]]]) |
|
|
|
|
|
|
|
Bsp = self.spcreator(B) |
|
Dsp = self.spcreator(D) |
|
Esp = self.spcreator(E) |
|
Fsp = self.spcreator(F) |
|
Hsp = self.spcreator(H) |
|
Hspp = self.spcreator(H[0,None]) |
|
Jsp = self.spcreator(J) |
|
Jspp = self.spcreator(J[:,0,None]) |
|
Ksp = self.spcreator(K) |
|
|
|
matrices = [A, B, C, D, E, F, G, H, J, K, L] |
|
spmatrices = [Bsp, Dsp, Esp, Fsp, Hsp, Hspp, Jsp, Jspp, Ksp] |
|
|
|
|
|
for i in spmatrices: |
|
for j in spmatrices: |
|
try: |
|
dense_mult = i.toarray() * j.toarray() |
|
except ValueError: |
|
assert_raises(ValueError, i.multiply, j) |
|
continue |
|
sp_mult = i.multiply(j) |
|
assert_almost_equal(sp_mult.toarray(), dense_mult) |
|
|
|
|
|
for i in spmatrices: |
|
for j in matrices: |
|
try: |
|
dense_mult = i.toarray() * j |
|
except TypeError: |
|
continue |
|
except ValueError: |
|
assert_raises(ValueError, i.multiply, j) |
|
continue |
|
sp_mult = i.multiply(j) |
|
if issparse(sp_mult): |
|
assert_almost_equal(sp_mult.toarray(), dense_mult) |
|
else: |
|
assert_almost_equal(sp_mult, dense_mult) |
|
|
|
def test_elementwise_divide(self): |
|
expected = [[1,np.nan,np.nan,1], |
|
[1,np.nan,1,np.nan], |
|
[np.nan,1,np.nan,np.nan]] |
|
assert_array_equal(toarray(self.datsp / self.datsp), expected) |
|
|
|
denom = self.spcreator([[1,0,0,4],[-1,0,0,0],[0,8,0,-5]],dtype='d') |
|
expected = [[1,np.nan,np.nan,0.5], |
|
[-3,np.nan,inf,np.nan], |
|
[np.nan,0.25,np.nan,0]] |
|
assert_array_equal(toarray(self.datsp / denom), expected) |
|
|
|
|
|
A = array([[1-2j,0+5j,-1+0j],[4-3j,-3+6j,5]]) |
|
B = array([[5+2j,7-3j,-2+1j],[0-1j,-4+2j,9]]) |
|
Asp = self.spcreator(A) |
|
Bsp = self.spcreator(B) |
|
assert_almost_equal(toarray(Asp / Bsp), A/B) |
|
|
|
|
|
A = array([[1,2,3],[-3,2,1]]) |
|
B = array([[0,1,2],[0,-2,3]]) |
|
Asp = self.spcreator(A) |
|
Bsp = self.spcreator(B) |
|
with np.errstate(divide='ignore'): |
|
assert_array_equal(toarray(Asp / Bsp), A / B) |
|
|
|
|
|
A = array([[0,1],[1,0]]) |
|
B = array([[1,0],[1,0]]) |
|
Asp = self.spcreator(A) |
|
Bsp = self.spcreator(B) |
|
with np.errstate(divide='ignore', invalid='ignore'): |
|
assert_array_equal(np.array(toarray(Asp / Bsp)), A / B) |
|
|
|
def test_pow(self): |
|
A = array([[1, 0, 2, 0], [0, 3, 4, 0], [0, 5, 0, 0], [0, 6, 7, 8]]) |
|
B = self.spcreator(A) |
|
|
|
if self.is_array_test: |
|
|
|
|
|
|
|
|
|
|
|
|
|
for exponent in [1, 2, 2.2, 3]: |
|
ret_sp = B**exponent |
|
ret_np = A**exponent |
|
assert_array_equal(ret_sp.toarray(), ret_np) |
|
assert_equal(ret_sp.dtype, ret_np.dtype) |
|
|
|
|
|
assert_raises(NotImplementedError, B.__pow__, 0) |
|
assert_raises(ValueError, B.__pow__, -1) |
|
|
|
|
|
B = self.spcreator(A[:3,:]) |
|
assert_equal((B**1).toarray(), B.toarray()) |
|
else: |
|
for exponent in [0,1,2,3]: |
|
ret_sp = B**exponent |
|
ret_np = np.linalg.matrix_power(A, exponent) |
|
assert_array_equal(ret_sp.toarray(), ret_np) |
|
assert_equal(ret_sp.dtype, ret_np.dtype) |
|
|
|
|
|
for exponent in [-1, 2.2, 1 + 3j]: |
|
assert_raises(ValueError, B.__pow__, exponent) |
|
|
|
|
|
B = self.spcreator(A[:3,:]) |
|
assert_raises(TypeError, B.__pow__, 1) |
|
|
|
def test_rmatvec(self): |
|
M = self.spcreator([[3,0,0],[0,1,0],[2,0,3.0],[2,3,0]]) |
|
assert_array_almost_equal([1,2,3,4] @ M, dot([1,2,3,4], M.toarray())) |
|
row = array([[1,2,3,4]]) |
|
assert_array_almost_equal(row @ M, row @ M.toarray()) |
|
|
|
def test_small_multiplication(self): |
|
|
|
A = self.spcreator([[1],[2],[3]]) |
|
|
|
assert_(issparse(A * array(1))) |
|
assert_equal((A * array(1)).toarray(), [[1], [2], [3]]) |
|
|
|
assert_equal(A @ array([1]), array([1, 2, 3])) |
|
assert_equal(A @ array([[1]]), array([[1], [2], [3]])) |
|
assert_equal(A @ np.ones((1, 1)), array([[1], [2], [3]])) |
|
assert_equal(A @ np.ones((1, 0)), np.ones((3, 0))) |
|
|
|
def test_star_vs_at_sign_for_sparray_and_spmatrix(self): |
|
|
|
A = np.array([[1], [2], [3]]) |
|
Asp = self.spcreator(A) |
|
|
|
if self.is_array_test: |
|
assert_array_almost_equal((Asp * np.ones((3, 1))).toarray(), A) |
|
assert_array_almost_equal((Asp * array([[1]])).toarray(), A) |
|
else: |
|
assert_equal(Asp * array([1]), array([1, 2, 3])) |
|
assert_equal(Asp * array([[1]]), array([[1], [2], [3]])) |
|
assert_equal(Asp * np.ones((1, 0)), np.ones((3, 0))) |
|
|
|
def test_binop_custom_type(self): |
|
|
|
|
|
|
|
|
|
A = self.spcreator([[1], [2], [3]]) |
|
B = BinopTester() |
|
assert_equal(A + B, "matrix on the left") |
|
assert_equal(A - B, "matrix on the left") |
|
assert_equal(A * B, "matrix on the left") |
|
assert_equal(B + A, "matrix on the right") |
|
assert_equal(B - A, "matrix on the right") |
|
assert_equal(B * A, "matrix on the right") |
|
|
|
assert_equal(A @ B, "matrix on the left") |
|
assert_equal(B @ A, "matrix on the right") |
|
|
|
def test_binop_custom_type_with_shape(self): |
|
A = self.spcreator([[1], [2], [3]]) |
|
B = BinopTester_with_shape((3,1)) |
|
assert_equal(A + B, "matrix on the left") |
|
assert_equal(A - B, "matrix on the left") |
|
assert_equal(A * B, "matrix on the left") |
|
assert_equal(B + A, "matrix on the right") |
|
assert_equal(B - A, "matrix on the right") |
|
assert_equal(B * A, "matrix on the right") |
|
|
|
assert_equal(A @ B, "matrix on the left") |
|
assert_equal(B @ A, "matrix on the right") |
|
|
|
def test_mul_custom_type(self): |
|
class Custom: |
|
def __init__(self, scalar): |
|
self.scalar = scalar |
|
|
|
def __rmul__(self, other): |
|
return other * self.scalar |
|
|
|
scalar = 2 |
|
A = self.spcreator([[1],[2],[3]]) |
|
c = Custom(scalar) |
|
A_scalar = A * scalar |
|
A_c = A * c |
|
assert_array_equal_dtype(A_scalar.toarray(), A_c.toarray()) |
|
assert_equal(A_scalar.format, A_c.format) |
|
|
|
def test_comparisons_custom_type(self): |
|
A = self.spcreator([[1], [2], [3]]) |
|
B = ComparisonTester() |
|
assert_equal(A == B, "eq") |
|
assert_equal(A != B, "ne") |
|
assert_equal(A > B, "lt") |
|
assert_equal(A >= B, "le") |
|
assert_equal(A < B, "gt") |
|
assert_equal(A <= B, "ge") |
|
|
|
def test_dot_scalar(self): |
|
M = self.spcreator(array([[3,0,0],[0,1,0],[2,0,3.0],[2,3,0]])) |
|
scalar = 10 |
|
actual = M.dot(scalar) |
|
expected = M * scalar |
|
|
|
assert_allclose(actual.toarray(), expected.toarray()) |
|
|
|
def test_matmul(self): |
|
M = self.spcreator(array([[3,0,0],[0,1,0],[2,0,3.0],[2,3,0]])) |
|
B = self.spcreator(array([[0,1],[1,0],[0,2]],'d')) |
|
col = array([[1,2,3]]).T |
|
|
|
matmul = operator.matmul |
|
|
|
assert_array_almost_equal(matmul(M, col), M.toarray() @ col) |
|
|
|
|
|
assert_array_almost_equal(matmul(M, B).toarray(), (M @ B).toarray()) |
|
assert_array_almost_equal(matmul(M.toarray(), B), (M @ B).toarray()) |
|
assert_array_almost_equal(matmul(M, B.toarray()), (M @ B).toarray()) |
|
|
|
|
|
assert_raises(ValueError, matmul, M, 1) |
|
assert_raises(ValueError, matmul, 1, M) |
|
|
|
def test_matvec(self): |
|
M = self.spcreator([[3,0,0],[0,1,0],[2,0,3.0],[2,3,0]]) |
|
col = array([[1,2,3]]).T |
|
|
|
assert_array_almost_equal(M @ col, M.toarray() @ col) |
|
|
|
|
|
assert_equal((M @ array([1,2,3])).shape,(4,)) |
|
assert_equal((M @ array([[1],[2],[3]])).shape,(4,1)) |
|
assert_equal((M @ matrix([[1],[2],[3]])).shape,(4,1)) |
|
|
|
|
|
assert_(isinstance(M @ array([1,2,3]), ndarray)) |
|
matrix_or_array = ndarray if self.is_array_test else np.matrix |
|
assert_(isinstance(M @ matrix([1,2,3]).T, matrix_or_array)) |
|
|
|
|
|
bad_vecs = [array([1,2]), array([1,2,3,4]), array([[1],[2]]), |
|
matrix([1,2,3]), matrix([[1],[2]])] |
|
for x in bad_vecs: |
|
assert_raises(ValueError, M.__matmul__, x) |
|
|
|
|
|
|
|
assert_almost_equal(M@array([1,2,3]), dot(M.toarray(),[1,2,3])) |
|
assert_almost_equal(M@[[1],[2],[3]], np.atleast_2d(dot(M.toarray(),[1,2,3])).T) |
|
|
|
|
|
|
|
|
|
|
|
def test_matmat_sparse(self): |
|
a = matrix([[3,0,0],[0,1,0],[2,0,3.0],[2,3,0]]) |
|
a2 = array([[3,0,0],[0,1,0],[2,0,3.0],[2,3,0]]) |
|
b = matrix([[0,1],[1,0],[0,2]],'d') |
|
asp = self.spcreator(a) |
|
bsp = self.spcreator(b) |
|
assert_array_almost_equal((asp @ bsp).toarray(), a @ b) |
|
assert_array_almost_equal(asp @ b, a @ b) |
|
assert_array_almost_equal(a @ bsp, a @ b) |
|
assert_array_almost_equal(a2 @ bsp, a @ b) |
|
|
|
|
|
csp = bsp.tocsc() |
|
c = b |
|
want = a @ c |
|
assert_array_almost_equal((asp @ csp).toarray(), want) |
|
assert_array_almost_equal(asp @ c, want) |
|
|
|
assert_array_almost_equal(a @ csp, want) |
|
assert_array_almost_equal(a2 @ csp, want) |
|
csp = bsp.tocsr() |
|
assert_array_almost_equal((asp @ csp).toarray(), want) |
|
assert_array_almost_equal(asp @ c, want) |
|
|
|
assert_array_almost_equal(a @ csp, want) |
|
assert_array_almost_equal(a2 @ csp, want) |
|
csp = bsp.tocoo() |
|
assert_array_almost_equal((asp @ csp).toarray(), want) |
|
assert_array_almost_equal(asp @ c, want) |
|
|
|
assert_array_almost_equal(a @ csp, want) |
|
assert_array_almost_equal(a2 @ csp, want) |
|
|
|
|
|
L = 30 |
|
frac = .3 |
|
random.seed(0) |
|
A = zeros((L,2)) |
|
for i in range(L): |
|
for j in range(2): |
|
r = random.random() |
|
if r < frac: |
|
A[i,j] = r/frac |
|
|
|
A = self.spcreator(A) |
|
B = A @ A.T |
|
assert_array_almost_equal(B.toarray(), A.toarray() @ A.T.toarray()) |
|
assert_array_almost_equal(B.toarray(), A.toarray() @ A.toarray().T) |
|
|
|
|
|
A = self.spcreator([[1,2],[3,4]]) |
|
B = self.spcreator([[1,2],[3,4],[5,6]]) |
|
assert_raises(ValueError, A.__matmul__, B) |
|
if self.is_array_test: |
|
assert_raises(ValueError, A.__mul__, B) |
|
|
|
def test_matmat_dense(self): |
|
a = [[3,0,0],[0,1,0],[2,0,3.0],[2,3,0]] |
|
asp = self.spcreator(a) |
|
|
|
|
|
bs = [array([[1,2],[3,4],[5,6]]), matrix([[1,2],[3,4],[5,6]])] |
|
|
|
for b in bs: |
|
result = asp @ b |
|
assert_(isinstance(result, ndarray if self.is_array_test else type(b))) |
|
assert_equal(result.shape, (4,2)) |
|
assert_equal(result, dot(a,b)) |
|
|
|
def test_sparse_format_conversions(self): |
|
A = sparse.kron([[1,0,2],[0,3,4],[5,0,0]], [[1,2],[0,3]]) |
|
D = A.toarray() |
|
A = self.spcreator(A) |
|
|
|
for format in ['bsr','coo','csc','csr','dia','dok','lil']: |
|
a = A.asformat(format) |
|
assert_equal(a.format,format) |
|
assert_array_equal(a.toarray(), D) |
|
|
|
b = self.spcreator(D+3j).asformat(format) |
|
assert_equal(b.format,format) |
|
assert_array_equal(b.toarray(), D+3j) |
|
|
|
c = self.spcreator(D).asformat(format) |
|
assert_equal(c.format,format) |
|
assert_array_equal(c.toarray(), D) |
|
|
|
for format in ['array', 'dense']: |
|
a = A.asformat(format) |
|
assert_array_equal(a, D) |
|
|
|
b = self.spcreator(D+3j).asformat(format) |
|
assert_array_equal(b, D+3j) |
|
|
|
def test_tobsr(self): |
|
x = array([[1,0,2,0],[0,0,0,0],[0,0,4,5]]) |
|
y = array([[0,1,2],[3,0,5]]) |
|
A = kron(x,y) |
|
Asp = self.spcreator(A) |
|
for format in ['bsr']: |
|
fn = getattr(Asp, 'to' + format) |
|
|
|
for X in [1, 2, 3, 6]: |
|
for Y in [1, 2, 3, 4, 6, 12]: |
|
assert_equal(fn(blocksize=(X, Y)).toarray(), A) |
|
|
|
def test_transpose(self): |
|
dat_1 = self.dat |
|
dat_2 = np.array([[]]) |
|
matrices = [dat_1, dat_2] |
|
|
|
def check(dtype, j): |
|
dat = array(matrices[j], dtype=dtype) |
|
datsp = self.spcreator(dat) |
|
|
|
a = datsp.transpose() |
|
b = dat.transpose() |
|
|
|
assert_array_equal(a.toarray(), b) |
|
assert_array_equal(a.transpose().toarray(), dat) |
|
assert_array_equal(datsp.transpose(axes=(1, 0)).toarray(), b) |
|
assert_equal(a.dtype, b.dtype) |
|
|
|
|
|
empty = self.spcreator((3, 4)) |
|
assert_array_equal(np.transpose(empty).toarray(), |
|
np.transpose(zeros((3, 4)))) |
|
assert_array_equal(empty.T.toarray(), zeros((4, 3))) |
|
assert_raises(ValueError, empty.transpose, axes=0) |
|
|
|
for dtype in self.checked_dtypes: |
|
for j in range(len(matrices)): |
|
check(dtype, j) |
|
|
|
def test_add_dense(self): |
|
def check(dtype): |
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
|
|
|
|
sum1 = dat + datsp |
|
assert_array_equal(sum1, dat + dat) |
|
sum2 = datsp + dat |
|
assert_array_equal(sum2, dat + dat) |
|
|
|
for dtype in self.math_dtypes: |
|
check(dtype) |
|
|
|
def test_sub_dense(self): |
|
|
|
def check(dtype): |
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
|
|
|
|
if dat.dtype == bool: |
|
sum1 = dat - datsp |
|
assert_array_equal(sum1, dat - dat) |
|
sum2 = datsp - dat |
|
assert_array_equal(sum2, dat - dat) |
|
else: |
|
|
|
|
|
sum1 = (dat + dat + dat) - datsp |
|
assert_array_equal(sum1, dat + dat) |
|
sum2 = (datsp + datsp + datsp) - dat |
|
assert_array_equal(sum2, dat + dat) |
|
|
|
for dtype in self.math_dtypes: |
|
if dtype == np.dtype('bool'): |
|
|
|
continue |
|
|
|
check(dtype) |
|
|
|
def test_maximum_minimum(self): |
|
A_dense = np.array([[1, 0, 3], [0, 4, 5], [0, 0, 0]]) |
|
B_dense = np.array([[1, 1, 2], [0, 3, 6], [1, -1, 0]]) |
|
|
|
A_dense_cpx = np.array([[1, 0, 3], [0, 4+2j, 5], [0, 1j, -1j]]) |
|
|
|
def check(dtype, dtype2, btype): |
|
if np.issubdtype(dtype, np.complexfloating): |
|
A = self.spcreator(A_dense_cpx.astype(dtype)) |
|
else: |
|
A = self.spcreator(A_dense.astype(dtype)) |
|
if btype == 'scalar': |
|
B = dtype2.type(1) |
|
elif btype == 'scalar2': |
|
B = dtype2.type(-1) |
|
elif btype == 'dense': |
|
B = B_dense.astype(dtype2) |
|
elif btype == 'sparse': |
|
B = self.spcreator(B_dense.astype(dtype2)) |
|
else: |
|
raise ValueError() |
|
|
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, |
|
"Taking maximum .minimum. with > 0 .< 0. number " |
|
"results to a dense matrix") |
|
|
|
max_s = A.maximum(B) |
|
min_s = A.minimum(B) |
|
|
|
max_d = np.maximum(toarray(A), toarray(B)) |
|
assert_array_equal(toarray(max_s), max_d) |
|
assert_equal(max_s.dtype, max_d.dtype) |
|
|
|
min_d = np.minimum(toarray(A), toarray(B)) |
|
assert_array_equal(toarray(min_s), min_d) |
|
assert_equal(min_s.dtype, min_d.dtype) |
|
|
|
for dtype in self.math_dtypes: |
|
for dtype2 in [np.int8, np.float64, np.complex128]: |
|
for btype in ['scalar', 'scalar2', 'dense', 'sparse']: |
|
check(np.dtype(dtype), np.dtype(dtype2), btype) |
|
|
|
def test_copy(self): |
|
|
|
A = self.datsp |
|
|
|
|
|
assert_equal(A.copy().format, A.format) |
|
assert_equal(A.__class__(A,copy=True).format, A.format) |
|
assert_equal(A.__class__(A,copy=False).format, A.format) |
|
|
|
assert_equal(A.copy().toarray(), A.toarray()) |
|
assert_equal(A.__class__(A, copy=True).toarray(), A.toarray()) |
|
assert_equal(A.__class__(A, copy=False).toarray(), A.toarray()) |
|
|
|
|
|
toself = getattr(A,'to' + A.format) |
|
assert_(toself() is A) |
|
assert_(toself(copy=False) is A) |
|
assert_equal(toself(copy=True).format, A.format) |
|
assert_equal(toself(copy=True).toarray(), A.toarray()) |
|
|
|
|
|
assert_(not sparse_may_share_memory(A.copy(), A)) |
|
|
|
|
|
def test_iterator(self): |
|
B = self.asdense(np.arange(50).reshape(5, 10)) |
|
A = self.spcreator(B) |
|
|
|
for x, y in zip(A, B): |
|
assert_equal(x.toarray(), y) |
|
|
|
def test_size_zero_matrix_arithmetic(self): |
|
|
|
|
|
mat = array([]) |
|
a = mat.reshape((0, 0)) |
|
b = mat.reshape((0, 1)) |
|
c = mat.reshape((0, 5)) |
|
d = mat.reshape((1, 0)) |
|
e = mat.reshape((5, 0)) |
|
f = np.ones([5, 5]) |
|
|
|
asp = self.spcreator(a) |
|
bsp = self.spcreator(b) |
|
csp = self.spcreator(c) |
|
dsp = self.spcreator(d) |
|
esp = self.spcreator(e) |
|
fsp = self.spcreator(f) |
|
|
|
|
|
assert_array_equal(asp.dot(asp).toarray(), np.dot(a, a)) |
|
assert_array_equal(bsp.dot(dsp).toarray(), np.dot(b, d)) |
|
assert_array_equal(dsp.dot(bsp).toarray(), np.dot(d, b)) |
|
assert_array_equal(csp.dot(esp).toarray(), np.dot(c, e)) |
|
assert_array_equal(csp.dot(fsp).toarray(), np.dot(c, f)) |
|
assert_array_equal(esp.dot(csp).toarray(), np.dot(e, c)) |
|
assert_array_equal(dsp.dot(csp).toarray(), np.dot(d, c)) |
|
assert_array_equal(fsp.dot(esp).toarray(), np.dot(f, e)) |
|
|
|
|
|
assert_raises(ValueError, dsp.dot, e) |
|
assert_raises(ValueError, asp.dot, d) |
|
|
|
|
|
assert_array_equal(asp.multiply(asp).toarray(), np.multiply(a, a)) |
|
assert_array_equal(bsp.multiply(bsp).toarray(), np.multiply(b, b)) |
|
assert_array_equal(dsp.multiply(dsp).toarray(), np.multiply(d, d)) |
|
|
|
assert_array_equal(asp.multiply(a).toarray(), np.multiply(a, a)) |
|
assert_array_equal(bsp.multiply(b).toarray(), np.multiply(b, b)) |
|
assert_array_equal(dsp.multiply(d).toarray(), np.multiply(d, d)) |
|
|
|
assert_array_equal(asp.multiply(6).toarray(), np.multiply(a, 6)) |
|
assert_array_equal(bsp.multiply(6).toarray(), np.multiply(b, 6)) |
|
assert_array_equal(dsp.multiply(6).toarray(), np.multiply(d, 6)) |
|
|
|
|
|
assert_raises(ValueError, asp.multiply, c) |
|
assert_raises(ValueError, esp.multiply, c) |
|
|
|
|
|
assert_array_equal(asp.__add__(asp).toarray(), a.__add__(a)) |
|
assert_array_equal(bsp.__add__(bsp).toarray(), b.__add__(b)) |
|
assert_array_equal(dsp.__add__(dsp).toarray(), d.__add__(d)) |
|
|
|
|
|
assert_raises(ValueError, asp.__add__, dsp) |
|
assert_raises(ValueError, bsp.__add__, asp) |
|
|
|
def test_size_zero_conversions(self): |
|
mat = array([]) |
|
a = mat.reshape((0, 0)) |
|
b = mat.reshape((0, 5)) |
|
c = mat.reshape((5, 0)) |
|
|
|
for m in [a, b, c]: |
|
spm = self.spcreator(m) |
|
assert_array_equal(spm.tocoo().toarray(), m) |
|
assert_array_equal(spm.tocsr().toarray(), m) |
|
assert_array_equal(spm.tocsc().toarray(), m) |
|
assert_array_equal(spm.tolil().toarray(), m) |
|
assert_array_equal(spm.todok().toarray(), m) |
|
assert_array_equal(spm.tobsr().toarray(), m) |
|
|
|
def test_dtype_check(self): |
|
a = np.array([[3.5, 0, 1.1], [0, 0, 0]], dtype=np.float16) |
|
with assert_raises(ValueError, match="does not support dtype"): |
|
self.spcreator(a) |
|
|
|
A32 = self.spcreator(a.astype(np.float32)) |
|
with assert_raises(ValueError, match="does not support dtype"): |
|
self.spcreator(A32, dtype=np.float16) |
|
|
|
def test_pickle(self): |
|
import pickle |
|
sup = suppress_warnings() |
|
sup.filter(SparseEfficiencyWarning) |
|
|
|
@sup |
|
def check(): |
|
datsp = self.datsp.copy() |
|
for protocol in range(pickle.HIGHEST_PROTOCOL): |
|
sploaded = pickle.loads(pickle.dumps(datsp, protocol=protocol)) |
|
assert_equal(datsp.shape, sploaded.shape) |
|
assert_array_equal(datsp.toarray(), sploaded.toarray()) |
|
assert_equal(datsp.format, sploaded.format) |
|
|
|
|
|
|
|
|
|
|
|
for key, val in datsp.__dict__.items(): |
|
if isinstance(val, np.ndarray): |
|
assert_array_equal(val, sploaded.__dict__[key]) |
|
elif (isinstance(val, tuple) and val |
|
and isinstance(val[0], np.ndarray)): |
|
assert_array_equal(val, sploaded.__dict__[key]) |
|
else: |
|
assert_(val == sploaded.__dict__[key]) |
|
check() |
|
|
|
def test_unary_ufunc_overrides(self): |
|
def check(name): |
|
if name == "sign": |
|
pytest.skip("sign conflicts with comparison op " |
|
"support on Numpy") |
|
if self.datsp.format in ["dok", "lil"]: |
|
pytest.skip("Unary ops not implemented for dok/lil") |
|
ufunc = getattr(np, name) |
|
|
|
X = self.spcreator(np.arange(20).reshape(4, 5) / 20.) |
|
X0 = ufunc(X.toarray()) |
|
|
|
X2 = ufunc(X) |
|
assert_array_equal(X2.toarray(), X0) |
|
|
|
for name in ["sin", "tan", "arcsin", "arctan", "sinh", "tanh", |
|
"arcsinh", "arctanh", "rint", "sign", "expm1", "log1p", |
|
"deg2rad", "rad2deg", "floor", "ceil", "trunc", "sqrt", |
|
"abs"]: |
|
check(name) |
|
|
|
def test_resize(self): |
|
|
|
D = np.array([[1, 0, 3, 4], |
|
[2, 0, 0, 0], |
|
[3, 0, 0, 0]]) |
|
S = self.spcreator(D) |
|
assert_(S.resize((3, 2)) is None) |
|
assert_array_equal(S.toarray(), [[1, 0], |
|
[2, 0], |
|
[3, 0]]) |
|
S.resize((2, 2)) |
|
assert_array_equal(S.toarray(), [[1, 0], |
|
[2, 0]]) |
|
S.resize((3, 2)) |
|
assert_array_equal(S.toarray(), [[1, 0], |
|
[2, 0], |
|
[0, 0]]) |
|
S.resize((3, 3)) |
|
assert_array_equal(S.toarray(), [[1, 0, 0], |
|
[2, 0, 0], |
|
[0, 0, 0]]) |
|
|
|
S.resize((3, 3)) |
|
assert_array_equal(S.toarray(), [[1, 0, 0], |
|
[2, 0, 0], |
|
[0, 0, 0]]) |
|
|
|
|
|
S.resize(3, 2) |
|
assert_array_equal(S.toarray(), [[1, 0], |
|
[2, 0], |
|
[0, 0]]) |
|
|
|
if self.is_array_test and S.format in ["coo", "csr"]: |
|
S.resize(1) |
|
else: |
|
assert_raises((ValueError, NotImplementedError, IndexError), S.resize, 1) |
|
|
|
for bad_shape in [(-1, 2), (2, -1), (1, 2, 3)]: |
|
assert_raises(ValueError, S.resize, bad_shape) |
|
|
|
def test_constructor1_base(self): |
|
A = self.datsp |
|
|
|
self_format = A.format |
|
|
|
C = A.__class__(A, copy=False) |
|
assert_array_equal_dtype(A.toarray(), C.toarray()) |
|
if self_format not in NON_ARRAY_BACKED_FORMATS: |
|
assert_(sparse_may_share_memory(A, C)) |
|
|
|
C = A.__class__(A, dtype=A.dtype, copy=False) |
|
assert_array_equal_dtype(A.toarray(), C.toarray()) |
|
if self_format not in NON_ARRAY_BACKED_FORMATS: |
|
assert_(sparse_may_share_memory(A, C)) |
|
|
|
C = A.__class__(A, dtype=np.float32, copy=False) |
|
assert_array_equal(A.toarray(), C.toarray()) |
|
|
|
C = A.__class__(A, copy=True) |
|
assert_array_equal_dtype(A.toarray(), C.toarray()) |
|
assert_(not sparse_may_share_memory(A, C)) |
|
|
|
for other_format in ['csr', 'csc', 'coo', 'dia', 'dok', 'lil']: |
|
if other_format == self_format: |
|
continue |
|
B = A.asformat(other_format) |
|
C = A.__class__(B, copy=False) |
|
assert_array_equal_dtype(A.toarray(), C.toarray()) |
|
|
|
C = A.__class__(B, copy=True) |
|
assert_array_equal_dtype(A.toarray(), C.toarray()) |
|
assert_(not sparse_may_share_memory(B, C)) |
|
|
|
|
|
class _TestInplaceArithmetic: |
|
def test_inplace_dense(self): |
|
a = np.ones((3, 4)) |
|
b = self.spcreator(a) |
|
|
|
x = a.copy() |
|
y = a.copy() |
|
x += a |
|
y += b |
|
assert_array_equal(x, y) |
|
|
|
x = a.copy() |
|
y = a.copy() |
|
x -= a |
|
y -= b |
|
assert_array_equal(x, y) |
|
|
|
if self.is_array_test: |
|
|
|
x = a.copy() |
|
y = a.copy() |
|
with assert_raises(ValueError, match="inconsistent shapes"): |
|
x *= b.T |
|
x = x * a |
|
y *= b |
|
assert_array_equal(x, y.toarray()) |
|
else: |
|
|
|
x = a.copy() |
|
y = a.copy() |
|
with assert_raises(ValueError, match="dimension mismatch"): |
|
x *= b |
|
x = x.dot(a.T) |
|
y *= b.T |
|
assert_array_equal(x, y) |
|
|
|
|
|
y = a.copy() |
|
|
|
|
|
try: |
|
y @= b.T |
|
except TypeError: |
|
pass |
|
else: |
|
x = a.copy() |
|
y = a.copy() |
|
with assert_raises(ValueError, match="dimension mismatch"): |
|
x @= b |
|
x = x.dot(a.T) |
|
y @= b.T |
|
assert_array_equal(x, y) |
|
|
|
|
|
with assert_raises(TypeError, match="unsupported operand"): |
|
x //= b |
|
|
|
def test_imul_scalar(self): |
|
def check(dtype): |
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
|
|
|
|
if np.can_cast(int, dtype, casting='same_kind'): |
|
a = datsp.copy() |
|
a *= 2 |
|
b = dat.copy() |
|
b *= 2 |
|
assert_array_equal(b, a.toarray()) |
|
|
|
if np.can_cast(float, dtype, casting='same_kind'): |
|
a = datsp.copy() |
|
a *= 17.3 |
|
b = dat.copy() |
|
b *= 17.3 |
|
assert_array_equal(b, a.toarray()) |
|
|
|
for dtype in self.math_dtypes: |
|
check(dtype) |
|
|
|
def test_idiv_scalar(self): |
|
def check(dtype): |
|
dat = self.dat_dtypes[dtype] |
|
datsp = self.datsp_dtypes[dtype] |
|
|
|
if np.can_cast(int, dtype, casting='same_kind'): |
|
a = datsp.copy() |
|
a /= 2 |
|
b = dat.copy() |
|
b /= 2 |
|
assert_array_equal(b, a.toarray()) |
|
|
|
if np.can_cast(float, dtype, casting='same_kind'): |
|
a = datsp.copy() |
|
a /= 17.3 |
|
b = dat.copy() |
|
b /= 17.3 |
|
assert_array_equal(b, a.toarray()) |
|
|
|
for dtype in self.math_dtypes: |
|
|
|
|
|
if not np.can_cast(dtype, np.dtype(int)): |
|
check(dtype) |
|
|
|
def test_inplace_success(self): |
|
|
|
|
|
a = self.spcreator(np.eye(5)) |
|
b = self.spcreator(np.eye(5)) |
|
bp = self.spcreator(np.eye(5)) |
|
|
|
b += a |
|
bp = bp + a |
|
assert_allclose(b.toarray(), bp.toarray()) |
|
|
|
if self.is_array_test: |
|
b *= a |
|
bp = bp * a |
|
assert_allclose(b.toarray(), bp.toarray()) |
|
|
|
b @= a |
|
bp = bp @ a |
|
assert_allclose(b.toarray(), bp.toarray()) |
|
|
|
b -= a |
|
bp = bp - a |
|
assert_allclose(b.toarray(), bp.toarray()) |
|
|
|
with assert_raises(TypeError, match="unsupported operand"): |
|
a //= b |
|
|
|
|
|
class _TestGetSet: |
|
def test_getelement(self): |
|
def check(dtype): |
|
D = array([[1,0,0], |
|
[4,3,0], |
|
[0,2,0], |
|
[0,0,0]], dtype=dtype) |
|
A = self.spcreator(D) |
|
|
|
M,N = D.shape |
|
|
|
for i in range(-M, M): |
|
for j in range(-N, N): |
|
assert_equal(A[i,j], D[i,j]) |
|
|
|
assert_equal(type(A[1,1]), dtype) |
|
|
|
for ij in [(0,3),(-1,3),(4,0),(4,3),(4,-1), (1, 2, 3)]: |
|
assert_raises((IndexError, TypeError), A.__getitem__, ij) |
|
|
|
for dtype in supported_dtypes: |
|
check(np.dtype(dtype)) |
|
|
|
def test_setelement(self): |
|
def check(dtype): |
|
A = self.spcreator((3,4), dtype=dtype) |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
A[0, 0] = dtype.type(0) |
|
A[1, 2] = dtype.type(4.0) |
|
A[0, 1] = dtype.type(3) |
|
A[2, 0] = dtype.type(2.0) |
|
A[0,-1] = dtype.type(8) |
|
A[-1,-2] = dtype.type(7) |
|
A[0, 1] = dtype.type(5) |
|
|
|
if dtype != np.bool_: |
|
assert_array_equal( |
|
A.toarray(), |
|
[ |
|
[0, 5, 0, 8], |
|
[0, 0, 4, 0], |
|
[2, 0, 7, 0] |
|
] |
|
) |
|
|
|
for ij in [(0,4),(-1,4),(3,0),(3,4),(3,-1)]: |
|
assert_raises(IndexError, A.__setitem__, ij, 123.0) |
|
|
|
for v in [[1,2,3], array([1,2,3])]: |
|
assert_raises(ValueError, A.__setitem__, (0,0), v) |
|
|
|
if (not np.issubdtype(dtype, np.complexfloating) and |
|
dtype != np.bool_): |
|
for v in [3j]: |
|
assert_raises(TypeError, A.__setitem__, (0,0), v) |
|
|
|
for dtype in supported_dtypes: |
|
check(np.dtype(dtype)) |
|
|
|
def test_negative_index_assignment(self): |
|
|
|
|
|
def check(dtype): |
|
A = self.spcreator((3, 10), dtype=dtype) |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
A[0, -4] = 1 |
|
assert_equal(A[0, -4], 1) |
|
|
|
for dtype in self.math_dtypes: |
|
check(np.dtype(dtype)) |
|
|
|
def test_scalar_assign_2(self): |
|
n, m = (5, 10) |
|
|
|
def _test_set(i, j, nitems): |
|
msg = f"{i!r} ; {j!r} ; {nitems!r}" |
|
A = self.spcreator((n, m)) |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
A[i, j] = 1 |
|
assert_almost_equal(A.sum(), nitems, err_msg=msg) |
|
assert_almost_equal(A[i, j], 1, err_msg=msg) |
|
|
|
|
|
for i, j in [(2, 3), (-1, 8), (-1, -2), (array(-1), -2), (-1, array(-2)), |
|
(array(-1), array(-2))]: |
|
_test_set(i, j, 1) |
|
|
|
def test_index_scalar_assign(self): |
|
A = self.spcreator((5, 5)) |
|
B = np.zeros((5, 5)) |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
for C in [A, B]: |
|
C[0,1] = 1 |
|
C[3,0] = 4 |
|
C[3,0] = 9 |
|
assert_array_equal(A.toarray(), B) |
|
|
|
|
|
@pytest.mark.thread_unsafe |
|
class _TestSolve: |
|
def test_solve(self): |
|
|
|
|
|
n = 20 |
|
np.random.seed(0) |
|
A = zeros((n,n), dtype=complex) |
|
x = np.random.rand(n) |
|
y = np.random.rand(n-1)+1j*np.random.rand(n-1) |
|
r = np.random.rand(n) |
|
for i in range(len(x)): |
|
A[i,i] = x[i] |
|
for i in range(len(y)): |
|
A[i,i+1] = y[i] |
|
A[i+1,i] = conjugate(y[i]) |
|
A = self.spcreator(A) |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, |
|
"splu converted its input to CSC format") |
|
x = splu(A).solve(r) |
|
assert_almost_equal(A @ x,r) |
|
|
|
|
|
class _TestSlicing: |
|
def test_dtype_preservation(self): |
|
assert_equal(self.spcreator((1,10), dtype=np.int16)[0,1:5].dtype, np.int16) |
|
assert_equal(self.spcreator((1,10), dtype=np.int32)[0,1:5].dtype, np.int32) |
|
assert_equal(self.spcreator((1,10), dtype=np.float32)[0,1:5].dtype, np.float32) |
|
assert_equal(self.spcreator((1,10), dtype=np.float64)[0,1:5].dtype, np.float64) |
|
|
|
def test_dtype_preservation_empty_slice(self): |
|
|
|
|
|
for dt in [np.int16, np.int32, np.float32, np.float64]: |
|
A = self.spcreator((3, 2), dtype=dt) |
|
assert_equal(A[:, 0:0:2].dtype, dt) |
|
assert_equal(A[0:0:2, :].dtype, dt) |
|
assert_equal(A[0, 0:0:2].dtype, dt) |
|
assert_equal(A[0:0:2, 0].dtype, dt) |
|
|
|
def test_get_horiz_slice(self): |
|
B = self.asdense(arange(50.).reshape(5,10)) |
|
A = self.spcreator(B) |
|
r0, r1, r2 = (0, 1, 2) if self.is_array_test else ([0], [1], [2]) |
|
assert_array_equal(B[r1, :], A[1, :].toarray()) |
|
assert_array_equal(B[r1, 2:5], A[1, 2:5].toarray()) |
|
|
|
C = self.asdense([[1, 2, 1], [4, 0, 6], [0, 0, 0], [0, 0, 1]]) |
|
D = self.spcreator(C) |
|
assert_array_equal(C[r1, 1:3], D[1, 1:3].toarray()) |
|
|
|
|
|
E = self.asdense([[1, 2, 1], [4, 0, 0], [0, 0, 0], [0, 0, 1]]) |
|
F = self.spcreator(E) |
|
assert_array_equal(E[r1, 1:3], F[1, 1:3].toarray()) |
|
assert_array_equal(E[r2, -2:], F[2, -2:].toarray()) |
|
|
|
|
|
assert_raises(IndexError, A.__getitem__, (slice(None), 11)) |
|
assert_raises(IndexError, A.__getitem__, (6, slice(3, 7))) |
|
|
|
def test_get_vert_slice(self): |
|
B = arange(50.).reshape(5, 10) |
|
A = self.spcreator(B) |
|
c0, c1, c2 = (0, 1, 2) if self.is_array_test else ([0], [1], [2]) |
|
assert_array_equal(B[2:5, c0], A[2:5, 0].toarray()) |
|
assert_array_equal(B[:, c1], A[:, 1].toarray()) |
|
|
|
C = array([[1, 2, 1], [4, 0, 6], [0, 0, 0], [0, 0, 1]]) |
|
D = self.spcreator(C) |
|
assert_array_equal(C[1:3, c1], D[1:3, 1].toarray()) |
|
assert_array_equal(C[:, c2], D[:, 2].toarray()) |
|
|
|
|
|
E = array([[1, 0, 1], [4, 0, 0], [0, 0, 0], [0, 0, 1]]) |
|
F = self.spcreator(E) |
|
assert_array_equal(E[:, c1], F[:, 1].toarray()) |
|
assert_array_equal(E[-2:, c2], F[-2:, 2].toarray()) |
|
|
|
|
|
assert_raises(IndexError, A.__getitem__, (slice(None), 11)) |
|
assert_raises(IndexError, A.__getitem__, (6, slice(3, 7))) |
|
|
|
def test_get_slices(self): |
|
B = arange(50.).reshape(5, 10) |
|
A = self.spcreator(B) |
|
assert_array_equal(A[2:5, 0:3].toarray(), B[2:5, 0:3]) |
|
assert_array_equal(A[1:, :-1].toarray(), B[1:, :-1]) |
|
assert_array_equal(A[:-1, 1:].toarray(), B[:-1, 1:]) |
|
|
|
|
|
E = array([[1, 0, 1], [4, 0, 0], [0, 0, 0], [0, 0, 1]]) |
|
F = self.spcreator(E) |
|
assert_array_equal(E[1:2, 1:2], F[1:2, 1:2].toarray()) |
|
assert_array_equal(E[:, 1:], F[:, 1:].toarray()) |
|
|
|
def test_non_unit_stride_2d_indexing(self): |
|
|
|
v0 = np.random.rand(50, 50) |
|
try: |
|
v = self.spcreator(v0)[0:25:2, 2:30:3] |
|
except ValueError: |
|
|
|
raise pytest.skip("feature not implemented") |
|
|
|
assert_array_equal(v.toarray(), v0[0:25:2, 2:30:3]) |
|
|
|
def test_slicing_2(self): |
|
B = self.asdense(arange(50).reshape(5,10)) |
|
A = self.spcreator(B) |
|
|
|
|
|
assert_equal(A[2,3], B[2,3]) |
|
assert_equal(A[-1,8], B[-1,8]) |
|
assert_equal(A[-1,-2],B[-1,-2]) |
|
assert_equal(A[array(-1),-2],B[-1,-2]) |
|
assert_equal(A[-1,array(-2)],B[-1,-2]) |
|
assert_equal(A[array(-1),array(-2)],B[-1,-2]) |
|
|
|
|
|
assert_equal(A[2, :].toarray(), B[2, :]) |
|
assert_equal(A[2, 5:-2].toarray(), B[2, 5:-2]) |
|
assert_equal(A[array(2), 5:-2].toarray(), B[2, 5:-2]) |
|
|
|
|
|
assert_equal(A[:, 2].toarray(), B[:, 2]) |
|
assert_equal(A[3:4, 9].toarray(), B[3:4, 9]) |
|
assert_equal(A[1:4, -5].toarray(), B[1:4, -5]) |
|
assert_equal(A[2:-1, 3].toarray(), B[2:-1, 3]) |
|
assert_equal(A[2:-1, array(3)].toarray(), B[2:-1, 3]) |
|
|
|
|
|
assert_equal(A[1:2, 1:2].toarray(), B[1:2, 1:2]) |
|
assert_equal(A[4:, 3:].toarray(), B[4:, 3:]) |
|
assert_equal(A[:4, :5].toarray(), B[:4, :5]) |
|
assert_equal(A[2:-1, :5].toarray(), B[2:-1, :5]) |
|
|
|
|
|
assert_equal(A[1, :].toarray(), B[1, :]) |
|
assert_equal(A[-2, :].toarray(), B[-2, :]) |
|
assert_equal(A[array(-2), :].toarray(), B[-2, :]) |
|
|
|
|
|
assert_equal(A[1:4].toarray(), B[1:4]) |
|
assert_equal(A[1:-2].toarray(), B[1:-2]) |
|
|
|
|
|
|
|
s = slice(int8(2),int8(4),None) |
|
assert_equal(A[s, :].toarray(), B[2:4, :]) |
|
assert_equal(A[:, s].toarray(), B[:, 2:4]) |
|
|
|
@pytest.mark.fail_slow(2) |
|
def test_slicing_3(self): |
|
B = self.asdense(arange(50).reshape(5,10)) |
|
A = self.spcreator(B) |
|
|
|
s_ = np.s_ |
|
slices = [s_[:2], s_[1:2], s_[3:], s_[3::2], |
|
s_[15:20], s_[3:2], |
|
s_[8:3:-1], s_[4::-2], s_[:5:-1], |
|
0, 1, s_[:], s_[1:5], -1, -2, -5, |
|
array(-1), np.int8(-3)] |
|
|
|
def check_1(a): |
|
x = A[a] |
|
y = B[a] |
|
if y.shape == (): |
|
assert_equal(x, y, repr(a)) |
|
else: |
|
if x.size == 0 and y.size == 0: |
|
pass |
|
else: |
|
assert_array_equal(x.toarray(), y, repr(a)) |
|
|
|
for j, a in enumerate(slices): |
|
check_1(a) |
|
|
|
def check_2(a, b): |
|
|
|
|
|
|
|
if isinstance(a, np.ndarray): |
|
ai = int(a) |
|
else: |
|
ai = a |
|
if isinstance(b, np.ndarray): |
|
bi = int(b) |
|
else: |
|
bi = b |
|
|
|
x = A[a, b] |
|
y = B[ai, bi] |
|
|
|
if y.shape == (): |
|
assert_equal(x, y, repr((a, b))) |
|
else: |
|
if x.size == 0 and y.size == 0: |
|
pass |
|
else: |
|
assert_array_equal(x.toarray(), y, repr((a, b))) |
|
|
|
for i, a in enumerate(slices): |
|
for j, b in enumerate(slices): |
|
check_2(a, b) |
|
|
|
|
|
extra_slices = [] |
|
for a, b, c in itertools.product(*([(None, 0, 1, 2, 5, 15, |
|
-1, -2, 5, -15)]*3)): |
|
if c == 0: |
|
continue |
|
extra_slices.append(slice(a, b, c)) |
|
|
|
for a in extra_slices: |
|
check_2(a, a) |
|
check_2(a, -2) |
|
check_2(-2, a) |
|
|
|
def test_None_slicing(self): |
|
B = self.asdense(arange(50).reshape(5,10)) |
|
A = self.spcreator(B) |
|
|
|
assert A[1, 2].ndim == 0 |
|
assert A[None, 1, 2:4].shape == (1, 2) |
|
assert A[None, 1, 2, None].shape == (1, 1) |
|
|
|
|
|
assert A[None, 1].shape == (1, 10) |
|
assert A[1, None].shape == (1, 10) |
|
assert A[None, 1, :].shape == (1, 10) |
|
assert A[1, None, :].shape == (1, 10) |
|
assert A[1, :, None].shape == (10, 1) |
|
|
|
assert A[None, 1:3, 2].shape == B[None, 1:3, 2].shape == (1, 2) |
|
assert A[1:3, None, 2].shape == B[1:3, None, 2].shape == (2, 1) |
|
assert A[1:3, 2, None].shape == B[1:3, 2, None].shape == (2, 1) |
|
assert A[None, 1, 2:4].shape == B[None, 1, 2:4].shape == (1, 2) |
|
assert A[1, None, 2:4].shape == B[1, None, 2:4].shape == (1, 2) |
|
assert A[1, 2:4, None].shape == B[1, 2:4, None].shape == (2, 1) |
|
|
|
|
|
if self.is_array_test: |
|
assert A[1:3, 2].shape == B[1:3, 2].shape == (2,) |
|
assert A[1, 2:4].shape == B[1, 2:4].shape == (2,) |
|
assert A[None, 1, 2].shape == B[None, 1, 2].shape == (1,) |
|
assert A[1, None, 2].shape == B[1, None, 2].shape == (1,) |
|
assert A[1, 2, None].shape == B[1, 2, None].shape == (1,) |
|
else: |
|
assert A[1, 2:4].shape == B[1, 2:4].shape == (1, 2) |
|
assert A[1:3, 2].shape == B[1:3, 2].shape == (2, 1) |
|
assert A[None, 1, 2].shape == B[None, 1, 2].shape == (1, 1) |
|
assert A[1, None, 2].shape == B[1, None, 2].shape == (1, 1) |
|
assert A[1, 2, None].shape == B[1, 2, None].shape == (1, 1) |
|
|
|
def test_ellipsis_slicing(self): |
|
b = self.asdense(arange(50).reshape(5,10)) |
|
a = self.spcreator(b) |
|
|
|
assert_array_equal(a[...].toarray(), b[...]) |
|
assert_array_equal(a[...,].toarray(), b[...,]) |
|
|
|
assert_array_equal(a[4, ...].toarray(), b[4, ...]) |
|
assert_array_equal(a[..., 4].toarray(), b[..., 4]) |
|
assert_array_equal(a[..., 5].toarray(), b[..., 5]) |
|
with pytest.raises(IndexError, match='index .5. out of range'): |
|
a[5, ...] |
|
with pytest.raises(IndexError, match='index .10. out of range'): |
|
a[..., 10] |
|
with pytest.raises(IndexError, match='index .5. out of range'): |
|
a.T[..., 5] |
|
|
|
assert_array_equal(a[1:, ...].toarray(), b[1:, ...]) |
|
assert_array_equal(a[..., 1:].toarray(), b[..., 1:]) |
|
assert_array_equal(a[:2, ...].toarray(), b[:2, ...]) |
|
assert_array_equal(a[..., :2].toarray(), b[..., :2]) |
|
|
|
|
|
assert_array_equal(a[:5, ...].toarray(), b[:5, ...]) |
|
assert_array_equal(a[..., :5].toarray(), b[..., :5]) |
|
assert_array_equal(a[5:, ...].toarray(), b[5:, ...]) |
|
assert_array_equal(a[..., 5:].toarray(), b[..., 5:]) |
|
assert_array_equal(a[10:, ...].toarray(), b[10:, ...]) |
|
assert_array_equal(a[..., 10:].toarray(), b[..., 10:]) |
|
|
|
|
|
assert_array_equal(a[1:, 1, ...].toarray(), b[1:, 1, ...]) |
|
assert_array_equal(a[1, ..., 1:].toarray(), b[1, ..., 1:]) |
|
assert_array_equal(a[..., 1, 1:].toarray(), b[1, ..., 1:]) |
|
assert_array_equal(a[:2, 1, ...].toarray(), b[:2, 1, ...]) |
|
assert_array_equal(a[1, ..., :2].toarray(), b[1, ..., :2]) |
|
assert_array_equal(a[..., 1, :2].toarray(), b[1, ..., :2]) |
|
|
|
assert_equal(a[1, 1, ...], b[1, 1, ...]) |
|
assert_equal(a[1, ..., 1], b[1, ..., 1]) |
|
|
|
def test_ellipsis_fancy_bool(self): |
|
numpy_a = self.asdense(arange(50).reshape(5, 10)) |
|
a = self.spcreator(numpy_a) |
|
|
|
ix5 = [True, False, True, False, True] |
|
ix10 = [False] * 5 + ix5 |
|
ix10_6True = ix5 + ix5 |
|
full_ix = [ix10] * 5 |
|
|
|
assert_array_equal(toarray(a[full_ix, ...]), numpy_a[full_ix, ...]) |
|
assert_array_equal(toarray(a[..., full_ix]), numpy_a[..., full_ix]) |
|
|
|
assert_array_equal(toarray(a[ix5, ...]), numpy_a[ix5, ...]) |
|
assert_array_equal(toarray(a[..., ix10]), numpy_a[..., ix10]) |
|
|
|
assert_array_equal(toarray(a[ix5, ..., ix10]), numpy_a[ix5, ..., ix10]) |
|
assert_array_equal(toarray(a[..., ix5, ix10]), numpy_a[..., ix5, ix10]) |
|
assert_array_equal(toarray(a[ix5, ix10, ...]), numpy_a[ix5, ix10, ...]) |
|
|
|
with assert_raises(ValueError, match="shape mismatch"): |
|
a[ix5, ix10_6True] |
|
|
|
def test_ellipsis_fancy_slicing(self): |
|
b = self.asdense(arange(50).reshape(5, 10)) |
|
a = self.spcreator(b) |
|
|
|
assert_array_equal(a[[4], ...].toarray(), b[[4], ...]) |
|
assert_array_equal(a[[2, 4], ...].toarray(), b[[2, 4], ...]) |
|
assert_array_equal(a[..., [4]].toarray(), b[..., [4]]) |
|
assert_array_equal(a[..., [2, 4]].toarray(), b[..., [2, 4]]) |
|
|
|
assert_array_equal(a[[4], 1, ...].toarray(), b[[4], 1, ...]) |
|
assert_array_equal(a[[2, 4], 1, ...].toarray(), b[[2, 4], 1, ...]) |
|
assert_array_equal(a[[4], ..., 1].toarray(), b[[4], ..., 1]) |
|
assert_array_equal(a[..., [4], 1].toarray(), b[..., [4], 1]) |
|
|
|
assert_array_equal(toarray(a[[2, 4], ..., [2, 4]]), b[[2, 4], ..., [2, 4]]) |
|
assert_array_equal(toarray(a[..., [2, 4], [2, 4]]), b[..., [2, 4], [2, 4]]) |
|
|
|
def test_multiple_ellipsis_slicing(self): |
|
a = self.spcreator(arange(6).reshape(3, 2)) |
|
|
|
with pytest.raises(IndexError, |
|
match='an index can only have a single ellipsis'): |
|
a[..., ...] |
|
with pytest.raises(IndexError, |
|
match='an index can only have a single ellipsis'): |
|
a[..., 1, ...] |
|
|
|
|
|
class _TestSlicingAssign: |
|
def test_slice_scalar_assign(self): |
|
A = self.spcreator((5, 5)) |
|
B = np.zeros((5, 5)) |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
for C in [A, B]: |
|
C[0:1,1] = 1 |
|
C[3:0,0] = 4 |
|
C[3:4,0] = 9 |
|
C[0,4:] = 1 |
|
C[3::-1,4:] = 9 |
|
assert_array_equal(A.toarray(), B) |
|
|
|
def test_slice_assign_2(self): |
|
n, m = (5, 10) |
|
|
|
def _test_set(i, j): |
|
msg = f"i={i!r}; j={j!r}" |
|
A = self.spcreator((n, m)) |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
A[i, j] = 1 |
|
B = np.zeros((n, m)) |
|
B[i, j] = 1 |
|
assert_array_almost_equal(A.toarray(), B, err_msg=msg) |
|
|
|
for i, j in [(2, slice(3)), (2, slice(None, 10, 4)), (2, slice(5, -2)), |
|
(array(2), slice(5, -2))]: |
|
_test_set(i, j) |
|
|
|
def test_self_self_assignment(self): |
|
|
|
B = self.spcreator((4,3)) |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
B[0,0] = 2 |
|
B[1,2] = 7 |
|
B[2,1] = 3 |
|
B[3,0] = 10 |
|
|
|
A = B / 10 |
|
B[0,:] = A[0,:] |
|
assert_array_equal(A[0,:].toarray(), B[0,:].toarray()) |
|
|
|
A = B / 10 |
|
B[:,:] = A[:1,:1] |
|
assert_array_equal(np.zeros((4,3)) + A[0,0], B.toarray()) |
|
|
|
A = B / 10 |
|
B[:-1,0] = A[None,0,:].T |
|
assert_array_equal(A[0,:].toarray().T, B[:-1,0].toarray()) |
|
|
|
def test_slice_assignment(self): |
|
B = self.spcreator((4,3)) |
|
expected = array([[10,0,0], |
|
[0,0,6], |
|
[0,14,0], |
|
[0,0,0]]) |
|
block = [[1,0],[0,4]] |
|
|
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
B[0,0] = 5 |
|
B[1,2] = 3 |
|
B[2,1] = 7 |
|
B[:,:] = B+B |
|
assert_array_equal(B.toarray(), expected) |
|
|
|
B[:2,:2] = self.csc_container(array(block)) |
|
assert_array_equal(B.toarray()[:2, :2], block) |
|
|
|
def test_sparsity_modifying_assignment(self): |
|
B = self.spcreator((4,3)) |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
B[0,0] = 5 |
|
B[1,2] = 3 |
|
B[2,1] = 7 |
|
B[3,0] = 10 |
|
B[:3] = self.csr_container(np.eye(3)) |
|
|
|
expected = array([[1,0,0],[0,1,0],[0,0,1],[10,0,0]]) |
|
assert_array_equal(B.toarray(), expected) |
|
|
|
def test_set_slice(self): |
|
A = self.spcreator((5,10)) |
|
B = array(zeros((5, 10), float)) |
|
s_ = np.s_ |
|
slices = [s_[:2], s_[1:2], s_[3:], s_[3::2], |
|
s_[8:3:-1], s_[4::-2], s_[:5:-1], |
|
0, 1, s_[:], s_[1:5], -1, -2, -5, |
|
array(-1), np.int8(-3)] |
|
|
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
for j, a in enumerate(slices): |
|
A[a] = j |
|
B[a] = j |
|
assert_array_equal(A.toarray(), B, repr(a)) |
|
|
|
for i, a in enumerate(slices): |
|
for j, b in enumerate(slices): |
|
A[a,b] = 10*i + 1000*(j+1) |
|
B[a,b] = 10*i + 1000*(j+1) |
|
assert_array_equal(A.toarray(), B, repr((a, b))) |
|
|
|
A[0, 1:10:2] = range(1, 10, 2) |
|
B[0, 1:10:2] = range(1, 10, 2) |
|
assert_array_equal(A.toarray(), B) |
|
A[1:5:2, 0] = np.arange(1, 5, 2)[:, None] |
|
B[1:5:2, 0] = np.arange(1, 5, 2)[:] |
|
assert_array_equal(A.toarray(), B) |
|
|
|
|
|
assert_raises(ValueError, A.__setitem__, (0, 0), list(range(100))) |
|
assert_raises(ValueError, A.__setitem__, (0, 0), arange(100)) |
|
assert_raises(ValueError, A.__setitem__, (0, slice(None)), |
|
list(range(100))) |
|
assert_raises(ValueError, A.__setitem__, (slice(None), 1), |
|
list(range(100))) |
|
assert_raises(ValueError, A.__setitem__, (slice(None), 1), A.copy()) |
|
assert_raises(ValueError, A.__setitem__, |
|
([[1, 2, 3], [0, 3, 4]], [1, 2, 3]), [1, 2, 3, 4]) |
|
assert_raises(ValueError, A.__setitem__, |
|
([[1, 2, 3], [0, 3, 4], [4, 1, 3]], |
|
[[1, 2, 4], [0, 1, 3]]), [2, 3, 4]) |
|
assert_raises(ValueError, A.__setitem__, (slice(4), 0), |
|
[[1, 2], [3, 4]]) |
|
|
|
def test_assign_empty(self): |
|
A = self.spcreator(np.ones((2, 3))) |
|
B = self.spcreator((1, 2)) |
|
A[1, :2] = B |
|
assert_array_equal(A.toarray(), [[1, 1, 1], [0, 0, 1]]) |
|
|
|
def test_assign_1d_slice(self): |
|
A = self.spcreator(np.ones((3, 3))) |
|
x = np.zeros(3) |
|
A[:, 0] = x |
|
A[1, :] = x |
|
assert_array_equal(A.toarray(), [[0, 1, 1], [0, 0, 0], [0, 1, 1]]) |
|
|
|
|
|
class _TestFancyIndexing: |
|
"""Tests fancy indexing features. The tests for any matrix formats |
|
that implement these features should derive from this class. |
|
""" |
|
|
|
def test_dtype_preservation_empty_index(self): |
|
|
|
|
|
for dt in [np.int16, np.int32, np.float32, np.float64]: |
|
A = self.spcreator((3, 2), dtype=dt) |
|
assert_equal(A[:, [False, False]].dtype, dt) |
|
assert_equal(A[[False, False, False], :].dtype, dt) |
|
assert_equal(A[:, []].dtype, dt) |
|
assert_equal(A[[], :].dtype, dt) |
|
|
|
def test_bad_index(self): |
|
A = self.spcreator(np.zeros([5, 5])) |
|
assert_raises((IndexError, ValueError, TypeError), A.__getitem__, "foo") |
|
assert_raises((IndexError, ValueError, TypeError), A.__getitem__, (2, "foo")) |
|
assert_raises((IndexError, ValueError), A.__getitem__, |
|
([1, 2, 3], [1, 2, 3, 4])) |
|
|
|
def test_fancy_indexing(self): |
|
B = self.asdense(arange(50).reshape(5,10)) |
|
A = self.spcreator(B) |
|
|
|
|
|
assert_equal(A[[3]].toarray(), B[[3]]) |
|
assert_equal(A[[1, 3]].toarray(), B[[1, 3]]) |
|
|
|
|
|
assert_equal(A[3, [3]].toarray(), B[3, [3]]) |
|
assert_equal(A[3, [1, 3]].toarray(), B[3, [1, 3]]) |
|
assert_equal(A[-1, [2, -5]].toarray(), B[-1, [2, -5]]) |
|
assert_equal(A[array(-1), [2, -5]].toarray(), B[-1, [2, -5]]) |
|
assert_equal(A[-1, array([2, -5])].toarray(), B[-1, [2, -5]]) |
|
assert_equal(A[array(-1), array([2, -5])].toarray(), B[-1, [2, -5]]) |
|
|
|
|
|
assert_equal(A[:, [2, 8, 3, -1]].toarray(), B[:, [2, 8, 3, -1]]) |
|
assert_equal(A[3:4, [9]].toarray(), B[3:4, [9]]) |
|
assert_equal(A[1:4, [-1, -5]].toarray(), B[1:4, [-1, -5]]) |
|
assert_equal(A[1:4, array([-1, -5])].toarray(), B[1:4, [-1, -5]]) |
|
|
|
|
|
assert_equal(A[[3], 3].toarray(), B[[3], 3]) |
|
assert_equal(A[[1, 3], 3].toarray(), B[[1, 3], 3]) |
|
assert_equal(A[[2, -5], -4].toarray(), B[[2, -5], -4]) |
|
assert_equal(A[array([2, -5]), -4].toarray(), B[[2, -5], -4]) |
|
assert_equal(A[[2, -5], array(-4)].toarray(), B[[2, -5], -4]) |
|
assert_equal(A[array([2, -5]), array(-4)].toarray(), B[[2, -5], -4]) |
|
|
|
|
|
assert_equal(A[[3], :].toarray(), B[[3], :]) |
|
assert_equal(A[[1, 3], :].toarray(), B[[1, 3], :]) |
|
assert_equal(A[[2, -5], 8:-1].toarray(), B[[2, -5], 8:-1]) |
|
assert_equal(A[array([2, -5]), 8:-1].toarray(), B[[2, -5], 8:-1]) |
|
|
|
|
|
assert_equal(toarray(A[[3], [4]]), B[[3], [4]]) |
|
assert_equal(toarray(A[[1, 3], [2, 4]]), B[[1, 3], [2, 4]]) |
|
assert_equal(toarray(A[[-1, -3], [2, -4]]), B[[-1, -3], [2, -4]]) |
|
assert_equal( |
|
toarray(A[array([-1, -3]), [2, -4]]), B[[-1, -3], [2, -4]] |
|
) |
|
assert_equal( |
|
toarray(A[[-1, -3], array([2, -4])]), B[[-1, -3], [2, -4]] |
|
) |
|
assert_equal( |
|
toarray(A[array([-1, -3]), array([2, -4])]), B[[-1, -3], [2, -4]] |
|
) |
|
|
|
|
|
assert_equal(A[[[1], [3]], [2, 4]].toarray(), B[[[1], [3]], [2, 4]]) |
|
assert_equal( |
|
A[[[-1], [-3], [-2]], [2, -4]].toarray(), |
|
B[[[-1], [-3], [-2]], [2, -4]] |
|
) |
|
assert_equal( |
|
A[array([[-1], [-3], [-2]]), [2, -4]].toarray(), |
|
B[[[-1], [-3], [-2]], [2, -4]] |
|
) |
|
assert_equal( |
|
A[[[-1], [-3], [-2]], array([2, -4])].toarray(), |
|
B[[[-1], [-3], [-2]], [2, -4]] |
|
) |
|
assert_equal( |
|
A[array([[-1], [-3], [-2]]), array([2, -4])].toarray(), |
|
B[[[-1], [-3], [-2]], [2, -4]] |
|
) |
|
|
|
|
|
assert_equal(A[[1, 3]].toarray(), B[[1, 3]]) |
|
assert_equal(A[[-1, -3]].toarray(), B[[-1, -3]]) |
|
assert_equal(A[array([-1, -3])].toarray(), B[[-1, -3]]) |
|
|
|
|
|
assert_equal(A[[3], :][:, [4]].toarray(), B[[3], :][:, [4]]) |
|
assert_equal( |
|
A[[1, 3], :][:, [2, 4]].toarray(), B[[1, 3], :][:, [2, 4]] |
|
) |
|
assert_equal( |
|
A[[-1, -3], :][:, [2, -4]].toarray(), B[[-1, -3], :][:, [2, -4]] |
|
) |
|
assert_equal( |
|
A[array([-1, -3]), :][:, array([2, -4])].toarray(), |
|
B[[-1, -3], :][:, [2, -4]] |
|
) |
|
|
|
|
|
assert_equal( |
|
A[1, [[1, 3]]][[[0, 0]], 1].toarray(), B[1, [[1, 3]]][[[0, 0]], 1] |
|
) |
|
assert_equal( |
|
A[1, [[-1, -3]]][[[0, -1]], 1].toarray(), B[1, [[-1, -3]]][[[0, -1]], 1] |
|
) |
|
|
|
with pytest.raises(IndexError, match="Only 1D or 2D arrays allowed"): |
|
A[:1, [[1, 3]]] |
|
with pytest.raises(IndexError, match="Only 1D or 2D arrays allowed"): |
|
A[[[0, 0]], :1] |
|
|
|
|
|
assert_equal( |
|
A[:, [1, 3]][[2, 4], :].toarray(), B[:, [1, 3]][[2, 4], :] |
|
) |
|
assert_equal( |
|
A[:, [-1, -3]][[2, -4], :].toarray(), B[:, [-1, -3]][[2, -4], :] |
|
) |
|
assert_equal( |
|
A[:, array([-1, -3])][array([2, -4]), :].toarray(), |
|
B[:, [-1, -3]][[2, -4], :] |
|
) |
|
|
|
|
|
|
|
s = slice(int8(2),int8(4),None) |
|
assert_equal(A[s, :].toarray(), B[2:4, :]) |
|
assert_equal(A[:, s].toarray(), B[:, 2:4]) |
|
|
|
|
|
i = np.array([[1]], dtype=int) |
|
assert_equal(A[i, i].toarray(), B[i, i]) |
|
|
|
|
|
assert_equal(A[[[]], [[]]].toarray(), B[[[]], [[]]]) |
|
|
|
def test_fancy_indexing_randomized(self): |
|
np.random.seed(1234) |
|
|
|
NUM_SAMPLES = 50 |
|
M = 6 |
|
N = 4 |
|
|
|
D = self.asdense(np.random.rand(M,N)) |
|
D = np.multiply(D, D > 0.5) |
|
|
|
I = np.random.randint(-M + 1, M, size=NUM_SAMPLES) |
|
J = np.random.randint(-N + 1, N, size=NUM_SAMPLES) |
|
|
|
S = self.spcreator(D) |
|
|
|
SIJ = S[I,J] |
|
if issparse(SIJ): |
|
SIJ = SIJ.toarray() |
|
assert_equal(SIJ, D[I,J]) |
|
|
|
I_bad = I + M |
|
J_bad = J - N |
|
|
|
assert_raises(IndexError, S.__getitem__, (I_bad,J)) |
|
assert_raises(IndexError, S.__getitem__, (I,J_bad)) |
|
|
|
def test_missized_masking(self): |
|
M, N = 5, 10 |
|
|
|
B = self.asdense(arange(M * N).reshape(M, N)) |
|
A = self.spcreator(B) |
|
|
|
|
|
row_long = np.ones(M + 1, dtype=bool) |
|
row_short = np.ones(M - 1, dtype=bool) |
|
col_long = np.ones(N + 2, dtype=bool) |
|
col_short = np.ones(N - 2, dtype=bool) |
|
|
|
match="bool index .* has shape .* instead of .*" |
|
for i, j in itertools.product( |
|
(row_long, row_short, slice(None)), |
|
(col_long, col_short, slice(None)), |
|
): |
|
if isinstance(i, slice) and isinstance(j, slice): |
|
continue |
|
with pytest.raises(IndexError, match=match): |
|
_ = A[i, j] |
|
|
|
def test_fancy_indexing_boolean(self): |
|
np.random.seed(1234) |
|
|
|
B = self.asdense(arange(50).reshape(5,10)) |
|
A = self.spcreator(B) |
|
|
|
I = np.array(np.random.randint(0, 2, size=5), dtype=bool) |
|
J = np.array(np.random.randint(0, 2, size=10), dtype=bool) |
|
X = np.array(np.random.randint(0, 2, size=(5, 10)), dtype=bool) |
|
|
|
assert_equal(toarray(A[I]), B[I]) |
|
assert_equal(toarray(A[:, J]), B[:, J]) |
|
assert_equal(toarray(A[X]), B[X]) |
|
assert_equal(toarray(A[B > 9]), B[B > 9]) |
|
|
|
I = np.array([True, False, True, True, False]) |
|
J = np.array([False, True, True, False, True, |
|
False, False, False, False, False]) |
|
|
|
assert_equal(toarray(A[I, J]), B[I, J]) |
|
|
|
Z1 = np.zeros((6, 11), dtype=bool) |
|
Z2 = np.zeros((6, 11), dtype=bool) |
|
Z2[0,-1] = True |
|
Z3 = np.zeros((6, 11), dtype=bool) |
|
Z3[-1,0] = True |
|
|
|
assert_raises(IndexError, A.__getitem__, Z1) |
|
assert_raises(IndexError, A.__getitem__, Z2) |
|
assert_raises(IndexError, A.__getitem__, Z3) |
|
assert_raises((IndexError, ValueError), A.__getitem__, (X, 1)) |
|
|
|
def test_fancy_indexing_sparse_boolean(self): |
|
np.random.seed(1234) |
|
|
|
B = self.asdense(arange(50).reshape(5,10)) |
|
A = self.spcreator(B) |
|
|
|
X = np.array(np.random.randint(0, 2, size=(5, 10)), dtype=bool) |
|
|
|
Xsp = self.csr_container(X) |
|
|
|
assert_equal(toarray(A[Xsp]), B[X]) |
|
assert_equal(toarray(A[A > 9]), B[B > 9]) |
|
|
|
Z = np.array(np.random.randint(0, 2, size=(5, 11)), dtype=bool) |
|
Y = np.array(np.random.randint(0, 2, size=(6, 10)), dtype=bool) |
|
|
|
Zsp = self.csr_container(Z) |
|
Ysp = self.csr_container(Y) |
|
|
|
assert_raises(IndexError, A.__getitem__, Zsp) |
|
assert_raises(IndexError, A.__getitem__, Ysp) |
|
assert_raises((IndexError, ValueError), A.__getitem__, (Xsp, 1)) |
|
|
|
def test_fancy_indexing_regression_3087(self): |
|
mat = self.spcreator(array([[1, 0, 0], [0,1,0], [1,0,0]])) |
|
desired_cols = np.ravel(mat.sum(0)) > 0 |
|
assert_equal(mat[:, desired_cols].toarray(), [[1, 0], [0, 1], [1, 0]]) |
|
|
|
def test_fancy_indexing_seq_assign(self): |
|
mat = self.spcreator(array([[1, 0], [0, 1]])) |
|
assert_raises(ValueError, mat.__setitem__, (0, 0), np.array([1,2])) |
|
|
|
def test_fancy_indexing_2d_assign(self): |
|
|
|
mat = self.spcreator(array([[1, 0], [2, 3]])) |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
mat[[0, 1], [1, 1]] = mat[[1, 0], [0, 0]] |
|
assert_equal(toarray(mat), array([[1, 2], [2, 1]])) |
|
|
|
def test_fancy_indexing_empty(self): |
|
B = self.asdense(arange(50).reshape(5,10)) |
|
B[1,:] = 0 |
|
B[:,2] = 0 |
|
B[3,6] = 0 |
|
A = self.spcreator(B) |
|
|
|
K = np.array([False, False, False, False, False]) |
|
assert_equal(toarray(A[K]), B[K]) |
|
K = np.array([], dtype=int) |
|
assert_equal(toarray(A[K]), B[K]) |
|
assert_equal(toarray(A[K, K]), B[K, K]) |
|
J = np.array([0, 1, 2, 3, 4], dtype=int)[:,None] |
|
assert_equal(toarray(A[K, J]), B[K, J]) |
|
assert_equal(toarray(A[J, K]), B[J, K]) |
|
|
|
|
|
@contextlib.contextmanager |
|
def check_remains_sorted(X): |
|
"""Checks that sorted indices property is retained through an operation |
|
""" |
|
if not hasattr(X, 'has_sorted_indices') or not X.has_sorted_indices: |
|
yield |
|
return |
|
yield |
|
indices = X.indices.copy() |
|
X.has_sorted_indices = False |
|
X.sort_indices() |
|
assert_array_equal(indices, X.indices, |
|
'Expected sorted indices, found unsorted') |
|
|
|
|
|
class _TestFancyIndexingAssign: |
|
def test_bad_index_assign(self): |
|
A = self.spcreator(np.zeros([5, 5])) |
|
assert_raises((IndexError, ValueError, TypeError), A.__setitem__, "foo", 2) |
|
assert_raises((IndexError, ValueError, TypeError), A.__setitem__, (2, "foo"), 5) |
|
|
|
def test_fancy_indexing_set(self): |
|
n, m = (5, 10) |
|
|
|
def _test_set_slice(i, j): |
|
A = self.spcreator((n, m)) |
|
B = self.asdense(np.zeros((n, m))) |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
B[i, j] = 1 |
|
with check_remains_sorted(A): |
|
A[i, j] = 1 |
|
assert_array_almost_equal(A.toarray(), B) |
|
|
|
for i, j in [((2, 3, 4), slice(None, 10, 4)), |
|
(np.arange(3), slice(5, -2)), |
|
(slice(2, 5), slice(5, -2))]: |
|
_test_set_slice(i, j) |
|
for i, j in [(np.arange(3), np.arange(3)), ((0, 3, 4), (1, 2, 4))]: |
|
_test_set_slice(i, j) |
|
|
|
def test_fancy_assignment_dtypes(self): |
|
def check(dtype): |
|
A = self.spcreator((5, 5), dtype=dtype) |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
A[[0,1],[0,1]] = dtype.type(1) |
|
assert_equal(A.sum(), dtype.type(1)*2) |
|
A[0:2,0:2] = dtype.type(1.0) |
|
assert_equal(A.sum(), dtype.type(1)*4) |
|
A[2,2] = dtype.type(1.0) |
|
assert_equal(A.sum(), dtype.type(1)*4 + dtype.type(1)) |
|
|
|
for dtype in supported_dtypes: |
|
check(np.dtype(dtype)) |
|
|
|
def test_sequence_assignment(self): |
|
A = self.spcreator((4,3)) |
|
B = self.spcreator(eye(3,4)) |
|
|
|
i0 = [0,1,2] |
|
i1 = (0,1,2) |
|
i2 = array(i0) |
|
|
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
with check_remains_sorted(A): |
|
A[0,i0] = B[i0,0].T |
|
A[1,i1] = B[i1,1].T |
|
A[2,i2] = B[i2,2].T |
|
assert_array_equal(A.toarray(), B.T.toarray()) |
|
|
|
|
|
A = self.spcreator((2,3)) |
|
with check_remains_sorted(A): |
|
A[1,1:3] = [10,20] |
|
assert_array_equal(A.toarray(), [[0, 0, 0], [0, 10, 20]]) |
|
|
|
|
|
A = self.spcreator((3,2)) |
|
with check_remains_sorted(A): |
|
A[1:3,1] = [[10],[20]] |
|
assert_array_equal(A.toarray(), [[0, 0], [0, 10], [0, 20]]) |
|
|
|
|
|
A = self.spcreator((3,3)) |
|
B = self.asdense(np.zeros((3,3))) |
|
with check_remains_sorted(A): |
|
for C in [A, B]: |
|
C[[0,1,2], [0,1,2]] = [4,5,6] |
|
assert_array_equal(A.toarray(), B) |
|
|
|
|
|
A = self.spcreator((4, 3)) |
|
with check_remains_sorted(A): |
|
A[(1, 2, 3), (0, 1, 2)] = [1, 2, 3] |
|
assert_almost_equal(A.sum(), 6) |
|
B = self.asdense(np.zeros((4, 3))) |
|
B[(1, 2, 3), (0, 1, 2)] = [1, 2, 3] |
|
assert_array_equal(A.toarray(), B) |
|
|
|
def test_fancy_assign_empty(self): |
|
B = self.asdense(arange(50).reshape(5,10)) |
|
B[1,:] = 0 |
|
B[:,2] = 0 |
|
B[3,6] = 0 |
|
A = self.spcreator(B) |
|
|
|
K = np.array([False, False, False, False, False]) |
|
A[K] = 42 |
|
assert_equal(toarray(A), B) |
|
|
|
K = np.array([], dtype=int) |
|
A[K] = 42 |
|
assert_equal(toarray(A), B) |
|
A[K,K] = 42 |
|
assert_equal(toarray(A), B) |
|
|
|
J = np.array([0, 1, 2, 3, 4], dtype=int)[:,None] |
|
A[K,J] = 42 |
|
assert_equal(toarray(A), B) |
|
A[J,K] = 42 |
|
assert_equal(toarray(A), B) |
|
|
|
|
|
class _TestFancyMultidim: |
|
def test_fancy_indexing_ndarray(self): |
|
sets = [ |
|
(np.array([[1], [2], [3]]), np.array([3, 4, 2])), |
|
(np.array([[1], [2], [3]]), np.array([[3, 4, 2]])), |
|
(np.array([[1, 2, 3]]), np.array([[3], [4], [2]])), |
|
(np.array([1, 2, 3]), np.array([[3], [4], [2]])), |
|
(np.array([[1, 2, 3], [3, 4, 2]]), |
|
np.array([[5, 6, 3], [2, 3, 1]])) |
|
] |
|
|
|
|
|
|
|
|
|
for I, J in sets: |
|
np.random.seed(1234) |
|
D = self.asdense(np.random.rand(5, 7)) |
|
S = self.spcreator(D) |
|
|
|
SIJ = S[I,J] |
|
if issparse(SIJ): |
|
SIJ = SIJ.toarray() |
|
assert_equal(SIJ, D[I,J]) |
|
|
|
I_bad = I + 5 |
|
J_bad = J + 7 |
|
|
|
assert_raises(IndexError, S.__getitem__, (I_bad,J)) |
|
assert_raises(IndexError, S.__getitem__, (I,J_bad)) |
|
|
|
|
|
assert_raises(IndexError, S.__getitem__, ([I, I], slice(None))) |
|
assert_raises(IndexError, S.__getitem__, (slice(None), [J, J])) |
|
|
|
|
|
class _TestFancyMultidimAssign: |
|
def test_fancy_assign_ndarray(self): |
|
np.random.seed(1234) |
|
|
|
D = self.asdense(np.random.rand(5, 7)) |
|
S = self.spcreator(D) |
|
X = np.random.rand(2, 3) |
|
|
|
I = np.array([[1, 2, 3], [3, 4, 2]]) |
|
J = np.array([[5, 6, 3], [2, 3, 1]]) |
|
|
|
with check_remains_sorted(S): |
|
S[I,J] = X |
|
D[I,J] = X |
|
assert_equal(S.toarray(), D) |
|
|
|
I_bad = I + 5 |
|
J_bad = J + 7 |
|
|
|
C = [1, 2, 3] |
|
|
|
with check_remains_sorted(S): |
|
S[I,J] = C |
|
D[I,J] = C |
|
assert_equal(S.toarray(), D) |
|
|
|
with check_remains_sorted(S): |
|
S[I,J] = 3 |
|
D[I,J] = 3 |
|
assert_equal(S.toarray(), D) |
|
|
|
assert_raises(IndexError, S.__setitem__, (I_bad,J), C) |
|
assert_raises(IndexError, S.__setitem__, (I,J_bad), C) |
|
|
|
def test_fancy_indexing_multidim_set(self): |
|
n, m = (5, 10) |
|
|
|
def _test_set_slice(i, j): |
|
A = self.spcreator((n, m)) |
|
with check_remains_sorted(A), suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
A[i, j] = 1 |
|
B = self.asdense(np.zeros((n, m))) |
|
B[i, j] = 1 |
|
assert_array_almost_equal(A.toarray(), B) |
|
|
|
for i, j in [(np.array([[1, 2], [1, 3]]), [1, 3]), |
|
(np.array([0, 4]), [[0, 3], [1, 2]]), |
|
([[1, 2, 3], [0, 2, 4]], [[0, 4, 3], [4, 1, 2]])]: |
|
_test_set_slice(i, j) |
|
|
|
def test_fancy_assign_list(self): |
|
np.random.seed(1234) |
|
|
|
D = self.asdense(np.random.rand(5, 7)) |
|
S = self.spcreator(D) |
|
X = np.random.rand(2, 3) |
|
|
|
I = [[1, 2, 3], [3, 4, 2]] |
|
J = [[5, 6, 3], [2, 3, 1]] |
|
|
|
S[I,J] = X |
|
D[I,J] = X |
|
assert_equal(S.toarray(), D) |
|
|
|
I_bad = [[ii + 5 for ii in i] for i in I] |
|
J_bad = [[jj + 7 for jj in j] for j in J] |
|
C = [1, 2, 3] |
|
|
|
S[I,J] = C |
|
D[I,J] = C |
|
assert_equal(S.toarray(), D) |
|
|
|
S[I,J] = 3 |
|
D[I,J] = 3 |
|
assert_equal(S.toarray(), D) |
|
|
|
assert_raises(IndexError, S.__setitem__, (I_bad,J), C) |
|
assert_raises(IndexError, S.__setitem__, (I,J_bad), C) |
|
|
|
def test_fancy_assign_slice(self): |
|
np.random.seed(1234) |
|
|
|
D = self.asdense(np.random.rand(5, 7)) |
|
S = self.spcreator(D) |
|
|
|
I = [1, 2, 3, 3, 4, 2] |
|
J = [5, 6, 3, 2, 3, 1] |
|
|
|
I_bad = [ii + 5 for ii in I] |
|
J_bad = [jj + 7 for jj in J] |
|
|
|
C1 = [1, 2, 3, 4, 5, 6, 7] |
|
C2 = np.arange(5)[:, None] |
|
assert_raises(IndexError, S.__setitem__, (I_bad, slice(None)), C1) |
|
assert_raises(IndexError, S.__setitem__, (slice(None), J_bad), C2) |
|
|
|
|
|
class _TestArithmetic: |
|
""" |
|
Test real/complex arithmetic |
|
""" |
|
def __arith_init(self): |
|
|
|
__A = array([[-1.5, 6.5, 0, 2.25, 0, 0], |
|
[3.125, -7.875, 0.625, 0, 0, 0], |
|
[0, 0, -0.125, 1.0, 0, 0], |
|
[0, 0, 8.375, 0, 0, 0]], 'float64') |
|
__B = array([[0.375, 0, 0, 0, -5, 2.5], |
|
[14.25, -3.75, 0, 0, -0.125, 0], |
|
[0, 7.25, 0, 0, 0, 0], |
|
[18.5, -0.0625, 0, 0, 0, 0]], 'complex128') |
|
__B.imag = array([[1.25, 0, 0, 0, 6, -3.875], |
|
[2.25, 4.125, 0, 0, 0, 2.75], |
|
[0, 4.125, 0, 0, 0, 0], |
|
[-0.0625, 0, 0, 0, 0, 0]], 'float64') |
|
|
|
|
|
assert_array_equal((__A*16).astype('int32'),16*__A) |
|
assert_array_equal((__B.real*16).astype('int32'),16*__B.real) |
|
assert_array_equal((__B.imag*16).astype('int32'),16*__B.imag) |
|
|
|
__Asp = self.spcreator(__A) |
|
__Bsp = self.spcreator(__B) |
|
return __A, __B, __Asp, __Bsp |
|
|
|
@pytest.mark.fail_slow(20) |
|
def test_add_sub(self): |
|
__A, __B, __Asp, __Bsp = self.__arith_init() |
|
|
|
|
|
assert_array_equal( |
|
(__Asp + __Bsp).toarray(), __A + __B |
|
) |
|
|
|
|
|
for x in supported_dtypes: |
|
with np.errstate(invalid="ignore"): |
|
A = __A.astype(x) |
|
Asp = self.spcreator(A) |
|
for y in supported_dtypes: |
|
if not np.issubdtype(y, np.complexfloating): |
|
with np.errstate(invalid="ignore"): |
|
B = __B.real.astype(y) |
|
else: |
|
B = __B.astype(y) |
|
Bsp = self.spcreator(B) |
|
|
|
|
|
D1 = A + B |
|
S1 = Asp + Bsp |
|
|
|
assert_equal(S1.dtype,D1.dtype) |
|
assert_array_equal(S1.toarray(), D1) |
|
assert_array_equal(Asp + B,D1) |
|
assert_array_equal(A + Bsp,D1) |
|
|
|
|
|
if np.dtype('bool') in [x, y]: |
|
|
|
continue |
|
|
|
D1 = A - B |
|
S1 = Asp - Bsp |
|
|
|
assert_equal(S1.dtype,D1.dtype) |
|
assert_array_equal(S1.toarray(), D1) |
|
assert_array_equal(Asp - B,D1) |
|
assert_array_equal(A - Bsp,D1) |
|
|
|
def test_mu(self): |
|
__A, __B, __Asp, __Bsp = self.__arith_init() |
|
|
|
|
|
assert_array_equal((__Asp @ __Bsp.T).toarray(), |
|
__A @ __B.T) |
|
|
|
for x in supported_dtypes: |
|
with np.errstate(invalid="ignore"): |
|
A = __A.astype(x) |
|
Asp = self.spcreator(A) |
|
for y in supported_dtypes: |
|
if np.issubdtype(y, np.complexfloating): |
|
B = __B.astype(y) |
|
else: |
|
with np.errstate(invalid="ignore"): |
|
B = __B.real.astype(y) |
|
Bsp = self.spcreator(B) |
|
|
|
D1 = A @ B.T |
|
S1 = Asp @ Bsp.T |
|
|
|
assert_allclose(S1.toarray(), D1, |
|
atol=1e-14*abs(D1).max()) |
|
assert_equal(S1.dtype,D1.dtype) |
|
|
|
|
|
class _TestMinMax: |
|
def test_minmax(self): |
|
for dtype in [np.float32, np.float64, np.int32, np.int64, np.complex128]: |
|
D = np.arange(20, dtype=dtype).reshape(5,4) |
|
|
|
X = self.spcreator(D) |
|
assert_equal(X.min(), 0) |
|
assert_equal(X.max(), 19) |
|
assert_equal(X.min().dtype, dtype) |
|
assert_equal(X.max().dtype, dtype) |
|
|
|
D *= -1 |
|
X = self.spcreator(D) |
|
assert_equal(X.min(), -19) |
|
assert_equal(X.max(), 0) |
|
|
|
D += 5 |
|
X = self.spcreator(D) |
|
assert_equal(X.min(), -14) |
|
assert_equal(X.max(), 5) |
|
|
|
|
|
X = self.spcreator(np.arange(1, 10).reshape(3, 3)) |
|
assert_equal(X.min(), 1) |
|
assert_equal(X.min().dtype, X.dtype) |
|
|
|
X = -X |
|
assert_equal(X.max(), -1) |
|
|
|
|
|
Z = self.spcreator(np.zeros((1, 1))) |
|
assert_equal(Z.min(), 0) |
|
assert_equal(Z.max(), 0) |
|
assert_equal(Z.max().dtype, Z.dtype) |
|
|
|
|
|
D = np.arange(20, dtype=float).reshape(5,4) |
|
D[0:2, :] = 0 |
|
X = self.spcreator(D) |
|
assert_equal(X.min(), 0) |
|
assert_equal(X.max(), 19) |
|
|
|
|
|
for D in [np.zeros((0, 0)), np.zeros((0, 10)), np.zeros((10, 0))]: |
|
X = self.spcreator(D) |
|
assert_raises(ValueError, X.min) |
|
assert_raises(ValueError, X.max) |
|
|
|
def test_minmax_axis(self): |
|
keep = not self.is_array_test |
|
D = np.arange(50).reshape(5, 10) |
|
|
|
D[1, :] = 0 |
|
|
|
D[:, 9] = 0 |
|
|
|
D[3, 3] = 0 |
|
|
|
D[2, 2] = -1 |
|
X = self.spcreator(D) |
|
|
|
axes_even = [0, -2] |
|
axes_odd = [1, -1] |
|
for axis in axes_odd + axes_even: |
|
assert_array_equal( |
|
X.max(axis=axis).toarray(), D.max(axis=axis, keepdims=keep) |
|
) |
|
assert_array_equal( |
|
X.min(axis=axis).toarray(), D.min(axis=axis, keepdims=keep) |
|
) |
|
|
|
for axis in axes_even: |
|
assert_equal( |
|
X.max(axis=axis, explicit=True).toarray(), |
|
self.asdense([40, 41, 42, 43, 44, 45, 46, 47, 48, 0]) |
|
) |
|
if np.any(X.data == 0): |
|
|
|
expected = self.asdense([20, 1, -1, 3, 4, 5, 0, 7, 8, 0]) |
|
else: |
|
expected = self.asdense([20, 1, -1, 3, 4, 5, 6, 7, 8, 0]) |
|
assert_equal(X.min(axis=axis, explicit=True).toarray(), expected) |
|
|
|
for axis in axes_odd: |
|
expected_max = np.array([8, 0, 28, 38, 48]) |
|
expected_min = np.array([1, 0, -1, 30, 40]) |
|
if not self.is_array_test: |
|
expected_max = expected_max.reshape((5, 1)) |
|
expected_min = expected_min.reshape((5, 1)) |
|
assert_equal(X.max(axis=axis, explicit=True).toarray(), expected_max) |
|
assert_equal(X.min(axis=axis, explicit=True).toarray(), expected_min) |
|
|
|
|
|
D = np.arange(1, 51).reshape(10, 5) |
|
X = self.spcreator(D) |
|
for axis in axes_odd + axes_even: |
|
assert_array_equal( |
|
X.max(axis=axis).toarray(), D.max(axis=axis, keepdims=keep) |
|
) |
|
assert_array_equal( |
|
X.min(axis=axis).toarray(), D.min(axis=axis, keepdims=keep) |
|
) |
|
|
|
for axis in axes_even: |
|
expected_max = D[-1, :] |
|
expected_min = D[0, :] |
|
if not self.is_array_test: |
|
expected_max = D[None, -1, :] |
|
expected_min = D[None, 0, :] |
|
assert_equal(X.max(axis=axis, explicit=True).toarray(), expected_max) |
|
assert_equal(X.min(axis=axis, explicit=True).toarray(), expected_min) |
|
for axis in axes_odd: |
|
expected_max = D[:, -1] |
|
expected_min = D[:, 0] |
|
if not self.is_array_test: |
|
expected_max = D[:, -1, None] |
|
expected_min = D[:, 0, None] |
|
assert_equal(X.max(axis=axis, explicit=True).toarray(), expected_max) |
|
assert_equal(X.min(axis=axis, explicit=True).toarray(), expected_min) |
|
|
|
|
|
D = self.asdense(np.zeros((10, 5))) |
|
X = self.spcreator(D) |
|
for axis in axes_even + axes_odd: |
|
assert_equal(X.max(axis=axis, explicit=True).toarray(), D.max(axis=axis)) |
|
assert_equal(X.min(axis=axis, explicit=True).toarray(), D.min(axis=axis)) |
|
|
|
|
|
D = self.asdense(np.zeros((0, 10))) |
|
X = self.spcreator(D) |
|
explicit_values = [True, False] |
|
even_explicit_pairs = list(itertools.product(axes_even, explicit_values)) |
|
odd_explicit_pairs = list(itertools.product(axes_odd, explicit_values)) |
|
for axis, ex in even_explicit_pairs: |
|
assert_raises(ValueError, X.min, axis=axis, explicit=ex) |
|
assert_raises(ValueError, X.max, axis=axis, explicit=ex) |
|
for axis, ex in odd_explicit_pairs: |
|
assert_equal(X.max(axis=axis, explicit=ex).toarray(), D.max(axis=axis)) |
|
assert_equal(X.min(axis=axis, explicit=ex).toarray(), D.min(axis=axis)) |
|
|
|
D = self.asdense(np.zeros((10, 0))) |
|
X = self.spcreator(D) |
|
for axis, ex in odd_explicit_pairs: |
|
assert_raises(ValueError, X.min, axis=axis, explicit=ex) |
|
assert_raises(ValueError, X.max, axis=axis, explicit=ex) |
|
for axis, ex in even_explicit_pairs: |
|
assert_equal(X.max(axis=axis, explicit=ex).toarray(), D.max(axis=axis)) |
|
assert_equal(X.min(axis=axis, explicit=ex).toarray(), D.min(axis=axis)) |
|
|
|
def test_nanminmax(self): |
|
D = self.asdense(np.arange(50).reshape(5,10), dtype=float) |
|
D[1, :] = 0 |
|
D[:, 9] = 0 |
|
D[3, 3] = 0 |
|
D[2, 2] = -1 |
|
D[4, 2] = np.nan |
|
D[1, 4] = np.nan |
|
X = self.spcreator(D) |
|
|
|
X_nan_maximum = X.nanmax() |
|
assert np.isscalar(X_nan_maximum) |
|
assert X_nan_maximum == np.nanmax(D) |
|
|
|
X_nan_minimum = X.nanmin() |
|
assert np.isscalar(X_nan_minimum) |
|
assert X_nan_minimum == np.nanmin(D) |
|
|
|
axes = [-2, -1, 0, 1] |
|
for axis in axes: |
|
X_nan_maxima = X.nanmax(axis=axis) |
|
assert_allclose(X_nan_maxima.toarray(), np.nanmax(D, axis=axis)) |
|
assert isinstance(X_nan_maxima, self.coo_container) |
|
|
|
X_nan_minima = X.nanmin(axis=axis) |
|
assert_allclose(X_nan_minima.toarray(), np.nanmin(D, axis=axis)) |
|
assert isinstance(X_nan_minima, self.coo_container) |
|
|
|
def test_minmax_invalid_params(self): |
|
dat = array([[0, 1, 2], |
|
[3, -4, 5], |
|
[-6, 7, 9]]) |
|
datsp = self.spcreator(dat) |
|
|
|
for fname in ('min', 'max'): |
|
func = getattr(datsp, fname) |
|
assert_raises(ValueError, func, axis=3) |
|
assert_raises(TypeError, func, axis=(0, 1)) |
|
assert_raises(TypeError, func, axis=1.5) |
|
assert_raises(ValueError, func, axis=1, out=1) |
|
|
|
def test_numpy_minmax(self): |
|
|
|
|
|
from scipy.sparse import _data |
|
|
|
dat = array([[0, 1, 2], |
|
[3, -4, 5], |
|
[-6, 7, 9]]) |
|
datsp = self.spcreator(dat) |
|
|
|
|
|
|
|
|
|
|
|
if isinstance(datsp, _data._minmax_mixin): |
|
assert_array_equal(np.min(datsp), np.min(dat)) |
|
assert_array_equal(np.max(datsp), np.max(dat)) |
|
|
|
def test_argmax(self): |
|
from scipy.sparse import _data |
|
D1 = np.array([ |
|
[-1, 5, 2, 3], |
|
[0, 0, -1, -2], |
|
[-1, -2, -3, -4], |
|
[1, 2, 3, 4], |
|
[1, 2, 0, 0], |
|
]) |
|
D2 = D1.transpose() |
|
|
|
D3 = np.array([[4, 3], [7, 5]]) |
|
D4 = np.array([[4, 3], [7, 0]]) |
|
D5 = np.array([[5, 5, 3], [4, 9, 10], [3, 4, 9]]) |
|
|
|
for D in [D1, D2, D3, D4, D5]: |
|
D = self.asdense(D) |
|
mat = self.spcreator(D) |
|
if not isinstance(mat, _data._minmax_mixin): |
|
continue |
|
|
|
assert_equal(mat.argmax(), np.argmax(D)) |
|
assert_equal(mat.argmin(), np.argmin(D)) |
|
|
|
assert_equal(mat.argmax(axis=0), np.argmax(D, axis=0)) |
|
assert_equal(mat.argmin(axis=0), np.argmin(D, axis=0)) |
|
|
|
assert_equal(mat.argmax(axis=1), np.argmax(D, axis=1)) |
|
assert_equal(mat.argmin(axis=1), np.argmin(D, axis=1)) |
|
|
|
|
|
D6 = self.spcreator(np.empty((0, 5))) |
|
D7 = self.spcreator(np.empty((5, 0))) |
|
explicits = [True, False] |
|
|
|
for mat, axis, ex in itertools.product([D6, D7], [None, 0, 1], explicits): |
|
if axis is None or mat.shape[axis] == 0: |
|
with pytest.raises(ValueError, match="Cannot apply"): |
|
mat.argmax(axis=axis, explicit=ex) |
|
with pytest.raises(ValueError, match="Cannot apply"): |
|
mat.argmin(axis=axis, explicit=ex) |
|
else: |
|
if self.is_array_test: |
|
expected = np.zeros(0) |
|
else: |
|
expected = np.zeros((0, 1) if axis == 1 else (1, 0)) |
|
assert_equal(mat.argmin(axis=axis, explicit=ex), expected) |
|
assert_equal(mat.argmax(axis=axis, explicit=ex), expected) |
|
|
|
mat = self.spcreator(D1) |
|
assert_equal(mat.argmax(axis=0, explicit=True), self.asdense([3, 0, 3, 3])) |
|
assert_equal(mat.argmin(axis=0, explicit=True), self.asdense([0, 2, 2, 2])) |
|
|
|
expected_max = np.array([1, 2, 0, 3, 1]) |
|
expected_min = np.array([0, 3, 3, 0, 0]) |
|
if mat.nnz != 16: |
|
|
|
expected_min[-1] = 2 |
|
if not self.is_array_test: |
|
expected_max = expected_max.reshape((5, 1)) |
|
expected_min = expected_min.reshape((5, 1)) |
|
|
|
assert_equal(mat.argmax(axis=1, explicit=True), expected_max) |
|
assert_equal(asarray(mat.argmin(axis=1, explicit=True)), expected_min) |
|
|
|
|
|
D = np.zeros((2, 2)) |
|
mat = self.spcreator(D) |
|
if mat.nnz != 0: |
|
|
|
assert_equal(mat.argmin(axis=None, explicit=True), 0) |
|
assert_equal(mat.argmax(axis=None, explicit=True), 0) |
|
else: |
|
|
|
with pytest.raises(ValueError, match="Cannot apply"): |
|
mat.argmin(axis=None, explicit=True) |
|
with pytest.raises(ValueError, match="Cannot apply"): |
|
mat.argmax(axis=None, explicit=True) |
|
|
|
|
|
class _TestGetNnzAxis: |
|
def test_getnnz_axis(self): |
|
dat = array([[0, 2], |
|
[3, 5], |
|
[-6, 9]]) |
|
bool_dat = dat.astype(bool) |
|
datsp = self.spcreator(dat) |
|
|
|
accepted_return_dtypes = (np.int32, np.int64) |
|
|
|
getnnz = datsp.count_nonzero if self.is_array_test else datsp.getnnz |
|
assert_array_equal(bool_dat.sum(axis=None), getnnz(axis=None)) |
|
assert_array_equal(bool_dat.sum(), getnnz()) |
|
assert_array_equal(bool_dat.sum(axis=0), getnnz(axis=0)) |
|
assert_in(getnnz(axis=0).dtype, accepted_return_dtypes) |
|
assert_array_equal(bool_dat.sum(axis=1), getnnz(axis=1)) |
|
assert_in(getnnz(axis=1).dtype, accepted_return_dtypes) |
|
assert_array_equal(bool_dat.sum(axis=-2), getnnz(axis=-2)) |
|
assert_in(getnnz(axis=-2).dtype, accepted_return_dtypes) |
|
assert_array_equal(bool_dat.sum(axis=-1), getnnz(axis=-1)) |
|
assert_in(getnnz(axis=-1).dtype, accepted_return_dtypes) |
|
|
|
assert_raises(ValueError, getnnz, axis=2) |
|
|
|
|
|
|
|
|
|
|
|
|
|
def _possibly_unimplemented(cls, require=True): |
|
""" |
|
Construct a class that either runs tests as usual (require=True), |
|
or each method skips if it encounters a common error. |
|
""" |
|
if require: |
|
return cls |
|
else: |
|
def wrap(fc): |
|
@functools.wraps(fc) |
|
def wrapper(*a, **kw): |
|
try: |
|
return fc(*a, **kw) |
|
except (NotImplementedError, TypeError, ValueError, |
|
IndexError, AttributeError): |
|
raise pytest.skip("feature not implemented") |
|
|
|
return wrapper |
|
|
|
new_dict = dict(cls.__dict__) |
|
for name, func in cls.__dict__.items(): |
|
if name.startswith('test_'): |
|
new_dict[name] = wrap(func) |
|
return type(cls.__name__ + "NotImplemented", |
|
cls.__bases__, |
|
new_dict) |
|
|
|
|
|
def sparse_test_class(getset=True, slicing=True, slicing_assign=True, |
|
fancy_indexing=True, fancy_assign=True, |
|
fancy_multidim_indexing=True, fancy_multidim_assign=True, |
|
minmax=True, nnz_axis=True): |
|
""" |
|
Construct a base class, optionally converting some of the tests in |
|
the suite to check that the feature is not implemented. |
|
""" |
|
bases = (_TestCommon, |
|
_possibly_unimplemented(_TestGetSet, getset), |
|
_TestSolve, |
|
_TestInplaceArithmetic, |
|
_TestArithmetic, |
|
_possibly_unimplemented(_TestSlicing, slicing), |
|
_possibly_unimplemented(_TestSlicingAssign, slicing_assign), |
|
_possibly_unimplemented(_TestFancyIndexing, fancy_indexing), |
|
_possibly_unimplemented(_TestFancyIndexingAssign, |
|
fancy_assign), |
|
_possibly_unimplemented(_TestFancyMultidim, |
|
fancy_indexing and fancy_multidim_indexing), |
|
_possibly_unimplemented(_TestFancyMultidimAssign, |
|
fancy_multidim_assign and fancy_assign), |
|
_possibly_unimplemented(_TestMinMax, minmax), |
|
_possibly_unimplemented(_TestGetNnzAxis, nnz_axis)) |
|
|
|
|
|
names = {} |
|
for cls in bases: |
|
for name in cls.__dict__: |
|
if not name.startswith('test_'): |
|
continue |
|
old_cls = names.get(name) |
|
if old_cls is not None: |
|
raise ValueError(f"Test class {cls.__name__} overloads test " |
|
f"{name} defined in {old_cls.__name__}") |
|
names[name] = cls |
|
|
|
return type("TestBase", bases, {}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestCSR(sparse_test_class()): |
|
@classmethod |
|
def spcreator(cls, *args, **kwargs): |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
return csr_array(*args, **kwargs) |
|
math_dtypes = [np.bool_, np.int_, np.float64, np.complex128] |
|
|
|
def test_constructor1(self): |
|
b = array([[0, 4, 0], |
|
[3, 0, 0], |
|
[0, 2, 0]], 'd') |
|
bsp = self.csr_container(b) |
|
assert_array_almost_equal(bsp.data,[4,3,2]) |
|
assert_array_equal(bsp.indices,[1,0,1]) |
|
assert_array_equal(bsp.indptr,[0,1,2,3]) |
|
assert_equal(bsp.nnz,3) |
|
assert_equal(bsp.format,'csr') |
|
assert_array_equal(bsp.toarray(), b) |
|
|
|
def test_constructor2(self): |
|
b = zeros((6,6),'d') |
|
b[3,4] = 5 |
|
bsp = self.csr_container(b) |
|
assert_array_almost_equal(bsp.data,[5]) |
|
assert_array_equal(bsp.indices,[4]) |
|
assert_array_equal(bsp.indptr,[0,0,0,0,1,1,1]) |
|
assert_array_almost_equal(bsp.toarray(), b) |
|
|
|
def test_constructor3(self): |
|
b = array([[1, 0], |
|
[0, 2], |
|
[3, 0]], 'd') |
|
bsp = self.csr_container(b) |
|
assert_array_almost_equal(bsp.data,[1,2,3]) |
|
assert_array_equal(bsp.indices,[0,1,0]) |
|
assert_array_equal(bsp.indptr,[0,1,2,3]) |
|
assert_array_almost_equal(bsp.toarray(), b) |
|
|
|
def test_constructor4(self): |
|
|
|
row = array([2, 3, 1, 3, 0, 1, 3, 0, 2, 1, 2]) |
|
col = array([0, 1, 0, 0, 1, 1, 2, 2, 2, 2, 1]) |
|
data = array([6., 10., 3., 9., 1., 4., |
|
11., 2., 8., 5., 7.]) |
|
|
|
ij = vstack((row,col)) |
|
csr = self.csr_container((data,ij),(4,3)) |
|
assert_array_equal(arange(12).reshape(4, 3), csr.toarray()) |
|
|
|
|
|
csr = self.csr_container(([2**63 + 1, 1], ([0, 1], [0, 1])), dtype=np.uint64) |
|
dense = array([[2**63 + 1, 0], [0, 1]], dtype=np.uint64) |
|
assert_array_equal(dense, csr.toarray()) |
|
|
|
|
|
csr = self.csr_container(([1,1,1,1], ([0,2,2,0], [0,1,1,0]))) |
|
assert csr.nnz == 2 |
|
|
|
def test_constructor5(self): |
|
|
|
indptr = array([0,1,3,3]) |
|
indices = array([0,5,1,2]) |
|
data = array([1,2,3,4]) |
|
csr = self.csr_container((data, indices, indptr)) |
|
assert_array_equal(csr.shape,(3,6)) |
|
|
|
def test_constructor6(self): |
|
|
|
indptr = [0, 1, 3, 3] |
|
indices = [0, 5, 1, 2] |
|
data = [1, 2, 3, 4] |
|
csr = self.csr_container((data, indices, indptr)) |
|
assert_array_equal(csr.shape, (3,6)) |
|
assert_(np.issubdtype(csr.dtype, np.signedinteger)) |
|
|
|
def test_constructor_smallcol(self): |
|
|
|
data = arange(6) + 1 |
|
col = array([1, 2, 1, 0, 0, 2], dtype=np.int64) |
|
ptr = array([0, 2, 4, 6], dtype=np.int64) |
|
|
|
a = self.csr_container((data, col, ptr), shape=(3, 3)) |
|
|
|
b = array([[0, 1, 2], |
|
[4, 3, 0], |
|
[5, 0, 6]], 'd') |
|
|
|
|
|
expected_dtype = np.dtype(np.int64 if self.is_array_test else np.int32) |
|
assert_equal(a.indptr.dtype, expected_dtype) |
|
assert_equal(a.indices.dtype, expected_dtype) |
|
assert_array_equal(a.toarray(), b) |
|
|
|
def test_constructor_largecol(self): |
|
|
|
data = arange(6) + 1 |
|
large = np.iinfo(np.int32).max + 100 |
|
col = array([0, 1, 2, large, large+1, large+2], dtype=np.int64) |
|
ptr = array([0, 2, 4, 6], dtype=np.int64) |
|
|
|
a = self.csr_container((data, col, ptr)) |
|
|
|
assert_equal(a.indptr.dtype, np.dtype(np.int64)) |
|
assert_equal(a.indices.dtype, np.dtype(np.int64)) |
|
assert_array_equal(a.shape, (3, max(col)+1)) |
|
|
|
def test_sort_indices(self): |
|
data = arange(5) |
|
indices = array([7, 2, 1, 5, 4]) |
|
indptr = array([0, 3, 5]) |
|
asp = self.csr_container((data, indices, indptr), shape=(2,10)) |
|
bsp = asp.copy() |
|
asp.sort_indices() |
|
assert_array_equal(asp.indices,[1, 2, 7, 4, 5]) |
|
assert_array_equal(asp.toarray(), bsp.toarray()) |
|
|
|
def test_eliminate_zeros(self): |
|
data = array([1, 0, 0, 0, 2, 0, 3, 0]) |
|
indices = array([1, 2, 3, 4, 5, 6, 7, 8]) |
|
indptr = array([0, 3, 8]) |
|
asp = self.csr_container((data, indices, indptr), shape=(2,10)) |
|
bsp = asp.copy() |
|
asp.eliminate_zeros() |
|
assert_array_equal(asp.nnz, 3) |
|
assert_array_equal(asp.data,[1, 2, 3]) |
|
assert_array_equal(asp.toarray(), bsp.toarray()) |
|
|
|
def test_ufuncs(self): |
|
X = self.csr_container(np.arange(20).reshape(4, 5) / 20.) |
|
for f in ["sin", "tan", "arcsin", "arctan", "sinh", "tanh", |
|
"arcsinh", "arctanh", "rint", "sign", "expm1", "log1p", |
|
"deg2rad", "rad2deg", "floor", "ceil", "trunc", "sqrt"]: |
|
assert_equal(hasattr(self.datsp, f), True) |
|
X2 = getattr(X, f)() |
|
assert_equal(X.shape, X2.shape) |
|
assert_array_equal(X.indices, X2.indices) |
|
assert_array_equal(X.indptr, X2.indptr) |
|
assert_array_equal(X2.toarray(), getattr(np, f)(X.toarray())) |
|
|
|
def test_unsorted_arithmetic(self): |
|
data = arange(5) |
|
indices = array([7, 2, 1, 5, 4]) |
|
indptr = array([0, 3, 5]) |
|
asp = self.csr_container((data, indices, indptr), shape=(2,10)) |
|
data = arange(6) |
|
indices = array([8, 1, 5, 7, 2, 4]) |
|
indptr = array([0, 2, 6]) |
|
bsp = self.csr_container((data, indices, indptr), shape=(2,10)) |
|
assert_equal((asp + bsp).toarray(), asp.toarray() + bsp.toarray()) |
|
|
|
def test_fancy_indexing_broadcast(self): |
|
|
|
I = np.array([[1], [2], [3]]) |
|
J = np.array([3, 4, 2]) |
|
|
|
np.random.seed(1234) |
|
D = self.asdense(np.random.rand(5, 7)) |
|
S = self.spcreator(D) |
|
|
|
SIJ = S[I,J] |
|
if issparse(SIJ): |
|
SIJ = SIJ.toarray() |
|
assert_equal(SIJ, D[I,J]) |
|
|
|
def test_has_sorted_indices(self): |
|
"Ensure has_sorted_indices memoizes sorted state for sort_indices" |
|
sorted_inds = np.array([0, 1]) |
|
unsorted_inds = np.array([1, 0]) |
|
data = np.array([1, 1]) |
|
indptr = np.array([0, 2]) |
|
M = self.csr_container((data, sorted_inds, indptr)).copy() |
|
assert_equal(True, M.has_sorted_indices) |
|
assert isinstance(M.has_sorted_indices, bool) |
|
|
|
M = self.csr_container((data, unsorted_inds, indptr)).copy() |
|
assert_equal(False, M.has_sorted_indices) |
|
|
|
|
|
M.sort_indices() |
|
assert_equal(True, M.has_sorted_indices) |
|
assert_array_equal(M.indices, sorted_inds) |
|
|
|
M = self.csr_container((data, unsorted_inds, indptr)).copy() |
|
|
|
M.has_sorted_indices = True |
|
assert_equal(True, M.has_sorted_indices) |
|
assert_array_equal(M.indices, unsorted_inds) |
|
|
|
|
|
M.sort_indices() |
|
assert_array_equal(M.indices, unsorted_inds) |
|
|
|
def test_has_canonical_format(self): |
|
"Ensure has_canonical_format memoizes state for sum_duplicates" |
|
|
|
M = self.csr_container((np.array([2]), np.array([0]), np.array([0, 1]))) |
|
assert_equal(True, M.has_canonical_format) |
|
|
|
indices = np.array([0, 0]) |
|
data = np.array([1, 1]) |
|
indptr = np.array([0, 2]) |
|
|
|
M = self.csr_container((data, indices, indptr)).copy() |
|
assert_equal(False, M.has_canonical_format) |
|
assert isinstance(M.has_canonical_format, bool) |
|
|
|
|
|
M.sum_duplicates() |
|
assert_equal(True, M.has_canonical_format) |
|
assert_equal(1, len(M.indices)) |
|
|
|
M = self.csr_container((data, indices, indptr)).copy() |
|
|
|
M.has_canonical_format = True |
|
assert_equal(True, M.has_canonical_format) |
|
assert_equal(2, len(M.indices)) |
|
|
|
|
|
M.sum_duplicates() |
|
assert_equal(2, len(M.indices)) |
|
|
|
def test_scalar_idx_dtype(self): |
|
|
|
|
|
indptr = np.zeros(2, dtype=np.int32) |
|
indices = np.zeros(0, dtype=np.int32) |
|
vals = np.zeros(0) |
|
a = self.csr_container((vals, indices, indptr), shape=(1, 2**31-1)) |
|
b = self.csr_container((vals, indices, indptr), shape=(1, 2**31)) |
|
ij = np.zeros((2, 0), dtype=np.int32) |
|
c = self.csr_container((vals, ij), shape=(1, 2**31-1)) |
|
d = self.csr_container((vals, ij), shape=(1, 2**31)) |
|
e = self.csr_container((1, 2**31-1)) |
|
f = self.csr_container((1, 2**31)) |
|
assert_equal(a.indptr.dtype, np.int32) |
|
assert_equal(b.indptr.dtype, np.int64) |
|
assert_equal(c.indptr.dtype, np.int32) |
|
assert_equal(d.indptr.dtype, np.int64) |
|
assert_equal(e.indptr.dtype, np.int32) |
|
assert_equal(f.indptr.dtype, np.int64) |
|
|
|
|
|
for x in [a, b, c, d, e, f]: |
|
x + x |
|
|
|
def test_setdiag_csr(self): |
|
|
|
D = self.dia_container(([np.arange(1002)], [0]), shape=(1002, 1002)) |
|
A = self.spcreator(D) |
|
A.setdiag(5 * np.ones(A.shape[0])) |
|
assert A[-1, -1] == 5 |
|
|
|
def test_binop_explicit_zeros(self): |
|
|
|
|
|
a = self.csr_container([[0, 1, 0]]) |
|
b = self.csr_container([[1, 1, 0]]) |
|
assert (a + b).nnz == 2 |
|
assert a.multiply(b).nnz == 1 |
|
|
|
|
|
TestCSR.init_class() |
|
|
|
|
|
class TestCSRMatrix(_MatrixMixin, TestCSR): |
|
@classmethod |
|
def spcreator(cls, *args, **kwargs): |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
return csr_matrix(*args, **kwargs) |
|
|
|
|
|
TestCSRMatrix.init_class() |
|
|
|
|
|
class TestCSC(sparse_test_class()): |
|
@classmethod |
|
def spcreator(cls, *args, **kwargs): |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
return csc_array(*args, **kwargs) |
|
math_dtypes = [np.bool_, np.int_, np.float64, np.complex128] |
|
|
|
def test_constructor1(self): |
|
b = array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 2, 0, 3]], 'd') |
|
bsp = self.csc_container(b) |
|
assert_array_almost_equal(bsp.data,[1,2,1,3]) |
|
assert_array_equal(bsp.indices,[0,2,1,2]) |
|
assert_array_equal(bsp.indptr,[0,1,2,3,4]) |
|
assert_equal(bsp.nnz,4) |
|
assert_equal(bsp.shape,b.shape) |
|
assert_equal(bsp.format,'csc') |
|
|
|
def test_constructor2(self): |
|
b = zeros((6,6),'d') |
|
b[2,4] = 5 |
|
bsp = self.csc_container(b) |
|
assert_array_almost_equal(bsp.data,[5]) |
|
assert_array_equal(bsp.indices,[2]) |
|
assert_array_equal(bsp.indptr,[0,0,0,0,0,1,1]) |
|
|
|
def test_constructor3(self): |
|
b = array([[1, 0], [0, 0], [0, 2]], 'd') |
|
bsp = self.csc_container(b) |
|
assert_array_almost_equal(bsp.data,[1,2]) |
|
assert_array_equal(bsp.indices,[0,2]) |
|
assert_array_equal(bsp.indptr,[0,1,2]) |
|
|
|
def test_constructor4(self): |
|
|
|
row = array([2, 3, 1, 3, 0, 1, 3, 0, 2, 1, 2]) |
|
col = array([0, 1, 0, 0, 1, 1, 2, 2, 2, 2, 1]) |
|
data = array([6., 10., 3., 9., 1., 4., 11., 2., 8., 5., 7.]) |
|
|
|
ij = vstack((row,col)) |
|
csc = self.csc_container((data,ij),(4,3)) |
|
assert_array_equal(arange(12).reshape(4, 3), csc.toarray()) |
|
|
|
|
|
csc = self.csc_container(([1,1,1,1], ([0,2,2,0], [0,1,1,0]))) |
|
assert csc.nnz == 2 |
|
|
|
def test_constructor5(self): |
|
|
|
indptr = array([0,1,3,3]) |
|
indices = array([0,5,1,2]) |
|
data = array([1,2,3,4]) |
|
csc = self.csc_container((data, indices, indptr)) |
|
assert_array_equal(csc.shape,(6,3)) |
|
|
|
def test_constructor6(self): |
|
|
|
indptr = [0, 1, 3, 3] |
|
indices = [0, 5, 1, 2] |
|
data = [1, 2, 3, 4] |
|
csc = self.csc_container((data, indices, indptr)) |
|
assert_array_equal(csc.shape,(6,3)) |
|
assert_(np.issubdtype(csc.dtype, np.signedinteger)) |
|
|
|
def test_eliminate_zeros(self): |
|
data = array([1, 0, 0, 0, 2, 0, 3, 0]) |
|
indices = array([1, 2, 3, 4, 5, 6, 7, 8]) |
|
indptr = array([0, 3, 8]) |
|
asp = self.csc_container((data, indices, indptr), shape=(10,2)) |
|
bsp = asp.copy() |
|
asp.eliminate_zeros() |
|
assert_array_equal(asp.nnz, 3) |
|
assert_array_equal(asp.data,[1, 2, 3]) |
|
assert_array_equal(asp.toarray(), bsp.toarray()) |
|
|
|
def test_sort_indices(self): |
|
data = arange(5) |
|
row = array([7, 2, 1, 5, 4]) |
|
ptr = [0, 3, 5] |
|
asp = self.csc_container((data, row, ptr), shape=(10,2)) |
|
bsp = asp.copy() |
|
asp.sort_indices() |
|
assert_array_equal(asp.indices,[1, 2, 7, 4, 5]) |
|
assert_array_equal(asp.toarray(), bsp.toarray()) |
|
|
|
def test_ufuncs(self): |
|
X = self.csc_container(np.arange(21).reshape(7, 3) / 21.) |
|
for f in ["sin", "tan", "arcsin", "arctan", "sinh", "tanh", |
|
"arcsinh", "arctanh", "rint", "sign", "expm1", "log1p", |
|
"deg2rad", "rad2deg", "floor", "ceil", "trunc", "sqrt"]: |
|
assert_equal(hasattr(self.datsp, f), True) |
|
X2 = getattr(X, f)() |
|
assert_equal(X.shape, X2.shape) |
|
assert_array_equal(X.indices, X2.indices) |
|
assert_array_equal(X.indptr, X2.indptr) |
|
assert_array_equal(X2.toarray(), getattr(np, f)(X.toarray())) |
|
|
|
def test_unsorted_arithmetic(self): |
|
data = arange(5) |
|
indices = array([7, 2, 1, 5, 4]) |
|
indptr = array([0, 3, 5]) |
|
asp = self.csc_container((data, indices, indptr), shape=(10,2)) |
|
data = arange(6) |
|
indices = array([8, 1, 5, 7, 2, 4]) |
|
indptr = array([0, 2, 6]) |
|
bsp = self.csc_container((data, indices, indptr), shape=(10,2)) |
|
assert_equal((asp + bsp).toarray(), asp.toarray() + bsp.toarray()) |
|
|
|
def test_fancy_indexing_broadcast(self): |
|
|
|
I = np.array([[1], [2], [3]]) |
|
J = np.array([3, 4, 2]) |
|
|
|
np.random.seed(1234) |
|
D = self.asdense(np.random.rand(5, 7)) |
|
S = self.spcreator(D) |
|
|
|
SIJ = S[I,J] |
|
if issparse(SIJ): |
|
SIJ = SIJ.toarray() |
|
assert_equal(SIJ, D[I,J]) |
|
|
|
def test_scalar_idx_dtype(self): |
|
|
|
|
|
indptr = np.zeros(2, dtype=np.int32) |
|
indices = np.zeros(0, dtype=np.int32) |
|
vals = np.zeros(0) |
|
a = self.csc_container((vals, indices, indptr), shape=(2**31-1, 1)) |
|
b = self.csc_container((vals, indices, indptr), shape=(2**31, 1)) |
|
ij = np.zeros((2, 0), dtype=np.int32) |
|
c = self.csc_container((vals, ij), shape=(2**31-1, 1)) |
|
d = self.csc_container((vals, ij), shape=(2**31, 1)) |
|
e = self.csr_container((1, 2**31-1)) |
|
f = self.csr_container((1, 2**31)) |
|
assert_equal(a.indptr.dtype, np.int32) |
|
assert_equal(b.indptr.dtype, np.int64) |
|
assert_equal(c.indptr.dtype, np.int32) |
|
assert_equal(d.indptr.dtype, np.int64) |
|
assert_equal(e.indptr.dtype, np.int32) |
|
assert_equal(f.indptr.dtype, np.int64) |
|
|
|
|
|
for x in [a, b, c, d, e, f]: |
|
x + x |
|
|
|
def test_setdiag_csc(self): |
|
|
|
D = self.dia_container(([np.arange(1002)], [0]), shape=(1002, 1002)) |
|
A = self.spcreator(D) |
|
A.setdiag(5 * np.ones(A.shape[0])) |
|
assert A[-1, -1] == 5 |
|
|
|
|
|
TestCSC.init_class() |
|
|
|
|
|
class TestCSCMatrix(_MatrixMixin, TestCSC): |
|
@classmethod |
|
def spcreator(cls, *args, **kwargs): |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
return csc_matrix(*args, **kwargs) |
|
|
|
|
|
TestCSCMatrix.init_class() |
|
|
|
|
|
class TestDOK(sparse_test_class(minmax=False, nnz_axis=False)): |
|
spcreator = dok_array |
|
math_dtypes = [np.int_, np.float64, np.complex128] |
|
|
|
def test_mult(self): |
|
A = self.dok_container((10, 12)) |
|
A[0, 3] = 10 |
|
A[5, 6] = 20 |
|
D = A @ A.T |
|
E = A @ A.T.conjugate() |
|
assert_array_equal(D.toarray(), E.toarray()) |
|
|
|
def test_add_nonzero(self): |
|
A = self.spcreator((3,2)) |
|
A[0,1] = -10 |
|
A[2,0] = 20 |
|
A = A + 10 |
|
B = array([[10, 0], [10, 10], [30, 10]]) |
|
assert_array_equal(A.toarray(), B) |
|
|
|
A = A + 1j |
|
B = B + 1j |
|
assert_array_equal(A.toarray(), B) |
|
|
|
def test_dok_divide_scalar(self): |
|
A = self.spcreator((3,2)) |
|
A[0,1] = -10 |
|
A[2,0] = 20 |
|
|
|
assert_array_equal((A/1j).toarray(), A.toarray()/1j) |
|
assert_array_equal((A/9).toarray(), A.toarray()/9) |
|
|
|
def test_convert(self): |
|
|
|
(m, n) = (6, 7) |
|
a = self.dok_container((m, n)) |
|
|
|
|
|
a[2,1] = 1 |
|
a[0,2] = 2 |
|
a[3,1] = 3 |
|
a[1,5] = 4 |
|
a[4,3] = 5 |
|
a[4,2] = 6 |
|
|
|
|
|
assert_array_equal(a.toarray()[:,n-1], zeros(m,)) |
|
|
|
|
|
csc = a.tocsc() |
|
assert_array_equal(csc.toarray()[:,n-1], zeros(m,)) |
|
|
|
|
|
(m, n) = (n, m) |
|
b = a.transpose() |
|
assert_equal(b.shape, (m, n)) |
|
|
|
assert_array_equal(b.toarray()[m-1,:], zeros(n,)) |
|
|
|
|
|
csr = b.tocsr() |
|
assert_array_equal(csr.toarray()[m-1,:], zeros(n,)) |
|
|
|
def test_ctor(self): |
|
|
|
assert_raises(TypeError, self.dok_container) |
|
|
|
|
|
b = array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 2, 0, 3]], 'd') |
|
A = self.dok_container(b) |
|
assert_equal(b.dtype, A.dtype) |
|
assert_equal(A.toarray(), b) |
|
|
|
|
|
c = self.csr_container(b) |
|
assert_equal(A.toarray(), c.toarray()) |
|
|
|
data = [[0, 1, 2], [3, 0, 0]] |
|
d = self.dok_container(data, dtype=np.float32) |
|
assert_equal(d.dtype, np.float32) |
|
da = d.toarray() |
|
assert_equal(da.dtype, np.float32) |
|
assert_array_equal(da, data) |
|
|
|
def test_ticket1160(self): |
|
|
|
a = self.dok_container((3,3)) |
|
a[0,0] = 0 |
|
|
|
|
|
assert_((0,0) not in a.keys(), "Unexpected entry (0,0) in keys") |
|
|
|
|
|
b = self.dok_container((3,3)) |
|
b[:,0] = 0 |
|
assert_(len(b.keys()) == 0, "Unexpected entries in keys") |
|
|
|
|
|
class TestDOKMatrix(_MatrixMixin, TestDOK): |
|
spcreator = dok_matrix |
|
|
|
|
|
TestDOK.init_class() |
|
TestDOKMatrix.init_class() |
|
|
|
|
|
class TestLIL(sparse_test_class(minmax=False)): |
|
spcreator = lil_array |
|
math_dtypes = [np.int_, np.float64, np.complex128] |
|
|
|
def test_dot(self): |
|
A = zeros((10, 10), np.complex128) |
|
A[0, 3] = 10 |
|
A[5, 6] = 20j |
|
|
|
B = self.lil_container((10, 10), dtype=np.complex128) |
|
B[0, 3] = 10 |
|
B[5, 6] = 20j |
|
|
|
|
|
if platform.machine() != 'ppc64le': |
|
assert_array_equal(A @ A.T, (B @ B.T).toarray()) |
|
|
|
assert_array_equal(A @ A.conjugate().T, (B @ B.conjugate().T).toarray()) |
|
|
|
def test_scalar_mul(self): |
|
x = self.lil_container((3, 3)) |
|
x[0, 0] = 2 |
|
|
|
x = x*2 |
|
assert_equal(x[0, 0], 4) |
|
|
|
x = x*0 |
|
assert_equal(x[0, 0], 0) |
|
|
|
def test_truediv_scalar(self): |
|
A = self.spcreator((3, 2)) |
|
A[0, 1] = -10 |
|
A[2, 0] = 20 |
|
|
|
assert_array_equal((A / 1j).toarray(), A.toarray() / 1j) |
|
assert_array_equal((A / 9).toarray(), A.toarray() / 9) |
|
|
|
def test_inplace_ops(self): |
|
A = self.lil_container([[0, 2, 3], [4, 0, 6]]) |
|
B = self.lil_container([[0, 1, 0], [0, 2, 3]]) |
|
|
|
data = {'add': (B, A + B), |
|
'sub': (B, A - B), |
|
'mul': (3, A * 3)} |
|
|
|
for op, (other, expected) in data.items(): |
|
result = A.copy() |
|
getattr(result, f'__i{op}__')(other) |
|
|
|
assert_array_equal(result.toarray(), expected.toarray()) |
|
|
|
|
|
A = self.lil_container((1, 3), dtype=np.dtype('float64')) |
|
B = self.asdense([0.1, 0.1, 0.1]) |
|
A[0, :] += B |
|
assert_array_equal(A[0, :].toarray(), B) |
|
|
|
def test_lil_iteration(self): |
|
row_data = [[1, 2, 3], [4, 5, 6]] |
|
B = self.lil_container(array(row_data)) |
|
for r, row in enumerate(B): |
|
assert_array_equal(row.toarray(), array(row_data[r], ndmin=row.ndim)) |
|
|
|
def test_lil_from_csr(self): |
|
|
|
B = self.lil_container((10, 10)) |
|
B[0, 3] = 10 |
|
B[5, 6] = 20 |
|
B[8, 3] = 30 |
|
B[3, 8] = 40 |
|
B[8, 9] = 50 |
|
C = B.tocsr() |
|
D = self.lil_container(C) |
|
assert_array_equal(C.toarray(), D.toarray()) |
|
|
|
def test_fancy_indexing_lil(self): |
|
M = self.asdense(arange(25).reshape(5, 5)) |
|
A = self.lil_container(M) |
|
|
|
assert_equal(A[array([1, 2, 3]), 2:3].toarray(), |
|
M[array([1, 2, 3]), 2:3]) |
|
|
|
def test_point_wise_multiply(self): |
|
l = self.lil_container((4, 3)) |
|
l[0, 0] = 1 |
|
l[1, 1] = 2 |
|
l[2, 2] = 3 |
|
l[3, 1] = 4 |
|
|
|
m = self.lil_container((4, 3)) |
|
m[0, 0] = 1 |
|
m[0, 1] = 2 |
|
m[2, 2] = 3 |
|
m[3, 1] = 4 |
|
m[3, 2] = 4 |
|
|
|
assert_array_equal(l.multiply(m).toarray(), |
|
m.multiply(l).toarray()) |
|
|
|
assert_array_equal(l.multiply(m).toarray(), |
|
[[1, 0, 0], |
|
[0, 0, 0], |
|
[0, 0, 9], |
|
[0, 16, 0]]) |
|
|
|
def test_lil_multiply_removal(self): |
|
|
|
a = self.lil_container(np.ones((3, 3))) |
|
a *= 2. |
|
a[0, :] = 0 |
|
|
|
|
|
class TestLILMatrix(_MatrixMixin, TestLIL): |
|
spcreator = lil_matrix |
|
|
|
|
|
TestLIL.init_class() |
|
TestLILMatrix.init_class() |
|
|
|
|
|
class TestCOO(sparse_test_class(getset=False, |
|
slicing=False, slicing_assign=False, |
|
fancy_indexing=False, fancy_assign=False)): |
|
spcreator = coo_array |
|
math_dtypes = [np.int_, np.float64, np.complex128] |
|
|
|
def test_constructor1(self): |
|
|
|
row = array([2, 3, 1, 3, 0, 1, 3, 0, 2, 1, 2]) |
|
col = array([0, 1, 0, 0, 1, 1, 2, 2, 2, 2, 1]) |
|
data = array([6., 10., 3., 9., 1., 4., 11., 2., 8., 5., 7.]) |
|
|
|
coo = self.coo_container((data,(row,col)),(4,3)) |
|
assert_array_equal(arange(12).reshape(4, 3), coo.toarray()) |
|
|
|
|
|
coo = self.coo_container(([2**63 + 1, 1], ([0, 1], [0, 1])), dtype=np.uint64) |
|
dense = array([[2**63 + 1, 0], [0, 1]], dtype=np.uint64) |
|
assert_array_equal(dense, coo.toarray()) |
|
|
|
def test_constructor2(self): |
|
|
|
row = array([0,1,2,2,2,2,0,0,2,2]) |
|
col = array([0,2,0,2,1,1,1,0,0,2]) |
|
data = array([2,9,-4,5,7,0,-1,2,1,-5]) |
|
coo = self.coo_container((data,(row,col)),(3,3)) |
|
|
|
mat = array([[4, -1, 0], [0, 0, 9], [-3, 7, 0]]) |
|
|
|
assert_array_equal(mat, coo.toarray()) |
|
|
|
def test_constructor3(self): |
|
|
|
coo = self.coo_container((4,3)) |
|
|
|
assert_array_equal(coo.shape,(4,3)) |
|
assert_array_equal(coo.row,[]) |
|
assert_array_equal(coo.col,[]) |
|
assert_array_equal(coo.data,[]) |
|
assert_array_equal(coo.toarray(), zeros((4, 3))) |
|
|
|
def test_constructor4(self): |
|
|
|
mat = array([[0,1,0,0], |
|
[7,0,3,0], |
|
[0,4,0,0]]) |
|
coo = self.coo_container(mat) |
|
assert_array_equal(coo.toarray(), mat) |
|
|
|
|
|
mat = array([0,1,0,0]) |
|
coo = self.coo_container(mat) |
|
expected = mat if self.is_array_test else mat.reshape(1, -1) |
|
assert_array_equal(coo.toarray(), expected) |
|
|
|
|
|
with pytest.raises(TypeError, match=r'object cannot be interpreted'): |
|
self.coo_container([0, 11, 22, 33], ([0, 1, 2, 3], [0, 0, 0, 0])) |
|
|
|
|
|
with pytest.raises(ValueError, match=r'inconsistent shapes'): |
|
self.coo_container([0, 11, 22, 33], shape=(4, 4)) |
|
|
|
def test_constructor_data_ij_dtypeNone(self): |
|
data = [1] |
|
coo = self.coo_container((data, ([0], [0])), dtype=None) |
|
assert coo.dtype == np.array(data).dtype |
|
|
|
@pytest.mark.xfail(run=False, reason='COO does not have a __getitem__') |
|
def test_iterator(self): |
|
pass |
|
|
|
def test_todia_all_zeros(self): |
|
zeros = [[0, 0]] |
|
dia = self.coo_container(zeros).todia() |
|
assert_array_equal(dia.toarray(), zeros) |
|
|
|
def test_sum_duplicates(self): |
|
coo = self.coo_container((4,3)) |
|
coo.sum_duplicates() |
|
coo = self.coo_container(([1,2], ([1,0], [1,0]))) |
|
coo.sum_duplicates() |
|
assert_array_equal(coo.toarray(), [[2,0],[0,1]]) |
|
coo = self.coo_container(([1,2], ([1,1], [1,1]))) |
|
coo.sum_duplicates() |
|
assert_array_equal(coo.toarray(), [[0,0],[0,3]]) |
|
assert_array_equal(coo.row, [1]) |
|
assert_array_equal(coo.col, [1]) |
|
assert_array_equal(coo.data, [3]) |
|
|
|
def test_todok_duplicates(self): |
|
coo = self.coo_container(([1,1,1,1], ([0,2,2,0], [0,1,1,0]))) |
|
dok = coo.todok() |
|
assert_array_equal(dok.toarray(), coo.toarray()) |
|
|
|
def test_tocompressed_duplicates(self): |
|
coo = self.coo_container(([1,1,1,1], ([0,2,2,0], [0,1,1,0]))) |
|
csr = coo.tocsr() |
|
assert_equal(csr.nnz + 2, coo.nnz) |
|
csc = coo.tocsc() |
|
assert_equal(csc.nnz + 2, coo.nnz) |
|
|
|
def test_eliminate_zeros(self): |
|
data = array([1, 0, 0, 0, 2, 0, 3, 0]) |
|
row = array([0, 0, 0, 1, 1, 1, 1, 1]) |
|
col = array([1, 2, 3, 4, 5, 6, 7, 8]) |
|
asp = self.coo_container((data, (row, col)), shape=(2,10)) |
|
bsp = asp.copy() |
|
asp.eliminate_zeros() |
|
assert_((asp.data != 0).all()) |
|
assert_array_equal(asp.toarray(), bsp.toarray()) |
|
|
|
def test_reshape_copy(self): |
|
arr = [[0, 10, 0, 0], [0, 0, 0, 0], [0, 20, 30, 40]] |
|
new_shape = (2, 6) |
|
x = self.coo_container(arr) |
|
|
|
y = x.reshape(new_shape) |
|
assert_(y.data is x.data) |
|
|
|
y = x.reshape(new_shape, copy=False) |
|
assert_(y.data is x.data) |
|
|
|
y = x.reshape(new_shape, copy=True) |
|
assert_(not np.may_share_memory(y.data, x.data)) |
|
|
|
def test_large_dimensions_reshape(self): |
|
|
|
|
|
mat1 = self.coo_container(([1], ([3000000], [1000])), (3000001, 1001)) |
|
mat2 = self.coo_container(([1], ([1000], [3000000])), (1001, 3000001)) |
|
|
|
|
|
|
|
assert_((mat1.reshape((1001, 3000001), order='C') != mat2).nnz == 0) |
|
assert_((mat2.reshape((3000001, 1001), order='F') != mat1).nnz == 0) |
|
|
|
|
|
class TestCOOMatrix(_MatrixMixin, TestCOO): |
|
spcreator = coo_matrix |
|
|
|
|
|
TestCOO.init_class() |
|
TestCOOMatrix.init_class() |
|
|
|
|
|
class TestDIA(sparse_test_class(getset=False, slicing=False, slicing_assign=False, |
|
fancy_indexing=False, fancy_assign=False, |
|
minmax=False, nnz_axis=False)): |
|
spcreator = dia_array |
|
math_dtypes = [np.int_, np.float64, np.complex128] |
|
|
|
def test_constructor1(self): |
|
D = array([[1, 0, 3, 0], |
|
[1, 2, 0, 4], |
|
[0, 2, 3, 0], |
|
[0, 0, 3, 4]]) |
|
data = np.array([[1,2,3,4]]).repeat(3,axis=0) |
|
offsets = np.array([0,-1,2]) |
|
assert_equal(self.dia_container((data, offsets), shape=(4, 4)).toarray(), D) |
|
|
|
@pytest.mark.xfail(run=False, reason='DIA does not have a __getitem__') |
|
def test_iterator(self): |
|
pass |
|
|
|
@with_64bit_maxval_limit(3) |
|
def test_setdiag_dtype(self): |
|
m = self.dia_container(np.eye(3)) |
|
assert_equal(m.offsets.dtype, np.int32) |
|
m.setdiag((3,), k=2) |
|
assert_equal(m.offsets.dtype, np.int32) |
|
|
|
m = self.dia_container(np.eye(4)) |
|
assert_equal(m.offsets.dtype, np.int64) |
|
m.setdiag((3,), k=3) |
|
assert_equal(m.offsets.dtype, np.int64) |
|
|
|
@pytest.mark.skip(reason='DIA stores extra zeros') |
|
def test_getnnz_axis(self): |
|
pass |
|
|
|
def test_convert_gh14555(self): |
|
|
|
m = self.dia_container(([[1, 1, 0]], [-1]), shape=(4, 2)) |
|
expected = m.toarray() |
|
assert_array_equal(m.tocsc().toarray(), expected) |
|
assert_array_equal(m.tocsr().toarray(), expected) |
|
|
|
def test_tocoo_gh10050(self): |
|
|
|
m = self.dia_container([[1, 2], [3, 4]]).tocoo() |
|
flat_inds = np.ravel_multi_index((m.row, m.col), m.shape) |
|
inds_are_sorted = np.all(np.diff(flat_inds) > 0) |
|
assert m.has_canonical_format == inds_are_sorted |
|
|
|
def test_tocoo_tocsr_tocsc_gh19245(self): |
|
|
|
data = np.array([[1, 2, 3, 4]]).repeat(3, axis=0) |
|
offsets = np.array([0, -1, 2], dtype=np.int32) |
|
dia = sparse.dia_array((data, offsets), shape=(4, 4)) |
|
|
|
coo = dia.tocoo() |
|
assert coo.col.dtype == np.int32 |
|
csr = dia.tocsr() |
|
assert csr.indices.dtype == np.int32 |
|
csc = dia.tocsc() |
|
assert csc.indices.dtype == np.int32 |
|
|
|
def test_mul_scalar(self): |
|
|
|
m = self.dia_container([[1, 2], [0, 4]]) |
|
res = m * 3 |
|
assert isinstance(res, m.__class__) |
|
assert_array_equal(res.toarray(), [[3, 6], [0, 12]]) |
|
|
|
res2 = m.multiply(3) |
|
assert isinstance(res2, m.__class__) |
|
assert_array_equal(res2.toarray(), [[3, 6], [0, 12]]) |
|
|
|
|
|
class TestDIAMatrix(_MatrixMixin, TestDIA): |
|
spcreator = dia_matrix |
|
|
|
|
|
TestDIA.init_class() |
|
TestDIAMatrix.init_class() |
|
|
|
|
|
class TestBSR(sparse_test_class(getset=False, |
|
slicing=False, slicing_assign=False, |
|
fancy_indexing=False, fancy_assign=False, |
|
nnz_axis=False)): |
|
spcreator = bsr_array |
|
math_dtypes = [np.int_, np.float64, np.complex128] |
|
|
|
def test_constructor1(self): |
|
|
|
indptr = array([0,2,2,4]) |
|
indices = array([0,2,2,3]) |
|
data = zeros((4,2,3)) |
|
|
|
data[0] = array([[0, 1, 2], |
|
[3, 0, 5]]) |
|
data[1] = array([[0, 2, 4], |
|
[6, 0, 10]]) |
|
data[2] = array([[0, 4, 8], |
|
[12, 0, 20]]) |
|
data[3] = array([[0, 5, 10], |
|
[15, 0, 25]]) |
|
|
|
A = kron([[1,0,2,0],[0,0,0,0],[0,0,4,5]], [[0,1,2],[3,0,5]]) |
|
Asp = self.bsr_container((data,indices,indptr),shape=(6,12)) |
|
assert_equal(Asp.toarray(), A) |
|
|
|
|
|
Asp = self.bsr_container((data,indices,indptr)) |
|
assert_equal(Asp.toarray(), A) |
|
|
|
def test_constructor2(self): |
|
|
|
|
|
|
|
for shape in [(1,1), (5,1), (1,10), (10,4), (3,7), (2,1)]: |
|
A = zeros(shape) |
|
assert_equal(self.bsr_container(A).toarray(), A) |
|
A = zeros((4,6)) |
|
assert_equal(self.bsr_container(A, blocksize=(2, 2)).toarray(), A) |
|
assert_equal(self.bsr_container(A, blocksize=(2, 3)).toarray(), A) |
|
|
|
A = kron([[1,0,2,0],[0,0,0,0],[0,0,4,5]], [[0,1,2],[3,0,5]]) |
|
assert_equal(self.bsr_container(A).toarray(), A) |
|
assert_equal(self.bsr_container(A, shape=(6, 12)).toarray(), A) |
|
assert_equal(self.bsr_container(A, blocksize=(1, 1)).toarray(), A) |
|
assert_equal(self.bsr_container(A, blocksize=(2, 3)).toarray(), A) |
|
assert_equal(self.bsr_container(A, blocksize=(2, 6)).toarray(), A) |
|
assert_equal(self.bsr_container(A, blocksize=(2, 12)).toarray(), A) |
|
assert_equal(self.bsr_container(A, blocksize=(3, 12)).toarray(), A) |
|
assert_equal(self.bsr_container(A, blocksize=(6, 12)).toarray(), A) |
|
|
|
A = kron([[1,0,2,0],[0,1,0,0],[0,0,0,0]], [[0,1,2],[3,0,5]]) |
|
assert_equal(self.bsr_container(A, blocksize=(2, 3)).toarray(), A) |
|
|
|
def test_constructor3(self): |
|
|
|
arg = ([1,2,3], ([0,1,1], [0,0,1])) |
|
A = array([[1,0],[2,3]]) |
|
assert_equal(self.bsr_container(arg, blocksize=(2, 2)).toarray(), A) |
|
|
|
def test_constructor4(self): |
|
|
|
|
|
n = 8 |
|
data = np.ones((n, n, 1), dtype=np.int8) |
|
indptr = np.array([0, n], dtype=np.int32) |
|
indices = np.arange(n, dtype=np.int32) |
|
self.bsr_container((data, indices, indptr), blocksize=(n, 1), copy=False) |
|
|
|
def test_constructor5(self): |
|
|
|
n = 8 |
|
data_1dim = np.ones(n) |
|
data = np.ones((n, n, n)) |
|
indptr = np.array([0, n]) |
|
indices = np.arange(n) |
|
|
|
with assert_raises(ValueError): |
|
|
|
self.bsr_container((data_1dim, indices, indptr)) |
|
|
|
with assert_raises(ValueError): |
|
|
|
self.bsr_container((data, indices, indptr), blocksize=(1, 1, 1)) |
|
|
|
with assert_raises(ValueError): |
|
|
|
self.bsr_container((data, indices, indptr), blocksize=(1, 1)) |
|
|
|
def test_default_dtype(self): |
|
|
|
values = [[[1], [1]], [[1], [1]]] |
|
indptr = np.array([0, 2], dtype=np.int32) |
|
indices = np.array([0, 1], dtype=np.int32) |
|
b = self.bsr_container((values, indices, indptr), blocksize=(2, 1)) |
|
assert b.dtype == np.array(values).dtype |
|
|
|
def test_bsr_tocsr(self): |
|
|
|
indptr = array([0, 2, 2, 4]) |
|
indices = array([0, 2, 2, 3]) |
|
data = zeros((4, 2, 3)) |
|
|
|
data[0] = array([[0, 1, 2], |
|
[3, 0, 5]]) |
|
data[1] = array([[0, 2, 4], |
|
[6, 0, 10]]) |
|
data[2] = array([[0, 4, 8], |
|
[12, 0, 20]]) |
|
data[3] = array([[0, 5, 10], |
|
[15, 0, 25]]) |
|
|
|
A = kron([[1, 0, 2, 0], [0, 0, 0, 0], [0, 0, 4, 5]], |
|
[[0, 1, 2], [3, 0, 5]]) |
|
Absr = self.bsr_container((data, indices, indptr), shape=(6, 12)) |
|
Acsr = Absr.tocsr() |
|
Acsr_via_coo = Absr.tocoo().tocsr() |
|
assert_equal(Acsr.toarray(), A) |
|
assert_equal(Acsr.toarray(), Acsr_via_coo.toarray()) |
|
|
|
def test_eliminate_zeros(self): |
|
data = kron([1, 0, 0, 0, 2, 0, 3, 0], [[1,1],[1,1]]).T |
|
data = data.reshape(-1,2,2) |
|
indices = array([1, 2, 3, 4, 5, 6, 7, 8]) |
|
indptr = array([0, 3, 8]) |
|
asp = self.bsr_container((data, indices, indptr), shape=(4,20)) |
|
bsp = asp.copy() |
|
asp.eliminate_zeros() |
|
assert_array_equal(asp.nnz, 3*4) |
|
assert_array_equal(asp.toarray(), bsp.toarray()) |
|
|
|
|
|
def test_eliminate_zeros_all_zero(self): |
|
np.random.seed(0) |
|
m = self.bsr_container(np.random.random((12, 12)), blocksize=(2, 3)) |
|
|
|
|
|
m.data[m.data <= 0.9] = 0 |
|
m.eliminate_zeros() |
|
assert_equal(m.nnz, 66) |
|
assert_array_equal(m.data.shape, (11, 2, 3)) |
|
|
|
|
|
m.data[m.data <= 1.0] = 0 |
|
m.eliminate_zeros() |
|
assert_equal(m.nnz, 0) |
|
assert_array_equal(m.data.shape, (0, 2, 3)) |
|
assert_array_equal(m.toarray(), np.zeros((12, 12))) |
|
|
|
|
|
m.eliminate_zeros() |
|
assert_equal(m.nnz, 0) |
|
assert_array_equal(m.data.shape, (0, 2, 3)) |
|
assert_array_equal(m.toarray(), np.zeros((12, 12))) |
|
|
|
def test_bsr_matvec(self): |
|
A = self.bsr_container(arange(2*3*4*5).reshape(2*4,3*5), blocksize=(4,5)) |
|
x = arange(A.shape[1]).reshape(-1,1) |
|
assert_equal(A @ x, A.toarray() @ x) |
|
|
|
def test_bsr_matvecs(self): |
|
A = self.bsr_container(arange(2*3*4*5).reshape(2*4,3*5), blocksize=(4,5)) |
|
x = arange(A.shape[1]*6).reshape(-1,6) |
|
assert_equal(A @ x, A.toarray() @ x) |
|
|
|
@pytest.mark.xfail(run=False, reason='BSR does not have a __getitem__') |
|
def test_iterator(self): |
|
pass |
|
|
|
@pytest.mark.xfail(run=False, reason='BSR does not have a __setitem__') |
|
def test_setdiag(self): |
|
pass |
|
|
|
def test_resize_blocked(self): |
|
|
|
D = np.array([[1, 0, 3, 4], |
|
[2, 0, 0, 0], |
|
[3, 0, 0, 0]]) |
|
S = self.spcreator(D, blocksize=(1, 2)) |
|
assert_(S.resize((3, 2)) is None) |
|
assert_array_equal(S.toarray(), [[1, 0], |
|
[2, 0], |
|
[3, 0]]) |
|
S.resize((2, 2)) |
|
assert_array_equal(S.toarray(), [[1, 0], |
|
[2, 0]]) |
|
S.resize((3, 2)) |
|
assert_array_equal(S.toarray(), [[1, 0], |
|
[2, 0], |
|
[0, 0]]) |
|
S.resize((3, 4)) |
|
assert_array_equal(S.toarray(), [[1, 0, 0, 0], |
|
[2, 0, 0, 0], |
|
[0, 0, 0, 0]]) |
|
assert_raises(ValueError, S.resize, (2, 3)) |
|
|
|
@pytest.mark.xfail(run=False, reason='BSR does not have a __setitem__') |
|
def test_setdiag_comprehensive(self): |
|
pass |
|
|
|
@pytest.mark.skipif(IS_COLAB, reason="exceeds memory limit") |
|
def test_scalar_idx_dtype(self): |
|
|
|
|
|
indptr = np.zeros(2, dtype=np.int32) |
|
indices = np.zeros(0, dtype=np.int32) |
|
vals = np.zeros((0, 1, 1)) |
|
a = self.bsr_container((vals, indices, indptr), shape=(1, 2**31-1)) |
|
b = self.bsr_container((vals, indices, indptr), shape=(1, 2**31)) |
|
c = self.bsr_container((1, 2**31-1)) |
|
d = self.bsr_container((1, 2**31)) |
|
assert_equal(a.indptr.dtype, np.int32) |
|
assert_equal(b.indptr.dtype, np.int64) |
|
assert_equal(c.indptr.dtype, np.int32) |
|
assert_equal(d.indptr.dtype, np.int64) |
|
|
|
try: |
|
vals2 = np.zeros((0, 1, 2**31-1)) |
|
vals3 = np.zeros((0, 1, 2**31)) |
|
e = self.bsr_container((vals2, indices, indptr), shape=(1, 2**31-1)) |
|
f = self.bsr_container((vals3, indices, indptr), shape=(1, 2**31)) |
|
assert_equal(e.indptr.dtype, np.int32) |
|
assert_equal(f.indptr.dtype, np.int64) |
|
except (MemoryError, ValueError): |
|
|
|
e = 0 |
|
f = 0 |
|
|
|
|
|
for x in [a, b, c, d, e, f]: |
|
x + x |
|
|
|
|
|
class TestBSRMatrix(_MatrixMixin, TestBSR): |
|
spcreator = bsr_matrix |
|
|
|
|
|
TestBSR.init_class() |
|
TestBSRMatrix.init_class() |
|
|
|
|
|
|
|
|
|
|
|
|
|
def _same_sum_duplicate(data, *inds, **kwargs): |
|
"""Duplicates entries to produce the same matrix""" |
|
indptr = kwargs.pop('indptr', None) |
|
if np.issubdtype(data.dtype, np.bool_) or \ |
|
np.issubdtype(data.dtype, np.unsignedinteger): |
|
if indptr is None: |
|
return (data,) + inds |
|
else: |
|
return (data,) + inds + (indptr,) |
|
|
|
zeros_pos = (data == 0).nonzero() |
|
|
|
|
|
data = data.repeat(2, axis=0) |
|
data[::2] -= 1 |
|
data[1::2] = 1 |
|
|
|
|
|
if zeros_pos[0].size > 0: |
|
pos = tuple(p[0] for p in zeros_pos) |
|
pos1 = (2*pos[0],) + pos[1:] |
|
pos2 = (2*pos[0]+1,) + pos[1:] |
|
data[pos1] = 0 |
|
data[pos2] = 0 |
|
|
|
inds = tuple(indices.repeat(2) for indices in inds) |
|
|
|
if indptr is None: |
|
return (data,) + inds |
|
else: |
|
return (data,) + inds + (indptr * 2,) |
|
|
|
|
|
class _NonCanonicalMixin: |
|
def spcreator(self, D, *args, sorted_indices=False, **kwargs): |
|
"""Replace D with a non-canonical equivalent: containing |
|
duplicate elements and explicit zeros""" |
|
construct = super().spcreator |
|
M = construct(D, *args, **kwargs) |
|
|
|
zero_pos = (M.toarray() == 0).nonzero() |
|
has_zeros = (zero_pos[0].size > 0) |
|
if has_zeros: |
|
k = zero_pos[0].size//2 |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
M = self._insert_explicit_zero(M, zero_pos[0][k], zero_pos[1][k]) |
|
|
|
arg1 = self._arg1_for_noncanonical(M, sorted_indices) |
|
if 'shape' not in kwargs: |
|
kwargs['shape'] = M.shape |
|
NC = construct(arg1, **kwargs) |
|
|
|
|
|
if NC.dtype in [np.float32, np.complex64]: |
|
|
|
|
|
|
|
|
|
rtol = 1e-05 |
|
else: |
|
rtol = 1e-07 |
|
assert_allclose(NC.toarray(), M.toarray(), rtol=rtol) |
|
|
|
|
|
if has_zeros: |
|
assert_((NC.data == 0).any()) |
|
|
|
|
|
return NC |
|
|
|
@pytest.mark.skip(reason='bool(matrix) counts explicit zeros') |
|
def test_bool(self): |
|
pass |
|
|
|
@pytest.mark.skip(reason='getnnz-axis counts explicit zeros') |
|
def test_getnnz_axis(self): |
|
pass |
|
|
|
@pytest.mark.skip(reason='nnz counts explicit zeros') |
|
def test_empty(self): |
|
pass |
|
|
|
|
|
class _NonCanonicalCompressedMixin(_NonCanonicalMixin): |
|
def _arg1_for_noncanonical(self, M, sorted_indices=False): |
|
"""Return non-canonical constructor arg1 equivalent to M""" |
|
data, indices, indptr = _same_sum_duplicate(M.data, M.indices, |
|
indptr=M.indptr) |
|
if not sorted_indices: |
|
for start, stop in zip(indptr, indptr[1:]): |
|
indices[start:stop] = indices[start:stop][::-1].copy() |
|
data[start:stop] = data[start:stop][::-1].copy() |
|
return data, indices, indptr |
|
|
|
def _insert_explicit_zero(self, M, i, j): |
|
M[i,j] = 0 |
|
return M |
|
|
|
|
|
class _NonCanonicalCSMixin(_NonCanonicalCompressedMixin): |
|
def test_getelement(self): |
|
def check(dtype, sorted_indices): |
|
D = array([[1,0,0], |
|
[4,3,0], |
|
[0,2,0], |
|
[0,0,0]], dtype=dtype) |
|
A = self.spcreator(D, sorted_indices=sorted_indices) |
|
|
|
M,N = D.shape |
|
|
|
for i in range(-M, M): |
|
for j in range(-N, N): |
|
assert_equal(A[i,j], D[i,j]) |
|
|
|
for ij in [(0,3),(-1,3),(4,0),(4,3),(4,-1), (1, 2, 3)]: |
|
assert_raises((IndexError, TypeError), A.__getitem__, ij) |
|
|
|
for dtype in supported_dtypes: |
|
for sorted_indices in [False, True]: |
|
check(np.dtype(dtype), sorted_indices) |
|
|
|
def test_setitem_sparse(self): |
|
D = np.eye(3) |
|
A = self.spcreator(D) |
|
B = self.spcreator([[1,2,3]]) |
|
|
|
D[1,:] = B.toarray() |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
A[1,:] = B |
|
assert_array_equal(A.toarray(), D) |
|
|
|
D[:,2] = B.toarray().ravel() |
|
with suppress_warnings() as sup: |
|
sup.filter(SparseEfficiencyWarning, "Changing the sparsity structure") |
|
A[:,2] = B.T |
|
assert_array_equal(A.toarray(), D) |
|
|
|
@pytest.mark.xfail(run=False, reason='inverse broken with non-canonical matrix') |
|
def test_inv(self): |
|
pass |
|
|
|
@pytest.mark.xfail(run=False, reason='solve broken with non-canonical matrix') |
|
def test_solve(self): |
|
pass |
|
|
|
|
|
class TestCSRNonCanonical(_NonCanonicalCSMixin, TestCSR): |
|
pass |
|
|
|
|
|
class TestCSRNonCanonicalMatrix(TestCSRNonCanonical, TestCSRMatrix): |
|
pass |
|
|
|
|
|
class TestCSCNonCanonical(_NonCanonicalCSMixin, TestCSC): |
|
pass |
|
|
|
|
|
class TestCSCNonCanonicalMatrix(TestCSCNonCanonical, TestCSCMatrix): |
|
pass |
|
|
|
|
|
class TestBSRNonCanonical(_NonCanonicalCompressedMixin, TestBSR): |
|
def _insert_explicit_zero(self, M, i, j): |
|
x = M.tocsr() |
|
x[i,j] = 0 |
|
return x.tobsr(blocksize=M.blocksize) |
|
|
|
@pytest.mark.xfail(run=False, reason='diagonal broken with non-canonical BSR') |
|
def test_diagonal(self): |
|
pass |
|
|
|
@pytest.mark.xfail(run=False, reason='expm broken with non-canonical BSR') |
|
def test_expm(self): |
|
pass |
|
|
|
|
|
class TestBSRNonCanonicalMatrix(TestBSRNonCanonical, TestBSRMatrix): |
|
pass |
|
|
|
|
|
class TestCOONonCanonical(_NonCanonicalMixin, TestCOO): |
|
def _arg1_for_noncanonical(self, M, sorted_indices=None): |
|
"""Return non-canonical constructor arg1 equivalent to M""" |
|
data, row, col = _same_sum_duplicate(M.data, M.row, M.col) |
|
return data, (row, col) |
|
|
|
def _insert_explicit_zero(self, M, i, j): |
|
M.data = np.r_[M.data.dtype.type(0), M.data] |
|
M.row = np.r_[M.row.dtype.type(i), M.row] |
|
M.col = np.r_[M.col.dtype.type(j), M.col] |
|
return M |
|
|
|
def test_setdiag_noncanonical(self): |
|
m = self.spcreator(np.eye(3)) |
|
m.sum_duplicates() |
|
m.setdiag([3, 2], k=1) |
|
m.sum_duplicates() |
|
assert_(np.all(np.diff(m.col) >= 0)) |
|
|
|
|
|
class TestCOONonCanonicalMatrix(TestCOONonCanonical, TestCOOMatrix): |
|
pass |
|
|
|
|
|
|
|
def cases_64bit(sp_api): |
|
"""Yield all tests for all formats that use get_index_dtype |
|
|
|
This is more than testing get_index_dtype. It allows checking whether upcasting |
|
or downcasting the index dtypes affects test results. The approach used here |
|
does not try to figure out which tests might fail due to 32/64-bit issues. |
|
We just run them all. |
|
So, each test method in that uses cases_64bit reruns most of the test suite! |
|
""" |
|
if sp_api == "sparray": |
|
TEST_CLASSES = [TestBSR, TestCOO, TestCSC, TestCSR, TestDIA, |
|
|
|
|
|
|
|
|
|
TestDOK, TestLIL |
|
] |
|
elif sp_api == "spmatrix": |
|
TEST_CLASSES = [TestBSRMatrix, TestCOOMatrix, TestCSCMatrix, |
|
TestCSRMatrix, TestDIAMatrix, |
|
|
|
TestDOKMatrix, TestLILMatrix |
|
] |
|
else: |
|
raise ValueError(f"parameter {sp_api=} is not one of 'sparray' or 'spmatrix'") |
|
|
|
|
|
SKIP_TESTS = { |
|
'test_expm': 'expm for 64-bit indices not available', |
|
'test_inv': 'linsolve for 64-bit indices not available', |
|
'test_solve': 'linsolve for 64-bit indices not available', |
|
'test_scalar_idx_dtype': 'test implemented in base class', |
|
'test_large_dimensions_reshape': 'test actually requires 64-bit to work', |
|
'test_constructor_smallcol': 'test verifies int32 indexes', |
|
'test_constructor_largecol': 'test verifies int64 indexes', |
|
'test_tocoo_tocsr_tocsc_gh19245': 'test verifies int32 indexes', |
|
} |
|
|
|
for cls in TEST_CLASSES: |
|
for method_name in sorted(dir(cls)): |
|
method = getattr(cls, method_name) |
|
if (method_name.startswith('test_') and |
|
not getattr(method, 'slow', False)): |
|
marks = [] |
|
|
|
msg = SKIP_TESTS.get(method_name) |
|
if bool(msg): |
|
marks += [pytest.mark.skip(reason=msg)] |
|
|
|
markers = getattr(method, 'pytestmark', []) |
|
for mark in markers: |
|
if mark.name in ('skipif', 'skip', 'xfail', 'xslow'): |
|
marks.append(mark) |
|
|
|
yield pytest.param(cls, method_name, marks=marks) |
|
|
|
|
|
class Test64Bit: |
|
|
|
MAT_CLASSES = [ |
|
bsr_matrix, coo_matrix, csc_matrix, csr_matrix, dia_matrix, |
|
bsr_array, coo_array, csc_array, csr_array, dia_array, |
|
] |
|
|
|
def _compare_index_dtype(self, m, dtype): |
|
dtype = np.dtype(dtype) |
|
if m.format in ['csc', 'csr', 'bsr']: |
|
return (m.indices.dtype == dtype) and (m.indptr.dtype == dtype) |
|
elif m.format == 'coo': |
|
return (m.row.dtype == dtype) and (m.col.dtype == dtype) |
|
elif m.format == 'dia': |
|
return (m.offsets.dtype == dtype) |
|
else: |
|
raise ValueError(f"matrix {m!r} has no integer indices") |
|
|
|
@pytest.mark.thread_unsafe |
|
def test_decorator_maxval_limit(self): |
|
|
|
|
|
@with_64bit_maxval_limit(maxval_limit=10) |
|
def check(mat_cls): |
|
m = mat_cls(np.random.rand(10, 1)) |
|
assert_(self._compare_index_dtype(m, np.int32)) |
|
m = mat_cls(np.random.rand(11, 1)) |
|
assert_(self._compare_index_dtype(m, np.int64)) |
|
|
|
for mat_cls in self.MAT_CLASSES: |
|
check(mat_cls) |
|
|
|
@pytest.mark.thread_unsafe |
|
def test_decorator_maxval_random(self): |
|
|
|
|
|
@with_64bit_maxval_limit(random=True) |
|
def check(mat_cls): |
|
seen_32 = False |
|
seen_64 = False |
|
for k in range(100): |
|
m = mat_cls(np.random.rand(9, 9)) |
|
seen_32 = seen_32 or self._compare_index_dtype(m, np.int32) |
|
seen_64 = seen_64 or self._compare_index_dtype(m, np.int64) |
|
if seen_32 and seen_64: |
|
break |
|
else: |
|
raise AssertionError("both 32 and 64 bit indices not seen") |
|
|
|
for mat_cls in self.MAT_CLASSES: |
|
check(mat_cls) |
|
|
|
@pytest.mark.thread_unsafe |
|
def test_downcast_intp(self): |
|
|
|
|
|
|
|
|
|
|
|
|
|
@with_64bit_maxval_limit(fixed_dtype=np.int64, downcast_maxval=1) |
|
def check_limited(csc_container, csr_container, coo_container): |
|
|
|
a = csc_container([[1, 2], [3, 4], [5, 6]]) |
|
assert_raises(AssertionError, a.count_nonzero, axis=1) |
|
assert_raises(AssertionError, a.sum, axis=0) |
|
|
|
a = csr_container([[1, 2, 3], [3, 4, 6]]) |
|
assert_raises(AssertionError, a.count_nonzero, axis=0) |
|
assert_raises(AssertionError, a.sum, axis=1) |
|
|
|
a = coo_container([[1, 2, 3], [3, 4, 5]]) |
|
assert_raises(AssertionError, a.count_nonzero, axis=0) |
|
a.has_canonical_format = False |
|
assert_raises(AssertionError, a.sum_duplicates) |
|
|
|
@with_64bit_maxval_limit(fixed_dtype=np.int64) |
|
def check_unlimited(csc_container, csr_container, coo_container): |
|
|
|
a = csc_container([[1, 2], [3, 4], [5, 6]]) |
|
a.count_nonzero(axis=1) |
|
a.sum(axis=0) |
|
|
|
a = csr_container([[1, 2, 3], [3, 4, 6]]) |
|
a.count_nonzero(axis=0) |
|
a.sum(axis=1) |
|
|
|
a = coo_container([[1, 2, 3], [3, 4, 5]]) |
|
a.count_nonzero(axis=0) |
|
a.has_canonical_format = False |
|
a.sum_duplicates() |
|
|
|
check_limited(csc_array, csr_array, coo_array) |
|
check_unlimited(csc_array, csr_array, coo_array) |
|
check_limited(csc_matrix, csr_matrix, coo_matrix) |
|
check_unlimited(csc_matrix, csr_matrix, coo_matrix) |
|
|
|
|
|
|
|
|
|
class RunAll64Bit: |
|
def _check_resiliency(self, cls, method_name, **kw): |
|
|
|
|
|
|
|
@with_64bit_maxval_limit(**kw) |
|
def check(cls, method_name): |
|
instance = cls() |
|
if hasattr(instance, 'setup_method'): |
|
instance.setup_method() |
|
try: |
|
getattr(instance, method_name)() |
|
finally: |
|
if hasattr(instance, 'teardown_method'): |
|
instance.teardown_method() |
|
|
|
check(cls, method_name) |
|
|
|
|
|
@pytest.mark.thread_unsafe |
|
@pytest.mark.slow |
|
class Test64BitArray(RunAll64Bit): |
|
|
|
|
|
@pytest.mark.parametrize('cls,method_name', cases_64bit("sparray")) |
|
def test_resiliency_limit_10(self, cls, method_name): |
|
self._check_resiliency(cls, method_name, maxval_limit=10) |
|
|
|
@pytest.mark.fail_slow(2) |
|
@pytest.mark.parametrize('cls,method_name', cases_64bit("sparray")) |
|
def test_resiliency_random(self, cls, method_name): |
|
|
|
|
|
|
|
self._check_resiliency(cls, method_name, random=True) |
|
|
|
@pytest.mark.parametrize('cls,method_name', cases_64bit("sparray")) |
|
def test_resiliency_all_32(self, cls, method_name): |
|
self._check_resiliency(cls, method_name, fixed_dtype=np.int32) |
|
|
|
@pytest.mark.parametrize('cls,method_name', cases_64bit("sparray")) |
|
def test_resiliency_all_64(self, cls, method_name): |
|
self._check_resiliency(cls, method_name, fixed_dtype=np.int64) |
|
|
|
|
|
@pytest.mark.thread_unsafe |
|
class Test64BitMatrix(RunAll64Bit): |
|
|
|
@pytest.mark.fail_slow(5) |
|
@pytest.mark.parametrize('cls,method_name', cases_64bit("spmatrix")) |
|
def test_no_64(self, cls, method_name): |
|
self._check_resiliency(cls, method_name, assert_32bit=True) |
|
|
|
|
|
|
|
@pytest.mark.parametrize('cls,method_name', cases_64bit("spmatrix")) |
|
def test_resiliency_limit_10(self, cls, method_name): |
|
self._check_resiliency(cls, method_name, maxval_limit=10) |
|
|
|
@pytest.mark.fail_slow(2) |
|
@pytest.mark.parametrize('cls,method_name', cases_64bit("spmatrix")) |
|
def test_resiliency_random(self, cls, method_name): |
|
|
|
|
|
|
|
self._check_resiliency(cls, method_name, random=True) |
|
|
|
@pytest.mark.parametrize('cls,method_name', cases_64bit("spmatrix")) |
|
def test_resiliency_all_32(self, cls, method_name): |
|
self._check_resiliency(cls, method_name, fixed_dtype=np.int32) |
|
|
|
@pytest.mark.parametrize('cls,method_name', cases_64bit("spmatrix")) |
|
def test_resiliency_all_64(self, cls, method_name): |
|
self._check_resiliency(cls, method_name, fixed_dtype=np.int64) |
|
|
|
def test_broadcast_to(): |
|
a = np.array([[1, 0, 2]]) |
|
b = np.array([[1], [0], [2]]) |
|
c = np.array([[1, 0, 2], [0, 3, 0]]) |
|
d = np.array([[7]]) |
|
e = np.array([[0]]) |
|
f = np.array([[0,0,0,0]]) |
|
for container in (csc_matrix, csc_array, csr_matrix, csr_array): |
|
res_a = container(a)._broadcast_to((2,3)) |
|
res_b = container(b)._broadcast_to((3,4)) |
|
res_c = container(c)._broadcast_to((2,3)) |
|
res_d = container(d)._broadcast_to((4,4)) |
|
res_e = container(e)._broadcast_to((5,6)) |
|
res_f = container(f)._broadcast_to((2,4)) |
|
assert_array_equal(res_a.toarray(), np.broadcast_to(a, (2,3))) |
|
assert_array_equal(res_b.toarray(), np.broadcast_to(b, (3,4))) |
|
assert_array_equal(res_c.toarray(), c) |
|
assert_array_equal(res_d.toarray(), np.broadcast_to(d, (4,4))) |
|
assert_array_equal(res_e.toarray(), np.broadcast_to(e, (5,6))) |
|
assert_array_equal(res_f.toarray(), np.broadcast_to(f, (2,4))) |
|
|
|
with pytest.raises(ValueError, match="cannot be broadcast"): |
|
container([[1, 2, 0], [3, 0, 1]])._broadcast_to(shape=(2, 1)) |
|
|
|
with pytest.raises(ValueError, match="cannot be broadcast"): |
|
container([[0, 1, 2]])._broadcast_to(shape=(3, 2)) |
|
|