Skip to content

Toeplitz matrices

A matrix that is constant along every diagonal is fixed by its first row and first column, 2n − 1 numbers for n × n, and filtering a signal is multiplying by one.

Helps to know first
This topic

First, the picture

Seven numbers, one per diagonal, are enough for a 4 × 4 matrix. Watch each entry read from its diagonal’s number, then a filter built the same way.

A whole matrix from one row and column

Seven numbers fill a 4 × 4 matrix; a filter fills another

static const int t[2 * N - 1] = { 7, 6, 5, 1, 2, 3, 4 };static const int h[TAPS] = { 1, 2, 1 }; int get(int i, int j){    return t[N - 1 + j - i];} int conv_entry(int i, int j){    int k = i - j;    return (k >= 0 && k < TAPS) ? h[k] : 0;} int main(void){    for (int i = 0; i < N; i++) {        for (int j = 0; j < N; j++)            printf("%d ", get(i, j));        printf("\n");    }    const int x[N] = { 1, 2, 3, 4 };    printf("Mx =");    for (int i = 0; i < N; i++) {        int s = 0;        for (int j = 0; j < N; j++)            s += get(i, j) * x[j];        printf(" %d", s);    }    const int u[LEN] = { 1, 2, 3, 4, 5 };    printf("\nfiltered =");    for (int i = 0; i < LEN + TAPS - 1; i++) {        int s = 0;        for (int j = 0; j < LEN; j++)            s += conv_entry(i, j) * u[j];        printf(" %d", s);    }    printf("\n");    return 0;}

Print the 4 × 4 matrix, each entry read from t, seven numbers.

numbers stored
7 for 16 entries

Output

0.00 / 15.70 s
Describe this picture

The picture has two parts, side by side on a wide screen and one above the other on a phone. The first is a 4 × 4 grid, M, over a strip of 7 boxes, t, holding 7, 6, 5, 1, 2, 3, 4. The second is a 7 × 5 grid, F, over a strip of 3 boxes, h, holding the filter taps 1, 2, 1; in F, only the cells on three diagonals, from the top left downwards, are tied to a box of h, and the others are faint. Both grids start blank. Each grid cell takes the tint of its row, and the box it reads takes the same tint. Under each grid is a line of text with the current formula. Under the picture are the program toeplitz.c, with the line about to run marked, one sentence on the current step, a readout “numbers stored” reading “7 for 16 entries”, and the output. The clip plays once, about 16 seconds. First M’s top row fills cell by cell, each cell lit together with the box it reads: M(0, 0) is t[3] = 1, then t[4], t[5] and t[6], giving 1 2 3 4. Rows 1, 2 and 3 fill a beat each, each one box further left in t, so every diagonal of M holds a single number. Next the rows of Mx light one at a time, with x = 1, 2, 3, 4, giving 30, 25, 27 and 38. Last, F fills a row a beat: row i has the taps in the columns i − 2 to i, and its sum with u = 1, 2, 3, 4, 5 is output i, from filtered[0] = 1 to filtered[6] = 5. The clip rests on the output filtered = 1 4 8 12 16 14 5. Watch only: there is no control. The transport plays and pauses, steps one beat back or forward, and scrubs; a paused step is kept in the page address as toeplitz.step.

One number per diagonal

A Toeplitz matrix is constant along every diagonal: M(i, j) depends only on j − i. In an n × n matrix j − i runs from −(n − 1) to n − 1, so the whole matrix is fixed by 2n − 1 numbers: its first column and its first row, which share the corner. The program’s 4 × 4 example is

1 2 3 4
5 1 2 3
6 5 1 2
7 6 5 1

and its seven numbers are stored in one array, the first column read upwards and then the first row:

static const int t[2 * N - 1] = { 7, 6, 5, 1, 2, 3, 4 };

A Toeplitz matrix need not be symmetric. This one is not: M(1, 0) = 5 but M(0, 1) = 2. It is symmetric only when the first row and the first column hold the same numbers.

The code and its cost

The index

Diagonal j − i is stored at t[n − 1 + j − i]. The offset n − 1 moves the lowest diagonal, j − i = −(n − 1), to cell 0:

int get(int i, int j)
{
    return t[N - 1 + j - i];
}

