Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sparse 3d matrix/array in Python?

In scipy, we can construct a sparse matrix using scipy.sparse.lil_matrix() etc. But the matrix is in 2d.

I am wondering if there is an existing data structure for sparse 3d matrix / array (tensor) in Python?

p.s. I have lots of sparse data in 3d and need a tensor to store / perform multiplication. Any suggestions to implement such a tensor if there's no existing data structure?

like image 738
zhongqi Avatar asked Oct 07 '11 09:10

zhongqi


1 Answers

Happy to suggest a (possibly obvious) implementation of this, which could be made in pure Python or C/Cython if you've got time and space for new dependencies, and need it to be faster.

A sparse matrix in N dimensions can assume most elements are empty, so we use a dictionary keyed on tuples:

class NDSparseMatrix:   def __init__(self):     self.elements = {}    def addValue(self, tuple, value):     self.elements[tuple] = value    def readValue(self, tuple):     try:       value = self.elements[tuple]     except KeyError:       # could also be 0.0 if using floats...       value = 0     return value 

and you would use it like so:

sparse = NDSparseMatrix() sparse.addValue((1,2,3), 15.7) should_be_zero = sparse.readValue((1,5,13)) 

You could make this implementation more robust by verifying that the input is in fact a tuple, and that it contains only integers, but that will just slow things down so I wouldn't worry unless you're releasing your code to the world later.

EDIT - a Cython implementation of the matrix multiplication problem, assuming other tensor is an N Dimensional NumPy array (numpy.ndarray) might look like this:

#cython: boundscheck=False #cython: wraparound=False  cimport numpy as np  def sparse_mult(object sparse, np.ndarray[double, ndim=3] u):   cdef unsigned int i, j, k    out = np.ndarray(shape=(u.shape[0],u.shape[1],u.shape[2]), dtype=double)    for i in xrange(1,u.shape[0]-1):     for j in xrange(1, u.shape[1]-1):       for k in xrange(1, u.shape[2]-1):         # note, here you must define your own rank-3 multiplication rule, which         # is, in general, nontrivial, especially if LxMxN tensor...          # loop over a dummy variable (or two) and perform some summation:         out[i,j,k] = u[i,j,k] * sparse((i,j,k))    return out 

Although you will always need to hand roll this for the problem at hand, because (as mentioned in code comment) you'll need to define which indices you're summing over, and be careful about the array lengths or things won't work!

EDIT 2 - if the other matrix is also sparse, then you don't need to do the three way looping:

def sparse_mult(sparse, other_sparse):    out = NDSparseMatrix()    for key, value in sparse.elements.items():     i, j, k = key     # note, here you must define your own rank-3 multiplication rule, which     # is, in general, nontrivial, especially if LxMxN tensor...      # loop over a dummy variable (or two) and perform some summation      # (example indices shown):     out.addValue(key) = out.readValue(key) +        other_sparse.readValue((i,j,k+1)) * sparse((i-3,j,k))    return out 

My suggestion for a C implementation would be to use a simple struct to hold the indices and the values:

typedef struct {   int index[3];   float value; } entry_t; 

you'll then need some functions to allocate and maintain a dynamic array of such structs, and search them as fast as you need; but you should test the Python implementation in place for performance before worrying about that stuff.

like image 105
tehwalrus Avatar answered Oct 04 '22 03:10

tehwalrus