Here's the note:

Fourier Transform and Fast Multiplication

When to Reach for Fourier

Here we revise when Fourier is the right tool, before how it works. The thing you have to remember: the test is about the system, not the signal.

The LTI Trigger

Fourier diagonalises every operator that is linear and shift-invariant (LTI). Complex exponentials are its eigenfunctions.

  • Linear: .
  • Shift-invariant: commutes with the shift , i.e. .
  • Consequence: . A sine goes in and the same sine comes out, only scaled and phase-shifted.

Why: the eigenvectors of the shift are exponentials, and an operator that commutes with the shift shares its eigenvectors (see Simultaneous Diagonalisation). Any LTI operator is a Convolution, and in the Fourier basis convolution becomes pointwise multiplication.

Ask about the system, not the signal

A one-off event (a clap, a drum strike) can still be analysed with Fourier if the medium it passes through is LTI. "Independent" means the system treats each frequency separately, not that the input's components are unrelated.

Surface cues

Blurring, smoothing, echo, diffusion, "each output is a weighted average of its neighbours", periodic forcing, and any sum whose indices add up ().

Calibration Drill

CaseFourier?Why
Un-blurring a photoYesBlur = convolution → divide spectra; regularise where the kernel's spectrum ≈ 0 (Wiener Filter)
Singing in the showerYesLTI room; hard tiles boost resonant modes and add reverb
TidesYesPeriodic astronomical forcing + approximately linear ocean → sum of known-period constituents
Stock pricesNoNon-stationary, no stable periods
Big-integer multiplicationYesLong multiplication is a convolution of digits
Heat on a ringYesMode decays as ; sharp bumps die first
A single clapBad lens for the clap…but an excellent probe: impulse ≈ all frequencies → gives the room's response
JPEGYesDCT; high-frequency coefficients stored crudely
Guitar vs drumYes, bothString modes are integer multiples (pitch); drumhead modes are not (≈1, 1.59, 2.14…)
Counting a crowdNoLocalised objects are smeared over all frequencies (except regular grids)

Anti-Triggers

  • Localised in time or space (transients, edges) → Short-Time Fourier Transform, Wavelets. Uncertainty principle: narrow in time means broad in frequency.
  • Nonlinear systems create new frequencies (harmonics), so no clean per-frequency description exists.
  • Non-stationary rules (the system changes over time) break shift-invariance.

Convolution in Disguise

Multiplication Is Convolution

Write digits units-first, so position = power of 10: . The core fact is that exponents add when you multiply.

Example: , so and :

(5) (4)
(3)15 → 12 →
(2)10 → 8 →
(1)5 → 4 →

Summing the anti-diagonals gives . Carrying then gives .

Schoolbook multiplication without carrying shows exactly the convolution:


          1    2    3
      ×        4    5
          5   10   15
     4    8   12
     4   13   22   15   ← c3 c2 c1 c0
  • Carrying is separate: it uses floor and mod, so it is nonlinear. Do it once, after the convolution.
  • Shifted copies: . This is a weighted sum of shifted copies of , structurally identical to a blur kernel.

The Flip and the ML Convolution

Sliding a kernel over "adjacent cells" (a CNN layer) is this operation. Adjacent cells = adjacent digit positions.

position:   0  3  2  1  0       (123 units-first, zero-padded)
k=0:       [4  5]           → 15
k=1:          [4  5]        → 22
k=2:             [4  5]     → 13
k=3:                [4  5]  → 4
Math convolutionML "convolution"
Formula
KernelFlippedNot flipped (cross-correlation)
Why it doesn't matter—Kernel is learned, so the network learns the flip
Origin of the flip

: a step forward in one sequence is a step backward in the other. Reading order is irrelevant; only the relative flip matters.

Circular Convolution and Padding

The DFT indexes modulo , so it computes circular convolution: high positions wrap onto low ones. With , wraps into , giving ✗.

Pad to .

Same phenomenon as zero-padding vs circular padding in CNNs.

Other Disguised Convolutions

  • Polynomial multiplication (coefficients).
  • PMF of a sum of independent random variables → Characteristic Function.
  • Moving averages, discretised diffusion.
  • Wildcard string matching via FFT.

From Convolution to Pointwise Product

Evaluate → Multiply → Interpolate

Replace 10 by : , , and for every .

  • : , , .
  • : , , .

