[Scipy-svn] r3651 - trunk/scipy/sparse

scipy-svn at scipy.org scipy-svn at scipy.org
Fri Dec 14 13:30:31 EST 2007


Author: wnbell
Date: 2007-12-14 12:30:20 -0600 (Fri, 14 Dec 2007)
New Revision: 3651

Added:
   trunk/scipy/sparse/csc.py
   trunk/scipy/sparse/csr.py
Modified:
   trunk/scipy/sparse/__init__.py
   trunk/scipy/sparse/base.py
   trunk/scipy/sparse/compressed.py
   trunk/scipy/sparse/construct.py
   trunk/scipy/sparse/coo.py
   trunk/scipy/sparse/lil.py
   trunk/scipy/sparse/spfuncs.py
Log:
moved csr_matrix and csc_matrix to individual files


Modified: trunk/scipy/sparse/__init__.py
===================================================================
--- trunk/scipy/sparse/__init__.py	2007-12-14 11:00:19 UTC (rev 3650)
+++ trunk/scipy/sparse/__init__.py	2007-12-14 18:30:20 UTC (rev 3651)
@@ -3,7 +3,8 @@
 from info import __doc__
 
 from base import *
-from compressed import *
+from csr import *
+from csc import *
 from lil import *
 from dok import *
 from coo import *

Modified: trunk/scipy/sparse/base.py
===================================================================
--- trunk/scipy/sparse/base.py	2007-12-14 11:00:19 UTC (rev 3650)
+++ trunk/scipy/sparse/base.py	2007-12-14 18:30:20 UTC (rev 3651)
@@ -2,6 +2,8 @@
 
 __all__ = ['spmatrix','isspmatrix','issparse']
 
+from warnings import warn
+
 from numpy import asarray, asmatrix, ones
 
 from sputils import isdense, isscalarlike 
@@ -447,8 +449,10 @@
 
 
     def save(self, file_name, format = '%d %d %f\n'):
-        #TODO deprecate, use io.mmwrite or mio instead
-
+        #deprecated on Dec 14 2007
+        warn('save() is deprecated, consider using mmwrite() or savemat()' \
+                ' provided by scipy.io instead',
+                DeprecationWarning)
         try:
             fd = open(file_name, 'w')
         except Exception, e:

Modified: trunk/scipy/sparse/compressed.py
===================================================================
--- trunk/scipy/sparse/compressed.py	2007-12-14 11:00:19 UTC (rev 3650)
+++ trunk/scipy/sparse/compressed.py	2007-12-14 18:30:20 UTC (rev 3651)
@@ -1,16 +1,14 @@
-"""Sparse matrix classes using compressed storage
+"""Base class for sparse matrix formats using compressed storage  
 """
 
+__all__ = []
 
-__all__ = ['csr_matrix', 'csc_matrix', 'isspmatrix_csr', 'isspmatrix_csc' ]
-
 import numpy
 from numpy import array, matrix, asarray, asmatrix, zeros, rank, intc, \
         empty, hstack, isscalar, ndarray, shape, searchsorted
 
 from base import spmatrix,isspmatrix
 import sparsetools
-from sparsetools import csrtodense, cootocsr, cootocsc, csctocsr, csrtocsc
 from sputils import upcast, to_native, isdense, isshape, getdtype, \
         isscalarlike
 
@@ -23,8 +21,6 @@
     return new
 
 
-
-
 class _cs_matrix(spmatrix):
     """base matrix class for compressed row and column oriented matrices"""
     
@@ -68,7 +64,8 @@
                         # Try interpreting it as (data, indices, indptr)
                         (data, indices, indptr) = arg1
                     except:
-                        raise ValueError, "unrecognized form for csr_matrix constructor"
+                        raise ValueError, "unrecognized form for" \
+                                " %s_matrix constructor" % self.format
                     else:
                         self.data    = array(data, copy=copy, dtype=getdtype(dtype, data))
                         self.indices = array(indices, copy=copy)
@@ -81,7 +78,8 @@
                     self._set_self( other )
 
         else:
-            raise ValueError, "unrecognized form for csr_matrix constructor"
+            raise ValueError, "unrecognized form for" \
+                    " %s_matrix constructor" % self.format
 
         # Read matrix dimensions given, if any
         if dims is not None:
@@ -120,7 +118,15 @@
         self.indptr  = other.indptr
         self.shape   = other.shape
     
-    def _check_format(self, full_check):
+    def check_format(self, full_check=True):
+        """check whether the matrix format is valid
+
+            *Parameters*:
+                full_check:
+                    True  - rigorous check, O(N) operations : default
+                    False - basic check, O(1) operations
+
+        """
         self.shape = tuple([int(x) for x in self.shape])  # for floats etc.
 
         #use _swap to determine proper bounds
@@ -179,17 +185,6 @@
     def astype(self, t):
         return self._with_data(self.data.astype(t))
 
-    def _with_data(self,data,copy=True):
-        """Returns a matrix with the same sparsity structure as self,
-        but with different data.  By default the structure arrays
-        (i.e. .indptr and .indices) are copied.
-        """
-        if copy:
-            return self.__class__((data,self.indices.copy(),self.indptr.copy()), \
-                                   dims=self.shape,dtype=data.dtype)
-        else:
-            return self.__class__((data,self.indices,self.indptr), \
-                                   dims=self.shape,dtype=data.dtype)
 
     def __abs__(self):
         return self._with_data(abs(self.data))
@@ -200,24 +195,7 @@
     def _imag(self):
         return self._with_data(numpy.imag(self.data))
 
-    def _binopt(self, other, op, in_shape=None, out_shape=None):
-        """apply the binary operation fn to two sparse matrices"""
-        other = self._tothis(other)
 
-        if in_shape is None:
-            in_shape = self.shape
-        if out_shape is None:
-            out_shape = self.shape
-
-        # e.g. csr_plus_csr, cscmucsc, etc.
-        fn = getattr(sparsetools, self.format + op + self.format)
-
-        indptr, ind, data = fn(in_shape[0], in_shape[1], \
-                               self.indptr, self.indices, self.data,
-                               other.indptr, other.indices, other.data)
-        return self.__class__((data, ind, indptr), dims=out_shape)
-
-
     def __add__(self,other):
         # First check if argument is a scalar
         if isscalarlike(other):
@@ -388,24 +366,6 @@
     def getdata(self, ind):
         return self.data[ind]
 
-#    def _other_format(self):
-#        if self.format == 'csr':
-#            return 'csc'
-#        elif self.format == 'csc':
-#            return 'csr'
-#        else:
-#            raise TypeError,'unrecognized type'
-#    
-#    def _other__class__(self):
-#        if self.format == 'csr':
-#            return csc_matrix
-#        elif self.format == 'csc':
-#            return csr_matrix
-#        else:
-#            raise TypeError,'unrecognized type'
-
-
-
     def sum(self, axis=None):
         """Sum the matrix over the given axis.  If the axis is None, sum
         over both rows and columns, returning a scalar.
