[Scipy-svn] r3319 - in trunk/scipy/sparse: . tests

scipy-svn at scipy.org scipy-svn at scipy.org
Tue Sep 18 11:04:56 EDT 2007


Author: rc
Date: 2007-09-18 10:04:50 -0500 (Tue, 18 Sep 2007)
New Revision: 3319

Modified:
   trunk/scipy/sparse/sparse.py
   trunk/scipy/sparse/tests/test_sparse.py
Log:
get_submatrix() for csc_matrix
csr_matrix, csc_matrix.__getitem__() now uses appropriate get_submatrix()
- indexing by row and column slices is possible, though it returns a new matrix,
  not a view


Modified: trunk/scipy/sparse/sparse.py
===================================================================
--- trunk/scipy/sparse/sparse.py	2007-09-18 03:18:35 UTC (rev 3318)
+++ trunk/scipy/sparse/sparse.py	2007-09-18 15:04:50 UTC (rev 3319)
@@ -762,8 +762,51 @@
         else:
             return self._toother()._toother()
 
+    def _get_submatrix( self, shape0, shape1, slice0, slice1 ):
+        """Return a submatrix of this matrix (new matrix is created)."""
+        def _process_slice( sl, num ):
+            if isinstance( sl, slice ):
+                i0, i1 = sl.start, sl.stop
+                if i0 is None:
+                    i0 = 0
+                elif i0 < 0:
+                    i0 = num + i0
 
+                if i1 is None:
+                    i1 = num
+                elif i1 < 0:
+                    i1 = num + i1
 
+                return i0, i1
+            
+            elif isscalar( sl ):
+                if sl < 0:
+                    sl += num
+
+                return sl, sl + 1
+
+            else:
+                return sl[0], sl[1]
+
+        def _in_bounds( i0, i1, num ):
+            if not (0<=i0<num) or not (0<i1<=num) or not (i0<i1):
+                raise IndexError,\
+                      "index out of bounds: 0<=%d<%d, 0<=%d<%d, %d<%d" %\
+                      (i0, num, i1, num, i0, i1)
+
+        i0, i1 = _process_slice( slice0, shape0 )
+        j0, j1 = _process_slice( slice1, shape1 )
+        _in_bounds( i0, i1, shape0 )
+        _in_bounds( j0, j1, shape1 )
+
+        aux = sparsetools.get_csr_submatrix( shape0, shape1,
+                                             self.indptr, self.indices,
+                                             self.data,
+                                             i0, i1, j0, j1 )
+        data, indices, indptr = aux[2], aux[1], aux[0]
+        return data, indices, indptr, i1 - i0, j1 - j0
+
+
 class csc_matrix(_cs_matrix):
     """ Compressed sparse column matrix
         This can be instantiated in several ways:
@@ -922,9 +965,12 @@
         if (self.indptr[0] != 0):
             raise ValueError,"index pointer should start with 0"
         if (len(self.indptr) != N+1):
-            raise ValueError, "index pointer should be of of size N+1"
+            raise ValueError, \
+                  "index pointer size (%d) should be N+1 (%d)" %\
+                  (len(self.indptr), N+1)
         if (nzmax < nnz):
-            raise ValueError, "nzmax must not be less than nnz"
+            raise ValueError, "nzmax (%d) must not be less than nnz (%d)" %\
+                  (nzmax, nnz)
 
         if full_check:
             #check format validity (more expensive)
@@ -994,8 +1040,8 @@
             row = key[0]
             col = key[1]
             if isinstance(col, slice):
-                raise IndexError, "csc_matrix supports slices only of a single"\
-                                  " column"
+                # Returns a new matrix!
+                return self.get_submatrix( row, col )
             elif isinstance(row, slice):
                 return self._getslice(row, col)
             M, N = self.shape
@@ -1123,6 +1169,14 @@
         """
         return _cs_matrix._ensure_sorted_indices(self, self.shape[1], self.shape[0], inplace)
 