At a single point, the whole convolution collapses to one scalar multiplication.

How many points: . Two distinct polynomials of degree agreeing on points would have a nonzero difference of degree with roots, which is impossible.

Worked interpolation with points , -values :

Logarithm tablesFourier
TransformEvaluate at points
Easy operationAddMultiply pointwise,
InverseInterpolate
The general move

Switch to a representation where the hard operation becomes easy, provided switching is cheap. With arbitrary points, evaluation and interpolation cost , so nothing is gained.

Evaluating at small points is itself a real algorithm family. Karatsuba Algorithm: split into halves (degree-1 polynomials), evaluate at , so 3 products instead of 4, giving . Toom–3: points . The FFT is the limit of this idea, with points chosen so the transform itself is fast.

The FFT

Even/Odd Split

For : and . The is factored out of the odd terms, so is constant here.

Butterfly (from one pair of child values, get two parent values):

Going up = evaluating the nested expression from the inside out: . The brackets depend only on , so they are shared by .

Why Roots of Unity

The regrouping holds for any . Roots are needed so that the set of points halves at every level.

Point set ()Distinct points per levelSaving
Random8 → 8 → 8None
8 → 4 → 4 → 4One level only (squares are positive)
8th roots of unity8 → 4 → 2 → 1Every level
Halving lemma

Squaring doubles the angle, so the equally spaced points fold onto equally spaced points, which again form pairs: .

Levels and Twiddle Factors

Points are fixed by the level, not chosen by hand (, ):

LevelSub-polynomial sizePoints
01
12
24
38every
  • At each level, the values are the points in the upper half of the circle, , and is the antipode.
  • The butterfly at needs child values at , which were computed one level below.
  • The multiplier is the twiddle factor.

Worked Example,

at :

Complexity

For : 3 levels × 4 butterflies = 12.

Inverse FFT

Evaluation at the roots is the Vandermonde Matrix . Orthogonality of sampled waves:

So interpolation is the same FFT with , divided by . With arbitrary points, inverting is expensive and ill-conditioned.

Where the Fourier Part Is

Evaluation at Roots = DFT

The powers of are a sampled wave with cycles. So = (sequence · probe wave), i.e. how much of frequency is in the sequence.

  • : frequency 0 (DC, the mean).
  • : the highest frequency (Nyquist).

Standard DFT convention uses : same thing, traversing the circle the other way.

Algebra viewSignal view
at every pointConvolution theorem:
Evaluate at the roots of unityMeasure each frequency
Even/odd split + halving lemmaCooley and Tukey's FFT (1965), anticipated by Gauss

Eigenvector View

Convolution with is a Circulant Matrix , and the DFT diagonalises it:

The algebra explains why it's fast; the eigenvector view explains why it works for any LTI system.

Big-Integer Multiplication: Full Algorithm

Pipeline

  1. Digits units-first; pad to a power of 2 with .
  2. FFT both, multiply pointwise, inverse FFT.
  3. Round to nearest integer (removes floating-point noise).
  4. Carry, .
import cmath