M(0, 0) is t[3] = 1, M(3, 0) is t[0] = 7, and M(0, 3) is t[6] = 4. The program prints all 16 entries through get; each row is the row above shifted one place right, with a new number coming in on the left.

The product

Mx needs every entry once, so it takes n² multiplications, as a full matrix does; the entries just come from 7 numbers instead of 16:

for (int i = 0; i < N; i++) {
    int s = 0;
    for (int j = 0; j < N; j++)
        s += get(i, j) * x[j];
    printf(" %d", s);
}

With x = (1, 2, 3, 4) the program prints Mx = 30 25 27 38. The saving is the memory: 2n − 1 numbers instead of n².

Convolution as a matrix

Convolution with a short filter is a Toeplitz matrix. Filter u = (1, 2, 3, 4, 5) with the taps h = (1, 2, 1): output i is the sum of h[k] × u[i − k]. Written as a matrix, entry (i, j) is h[i − j] when 0 ≤ i − j < 3, and 0 otherwise. It depends only on i − j, so the matrix is Toeplitz, and it is banded: only three diagonals are non-zero. A k-tap filter on L samples gives L + k − 1 outputs, so the matrix is (L + k − 1) × L, here 7 × 5:

int conv_entry(int i, int j)
{
    int k = i - j;
    return (k >= 0 && k < TAPS) ? h[k] : 0;
}

The program never stores the 35 entries; it works each one out from h when it needs it. Each column of the matrix holds the taps 1, 2, 1, one row lower than the column before. Multiplying by u gives

filtered = 1 4 8 12 16 14 5

which adds to 60, the input’s sum, 15, times the taps’ sum, 4.

The cost

A Toeplitz matrix takes 2n − 1 numbers instead of n². Reading an entry is one subtraction and one array read. The product with a vector still takes n² multiplications when done this way.

Running it yourself

gcc -std=c11 -Wall -Wextra -pedantic toeplitz.c -o toeplitz
./toeplitz

Worked example

Row 2 of Mx. Row 2 of M is 6 5 1 2, so its entry of Mx is 6 × 1 + 5 × 2 + 1 × 3 + 2 × 4 = 6 + 10 + 3 + 8 = 27.

One filtered sample. Row 3 of the filter matrix has the taps in columns 1, 2 and 3: filtered[3] = 1 × 2 + 2 × 3 + 1 × 4 = 12.

A large matrix. For n = 1,000 the store holds 2 × 1,000 − 1 = 1,999 numbers against 1,000,000 entries.

Two checks. Which cell of t holds M(3, 1)? (3 + 1 − 3 = 1, the value 6.) How large is the matrix for a 4-tap filter on 10 samples? (13 × 10.)

Where it’s used

Digital filters. A filter applied to a block of samples is a banded Toeplitz matrix times the block; writing it that way lets a filter be analysed with the tools of linear algebra.

Speech coding. Linear prediction solves a system whose matrix, the autocorrelation matrix, is symmetric Toeplitz; fast solvers use the structure to work in about n² steps instead of n³.

Image blurring. Blurring an image with a small kernel is a block Toeplitz matrix: Toeplitz blocks arranged in a Toeplitz pattern.

Time series. Models of a series that depend only on the lag between samples give Toeplitz covariance matrices.

Reference card

Code or ideaMeaning
M(i, j) depends only on j − ia Toeplitz matrix
2n − 1numbers for an n × n Toeplitz matrix
t[N - 1 + j - i]where M(i, j) is stored
h[i − j], 0 ≤ i − j < kentry (i, j) of a k-tap filter’s matrix
(L + k − 1) × Lsize of the filter matrix for L samples

Next, sparse matrices store only the entries that are not zero, wherever they are. Multiplying polynomials is the same convolution.

Platform: C11, gcc on x86-64 Linux: int 4 bytes, pointers 8, little-endian. Addresses in the pictures are short stand-ins, by one rule for the whole course; sizes are the real ones.

End of the lesson

Where to go next.

New lessons by email

Are you 13 or over?

Accounts and email updates are for people aged 13 or over. We keep only your answer, never your date of birth.

Phasorium

Account

Sign inWith Google, GitHub or your email

Subjects

Site

Look