+    def get_submatrix( self, slice0, slice1 ):
+        """Return a submatrix of this matrix (new matrix is created).
+        Rows and columns can be selected using slice instances, tuples,
+        or scalars."""
+        aux = _cs_matrix._get_submatrix( self, self.shape[1], self.shape[0],
+                                         slice1, slice0 )
+        nr, nc = aux[3:]
+        return self.__class__( aux[:3], dims = (nc, nr) )
 
 class csr_matrix(_cs_matrix):
     """ Compressed sparse row matrix
@@ -1337,8 +1391,8 @@
             row = key[0]
             col = key[1]
             if isinstance(row, slice):
-                raise IndexError, "csr_matrix supports slices only of a single"\
-                                  " row"
+                # Returns a new matrix!
+                return self.get_submatrix( row, col )
             elif isinstance(col, slice):
                 return self._getslice(row, col)
             M, N = self.shape
@@ -1466,16 +1520,13 @@
         return _cs_matrix._ensure_sorted_indices(self, self.shape[0], self.shape[1], inplace)
 
     def get_submatrix( self, slice0, slice1 ):
-        """Return a submatrix of this matrix (new matrix is created)."""
-        aux = sparsetools.get_csr_submatrix( self.shape[0], self.shape[1],
-                                             self.indptr, self.indices,
-                                             self.data,
-                                             slice0.start, slice0.stop,
-                                             slice1.start, slice1.stop )
-        data, indices, indptr = aux[2], aux[1], aux[0]
-        return self.__class__( (data, indices, indptr),
-                               dims = (slice0.stop - slice0.start,
-                                       slice1.stop - slice1.start) )
+        """Return a submatrix of this matrix (new matrix is created)..
+        Rows and columns can be selected using slice instances, tuples,
+        or scalars."""
+        aux = _cs_matrix._get_submatrix( self, self.shape[0], self.shape[1],
+                                         slice0, slice1 )
+        nr, nc = aux[3:]
+        return self.__class__( aux[:3], dims = (nr, nc) )
 
 # This function was for sorting dictionary keys by the second tuple element.
 # (We now use the Schwartzian transform instead for efficiency.)

Modified: trunk/scipy/sparse/tests/test_sparse.py
===================================================================
--- trunk/scipy/sparse/tests/test_sparse.py	2007-09-18 03:18:35 UTC (rev 3318)
+++ trunk/scipy/sparse/tests/test_sparse.py	2007-09-18 15:04:50 UTC (rev 3319)
@@ -361,7 +361,7 @@
             
 
 class _test_horiz_slicing:
-    """Tests vertical slicing (e.g. [:, 0]).  Tests for individual sparse
+    """Tests horizontal slicing (e.g. [:, 0]).  Tests for individual sparse
     matrix types that implement this should derive from this class.
     """
     def check_get_horiz_slice(self):
@@ -428,6 +428,23 @@
             caught += 1
         assert caught == 2
 
+class _test_slicing:
+    """Tests vertical and horizontal slicing (e.g. [:,0:2]). Tests for
+    individual sparse matrix types that implement this should derive from this
+    class.
+    """
+    def check_get_slices(self):
+        B = asmatrix(arange(50.).reshape(5,10))
+        A = self.spmatrix(B)
+        assert_array_equal(B[2:5,0:3], A[2:5,0:3].todense())
+        assert_array_equal(B[1:,:-1], A[1:,:-1].todense())
+        assert_array_equal(B[:-1,1:], A[:-1,1:].todense())
+        
+        # Now test slicing when a column contains only zeros
+        E = matrix([[1, 0, 1], [4, 0, 0], [0, 0, 0], [0, 0, 1]])
+        F = self.spmatrix(E)
+        assert_array_equal(E[1:2, 1:2], F[1:2, 1:2].todense())
+        assert_array_equal(E[:, 1:], F[:, 1:].todense())
 
 class _test_fancy_indexing:
     """Tests fancy indexing features.  The tests for any matrix formats
@@ -574,7 +591,8 @@
 
 
 
-class test_csr(_test_cs, _test_horiz_slicing, _test_arith, NumpyTestCase):
+class test_csr(_test_cs, _test_horiz_slicing, _test_vert_slicing,
+               _test_slicing, _test_arith, NumpyTestCase):
     spmatrix = csr_matrix
 
     def check_constructor1(self):
@@ -642,9 +660,9 @@
                 assert_equal( asp[ir, ic], bsp[ir, ic] )
 
     def check_get_submatrix(self):
-        a = csr_matrix( array([[1,2,3],[1,2,3],[0,2,0]]) )
+        a = csr_matrix( array([[1,2,3,4],[1,2,3,5],[0,2,0,1]]) )
         i0 = slice( 0, 2 )
-        i1 = slice( 1, 3 )
+        i1 = ( 1, 3 )
         b = a.get_submatrix( i0, i1 )
 
         aa = a.toarray()
@@ -652,9 +670,10 @@
 
         assert b.dtype == a.dtype
         assert b.shape == (2,2)
-        assert_equal( ab, aa[i0,i1] )
+        assert_equal( ab, aa[i0,i1[0]:i1[1]] )
 
-class test_csc(_test_cs, _test_vert_slicing, _test_arith, NumpyTestCase):
+class test_csc(_test_cs, _test_horiz_slicing, _test_vert_slicing,
+               _test_slicing, _test_arith, NumpyTestCase):
     spmatrix = csc_matrix
 
     def check_constructor1(self):
@@ -713,6 +732,19 @@
             for ic in range( asp.shape[1] ):
                 assert_equal( asp[ir, ic], bsp[ir, ic] )
 
+    def check_get_submatrix(self):
+        a = csc_matrix( array([[1,2,3,4],[1,2,3,5],[0,2,0,1]]) )
+        i0 = slice( 0, 2 )
+        i1 = ( 1, 3 )
+        b = a.get_submatrix( i0, i1 )
+
+        aa = a.toarray()
+        ab = b.toarray()
+
+        assert b.dtype == a.dtype
+        assert b.shape == (2,2)
+        assert_equal( ab, aa[i0,i1[0]:i1[1]] )
+
 class test_dok(_test_cs, NumpyTestCase):
     spmatrix = dok_matrix
 




More information about the Scipy-svn mailing list