def fft(a, inv=False):
    n = len(a)
    if n == 1:
        return a
    E, O = fft(a[0::2], inv), fft(a[1::2], inv)   # even / odd split
    s = -1 if inv else 1
    out = [0] * n
    for k in range(n // 2):
        w = cmath.exp(s * 2j * cmath.pi * k / n)   # twiddle factor
        out[k] = E[k] + w * O[k]                   # A(x)
        out[k + n // 2] = E[k] - w * O[k]          # A(-x)
    return out

def multiply(x, y):
    a = [int(d) for d in str(x)[::-1]]             # units first
    b = [int(d) for d in str(y)[::-1]]
    n = 1
    while n < len(a) + len(b) - 1:                 # avoid wrap-around
        n *= 2
    A = fft(a + [0] * (n - len(a)))
    B = fft(b + [0] * (n - len(b)))
    c = fft([p * q for p, q in zip(A, B)], inv=True)
    c = [round((v / n).real) for v in c]           # 1/N, kill float noise
    return sum(ck * 10**k for k, ck in enumerate(c))   # carry

assert multiply(123, 45) == 5535

State of the Art

  • Number-Theoretic Transform: replace with (roots of unity exist mod suitable primes), so the arithmetic is exact.
  • Schönhage and Strassen's algorithm (1971): rings , where 2 is a root of unity. .
  • Harvey and van der Hoeven's algorithm (2019): , conjectured optimal.
  • GMP: schoolbook → Karatsuba → Toom–Cook → FFT as the size grows.

Drawbacks

  • Constant factors: the FFT wins only for large .
  • Floating-point precision: rounding fails at large or large digit bases → NTT.
  • Wrap-around if padding is forgotten.

CNN Layers Through the Fourier Lens

Conv Layer as Per-Frequency Matrices

Without the activation, a conv layer is LTI. In the Fourier domain:

So a conv layer is one matrix per frequency, with no mixing across frequencies.

  • Fast conv via FFT for large kernels; 3×3 kernels use Winograd instead.
  • Small kernels give blunt filters: compact support forces smooth frequency responses (uncertainty principle). Depth multiplies responses, which sharpens them.
  • Exact singular values = singular values of the per-frequency matrices → Lipschitz control (Sedghi et al., ICLR 2019).
  • Fourier Neural Operator (Anandkumar's group, ICLR 2021): learn the per-frequency weights directly; keep low modes.

Where the Picture Breaks

ComponentBreaksEffect
ReLULinearityCreates new frequencies; can't Fourier the whole net
StrideShift-invarianceDownsampling → Aliasing; fixed by blur-before-subsample (Richard Zhang, ICML 2019)
Zero paddingCircularityBoundary effects; FFT assumes wrap-around

Connections

Adjacent and Distant Ideas

  • Logarithms: the original transform → cheap operation → inverse trick.
  • Probability: characteristic functions turn sums of independent RVs into products.
  • Heat equation: Fourier's original problem; each mode decays independently at a rate .
  • Graph Fourier Transform: on a graph, Laplacian eigenvectors replace sines; this is the basis of spectral GNNs.
  • Consensus dynamics: averaging on a ring or lattice is LTI, so disagreement decomposes into modes; long-wavelength disagreement decays slowest. This is relevant when thinking about how norms spread over a lattice of agents (norm-emergence).

Checklist

  • State the LTI test and why exponentials are eigenfunctions of shift-commuting operators.
  • Classify a new case as Fourier / not Fourier, asking about the system.
  • Derive from multiplying powers of 10.
  • Explain the kernel flip and why ML layers skip it.
  • Padding rule and what goes wrong without it.
  • Evaluate → multiply → interpolate; why points suffice.
  • Even/odd split, the butterfly, and why real pairs fail at level 2.
  • Which points each level uses, and the twiddle factor.
  • Count: butterflies.
  • Inverse FFT via .
  • Interpret as frequency content; = DC, = Nyquist.
  • Conv layer = per-frequency channel-mixing matrices; where ReLU, stride and padding break it.
  • Why the FFT needs NTT at scale; Schönhage–Strassen vs Harvey–van der Hoeven.

I ran the Python and it matches Python's built-in multiplication on random 60-digit numbers. The note also includes the inverse FFT and the A(1) answer, which we hadn't reached in the walkthrough.

Fourier's heat problem — Step 1: Heat on a ring of cells

Fourier studied how temperature evolves in a solid, including a metal ring. Start with a ring cut into cells. At each time step, every cell moves a little toward the average of its two neighbours:

u_j ← u_j + α·(u_{j−1} − 2u_j + u_{j+1})

A cell hotter than its neighbours cools down, and a colder one warms up. Written as a kernel, the update is a sliding window with weights [α, 1−2α, α]: the same kernel applied at every cell, wrapping around the ring.

Example: 4 cells, α = 0.25, starting at [4, 0, 0, 0], so all the heat is in one spot.

  • u₀ = 4 + 0.25·(0 − 8 + 0) = 2
  • u₁ = 0 + 0.25·(4 − 0 + 0) = 1
  • u₂ = 0 + 0.25·(0 − 0 + 0) = 0
  • u₃ = 0 + 0.25·(0 − 0 + 4) = 1

After one step the heat is [2, 1, 0, 1]: the peak has spread to its neighbours, and the total is still 4.

Check (two parts):

  1. Is this update linear and shift-invariant? What does that tell you, given everything above?
  2. Compute the next step from [2, 1, 0, 1].

Old Note

The algorithm has been the same, some ideas are in Fourier Series, but architectures change, which means there are new ways to make this algorithm even faster.

Example of transforms

We have learned in Algebra lineare numerica, Cambio di Base that linear transforms are usually a change of basis. They are matrix vector multiplications (additions and multiplications by constants). The optimizations are based on what sorts of transforms we have (e.g. Sparse Matrix Vector Multiplication, or dense versions). The same idea applies also for Fourier transforms.

Discrete Fourier Transforms

Primitive roots

It uses primitive roots of as coefficients. Discrete Fourier transform computes:

Where is the primitive root of .

The matrix is a square matrix of size and the entries are given by:

Example of DFT matrices

At each index we will have the th unit of root. For example if we know that the root is , then the matrix would be:

This has two adds (one add and sub), it would be quite inefficient to write the multiplication part. This is usually called butterflies in signal processing, due to the nature of the circuit.

for , the primitive root is we have:

If we assume complex everything, it has 12 additions and 4 multiplications. This matrix can be factorized, then we can add it as a series of matrix vector products.

Decomposing into sparse MVM

If , we can write:

This makes sense if are sparse (see Sparse Matrix Vector Multiplication, and not too many steps).

Fast Fourier Transforms-20250407104034779 You can use Group Theory to find this kind of transformations.

The above representation can be rewritten using matrix algebra:

You can see that it is also quite easy to implement it in hardware.

It can be similar for size and radix .

Fast Fourier Transforms-20250407104645928

Other transforms

IMDCT and DCT are useful transforms for MPEG and JPEG format, while DFT and its inverse can be considered universal transformation tools.

FFT transformations

General Radix Recursive Cooley-Tukey FFT

This is the most general version of DFT, it has a similar structure compared to the previous ones.

The diagonal matrix has the roots of unity. This is called the decimation in time frequency. It is possible also to use the decimation in frequency, which is just the transpose. We can decompose everything until we have size two butterfly operations (bunch of adds).

Cost of DFT

Independently of recursion (the radix), we have a number of

  • additions and multiplications, but to be real we would need to consider real additions, so we have to multiply everything by two, to get the adds. For multiplication, we have four multiplication and two additions (image it as a matrix) (in reality you use the structure of roots of unity, so in reality you have less adds). Usually best is around radix 8
  • You will have about real additions and complex multiplications, so upper bound of 5 operations. For a long time radix 2 iterative version was the best version, after superscalar processors like Skylake Microprocessor it has better versions. Fast Fourier Transforms-20250407113518669 There is a practical lower bound analysis, but that is like Strassen Fast Linear Algebra, which is not much useful.

Recursive vs iterative FFT

The recursive version is good for re-use, has better locality. Triple loop is like the blocked MMM in Fast Linear Algebra. If we have big stages computed, we can continue with the next stage immediately.

Iterative similar, the op count is the same, is slower because of the (log n passes through the data). The code change is quite difficult. If we have much data, then at each iteration we need to load the whole data which could be expensive.

Decimation in Time and Frequency

TODO

Other FFTs

Pease FFT

Highly parallelized with maps and shuffles.

Fast Fourier Transforms-20250407113023076

Stockham FFT

It is good for vector computers of the 80s, where we have long vectors Fast Fourier Transforms-20250407113041765

Six-Step FFT

Fast Fourier Transforms-20250407113054802

Multi-core FFT

Good for Sharing memory. Fast Fourier Transforms-20250407113116841

Fastest Fourier Transform of the West

Also known as FFTW, we say.

Ideas for FFTW

Merging Steps

  1. In the original version, the original permutation could be very expensive, to load everything. There is no need to keep it as a sperate step, we can fuse it in the next step.
    1. This fusion would need more data, because it needs to write to another place (no-inplace computation!).
  2. The scaling can also be fused, with the previous or next step (just change the kernel). Fast Fourier Transforms-20250414103632830

Strides will change as we recurse for the DFTrec, and we can also interchange input and output to save space. Because of the power of two strides, often it is very difficult to reach peak performance.

Constants

We precompute the constants of the sins and cosines to save time (just need what roots of unity you need in order to compute it). They just depend on the input size, so they precompute it at the beginning of the function.

Block un-rolling

We un-roll the basic blocks at the end to get longer codes, less recursion (size 32 is good basecase for example).

Program Generator

We have DAG generator (for many types of FFT), a simplifier for the DAG (specific for the FFT computation).

  • An example of a simplification is when you have and , an optimization would be flipping one after you have computed one.
  • Also constants come in pairs (minus and positive version).
    • Reduces register pressure.