@@ -418,7 +378,6 @@
             return spmatrix.sum(self,axis)
             raise ValueError, "axis out of bounds"
 
-
     def copy(self):
         return self._with_data(self.data.copy(),copy=True)
 
@@ -564,392 +523,34 @@
         return data, indices, indptr, i1 - i0, j1 - j0
 
 
-class csc_matrix(_cs_matrix):
-    """ Compressed sparse column matrix
-        This can be instantiated in several ways:
-          - csc_matrix(d)
-            with a dense matrix d
-
-          - csc_matrix(s)
-            with another sparse matrix s (sugar for .tocsc())
-
-          - csc_matrix((M, N), [dtype])
-            to construct a container, where (M, N) are dimensions and
-            dtype is optional, defaulting to dtype='d'.
-
-          - csc_matrix((data, ij), [(M, N)])
-            where data, ij satisfy:
-                a[ij[0, k], ij[1, k]] = data[k]
-
-          - csc_matrix((data, row, ptr), [(M, N)])
-            standard CSC representation
-    """
-    
-    def check_format(self,full_check=True):
-        """check whether matrix is in valid CSC format
-
-            *Parameters*:
-                full_check:
-                    True  - rigorous check, O(N) operations : default
-                    False - basic check, O(1) operations
-
+    # utility functions 
+    def _with_data(self,data,copy=True):
+        """Returns a matrix with the same sparsity structure as self,
+        but with different data.  By default the structure arrays
+        (i.e. .indptr and .indices) are copied.
         """
-        _cs_matrix._check_format(self,full_check)
-
-    def __getattr__(self, attr):
-        if attr == 'rowind':
-            warnings.warn("rowind attribute no longer in use. Use .indices instead",
-                          DeprecationWarning)
-            return self.indices
+        if copy:
+            return self.__class__((data,self.indices.copy(),self.indptr.copy()), \
+                                   dims=self.shape,dtype=data.dtype)
         else:
-            return _cs_matrix.__getattr__(self, attr)
+            return self.__class__((data,self.indices,self.indptr), \
+                                   dims=self.shape,dtype=data.dtype)
 
-    def __iter__(self):
-        csr = self.tocsr()
-        for r in xrange(self.shape[0]):
-            yield csr[r,:]
+    def _binopt(self, other, op, in_shape=None, out_shape=None):
+        """apply the binary operation fn to two sparse matrices"""
+        other = self._tothis(other)
 
-    def transpose(self, copy=False):
-        return _cs_matrix._transpose(self, csr_matrix, copy)
+        if in_shape is None:
+            in_shape = self.shape
+        if out_shape is None:
+            out_shape = self.shape
 
-    def __getitem__(self, key):
-        if isinstance(key, tuple):
-            #TODO use _swap() to unify this in _cs_matrix
-            row = key[0]
-            col = key[1]
-            if isinstance(col, slice):
-                # Returns a new matrix!
-                return self.get_submatrix( row, col )
-            elif isinstance(row, slice):
-                return self._getslice(row, col)
-            M, N = self.shape
-            if (row < 0):
-                row = M + row
-            if (col < 0):
-                col = N + col
-            if not (0<=row<M) or not (0<=col<N):
-                raise IndexError, "index out of bounds"
-            #this was implemented in fortran before - is there a noticable performance advantage?
-            indxs = numpy.where(row == self.indices[self.indptr[col]:self.indptr[col+1]])
-            if len(indxs[0]) == 0:
-                return 0
-            else:
-                return self.data[self.indptr[col]:self.indptr[col+1]][indxs[0]]
-        elif isintlike(key):
-            # Was: return self.data[key]
-            # If this is allowed, it should return the relevant row, as for
-            # dense matrices (and __len__ should be supported again).
-            raise IndexError, "integer index not supported for csc_matrix"
-        else:
-            raise IndexError, "invalid index"
+        # e.g. csr_plus_csr, cscmucsc, etc.
+        fn = getattr(sparsetools, self.format + op + self.format)
 
+        indptr, ind, data = fn(in_shape[0], in_shape[1], \
+                               self.indptr, self.indices, self.data,
+                               other.indptr, other.indices, other.data)
+        return self.__class__((data, ind, indptr), dims=out_shape)
 
-    def __setitem__(self, key, val):
-        if isinstance(key, tuple):
-            row = key[0]
-            col = key[1]
-            if not (isscalarlike(row) and isscalarlike(col)):
-                raise NotImplementedError("Fancy indexing in assignments not"
-                                          "supported for csc matrices.")
-            M, N = self.shape
-            if (row < 0):
-                row = M + row
-            if (col < 0):
-                col = N + col
-            if (row < 0) or (col < 0):
-                raise IndexError, "index out of bounds"
-            if (col >= N):
-                self.indptr = resize1d(self.indptr, col+2)
-                self.indptr[N+1:] = self.indptr[N]
-                N = col+1
-            if (row >= M):
-                M = row+1
-            self.shape = (M, N)
 
-            indxs = numpy.where(row == self.indices[self.indptr[col]:self.indptr[col+1]])
-    
-            if len(indxs[0]) == 0:
-                #value not present
-                #TODO handle this with concatenation
-                self.data    = resize1d(self.data,    self.nnz + 1)
-                self.indices = resize1d(self.indices, self.nnz + 1)
-
-                newindex = self.indptr[col]
-                self.data[newindex+1:]    = self.data[newindex:-1]
-                self.indices[newindex+1:] = self.indices[newindex:-1]
-
-                self.data[newindex]   = val
-                self.indices[newindex] = row
-                self.indptr[col+1:] += 1
-
-            elif len(indxs[0]) == 1:
-                #value already present
-                self.data[self.indptr[col]:self.indptr[col+1]][indxs[0]] = val
-            else:
-                raise IndexError, "row index occurs more than once"
-
-            self.check_format(full_check=False)
-        else:
-            # We should allow slices here!
-            raise IndexError, "invalid index"
-
-    def _getslice(self, i, myslice):
-        return self._getcolslice(i, myslice)
-
-    def _getcolslice(self, myslice, j):
-        """Returns a view of the elements [myslice.start:myslice.stop, j].
-        """
-        start, stop, stride = myslice.indices(self.shape[0])
-        return _cs_matrix._get_slice(self, j, start, stop, stride, (stop - start, 1))
-
-    def rowcol(self, ind):
-        row = self.indices[ind]
-        col = searchsorted(self.indptr, ind+1)-1
-        return (row, col)
-
-
-    def tocsc(self, copy=False):
-        return self.toself(copy)
-    
-    def tocsr(self):
-        indptr  = empty(self.shape[0] + 1, dtype=intc)
-        indices = empty(self.nnz, dtype=intc)
-        data    = empty(self.nnz, dtype=upcast(self.dtype))
-
-        csctocsr(self.shape[0], self.shape[1], \
-                self.indptr, self.indices, self.data, \
-                indptr, indices, data)
-
-        return csr_matrix((data, indices, indptr), self.shape)
-
-    def toarray(self):
-        return self.tocsr().toarray()
-
-    def get_submatrix( self, slice0, slice1 ):
-        """Return a submatrix of this matrix (new matrix is created).
-        Contigous range of rows and columns can be selected using:
-        1. a slice object
-        2. a tuple (from, to)
-        3. a scalar for single row/column selection."""
-        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) )
-    
-    # these functions are used by the parent class (_cs_matrix)
-    # to remove redudancy between csc_matrix and csr_matrix
-    def _swap(self,x):
-        """swap the members of x if this is a column-oriented matrix
-        """
-        return (x[1],x[0])
-
-    def _toother(self):
-        return self.tocsr()
-
-    def _tothis(self, other):
-        return other.tocsc()
-
-class csr_matrix(_cs_matrix):
-    """ Compressed sparse row matrix
-        This can be instantiated in several ways:
-          - csr_matrix(d)
-            with a dense matrix d
-
-          - csr_matrix(s)
-            with another sparse matrix s (sugar for .tocsr())
-
-          - csr_matrix((M, N), [dtype])
-            to construct a container, where (M, N) are dimensions and
-            dtype is optional, defaulting to dtype='d'.
-
-          - csr_matrix((data, ij), [dims=(M, N)])
-            where data, ij satisfy:
-                a[ij[0, k], ij[1, k]] = data[k]
-
-          - csr_matrix((data, col, ptr), [dims=(M, N)])
-            standard CSR representation
-    """
-
-    def check_format(self,full_check=True):
-        """check whether matrix is in valid CSR format
-
-            *Parameters*:
-                full_check:
-                    True  - perform rigorous checking - default
-                    False - perform basic format check
-
-        """
-        _cs_matrix._check_format(self,full_check)
-
-    def __getattr__(self, attr):
-        if attr == 'colind':
-            warnings.warn("colind attribute no longer in use. Use .indices instead",
-                          DeprecationWarning)
-            return self.indices
-        else:
-            return _cs_matrix.__getattr__(self, attr)
-
-    def transpose(self, copy=False):
-        return _cs_matrix._transpose(self, csc_matrix, copy)
-
-    def __getitem__(self, key):
-        if isinstance(key, tuple):
-            #TODO use _swap() to unify this in _cs_matrix
-            row = key[0]
-            col = key[1]
-            if isinstance(row, slice):
-                # Returns a new matrix!
-                return self.get_submatrix( row, col )
-            elif isinstance(col, slice):
-                return self._getslice(row, col)
-            M, N = self.shape
-            if (row < 0):
-                row = M + row
-            if (col < 0):
-                col = N + col
-            if not (0<=row<M) or not (0<=col<N):
-                raise IndexError, "index out of bounds"
-            #this was implemented in fortran before - is there a noticable performance advantage?
-            indxs = numpy.where(col == self.indices[self.indptr[row]:self.indptr[row+1]])
-            if len(indxs[0]) == 0:
-                return 0
-            else:
-                return self.data[self.indptr[row]:self.indptr[row+1]][indxs[0]]
-        elif isintlike(key):
-            return self[key, :]
-        else:
-            raise IndexError, "invalid index"
-
-    def _getslice(self, i, myslice):
-        return self._getrowslice(i, myslice)
-
-    def _getrowslice(self, i, myslice):
-        """Returns a view of the elements [i, myslice.start:myslice.stop].
-        """
-        start, stop, stride = myslice.indices(self.shape[1])
-        return _cs_matrix._get_slice(self, i, start, stop, stride, (1, stop-start))
-
-    def __setitem__(self, key, val):
-        if isinstance(key, tuple):
-            row = key[0]
-            col = key[1]
-            if not (isscalarlike(row) and isscalarlike(col)):
-                raise NotImplementedError("Fancy indexing in assignment not "
-                                          "supported for csr matrices.")
-            M, N = self.shape
-            if (row < 0):
-                row = M + row
-            if (col < 0):
-                col = N + col
-            if (row < 0) or (col < 0):
-                raise IndexError, "index out of bounds"
-            if (row >= M):
-                self.indptr = resize1d(self.indptr, row+2)
-                self.indptr[M+1:] = self.indptr[M]
-                M = row+1
-            if (col >= N):
-                N = col+1
-            self.shape = (M, N)
-
-            indxs = numpy.where(col == self.indices[self.indptr[row]:self.indptr[row+1]])
-            if len(indxs[0]) == 0:
-                #value not present
-                self.data    = resize1d(self.data, self.nnz + 1)
-                self.indices = resize1d(self.indices, self.nnz + 1)
-
-                newindex = self.indptr[row]
-                self.data[newindex+1:]   = self.data[newindex:-1]
-                self.indices[newindex+1:] = self.indices[newindex:-1]
-
-                self.data[newindex]   = val
-                self.indices[newindex] = col
-                self.indptr[row+1:] += 1
-
-            elif len(indxs[0]) == 1:
-                #value already present
-                self.data[self.indptr[row]:self.indptr[row+1]][indxs[0]] = val
-            else:
-                raise IndexError, "row index occurs more than once"
-
-            self.check_format(full_check=False)
-        else:
-            # We should allow slices here!
-            raise IndexError, "invalid index"
-
-    def rowcol(self, ind):
-        col = self.indices[ind]
-        row = searchsorted(self.indptr, ind+1)-1
-        return (row, col)
-
-
-    def tolil(self):
-        from lil import lil_matrix
-        lil = lil_matrix(self.shape,dtype=self.dtype)
-     
-        csr = self.sorted_indices() #lil_matrix needs sorted rows
-        
-        rows,data = lil.rows,lil.data
-        ptr,ind,dat = csr.indptr,csr.indices,csr.data
-
-        for n in xrange(self.shape[0]):
-            start = ptr[n]
-            end   = ptr[n+1]
-            rows[n] = ind[start:end].tolist()
-            data[n] = dat[start:end].tolist()
-
-        return lil
-
-    def tocsr(self, copy=False):
-        return self.toself(copy)
-
-    def tocsc(self):
-        indptr  = empty(self.shape[1] + 1, dtype=intc)
-        indices = empty(self.nnz, dtype=intc)
-        data    = empty(self.nnz, dtype=upcast(self.dtype))
-
-        csrtocsc(self.shape[0], self.shape[1], \
-                 self.indptr, self.indices, self.data, \
-                 indptr, indices, data)
-
-        return csc_matrix((data, indices, indptr), self.shape)
-    
-    def toarray(self):
-        data = numpy.zeros(self.shape, dtype=upcast(self.data.dtype))
-        csrtodense(self.shape[0], self.shape[1], self.indptr, self.indices,
-                   self.data, data)
-        return data
-    
-    def get_submatrix( self, slice0, slice1 ):
-        """Return a submatrix of this matrix (new matrix is created).
-        Contigous range of rows and columns can be selected using:
-        1. a slice object
-        2. a tuple (from, to)
-        3. a scalar for single row/column selection."""
-        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) )
-
-    # these functions are used by the parent class (_cs_matrix)
-    # to remove redudancy between csc_matrix and csr_matrix
-    def _swap(self,x):
-        """swap the members of x if this is a column-oriented matrix
-        """
-        return (x[0],x[1])
-
-    def _toother(self):
-        return self.tocsc()
-
-    def _tothis(self, other):
-        return other.tocsr()
-
-
-from sputils import _isinstance
-
-def isspmatrix_csr(x):
-    return _isinstance(x, csr_matrix)
-
-def isspmatrix_csc(x):
-    return _isinstance(x, csc_matrix)
-
-

Modified: trunk/scipy/sparse/construct.py
===================================================================
--- trunk/scipy/sparse/construct.py	2007-12-14 11:00:19 UTC (rev 3650)
+++ trunk/scipy/sparse/construct.py	2007-12-14 18:30:20 UTC (rev 3651)
@@ -10,7 +10,8 @@
 import numpy
 from numpy import ones, clip, array, arange, intc
 
-from compressed import csr_matrix, csc_matrix, isspmatrix_csr, isspmatrix_csc
+from csr import csr_matrix, isspmatrix_csr
+from csc import csc_matrix, isspmatrix_csc
 from coo import coo_matrix
 from dok import dok_matrix
 from lil import lil_matrix

Modified: trunk/scipy/sparse/coo.py
===================================================================
--- trunk/scipy/sparse/coo.py	2007-12-14 11:00:19 UTC (rev 3650)
+++ trunk/scipy/sparse/coo.py	2007-12-14 18:30:20 UTC (rev 3651)
@@ -149,7 +149,7 @@
         return self.data[num]
 
     def tocsc(self):
-        from compressed import csc_matrix
+        from csc import csc_matrix
         if self.nnz == 0:
             return csc_matrix(self.shape, dtype=self.dtype)
         else:
@@ -164,7 +164,7 @@
             return csc_matrix((data, indices, indptr), self.shape)
 
     def tocsr(self):
-        from compressed import csr_matrix
+        from csr import csr_matrix
         if self.nnz == 0:
             return csr_matrix(self.shape, dtype=self.dtype)
         else:

Added: trunk/scipy/sparse/csc.py
===================================================================
--- trunk/scipy/sparse/csc.py	2007-12-14 11:00:19 UTC (rev 3650)
+++ trunk/scipy/sparse/csc.py	2007-12-14 18:30:20 UTC (rev 3651)
@@ -0,0 +1,198 @@
+"""Compressed Sparse Column sparse matrix format
+"""
+
+__all__ = ['csc_matrix', 'isspmatrix_csc']
+
+
+import numpy
+from numpy import array, matrix, asarray, asmatrix, zeros, rank, intc, \
+        empty, hstack, isscalar, ndarray, shape, searchsorted
+
+from base import spmatrix,isspmatrix
+from sparsetools import csctocsr
+from sputils import upcast, to_native, isdense, isshape, getdtype, \
+        isscalarlike
+
+from compressed import _cs_matrix,resize1d
+
+
+class csc_matrix(_cs_matrix):
+    """ Compressed sparse column matrix
+        This can be instantiated in several ways:
+          - csc_matrix(d)
+            with a dense matrix d
+
+          - csc_matrix(s)
+            with another sparse matrix s (sugar for .tocsc())
+
+          - csc_matrix((M, N), [dtype])
+            to construct a container, where (M, N) are dimensions and
+            dtype is optional, defaulting to dtype='d'.
+
+          - csc_matrix((data, ij), [(M, N)])
+            where data, ij satisfy:
+                a[ij[0, k], ij[1, k]] = data[k]
+
+          - csc_matrix((data, row, ptr), [(M, N)])
+            standard CSC representation
+    """
+    
+    def __getattr__(self, attr):
+        if attr == 'rowind':
+            warnings.warn("rowind attribute no longer in use. Use .indices instead",
+                          DeprecationWarning)
+            return self.indices
+        else:
+            return _cs_matrix.__getattr__(self, attr)
+
+    def __iter__(self):
+        csr = self.tocsr()
+        for r in xrange(self.shape[0]):
+            yield csr[r,:]
+
+    def transpose(self, copy=False):
+        from csr import csr_matrix
+        return _cs_matrix._transpose(self, csr_matrix, copy)
+
+    def __getitem__(self, key):
+        if isinstance(key, tuple):
+            #TODO use _swap() to unify this in _cs_matrix
+            row = key[0]
+            col = key[1]
+            if isinstance(col, slice):
+                # Returns a new matrix!
+                return self.get_submatrix( row, col )
+            elif isinstance(row, slice):
+                return self._getslice(row, col)
+            M, N = self.shape
+            if (row < 0):
+                row = M + row
+            if (col < 0):
+                col = N + col
+            if not (0<=row<M) or not (0<=col<N):
+                raise IndexError, "index out of bounds"
+            #this was implemented in fortran before - is there a noticable performance advantage?
+            indxs = numpy.where(row == self.indices[self.indptr[col]:self.indptr[col+1]])
+            if len(indxs[0]) == 0:
+                return 0
+            else:
+                return self.data[self.indptr[col]:self.indptr[col+1]][indxs[0]]
+        elif isintlike(key):
+            # Was: return self.data[key]
+            # If this is allowed, it should return the relevant row, as for
+            # dense matrices (and __len__ should be supported again).
+            raise IndexError, "integer index not supported for csc_matrix"
+        else:
+            raise IndexError, "invalid index"
+
+
+    def __setitem__(self, key, val):
+        if isinstance(key, tuple):
+            row = key[0]
+            col = key[1]
+            if not (isscalarlike(row) and isscalarlike(col)):
+                raise NotImplementedError("Fancy indexing in assignments not"
+                                          "supported for csc matrices.")
+            M, N = self.shape
+            if (row < 0):
+                row = M + row
+            if (col < 0):
+                col = N + col
+            if (row < 0) or (col < 0):
+                raise IndexError, "index out of bounds"
+            if (col >= N):
+                self.indptr = resize1d(self.indptr, col+2)
+                self.indptr[N+1:] = self.indptr[N]
+                N = col+1
+            if (row >= M):
+                M = row+1
+            self.shape = (M, N)
+
+            indxs = numpy.where(row == self.indices[self.indptr[col]:self.indptr[col+1]])
+    
+            if len(indxs[0]) == 0:
+                #value not present
+                #TODO handle this with concatenation
+                self.data    = resize1d(self.data,    self.nnz + 1)
+                self.indices = resize1d(self.indices, self.nnz + 1)
+
+                newindex = self.indptr[col]
+                self.data[newindex+1:]    = self.data[newindex:-1]
+                self.indices[newindex+1:] = self.indices[newindex:-1]
+
+                self.data[newindex]   = val
+                self.indices[newindex] = row
+                self.indptr[col+1:] += 1
+
+            elif len(indxs[0]) == 1:
+                #value already present
+                self.data[self.indptr[col]:self.indptr[col+1]][indxs[0]] = val
+            else:
+                raise IndexError, "row index occurs more than once"
+
+            self.check_format(full_check=False)
+        else:
+            # We should allow slices here!
+            raise IndexError, "invalid index"
+
+    def _getslice(self, i, myslice):
+        return self._getcolslice(i, myslice)
+
+    def _getcolslice(self, myslice, j):
+        """Returns a view of the elements [myslice.start:myslice.stop, j].
+        """
+        start, stop, stride = myslice.indices(self.shape[0])
+        return _cs_matrix._get_slice(self, j, start, stop, stride, (stop - start, 1))
+
+    def rowcol(self, ind):
+        row = self.indices[ind]
+        col = searchsorted(self.indptr, ind+1)-1
+        return (row, col)
+
+
+    def tocsc(self, copy=False):
+        return self.toself(copy)
+    
+    def tocsr(self):
+        indptr  = empty(self.shape[0] + 1, dtype=intc)
+        indices = empty(self.nnz, dtype=intc)
+        data    = empty(self.nnz, dtype=upcast(self.dtype))
+
+        csctocsr(self.shape[0], self.shape[1], \
+                self.indptr, self.indices, self.data, \
+                indptr, indices, data)
+
+        from csr import csr_matrix
+        return csr_matrix((data, indices, indptr), self.shape)
+
+    def toarray(self):
+        return self.tocsr().toarray()
+
+    def get_submatrix( self, slice0, slice1 ):
+        """Return a submatrix of this matrix (new matrix is created).
+        Contigous range of rows and columns can be selected using:
+        1. a slice object
+        2. a tuple (from, to)
+        3. a scalar for single row/column selection."""
+        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) )
+    
+    # these functions are used by the parent class (_cs_matrix)
+    # to remove redudancy between csc_matrix and csr_matrix
+    def _swap(self,x):
+        """swap the members of x if this is a column-oriented matrix
+        """
+        return (x[1],x[0])
+
+    def _toother(self):
+        return self.tocsr()
+
+    def _tothis(self, other):
+        return other.tocsc()
+from sputils import _isinstance
+
+def isspmatrix_csc(x):
+    return _isinstance(x, csc_matrix)
+

Added: trunk/scipy/sparse/csr.py
===================================================================
--- trunk/scipy/sparse/csr.py	2007-12-14 11:00:19 UTC (rev 3650)
+++ trunk/scipy/sparse/csr.py	2007-12-14 18:30:20 UTC (rev 3651)
@@ -0,0 +1,209 @@
+"""Compressed Sparse Row sparse matrix format
+"""
+
+__all__ = ['csr_matrix', 'isspmatrix_csr']
+
+
+import numpy
+from numpy import array, matrix, asarray, asmatrix, zeros, rank, intc, \
+        empty, hstack, isscalar, ndarray, shape, searchsorted
+
+from base import spmatrix,isspmatrix
+from sparsetools import csrtodense, csrtocsc
+from sputils import upcast, to_native, isdense, isshape, getdtype, \
+        isscalarlike
+
+from compressed import _cs_matrix,resize1d
+
+class csr_matrix(_cs_matrix):
+    """ Compressed sparse row matrix
+        This can be instantiated in several ways:
+          - csr_matrix(d)
+            with a dense matrix d
+
+          - csr_matrix(s)
+            with another sparse matrix s (sugar for .tocsr())
+
+          - csr_matrix((M, N), [dtype])
+            to construct a container, where (M, N) are dimensions and
+            dtype is optional, defaulting to dtype='d'.
+
+          - csr_matrix((data, ij), [dims=(M, N)])
+            where data, ij satisfy:
+                a[ij[0, k], ij[1, k]] = data[k]
+
+          - csr_matrix((data, col, ptr), [dims=(M, N)])
+            standard CSR representation
+    """
+
+    def __getattr__(self, attr):
+        if attr == 'colind':
+            warnings.warn("colind attribute no longer in use. Use .indices instead",
+                          DeprecationWarning)
+            return self.indices
+        else:
+            return _cs_matrix.__getattr__(self, attr)
+
+    def transpose(self, copy=False):
+        from csc import csc_matrix
+        return _cs_matrix._transpose(self, csc_matrix, copy)
+
+    def __getitem__(self, key):
+        if isinstance(key, tuple):
+            #TODO use _swap() to unify this in _cs_matrix
+            row = key[0]
+            col = key[1]
+            if isinstance(row, slice):
+                # Returns a new matrix!
+                return self.get_submatrix( row, col )
+            elif isinstance(col, slice):
+                return self._getslice(row, col)
+            M, N = self.shape
+            if (row < 0):
+                row = M + row
+            if (col < 0):
+                col = N + col
+            if not (0<=row<M) or not (0<=col<N):
+                raise IndexError, "index out of bounds"
+            #this was implemented in fortran before - is there a noticable performance advantage?
+            indxs = numpy.where(col == self.indices[self.indptr[row]:self.indptr[row+1]])
+            if len(indxs[0]) == 0:
+                return 0
+            else:
+                return self.data[self.indptr[row]:self.indptr[row+1]][indxs[0]]
+        elif isintlike(key):
+            return self[key, :]
+        else:
+            raise IndexError, "invalid index"
+
+    def _getslice(self, i, myslice):
+        return self._getrowslice(i, myslice)
+
+    def _getrowslice(self, i, myslice):
+        """Returns a view of the elements [i, myslice.start:myslice.stop].
+        """
+        start, stop, stride = myslice.indices(self.shape[1])
+        return _cs_matrix._get_slice(self, i, start, stop, stride, (1, stop-start))
+
+    def __setitem__(self, key, val):
+        if isinstance(key, tuple):
+            row = key[0]
+            col = key[1]
+            if not (isscalarlike(row) and isscalarlike(col)):
+                raise NotImplementedError("Fancy indexing in assignment not "
+                                          "supported for csr matrices.")
+            M, N = self.shape
+            if (row < 0):
+                row = M + row
+            if (col < 0):
+                col = N + col
+            if (row < 0) or (col < 0):
+                raise IndexError, "index out of bounds"
+            if (row >= M):
+                self.indptr = resize1d(self.indptr, row+2)
+                self.indptr[M+1:] = self.indptr[M]
+                M = row+1
+            if (col >= N):
+                N = col+1
+            self.shape = (M, N)
+
+            indxs = numpy.where(col == self.indices[self.indptr[row]:self.indptr[row+1]])
+            if len(indxs[0]) == 0:
+                #value not present
+                self.data    = resize1d(self.data, self.nnz + 1)
+                self.indices = resize1d(self.indices, self.nnz + 1)
+
+                newindex = self.indptr[row]
+                self.data[newindex+1:]   = self.data[newindex:-1]
+                self.indices[newindex+1:] = self.indices[newindex:-1]
+
+                self.data[newindex]   = val
+                self.indices[newindex] = col
+                self.indptr[row+1:] += 1
+
+            elif len(indxs[0]) == 1:
+                #value already present
+                self.data[self.indptr[row]:self.indptr[row+1]][indxs[0]] = val
+            else:
+                raise IndexError, "row index occurs more than once"
+
+            self.check_format(full_check=False)
+        else:
+            # We should allow slices here!
+            raise IndexError, "invalid index"
+
+    def rowcol(self, ind):
+        col = self.indices[ind]
+        row = searchsorted(self.indptr, ind+1)-1
+        return (row, col)
+
+
+    def tolil(self):
+        from lil import lil_matrix
+        lil = lil_matrix(self.shape,dtype=self.dtype)
+     
+        csr = self.sorted_indices() #lil_matrix needs sorted rows
+        
+        rows,data = lil.rows,lil.data
+        ptr,ind,dat = csr.indptr,csr.indices,csr.data
+
+        for n in xrange(self.shape[0]):
+            start = ptr[n]
+            end   = ptr[n+1]
+            rows[n] = ind[start:end].tolist()
+            data[n] = dat[start:end].tolist()
+
+        return lil
+
+    def tocsr(self, copy=False):
+        return self.toself(copy)
+
+    def tocsc(self):
+        indptr  = empty(self.shape[1] + 1, dtype=intc)
+        indices = empty(self.nnz, dtype=intc)
+        data    = empty(self.nnz, dtype=upcast(self.dtype))
+
+        csrtocsc(self.shape[0], self.shape[1], \
+                 self.indptr, self.indices, self.data, \
+                 indptr, indices, data)
+
+        from csc import csc_matrix
+        return csc_matrix((data, indices, indptr), self.shape)
+    
+    def toarray(self):
+        #TODO use a cheap tocoo() and make coo->todense()
+        data = numpy.zeros(self.shape, dtype=upcast(self.data.dtype))
+        csrtodense(self.shape[0], self.shape[1], self.indptr, self.indices,
+                   self.data, data)
+        return data
+    
+    def get_submatrix( self, slice0, slice1 ):
+        """Return a submatrix of this matrix (new matrix is created).
+        Contigous range of rows and columns can be selected using:
+        1. a slice object
+        2. a tuple (from, to)
+        3. a scalar for single row/column selection."""
+        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) )
+
+    # these functions are used by the parent class (_cs_matrix)
+    # to remove redudancy between csc_matrix and csr_matrix
+    def _swap(self,x):
+        """swap the members of x if this is a column-oriented matrix
+        """
+        return (x[0],x[1])
+
+    def _toother(self):
+        return self.tocsc()
+
+    def _tothis(self, other):
+        return other.tocsr()
+
+
+from sputils import _isinstance
+
+def isspmatrix_csr(x):
+    return _isinstance(x, csr_matrix)
+

Modified: trunk/scipy/sparse/lil.py
===================================================================
--- trunk/scipy/sparse/lil.py	2007-12-14 11:00:19 UTC (rev 3650)
+++ trunk/scipy/sparse/lil.py	2007-12-14 18:30:20 UTC (rev 3651)
@@ -25,9 +25,7 @@
         """ Create a new list-of-lists sparse matrix.  An optional
         argument A is accepted, which initializes the lil_matrix with it.
         This can be a tuple of dimensions (M, N) or a dense array /
