A sparse matrix is a matrix most of whose entries are 0's. Idea for storing a sparse matrix: store only the non-zero entries in a dictionary. Any entry not in the dictionary is assumed to be 0.
For example, consider the matrix
$$\begin{bmatrix} 0 & 1& 0& 1& 0\\ 0 & 0& 0& 0& 5\\ 2 & 0& 0& 0& 0 \end{bmatrix}$$We can store it by only storing the non-zero entries. The keys will be tuples containing the coordinates of the entires, and the values will be the actual entries:
M = {(0, 3): 1, (0, 1): 1, (1, 4):5, (2, 0): 2 }
We'll store the dimensions of the matrix in the tuple Mdim:
Mdim = (3, 5)
Suppose now that we want to multiply our sparse matrix by a vector:
$$\begin{pmatrix} 0 & 1& 0& 1& 0\\ 0 & 0& 0& 0& 5\\ 2 & 0& 0& 0& 0 \end{pmatrix} \begin{pmatrix}1\\2\\3\\4\\5\\ \end{pmatrix} = \begin{pmatrix}1\times2 + 1\times 4\\ 5\times 5 \\ 2\times 1\end{pmatrix}$$We see that, for example, the $1$ at coordinates $(0, 3)$ gets multiplied by the 3-rd entry in the vector that we are multiplying by, and then the product is added into the sum in the 0-th row of the result. We can generalize this to write the function that multiplies a sparse matrix by a vector:
def mult_mat_vec(M, Mdim, v):
'''Return the product Mv, where M is a sparse matrix
with dimensions Mdim[0] by Mdim[1], and v is a list of
length Mdim[1]'''
res = [0]*Mdim[0]
for coords, entry in M.items():
res[coords[0]] += entry*v[coords[1]]
return res
mult_mat_vec(M, Mdim, [1, 2, 3, 4, 5])