Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/scipy/sparse/base.py : 24%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""Base class for sparse matrices"""
2import numpy as np
4from .sputils import (isdense, isscalarlike, isintlike,
5 get_sum_dtype, validateaxis, check_reshape_kwargs,
6 check_shape, asmatrix)
8__all__ = ['spmatrix', 'isspmatrix', 'issparse',
9 'SparseWarning', 'SparseEfficiencyWarning']
12class SparseWarning(Warning):
13 pass
16class SparseFormatWarning(SparseWarning):
17 pass
20class SparseEfficiencyWarning(SparseWarning):
21 pass
24# The formats that we might potentially understand.
25_formats = {'csc': [0, "Compressed Sparse Column"],
26 'csr': [1, "Compressed Sparse Row"],
27 'dok': [2, "Dictionary Of Keys"],
28 'lil': [3, "List of Lists"],
29 'dod': [4, "Dictionary of Dictionaries"],
30 'sss': [5, "Symmetric Sparse Skyline"],
31 'coo': [6, "COOrdinate"],
32 'lba': [7, "Linpack BAnded"],
33 'egd': [8, "Ellpack-itpack Generalized Diagonal"],
34 'dia': [9, "DIAgonal"],
35 'bsr': [10, "Block Sparse Row"],
36 'msr': [11, "Modified compressed Sparse Row"],
37 'bsc': [12, "Block Sparse Column"],
38 'msc': [13, "Modified compressed Sparse Column"],
39 'ssk': [14, "Symmetric SKyline"],
40 'nsk': [15, "Nonsymmetric SKyline"],
41 'jad': [16, "JAgged Diagonal"],
42 'uss': [17, "Unsymmetric Sparse Skyline"],
43 'vbr': [18, "Variable Block Row"],
44 'und': [19, "Undefined"]
45 }
48# These univariate ufuncs preserve zeros.
49_ufuncs_with_fixed_point_at_zero = frozenset([
50 np.sin, np.tan, np.arcsin, np.arctan, np.sinh, np.tanh, np.arcsinh,
51 np.arctanh, np.rint, np.sign, np.expm1, np.log1p, np.deg2rad,
52 np.rad2deg, np.floor, np.ceil, np.trunc, np.sqrt])
55MAXPRINT = 50
58class spmatrix(object):
59 """ This class provides a base class for all sparse matrices. It
60 cannot be instantiated. Most of the work is provided by subclasses.
61 """
63 __array_priority__ = 10.1
64 ndim = 2
66 def __init__(self, maxprint=MAXPRINT):
67 self._shape = None
68 if self.__class__.__name__ == 'spmatrix':
69 raise ValueError("This class is not intended"
70 " to be instantiated directly.")
71 self.maxprint = maxprint
73 def set_shape(self, shape):
74 """See `reshape`."""
75 # Make sure copy is False since this is in place
76 # Make sure format is unchanged because we are doing a __dict__ swap
77 new_matrix = self.reshape(shape, copy=False).asformat(self.format)
78 self.__dict__ = new_matrix.__dict__
80 def get_shape(self):
81 """Get shape of a matrix."""
82 return self._shape
84 shape = property(fget=get_shape, fset=set_shape)
86 def reshape(self, *args, **kwargs):
87 """reshape(self, shape, order='C', copy=False)
89 Gives a new shape to a sparse matrix without changing its data.
91 Parameters
92 ----------
93 shape : length-2 tuple of ints
94 The new shape should be compatible with the original shape.
95 order : {'C', 'F'}, optional
96 Read the elements using this index order. 'C' means to read and
97 write the elements using C-like index order; e.g., read entire first
98 row, then second row, etc. 'F' means to read and write the elements
99 using Fortran-like index order; e.g., read entire first column, then
100 second column, etc.
101 copy : bool, optional
102 Indicates whether or not attributes of self should be copied
103 whenever possible. The degree to which attributes are copied varies
104 depending on the type of sparse matrix being used.
106 Returns
107 -------
108 reshaped_matrix : sparse matrix
109 A sparse matrix with the given `shape`, not necessarily of the same
110 format as the current object.
112 See Also
113 --------
114 numpy.matrix.reshape : NumPy's implementation of 'reshape' for
115 matrices
116 """
117 # If the shape already matches, don't bother doing an actual reshape
118 # Otherwise, the default is to convert to COO and use its reshape
119 shape = check_shape(args, self.shape)
120 order, copy = check_reshape_kwargs(kwargs)
121 if shape == self.shape:
122 if copy:
123 return self.copy()
124 else:
125 return self
127 return self.tocoo(copy=copy).reshape(shape, order=order, copy=False)
129 def resize(self, shape):
130 """Resize the matrix in-place to dimensions given by ``shape``
132 Any elements that lie within the new shape will remain at the same
133 indices, while non-zero elements lying outside the new shape are
134 removed.
136 Parameters
137 ----------
138 shape : (int, int)
139 number of rows and columns in the new matrix
141 Notes
142 -----
143 The semantics are not identical to `numpy.ndarray.resize` or
144 `numpy.resize`. Here, the same data will be maintained at each index
145 before and after reshape, if that index is within the new bounds. In
146 numpy, resizing maintains contiguity of the array, moving elements
147 around in the logical matrix but not within a flattened representation.
149 We give no guarantees about whether the underlying data attributes
150 (arrays, etc.) will be modified in place or replaced with new objects.
151 """
152 # As an inplace operation, this requires implementation in each format.
153 raise NotImplementedError(
154 '{}.resize is not implemented'.format(type(self).__name__))
156 def astype(self, dtype, casting='unsafe', copy=True):
157 """Cast the matrix elements to a specified type.
159 Parameters
160 ----------
161 dtype : string or numpy dtype
162 Typecode or data-type to which to cast the data.
163 casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
164 Controls what kind of data casting may occur.
165 Defaults to 'unsafe' for backwards compatibility.
166 'no' means the data types should not be cast at all.
167 'equiv' means only byte-order changes are allowed.
168 'safe' means only casts which can preserve values are allowed.
169 'same_kind' means only safe casts or casts within a kind,
170 like float64 to float32, are allowed.
171 'unsafe' means any data conversions may be done.
172 copy : bool, optional
173 If `copy` is `False`, the result might share some memory with this
174 matrix. If `copy` is `True`, it is guaranteed that the result and
175 this matrix do not share any memory.
176 """
178 dtype = np.dtype(dtype)
179 if self.dtype != dtype:
180 return self.tocsr().astype(
181 dtype, casting=casting, copy=copy).asformat(self.format)
182 elif copy:
183 return self.copy()
184 else:
185 return self
187 def asfptype(self):
188 """Upcast matrix to a floating point format (if necessary)"""
190 fp_types = ['f', 'd', 'F', 'D']
192 if self.dtype.char in fp_types:
193 return self
194 else:
195 for fp_type in fp_types:
196 if self.dtype <= np.dtype(fp_type):
197 return self.astype(fp_type)
199 raise TypeError('cannot upcast [%s] to a floating '
200 'point format' % self.dtype.name)
202 def __iter__(self):
203 for r in range(self.shape[0]):
204 yield self[r, :]
206 def getmaxprint(self):
207 """Maximum number of elements to display when printed."""
208 return self.maxprint
210 def count_nonzero(self):
211 """Number of non-zero entries, equivalent to
213 np.count_nonzero(a.toarray())
215 Unlike getnnz() and the nnz property, which return the number of stored
216 entries (the length of the data attribute), this method counts the
217 actual number of non-zero entries in data.
218 """
219 raise NotImplementedError("count_nonzero not implemented for %s." %
220 self.__class__.__name__)
222 def getnnz(self, axis=None):
223 """Number of stored values, including explicit zeros.
225 Parameters
226 ----------
227 axis : None, 0, or 1
228 Select between the number of values across the whole matrix, in
229 each column, or in each row.
231 See also
232 --------
233 count_nonzero : Number of non-zero entries
234 """
235 raise NotImplementedError("getnnz not implemented for %s." %
236 self.__class__.__name__)
238 @property
239 def nnz(self):
240 """Number of stored values, including explicit zeros.
242 See also
243 --------
244 count_nonzero : Number of non-zero entries
245 """
246 return self.getnnz()
248 def getformat(self):
249 """Format of a matrix representation as a string."""
250 return getattr(self, 'format', 'und')
252 def __repr__(self):
253 _, format_name = _formats[self.getformat()]
254 return "<%dx%d sparse matrix of type '%s'\n" \
255 "\twith %d stored elements in %s format>" % \
256 (self.shape + (self.dtype.type, self.nnz, format_name))
258 def __str__(self):
259 maxprint = self.getmaxprint()
261 A = self.tocoo()
263 # helper function, outputs "(i,j) v"
264 def tostr(row, col, data):
265 triples = zip(list(zip(row, col)), data)
266 return '\n'.join([(' %s\t%s' % t) for t in triples])
268 if self.nnz > maxprint:
269 half = maxprint // 2
270 out = tostr(A.row[:half], A.col[:half], A.data[:half])
271 out += "\n :\t:\n"
272 half = maxprint - maxprint//2
273 out += tostr(A.row[-half:], A.col[-half:], A.data[-half:])
274 else:
275 out = tostr(A.row, A.col, A.data)
277 return out
279 def __bool__(self): # Simple -- other ideas?
280 if self.shape == (1, 1):
281 return self.nnz != 0
282 else:
283 raise ValueError("The truth value of an array with more than one "
284 "element is ambiguous. Use a.any() or a.all().")
285 __nonzero__ = __bool__
287 # What should len(sparse) return? For consistency with dense matrices,
288 # perhaps it should be the number of rows? But for some uses the number of
289 # non-zeros is more important. For now, raise an exception!
290 def __len__(self):
291 raise TypeError("sparse matrix length is ambiguous; use getnnz()"
292 " or shape[0]")
294 def asformat(self, format, copy=False):
295 """Return this matrix in the passed format.
297 Parameters
298 ----------
299 format : {str, None}
300 The desired matrix format ("csr", "csc", "lil", "dok", "array", ...)
301 or None for no conversion.
302 copy : bool, optional
303 If True, the result is guaranteed to not share data with self.
305 Returns
306 -------
307 A : This matrix in the passed format.
308 """
309 if format is None or format == self.format:
310 if copy:
311 return self.copy()
312 else:
313 return self
314 else:
315 try:
316 convert_method = getattr(self, 'to' + format)
317 except AttributeError:
318 raise ValueError('Format {} is unknown.'.format(format))
320 # Forward the copy kwarg, if it's accepted.
321 try:
322 return convert_method(copy=copy)
323 except TypeError:
324 return convert_method()
326 ###################################################################
327 # NOTE: All arithmetic operations use csr_matrix by default.
328 # Therefore a new sparse matrix format just needs to define a
329 # .tocsr() method to provide arithmetic support. Any of these
330 # methods can be overridden for efficiency.
331 ####################################################################
333 def multiply(self, other):
334 """Point-wise multiplication by another matrix
335 """
336 return self.tocsr().multiply(other)
338 def maximum(self, other):
339 """Element-wise maximum between this and another matrix."""
340 return self.tocsr().maximum(other)
342 def minimum(self, other):
343 """Element-wise minimum between this and another matrix."""
344 return self.tocsr().minimum(other)
346 def dot(self, other):
347 """Ordinary dot product
349 Examples
350 --------
351 >>> import numpy as np
352 >>> from scipy.sparse import csr_matrix
353 >>> A = csr_matrix([[1, 2, 0], [0, 0, 3], [4, 0, 5]])
354 >>> v = np.array([1, 0, -1])
355 >>> A.dot(v)
356 array([ 1, -3, -1], dtype=int64)
358 """
359 return self * other
361 def power(self, n, dtype=None):
362 """Element-wise power."""
363 return self.tocsr().power(n, dtype=dtype)
365 def __eq__(self, other):
366 return self.tocsr().__eq__(other)
368 def __ne__(self, other):
369 return self.tocsr().__ne__(other)
371 def __lt__(self, other):
372 return self.tocsr().__lt__(other)
374 def __gt__(self, other):
375 return self.tocsr().__gt__(other)
377 def __le__(self, other):
378 return self.tocsr().__le__(other)
380 def __ge__(self, other):
381 return self.tocsr().__ge__(other)
383 def __abs__(self):
384 return abs(self.tocsr())
386 def __round__(self, ndigits=0):
387 return round(self.tocsr(), ndigits=ndigits)
389 def _add_sparse(self, other):
390 return self.tocsr()._add_sparse(other)
392 def _add_dense(self, other):
393 return self.tocoo()._add_dense(other)
395 def _sub_sparse(self, other):
396 return self.tocsr()._sub_sparse(other)
398 def _sub_dense(self, other):
399 return self.todense() - other
401 def _rsub_dense(self, other):
402 # note: this can't be replaced by other + (-self) for unsigned types
403 return other - self.todense()
405 def __add__(self, other): # self + other
406 if isscalarlike(other):
407 if other == 0:
408 return self.copy()
409 # Now we would add this scalar to every element.
410 raise NotImplementedError('adding a nonzero scalar to a '
411 'sparse matrix is not supported')
412 elif isspmatrix(other):
413 if other.shape != self.shape:
414 raise ValueError("inconsistent shapes")
415 return self._add_sparse(other)
416 elif isdense(other):
417 other = np.broadcast_to(other, self.shape)
418 return self._add_dense(other)
419 else:
420 return NotImplemented
422 def __radd__(self,other): # other + self
423 return self.__add__(other)
425 def __sub__(self, other): # self - other
426 if isscalarlike(other):
427 if other == 0:
428 return self.copy()
429 raise NotImplementedError('subtracting a nonzero scalar from a '
430 'sparse matrix is not supported')
431 elif isspmatrix(other):
432 if other.shape != self.shape:
433 raise ValueError("inconsistent shapes")
434 return self._sub_sparse(other)
435 elif isdense(other):
436 other = np.broadcast_to(other, self.shape)
437 return self._sub_dense(other)
438 else:
439 return NotImplemented
441 def __rsub__(self,other): # other - self
442 if isscalarlike(other):
443 if other == 0:
444 return -self.copy()
445 raise NotImplementedError('subtracting a sparse matrix from a '
446 'nonzero scalar is not supported')
447 elif isdense(other):
448 other = np.broadcast_to(other, self.shape)
449 return self._rsub_dense(other)
450 else:
451 return NotImplemented
453 def __mul__(self, other):
454 """interpret other and call one of the following
456 self._mul_scalar()
457 self._mul_vector()
458 self._mul_multivector()
459 self._mul_sparse_matrix()
460 """
462 M, N = self.shape
464 if other.__class__ is np.ndarray:
465 # Fast path for the most common case
466 if other.shape == (N,):
467 return self._mul_vector(other)
468 elif other.shape == (N, 1):
469 return self._mul_vector(other.ravel()).reshape(M, 1)
470 elif other.ndim == 2 and other.shape[0] == N:
471 return self._mul_multivector(other)
473 if isscalarlike(other):
474 # scalar value
475 return self._mul_scalar(other)
477 if issparse(other):
478 if self.shape[1] != other.shape[0]:
479 raise ValueError('dimension mismatch')
480 return self._mul_sparse_matrix(other)
482 # If it's a list or whatever, treat it like a matrix
483 other_a = np.asanyarray(other)
485 if other_a.ndim == 0 and other_a.dtype == np.object_:
486 # Not interpretable as an array; return NotImplemented so that
487 # other's __rmul__ can kick in if that's implemented.
488 return NotImplemented
490 try:
491 other.shape
492 except AttributeError:
493 other = other_a
495 if other.ndim == 1 or other.ndim == 2 and other.shape[1] == 1:
496 # dense row or column vector
497 if other.shape != (N,) and other.shape != (N, 1):
498 raise ValueError('dimension mismatch')
500 result = self._mul_vector(np.ravel(other))
502 if isinstance(other, np.matrix):
503 result = asmatrix(result)
505 if other.ndim == 2 and other.shape[1] == 1:
506 # If 'other' was an (nx1) column vector, reshape the result
507 result = result.reshape(-1, 1)
509 return result
511 elif other.ndim == 2:
512 ##
513 # dense 2D array or matrix ("multivector")
515 if other.shape[0] != self.shape[1]:
516 raise ValueError('dimension mismatch')
518 result = self._mul_multivector(np.asarray(other))
520 if isinstance(other, np.matrix):
521 result = asmatrix(result)
523 return result
525 else:
526 raise ValueError('could not interpret dimensions')
528 # by default, use CSR for __mul__ handlers
529 def _mul_scalar(self, other):
530 return self.tocsr()._mul_scalar(other)
532 def _mul_vector(self, other):
533 return self.tocsr()._mul_vector(other)
535 def _mul_multivector(self, other):
536 return self.tocsr()._mul_multivector(other)
538 def _mul_sparse_matrix(self, other):
539 return self.tocsr()._mul_sparse_matrix(other)
541 def __rmul__(self, other): # other * self
542 if isscalarlike(other):
543 return self.__mul__(other)
544 else:
545 # Don't use asarray unless we have to
546 try:
547 tr = other.transpose()
548 except AttributeError:
549 tr = np.asarray(other).transpose()
550 return (self.transpose() * tr).transpose()
552 #######################
553 # matmul (@) operator #
554 #######################
556 def __matmul__(self, other):
557 if isscalarlike(other):
558 raise ValueError("Scalar operands are not allowed, "
559 "use '*' instead")
560 return self.__mul__(other)
562 def __rmatmul__(self, other):
563 if isscalarlike(other):
564 raise ValueError("Scalar operands are not allowed, "
565 "use '*' instead")
566 return self.__rmul__(other)
568 ####################
569 # Other Arithmetic #
570 ####################
572 def _divide(self, other, true_divide=False, rdivide=False):
573 if isscalarlike(other):
574 if rdivide:
575 if true_divide:
576 return np.true_divide(other, self.todense())
577 else:
578 return np.divide(other, self.todense())
580 if true_divide and np.can_cast(self.dtype, np.float_):
581 return self.astype(np.float_)._mul_scalar(1./other)
582 else:
583 r = self._mul_scalar(1./other)
585 scalar_dtype = np.asarray(other).dtype
586 if (np.issubdtype(self.dtype, np.integer) and
587 np.issubdtype(scalar_dtype, np.integer)):
588 return r.astype(self.dtype)
589 else:
590 return r
592 elif isdense(other):
593 if not rdivide:
594 if true_divide:
595 return np.true_divide(self.todense(), other)
596 else:
597 return np.divide(self.todense(), other)
598 else:
599 if true_divide:
600 return np.true_divide(other, self.todense())
601 else:
602 return np.divide(other, self.todense())
603 elif isspmatrix(other):
604 if rdivide:
605 return other._divide(self, true_divide, rdivide=False)
607 self_csr = self.tocsr()
608 if true_divide and np.can_cast(self.dtype, np.float_):
609 return self_csr.astype(np.float_)._divide_sparse(other)
610 else:
611 return self_csr._divide_sparse(other)
612 else:
613 return NotImplemented
615 def __truediv__(self, other):
616 return self._divide(other, true_divide=True)
618 def __div__(self, other):
619 # Always do true division
620 return self._divide(other, true_divide=True)
622 def __rtruediv__(self, other):
623 # Implementing this as the inverse would be too magical -- bail out
624 return NotImplemented
626 def __rdiv__(self, other):
627 # Implementing this as the inverse would be too magical -- bail out
628 return NotImplemented
630 def __neg__(self):
631 return -self.tocsr()
633 def __iadd__(self, other):
634 return NotImplemented
636 def __isub__(self, other):
637 return NotImplemented
639 def __imul__(self, other):
640 return NotImplemented
642 def __idiv__(self, other):
643 return self.__itruediv__(other)
645 def __itruediv__(self, other):
646 return NotImplemented
648 def __pow__(self, other):
649 if self.shape[0] != self.shape[1]:
650 raise TypeError('matrix is not square')
652 if isintlike(other):
653 other = int(other)
654 if other < 0:
655 raise ValueError('exponent must be >= 0')
657 if other == 0:
658 from .construct import eye
659 return eye(self.shape[0], dtype=self.dtype)
660 elif other == 1:
661 return self.copy()
662 else:
663 tmp = self.__pow__(other//2)
664 if (other % 2):
665 return self * tmp * tmp
666 else:
667 return tmp * tmp
668 elif isscalarlike(other):
669 raise ValueError('exponent must be an integer')
670 else:
671 return NotImplemented
673 def __getattr__(self, attr):
674 if attr == 'A':
675 return self.toarray()
676 elif attr == 'T':
677 return self.transpose()
678 elif attr == 'H':
679 return self.getH()
680 elif attr == 'real':
681 return self._real()
682 elif attr == 'imag':
683 return self._imag()
684 elif attr == 'size':
685 return self.getnnz()
686 else:
687 raise AttributeError(attr + " not found")
689 def transpose(self, axes=None, copy=False):
690 """
691 Reverses the dimensions of the sparse matrix.
693 Parameters
694 ----------
695 axes : None, optional
696 This argument is in the signature *solely* for NumPy
697 compatibility reasons. Do not pass in anything except
698 for the default value.
699 copy : bool, optional
700 Indicates whether or not attributes of `self` should be
701 copied whenever possible. The degree to which attributes
702 are copied varies depending on the type of sparse matrix
703 being used.
705 Returns
706 -------
707 p : `self` with the dimensions reversed.
709 See Also
710 --------
711 numpy.matrix.transpose : NumPy's implementation of 'transpose'
712 for matrices
713 """
714 return self.tocsr(copy=copy).transpose(axes=axes, copy=False)
716 def conj(self, copy=True):
717 """Element-wise complex conjugation.
719 If the matrix is of non-complex data type and `copy` is False,
720 this method does nothing and the data is not copied.
722 Parameters
723 ----------
724 copy : bool, optional
725 If True, the result is guaranteed to not share data with self.
727 Returns
728 -------
729 A : The element-wise complex conjugate.
731 """
732 if np.issubdtype(self.dtype, np.complexfloating):
733 return self.tocsr(copy=copy).conj(copy=False)
734 elif copy:
735 return self.copy()
736 else:
737 return self
739 def conjugate(self, copy=True):
740 return self.conj(copy=copy)
742 conjugate.__doc__ = conj.__doc__
744 # Renamed conjtranspose() -> getH() for compatibility with dense matrices
745 def getH(self):
746 """Return the Hermitian transpose of this matrix.
748 See Also
749 --------
750 numpy.matrix.getH : NumPy's implementation of `getH` for matrices
751 """
752 return self.transpose().conj()
754 def _real(self):
755 return self.tocsr()._real()
757 def _imag(self):
758 return self.tocsr()._imag()
760 def nonzero(self):
761 """nonzero indices
763 Returns a tuple of arrays (row,col) containing the indices
764 of the non-zero elements of the matrix.
766 Examples
767 --------
768 >>> from scipy.sparse import csr_matrix
769 >>> A = csr_matrix([[1,2,0],[0,0,3],[4,0,5]])
770 >>> A.nonzero()
771 (array([0, 0, 1, 2, 2]), array([0, 1, 2, 0, 2]))
773 """
775 # convert to COOrdinate format
776 A = self.tocoo()
777 nz_mask = A.data != 0
778 return (A.row[nz_mask], A.col[nz_mask])
780 def getcol(self, j):
781 """Returns a copy of column j of the matrix, as an (m x 1) sparse
782 matrix (column vector).
783 """
784 # Spmatrix subclasses should override this method for efficiency.
785 # Post-multiply by a (n x 1) column vector 'a' containing all zeros
786 # except for a_j = 1
787 from .csc import csc_matrix
788 n = self.shape[1]
789 if j < 0:
790 j += n
791 if j < 0 or j >= n:
792 raise IndexError("index out of bounds")
793 col_selector = csc_matrix(([1], [[j], [0]]),
794 shape=(n, 1), dtype=self.dtype)
795 return self * col_selector
797 def getrow(self, i):
798 """Returns a copy of row i of the matrix, as a (1 x n) sparse
799 matrix (row vector).
800 """
801 # Spmatrix subclasses should override this method for efficiency.
802 # Pre-multiply by a (1 x m) row vector 'a' containing all zeros
803 # except for a_i = 1
804 from .csr import csr_matrix
805 m = self.shape[0]
806 if i < 0:
807 i += m
808 if i < 0 or i >= m:
809 raise IndexError("index out of bounds")
810 row_selector = csr_matrix(([1], [[0], [i]]),
811 shape=(1, m), dtype=self.dtype)
812 return row_selector * self
814 # def __array__(self):
815 # return self.toarray()
817 def todense(self, order=None, out=None):
818 """
819 Return a dense matrix representation of this matrix.
821 Parameters
822 ----------
823 order : {'C', 'F'}, optional
824 Whether to store multi-dimensional data in C (row-major)
825 or Fortran (column-major) order in memory. The default
826 is 'None', indicating the NumPy default of C-ordered.
827 Cannot be specified in conjunction with the `out`
828 argument.
830 out : ndarray, 2-D, optional
831 If specified, uses this array (or `numpy.matrix`) as the
832 output buffer instead of allocating a new array to
833 return. The provided array must have the same shape and
834 dtype as the sparse matrix on which you are calling the
835 method.
837 Returns
838 -------
839 arr : numpy.matrix, 2-D
840 A NumPy matrix object with the same shape and containing
841 the same data represented by the sparse matrix, with the
842 requested memory order. If `out` was passed and was an
843 array (rather than a `numpy.matrix`), it will be filled
844 with the appropriate values and returned wrapped in a
845 `numpy.matrix` object that shares the same memory.
846 """
847 return asmatrix(self.toarray(order=order, out=out))
849 def toarray(self, order=None, out=None):
850 """
851 Return a dense ndarray representation of this matrix.
853 Parameters
854 ----------
855 order : {'C', 'F'}, optional
856 Whether to store multidimensional data in C (row-major)
857 or Fortran (column-major) order in memory. The default
858 is 'None', indicating the NumPy default of C-ordered.
859 Cannot be specified in conjunction with the `out`
860 argument.
862 out : ndarray, 2-D, optional
863 If specified, uses this array as the output buffer
864 instead of allocating a new array to return. The provided
865 array must have the same shape and dtype as the sparse
866 matrix on which you are calling the method. For most
867 sparse types, `out` is required to be memory contiguous
868 (either C or Fortran ordered).
870 Returns
871 -------
872 arr : ndarray, 2-D
873 An array with the same shape and containing the same
874 data represented by the sparse matrix, with the requested
875 memory order. If `out` was passed, the same object is
876 returned after being modified in-place to contain the
877 appropriate values.
878 """
879 return self.tocoo(copy=False).toarray(order=order, out=out)
881 # Any sparse matrix format deriving from spmatrix must define one of
882 # tocsr or tocoo. The other conversion methods may be implemented for
883 # efficiency, but are not required.
884 def tocsr(self, copy=False):
885 """Convert this matrix to Compressed Sparse Row format.
887 With copy=False, the data/indices may be shared between this matrix and
888 the resultant csr_matrix.
889 """
890 return self.tocoo(copy=copy).tocsr(copy=False)
892 def todok(self, copy=False):
893 """Convert this matrix to Dictionary Of Keys format.
895 With copy=False, the data/indices may be shared between this matrix and
896 the resultant dok_matrix.
897 """
898 return self.tocoo(copy=copy).todok(copy=False)
900 def tocoo(self, copy=False):
901 """Convert this matrix to COOrdinate format.
903 With copy=False, the data/indices may be shared between this matrix and
904 the resultant coo_matrix.
905 """
906 return self.tocsr(copy=False).tocoo(copy=copy)
908 def tolil(self, copy=False):
909 """Convert this matrix to List of Lists format.
911 With copy=False, the data/indices may be shared between this matrix and
912 the resultant lil_matrix.
913 """
914 return self.tocsr(copy=False).tolil(copy=copy)
916 def todia(self, copy=False):
917 """Convert this matrix to sparse DIAgonal format.
919 With copy=False, the data/indices may be shared between this matrix and
920 the resultant dia_matrix.
921 """
922 return self.tocoo(copy=copy).todia(copy=False)
924 def tobsr(self, blocksize=None, copy=False):
925 """Convert this matrix to Block Sparse Row format.
927 With copy=False, the data/indices may be shared between this matrix and
928 the resultant bsr_matrix.
930 When blocksize=(R, C) is provided, it will be used for construction of
931 the bsr_matrix.
932 """
933 return self.tocsr(copy=False).tobsr(blocksize=blocksize, copy=copy)
935 def tocsc(self, copy=False):
936 """Convert this matrix to Compressed Sparse Column format.
938 With copy=False, the data/indices may be shared between this matrix and
939 the resultant csc_matrix.
940 """
941 return self.tocsr(copy=copy).tocsc(copy=False)
943 def copy(self):
944 """Returns a copy of this matrix.
946 No data/indices will be shared between the returned value and current
947 matrix.
948 """
949 return self.__class__(self, copy=True)
951 def sum(self, axis=None, dtype=None, out=None):
952 """
953 Sum the matrix elements over a given axis.
955 Parameters
956 ----------
957 axis : {-2, -1, 0, 1, None} optional
958 Axis along which the sum is computed. The default is to
959 compute the sum of all the matrix elements, returning a scalar
960 (i.e., `axis` = `None`).
961 dtype : dtype, optional
962 The type of the returned matrix and of the accumulator in which
963 the elements are summed. The dtype of `a` is used by default
964 unless `a` has an integer dtype of less precision than the default
965 platform integer. In that case, if `a` is signed then the platform
966 integer is used while if `a` is unsigned then an unsigned integer
967 of the same precision as the platform integer is used.
969 .. versionadded:: 0.18.0
971 out : np.matrix, optional
972 Alternative output matrix in which to place the result. It must
973 have the same shape as the expected output, but the type of the
974 output values will be cast if necessary.
976 .. versionadded:: 0.18.0
978 Returns
979 -------
980 sum_along_axis : np.matrix
981 A matrix with the same shape as `self`, with the specified
982 axis removed.
984 See Also
985 --------
986 numpy.matrix.sum : NumPy's implementation of 'sum' for matrices
988 """
989 validateaxis(axis)
991 # We use multiplication by a matrix of ones to achieve this.
992 # For some sparse matrix formats more efficient methods are
993 # possible -- these should override this function.
994 m, n = self.shape
996 # Mimic numpy's casting.
997 res_dtype = get_sum_dtype(self.dtype)
999 if axis is None:
1000 # sum over rows and columns
1001 return (self * asmatrix(np.ones(
1002 (n, 1), dtype=res_dtype))).sum(
1003 dtype=dtype, out=out)
1005 if axis < 0:
1006 axis += 2
1008 # axis = 0 or 1 now
1009 if axis == 0:
1010 # sum over columns
1011 ret = asmatrix(np.ones(
1012 (1, m), dtype=res_dtype)) * self
1013 else:
1014 # sum over rows
1015 ret = self * asmatrix(
1016 np.ones((n, 1), dtype=res_dtype))
1018 if out is not None and out.shape != ret.shape:
1019 raise ValueError("dimensions do not match")
1021 return ret.sum(axis=(), dtype=dtype, out=out)
1023 def mean(self, axis=None, dtype=None, out=None):
1024 """
1025 Compute the arithmetic mean along the specified axis.
1027 Returns the average of the matrix elements. The average is taken
1028 over all elements in the matrix by default, otherwise over the
1029 specified axis. `float64` intermediate and return values are used
1030 for integer inputs.
1032 Parameters
1033 ----------
1034 axis : {-2, -1, 0, 1, None} optional
1035 Axis along which the mean is computed. The default is to compute
1036 the mean of all elements in the matrix (i.e., `axis` = `None`).
1037 dtype : data-type, optional
1038 Type to use in computing the mean. For integer inputs, the default
1039 is `float64`; for floating point inputs, it is the same as the
1040 input dtype.
1042 .. versionadded:: 0.18.0
1044 out : np.matrix, optional
1045 Alternative output matrix in which to place the result. It must
1046 have the same shape as the expected output, but the type of the
1047 output values will be cast if necessary.
1049 .. versionadded:: 0.18.0
1051 Returns
1052 -------
1053 m : np.matrix
1055 See Also
1056 --------
1057 numpy.matrix.mean : NumPy's implementation of 'mean' for matrices
1059 """
1060 def _is_integral(dtype):
1061 return (np.issubdtype(dtype, np.integer) or
1062 np.issubdtype(dtype, np.bool_))
1064 validateaxis(axis)
1066 res_dtype = self.dtype.type
1067 integral = _is_integral(self.dtype)
1069 # output dtype
1070 if dtype is None:
1071 if integral:
1072 res_dtype = np.float64
1073 else:
1074 res_dtype = np.dtype(dtype).type
1076 # intermediate dtype for summation
1077 inter_dtype = np.float64 if integral else res_dtype
1078 inter_self = self.astype(inter_dtype)
1080 if axis is None:
1081 return (inter_self / np.array(
1082 self.shape[0] * self.shape[1]))\
1083 .sum(dtype=res_dtype, out=out)
1085 if axis < 0:
1086 axis += 2
1088 # axis = 0 or 1 now
1089 if axis == 0:
1090 return (inter_self * (1.0 / self.shape[0])).sum(
1091 axis=0, dtype=res_dtype, out=out)
1092 else:
1093 return (inter_self * (1.0 / self.shape[1])).sum(
1094 axis=1, dtype=res_dtype, out=out)
1096 def diagonal(self, k=0):
1097 """Returns the kth diagonal of the matrix.
1099 Parameters
1100 ----------
1101 k : int, optional
1102 Which diagonal to get, corresponding to elements a[i, i+k].
1103 Default: 0 (the main diagonal).
1105 .. versionadded:: 1.0
1107 See also
1108 --------
1109 numpy.diagonal : Equivalent numpy function.
1111 Examples
1112 --------
1113 >>> from scipy.sparse import csr_matrix
1114 >>> A = csr_matrix([[1, 2, 0], [0, 0, 3], [4, 0, 5]])
1115 >>> A.diagonal()
1116 array([1, 0, 5])
1117 >>> A.diagonal(k=1)
1118 array([2, 3])
1119 """
1120 return self.tocsr().diagonal(k=k)
1122 def setdiag(self, values, k=0):
1123 """
1124 Set diagonal or off-diagonal elements of the array.
1126 Parameters
1127 ----------
1128 values : array_like
1129 New values of the diagonal elements.
1131 Values may have any length. If the diagonal is longer than values,
1132 then the remaining diagonal entries will not be set. If values if
1133 longer than the diagonal, then the remaining values are ignored.
1135 If a scalar value is given, all of the diagonal is set to it.
1137 k : int, optional
1138 Which off-diagonal to set, corresponding to elements a[i,i+k].
1139 Default: 0 (the main diagonal).
1141 """
1142 M, N = self.shape
1143 if (k > 0 and k >= N) or (k < 0 and -k >= M):
1144 raise ValueError("k exceeds matrix dimensions")
1145 self._setdiag(np.asarray(values), k)
1147 def _setdiag(self, values, k):
1148 M, N = self.shape
1149 if k < 0:
1150 if values.ndim == 0:
1151 # broadcast
1152 max_index = min(M+k, N)
1153 for i in range(max_index):
1154 self[i - k, i] = values
1155 else:
1156 max_index = min(M+k, N, len(values))
1157 if max_index <= 0:
1158 return
1159 for i, v in enumerate(values[:max_index]):
1160 self[i - k, i] = v
1161 else:
1162 if values.ndim == 0:
1163 # broadcast
1164 max_index = min(M, N-k)
1165 for i in range(max_index):
1166 self[i, i + k] = values
1167 else:
1168 max_index = min(M, N-k, len(values))
1169 if max_index <= 0:
1170 return
1171 for i, v in enumerate(values[:max_index]):
1172 self[i, i + k] = v
1174 def _process_toarray_args(self, order, out):
1175 if out is not None:
1176 if order is not None:
1177 raise ValueError('order cannot be specified if out '
1178 'is not None')
1179 if out.shape != self.shape or out.dtype != self.dtype:
1180 raise ValueError('out array must be same dtype and shape as '
1181 'sparse matrix')
1182 out[...] = 0.
1183 return out
1184 else:
1185 return np.zeros(self.shape, dtype=self.dtype, order=order)
1188def isspmatrix(x):
1189 """Is x of a sparse matrix type?
1191 Parameters
1192 ----------
1193 x
1194 object to check for being a sparse matrix
1196 Returns
1197 -------
1198 bool
1199 True if x is a sparse matrix, False otherwise
1201 Notes
1202 -----
1203 issparse and isspmatrix are aliases for the same function.
1205 Examples
1206 --------
1207 >>> from scipy.sparse import csr_matrix, isspmatrix
1208 >>> isspmatrix(csr_matrix([[5]]))
1209 True
1211 >>> from scipy.sparse import isspmatrix
1212 >>> isspmatrix(5)
1213 False
1214 """
1215 return isinstance(x, spmatrix)
1218issparse = isspmatrix