5.4.13 · D1Scientific Computing (Python)

Foundations — scipy.sparse — sparse matrix formats (CSR, CSC), sparse solvers

2,320 words11 min readBack to topic

Before we can talk about CSR, CSC, indptr, or spsolve, we need to earn every symbol the parent note throws at you. Three names to hold loosely for now (each fully unpacked in later Deep Dives):

  • CSR = Compressed Sparse Row — a layout that stores the non-zeros row by row.
  • CSC = Compressed Sparse Column — the same idea but column by column.
  • spsolve = SciPy's ==sparse solve== function: hand it a sparse matrix and a vector , and it returns the with .

This page assumes you have seen nothing else. We build each idea, anchor it to a picture, and only then use its notation.


0. What is a matrix, really?

Picture a spreadsheet. Every cell has an address: which row, which column. The number in row , column is written (read "A-sub-i-j"). By near-universal convention in programming, counting starts at 0, not 1 — so the top-left cell is .

Figure — scipy.sparse — sparse matrix formats (CSR, CSC), sparse solvers
  • = the row index — how far down (the red arrow points down the rows).
  • = the column index — how far across (the blue arrow points across the columns).
  • The pair is the cell's coordinate, its full address.

Why the topic needs this: every sparse format is nothing but a clever way to remember, for each stored number, its coordinate . If you are shaky on "row index vs column index," none of CSR (Compressed Sparse Row) will land.


1. The shape symbols: , , and

Picture: the grid is tall and wide. In the parent note you meet things like a matrix — that just means one million rows and one million columns, a square grid.

Recall Why do the solvers assume square?

Solving ::: means "find the input that the grid turns into the output ." That only makes sense when there are as many equations (rows) as unknowns (columns) — i.e. , a square matrix.


2. "Mostly zeros": nnz, density , and

Why ? A square grid has rows each with cells, so cells total. That is the count we are trying not to pay for.

Figure — scipy.sparse — sparse matrix formats (CSR, CSC), sparse solvers

Every case, so you never get surprised:

  • : the grid is all zeros — store nothing.
  • small (say ): the sweet spot — sparse wins hugely.
  • : the break-even zone — sparse and dense cost about the same.
  • : nearly full — sparse is worse (it pays extra to store coordinates for numbers that were going to be there anyway). This is exactly the "sparse isn't always smaller" mistake in the parent.

Why the topic needs this: is the single number that decides whether you should use scipy.sparse at all.


3. Big-O: the language of "how much does it cost?"

Picture two curves as increases: a straight line () and a fast-bending parabola (). For a million rows the parabola is a million times taller than the line — that gap is the entire reason we bother with sparsity.

Figure — scipy.sparse — sparse matrix formats (CSR, CSC), sparse solvers
  • Dense storage / dense work: — one cost per cell.
  • Sparse storage / sparse work: — one cost per stored number only.

Why the topic needs this: every claim in the parent ("memory less," "SpMV is ") is a Big-O comparison. Without this symbol you cannot read those claims.


4. Arrays and indexing: data[k], slices a:b

Picture a row of numbered mailboxes; a slice is grabbing a contiguous run of them, stopping one short of the last label.

Why the topic needs this: CSR's headline trick is "row 's non-zeros are data[indptr[i]:indptr[i+1]]." That is pure slice notation. If a:b is fuzzy, that line is unreadable.


5. Cumulative sum (the heart of indptr)

Example the parent uses: counts of non-zeros per row are . Running total, starting at : Result: .

Figure — scipy.sparse — sparse matrix formats (CSR, CSC), sparse solvers

Picture bookmarks in a book: bookmark marks the page where chapter starts. The distance between two neighbouring bookmarks tells you how long that chapter is. Here "chapters" are rows and "pages" are stored non-zeros — this list of bookmarks is exactly indptr, and its last value is the grand total .

Recall Why is

indptr length and not ? You need one bookmark before each of the rows ::: plus one final bookmark marking the end of the last row, so bookmarks in total. The last one always equals .

Why the topic needs this: indptr is a cumulative sum, and understanding it as "row-start bookmarks" is the whole reason CSR gets row access.


6. Summation and the mat–vec product

Picture row of the grid sliding down over the column , pairing up cell-by-cell, multiplying, and summing into one number .

Why the topic needs this: "" is the operation sparse matrices are optimised for, and the parent's SpMV (sparse matrix–vector product) formula is exactly this sum restricted to the stored non-zeros of each row. Iterative solvers like Conjugate Gradient method do nothing but repeated products.


7. The solve and its two toolkits

Two families do this, and the parent uses both — here is the plain-words picture of each:

  • Direct solvers (e.g. LU decomposition, Cholesky decomposition): factor into simpler triangular pieces, then unwind. Exact, but factoring can create new non-zeros ("fill-in").
  • Iterative solvers (e.g. Conjugate Gradient method, part of the broader Krylov subspace methods): start from a guess and improve it step by step using only products, often sped up with Preconditioning. Low memory, no fill-in.

You do not need to master these yet — later Deep Dives do. Here you only need to know the symbols: , , , and that "solve" means "invert the arrow." The parent's spsolve is one concrete direct solver of this kind.

Why the topic needs this: solving is the destination of the whole topic — sparse formats, SpMV, and Big-O all exist so this solve is affordable at a million rows. Every solver name in the parent (spsolve, cg, gmres) is just a different way of doing this one thing.


8. Contrast anchor: the dense matrix

Everything above earns its keep by comparison with a plain Dense matrices (NumPy ndarray), which stores all cells including every zero. Sparse formats exist to store only section 2's non-zeros with only the coordinates from section 0.


Prerequisite map

Matrix and cell address i j

Dimensions n and m

nnz and density rho

Big-O cost O n vs O n squared

Arrays and slice a to b

Cumulative sum equals indptr

Summation sigma

Mat vec product y equals A x

scipy.sparse CSR CSC and solvers

Solve A x equals b

Each foundation on the left feeds the sparse-matrix topic on the right: coordinates and dimensions let us name non-zeros, and Big-O tell us when sparsity wins, slices + cumulative sum are the CSR arrays, and the -based mat–vec is what we make fast.


Equipment checklist

Cover the right side and answer each before moving to D2.

  • What does mean, and what does vs point to? ::: The number in row , column ; = row (down), = column (across), both 0-based.
  • What do CSR and CSC stand for? ::: Compressed Sparse Row and Compressed Sparse Column.
  • What does spsolve do? ::: Takes a sparse matrix and vector and returns the solving .
  • What is counting for a square matrix? ::: The total number of cells: rows times columns.
  • Define and density . ::: nnz = count of non-zero cells; , the fraction that are non-zero.
  • What do and mean? ::: = "very much less than"; = "of roughly this size / order of magnitude."
  • When does sparse storage stop being worth it? ::: When approaches or higher; near sparse is bigger and slower than dense.
  • What does data[2:5] return? ::: Entries at positions 2, 3, 4 — the right end 5 is excluded.
  • Compute the cumulative sum of counts starting at 0. ::: .
  • Why is the cumulative-sum array length ? ::: One bookmark before each of the rows plus one final end-marker equal to nnz.
  • What does compute, and over what range? ::: Output entry of , summing over every column from 0 to .
  • What is SpMV? ::: Sparse matrix–vector product: computing touching only the non-zeros.
  • What does "solve " ask for? ::: The unknown input vector that the matrix turns into the known output .
  • What does vs describe? ::: How work grows with problem size — linearly vs quadratically, ignoring constants.