Sparse matrix multiplication
Keep each row by its non-zero terms only and do only the non-zero products; far fewer than n³ for sparse matrices.
In a sparse matrix most products A[i][k]·B[k][j] are zero and doing them is wasted work. If each row is kept by its
non-zero terms only:
- Time:
O(rows + the number of non-zero products) - Space:
O(non-zeros) - Horowitz–Sahni, chapter 2
Two 4×4 matrices with mostly zero cells; only 5 products are needed instead of 64.
def sparse_multiply(A, B):if len(A[0]) != len(B):return None# Row lists: for each row, only its non-zero (column, value) pairs.a_rows = [[(j, v) for j, v in enumerate(row) if v != 0] for row in A]b_rows = [[(j, v) for j, v in enumerate(row) if v != 0] for row in B]C = []products = 0for i in range(len(A)):acc = {}for k, a in a_rows[i]:for j, b in b_rows[k]:acc[j] = acc.get(j, 0) + a * bproducts = products + 1C.append(sorted((j, v) for j, v in acc.items() if v != 0))return products
Start
a_rows
The table is still empty.
b_rows
The table is still empty.
C
The table is still empty.
Local variables
Orange = changed in this step
A list
B list
Call stack
- sparse_multiply()line 1
Explanation
The idea
In a sparse matrix most products A[i][k]·B[k][j] are zero and doing them is wasted work. If each row is kept by its
non-zero terms only:
- for row
iofA, multiply each non-zeroA[i][k]by the non-zero terms of rowkofB, adding intoacc[j]; accis rowiof the result; zeros are dropped.
Cost
The number of products is exactly the number of non-zero pairs (A[i][k], B[k][j]), far fewer than n³ for sparse
matrices. Horowitz–Sahni do the same with triples and the transpose of B; the idea is the same.
What to watch in the trace
- The
a_rowsandb_rowstables list each row's non-zero terms, andCis the result in the same form.productscounts the products done.