-        matrix to copy, or a sparse matrix of the following types:
-          - csr_matrix
-          - lil_matrix
+        matrix to copy, or a sparse matrix.
         """
         spmatrix.__init__(self)
         self.dtype = getdtype(dtype, A, default=float)
@@ -65,7 +63,7 @@
                     except TypeError:
                         raise TypeError, "unsupported matrix type"
                     else:
-                        from compressed import csr_matrix
+                        from csr import csr_matrix
                         A = csr_matrix(A).tolil()
                 
                 #A is a lil matrix
@@ -409,7 +407,7 @@
             data.extend(x)
         data = asarray(data,dtype=self.dtype)
 
-        from compressed import csr_matrix
+        from csr import csr_matrix
         return csr_matrix((data, indices, indptr), dims=self.shape)
 
     def tocsc(self):

Modified: trunk/scipy/sparse/spfuncs.py
===================================================================
--- trunk/scipy/sparse/spfuncs.py	2007-12-14 11:00:19 UTC (rev 3650)
+++ trunk/scipy/sparse/spfuncs.py	2007-12-14 18:30:20 UTC (rev 3651)
@@ -4,7 +4,8 @@
 from numpy import empty
 
 from base import isspmatrix
-from compressed import isspmatrix_csr, isspmatrix_csc
+from csr import isspmatrix_csr
+from csc import isspmatrix_csc
 from sputils import upcast
 
 import sparsetools




More information about the Scipy-svn mailing list