Search code examples
pythonviewscipysparse-matrix

How to create view/python reference on scipy sparse matrix?


I am working on an algorithm that uses diagonal and first off-diagonal blocks of a large (will be e06 x e06) block diagonal sparse matrix.

Right now I create a dict that stores the blocks in such a way that I can access the blocks in a matrix like fashion. For example B[0,0](5x5) gives the first block of matrix A(20x20), assuming 5x5 blocks and that matrix A is of type sparse.lil.

This works fine but takes horribly long too run. It is inefficient because it copies the data, as this reference revealed to my astonishment: GetItem Method

Is there a way to only store a view on a sparse matrix in a dict? I would like to change the content and still be able to use the same identifiers. It is fine if it takes a little longer as it should only be done once. The blocks will have many different dimensions and shapes.


Solution

  • As far as I know, all of the various sparse matricies in scipy.sparse return copies rather than a view of some sort. (Some of the others may be significantly faster at doing so than lil_matrix, though!)

    One way of doing what you want is to just work with slice objects. For example:

    import scipy.sparse
    
    class SparseBlocks(object):
        def __init__(self, data, chunksize=5):
            self.data = data
            self.chunksize = chunksize
        def _convert_slices(self, slices):
            newslices = []
            for axslice in slices:
                if isinstance(axslice, slice):
                    start, stop = axslice.start, axslice.stop
                    if axslice.start is not None:
                        start *= self.chunksize
                    if axslice.stop is not None:
                        stop *= self.chunksize
                    axslice = slice(start, stop, None)
                elif axslice is not None:
                    axslice = slice(axslice, axslice+self.chunksize)
                newslices.append(axslice)
            return tuple(newslices)
    
        def __getitem__(self, item):
            item = self._convert_slices(item)
            return self.data.__getitem__(item)
        def __setitem__(self, item, value):
            item = self._convert_slices(item)
            return self.data.__setitem__(item, value)
    
    data = scipy.sparse.lil_matrix((20,20))
    s = SparseBlocks(data)
    s[0,0] = 1
    print s.data
    

    Now, whenever we modify s[whatever] it will modify s.data of the appropriate chunk. In other words, s[0,0] will return or set s.data[:5, :5], and so on.