Part III: Temporal Deep Learning
Chapter 13: State-Space and Continuous-Time Neural Models

From HiPPO to Structured State-Space Models (S4, S5)

"They asked me to remember the whole sequence, and I said fine, I will keep a small state and let it evolve. When you want me as a recurrence I answer one step at a time, cheap and tidy. When you want me as a convolution I hand you a single long kernel and we do it all at once. I am the same equation either way; I just change costume for the audience I am facing."

A State-Space Layer Remembering the Whole Sequence
Big Picture

A deep state-space model (SSM) takes the continuous linear state-space system you already met as the Kalman filter, $\mathbf{x}'(t) = \mathbf{A}\mathbf{x}(t) + \mathbf{B}u(t)$, $y(t) = \mathbf{C}\mathbf{x}(t)$, and turns it into a trainable neural sequence layer. The single structural fact that makes it powerful is a duality: once discretized, the layer is simultaneously a linear recurrence (compute it step by step, $O(L)$ time and $O(1)$ memory per step, perfect for streaming inference) and a long convolution with one fixed kernel (compute it all at once with an FFT, parallel across the whole sequence, perfect for training). That best-of-both-worlds framing answers the two great efficiency complaints of Part III at once: it removes the sequential bottleneck and vanishing gradients of the RNN (Section 9.4) and it removes the quadratic-in-length cost of attention (Section 12.4), scaling linearly in sequence length while reaching across tens of thousands of steps. The trick that made it actually work is not the layer but its initialization: the HiPPO theory chooses a structured matrix $\mathbf{A}$ so the state optimally compresses the entire history seen so far, and that one choice is what lifted long-range benchmarks from chance to near-perfect. This section derives the continuous system and both of its discrete views, explains why HiPPO structure is the whole game, walks through S4 (diagonal-plus-low-rank) and its simplified successor S5 (a MIMO diagonal recurrence trained by parallel scan), and closes by building a minimal diagonal SSM from scratch (verifying the recurrent and convolutional views give the same output) before solving a long-memory copy task with a library S4/S5 layer.

In Section 7.1 of Part II we wrote the linear state-space model by hand: a latent state evolving by fixed dynamics, a noisy linear readout, and the Kalman filter recursively updating our belief about the state. There the matrices $\mathbf{A}$, $\mathbf{B}$, $\mathbf{C}$ came from a physical or statistical model we specified in advance. This section keeps the same equation and changes who fills in the matrices: we learn them by gradient descent, stack many such layers, and obtain one of the most important sequence architectures of the 2020s. The temporal thread of this book promised that the Kalman state-space would return in learned form; this is where it returns. We use the unified notation of Appendix A: $u(t)$ the scalar input signal, $\mathbf{x}(t)$ the latent state vector of dimension $N$, $y(t)$ the scalar output, and a discrete sequence indexed $k = 0, 1, \dots, L-1$ after sampling.

Why does a linear recurrence deserve a whole chapter when Chapter 10 spent its energy on nonlinear gated cells? Because linearity is exactly what buys the two superpowers. A nonlinear recurrence $\mathbf{h}_t = f(\mathbf{h}_{t-1}, \mathbf{x}_t)$ must be computed one step at a time, and its repeated Jacobian product makes gradients vanish or explode over long horizons. A linear recurrence $\mathbf{x}_k = \bar{\mathbf{A}}\mathbf{x}_{k-1} + \bar{\mathbf{B}}u_k$ can be unrolled into a closed-form convolution and trained in parallel, and with the right structured $\bar{\mathbf{A}}$ its state can carry information across thousands of steps without decaying to noise. The nonlinearity that gives the model its expressive power is moved between layers (a pointwise activation and mixing applied to each layer's output), not inside the recurrence, so the recurrence itself stays linear and tractable. This separation, linear sequence mixing plus pointwise nonlinear channel mixing, is the architectural heart of the SSM family.

The competencies this section installs are four. First, to write the continuous SSM and its discretization, and to see the discretized layer as both a recurrence and a convolution. Second, to explain why HiPPO initialization, not the layer form, is what made deep SSMs work, and what "optimally compress history" means. Third, to describe S4 and S5 at the level of their structure (diagonal-plus-low-rank versus simplified diagonal MIMO) and their training and inference costs. Fourth, to implement a diagonal SSM from scratch in both views, verify they agree, and call a library layer on a long-memory task. These skills carry directly into Mamba and selective SSMs in Section 13.2, the linear-attention family in Section 13.3, and the continuous-time models of Section 13.4 and Section 13.5.

1. The Deep SSM Idea: A Continuous Linear System, Discretized Two Ways Intermediate

A single mechanical box casts two different shadows on a wall, one shaped like a chain of stepping stones and one shaped like a smooth flowing wave, showing the same state-space layer being both a step-by-step recurrence and a global convolution depending on how you look at it.
Figure 13.1.0: One linear-recurrence machine, two faces: it trains as a parallel convolution and runs as a constant-memory scan, the dual nature that powers the whole chapter.

Start from the continuous-time linear state-space model, the very system that Section 7.1 used to define the Kalman filter. A single-input single-output (SISO) layer maps a scalar input signal $u(t)$ to a scalar output $y(t)$ through an $N$-dimensional latent state $\mathbf{x}(t)$:

$$\mathbf{x}'(t) = \mathbf{A}\,\mathbf{x}(t) + \mathbf{B}\,u(t), \qquad y(t) = \mathbf{C}\,\mathbf{x}(t),$$

with state matrix $\mathbf{A} \in \mathbb{R}^{N \times N}$, input matrix $\mathbf{B} \in \mathbb{R}^{N \times 1}$, and output matrix $\mathbf{C} \in \mathbb{R}^{1 \times N}$. This is identical to the Kalman state equation of Part II with the process and measurement noise dropped: where the Kalman filter treated $\mathbf{A}$, $\mathbf{B}$, $\mathbf{C}$ as known and inferred the state, the deep SSM treats the state as deterministic and learns the matrices. Structured state-space models are the third generation of learned state updates: the Kalman filter (Section 7.3) gave us the optimal linear update, the RNN (Section 10.1) made the update nonlinear and data-driven, and the SSM makes the linear update efficient and parallelizable. The state $\mathbf{x}(t)$ is a continuously updated summary of the input history; the only question is how to compute it on the discretely sampled sequences computers actually hold.

Real signals arrive as samples $u_0, u_1, \dots$ taken at a step size $\Delta$ (the sampling interval). Discretizing the continuous system with step $\Delta$ replaces the differential equation by a difference equation. The standard zero-order-hold (ZOH) discretization, which assumes $u$ is held constant across each interval, gives the discrete matrices

$$\bar{\mathbf{A}} = \exp(\Delta \mathbf{A}), \qquad \bar{\mathbf{B}} = (\Delta \mathbf{A})^{-1}\big(\exp(\Delta \mathbf{A}) - \mathbf{I}\big)\,\Delta \mathbf{B}, \qquad \bar{\mathbf{C}} = \mathbf{C},$$

where $\exp(\cdot)$ is the matrix exponential. The continuous layer becomes a discrete linear recurrence, the recurrent view:

$$\mathbf{x}_k = \bar{\mathbf{A}}\,\mathbf{x}_{k-1} + \bar{\mathbf{B}}\,u_k, \qquad y_k = \bar{\mathbf{C}}\,\mathbf{x}_k.$$

This is a state-space recurrence with no nonlinearity inside the loop, the same skeleton as the RNN of Section 9.2 but linear. Computed step by step it costs $O(L)$ time for a length-$L$ sequence and stores only the current state $\mathbf{x}_k$ of size $N$, so streaming inference is $O(1)$ memory per step. That is the ideal inference mode.

Now comes the duality that defines the whole architecture. Because the recurrence is linear, we can unroll it in closed form. Start from $\mathbf{x}_{-1} = \mathbf{0}$ and expand: $\mathbf{x}_0 = \bar{\mathbf{B}}u_0$, $\mathbf{x}_1 = \bar{\mathbf{A}}\bar{\mathbf{B}}u_0 + \bar{\mathbf{B}}u_1$, $\mathbf{x}_2 = \bar{\mathbf{A}}^2\bar{\mathbf{B}}u_0 + \bar{\mathbf{A}}\bar{\mathbf{B}}u_1 + \bar{\mathbf{B}}u_2$, and in general $\mathbf{x}_k = \sum_{j=0}^{k} \bar{\mathbf{A}}^{\,k-j}\bar{\mathbf{B}}\,u_j$. Reading out $y_k = \bar{\mathbf{C}}\mathbf{x}_k$ collapses this to a discrete convolution, the convolutional view:

$$y_k = \sum_{j=0}^{k} \bar{\mathbf{C}}\bar{\mathbf{A}}^{\,k-j}\bar{\mathbf{B}}\;u_j = (\bar{\mathbf{K}} * u)_k, \qquad \bar{\mathbf{K}} = \big(\bar{\mathbf{C}}\bar{\mathbf{B}},\; \bar{\mathbf{C}}\bar{\mathbf{A}}\bar{\mathbf{B}},\; \bar{\mathbf{C}}\bar{\mathbf{A}}^2\bar{\mathbf{B}},\; \dots,\; \bar{\mathbf{C}}\bar{\mathbf{A}}^{L-1}\bar{\mathbf{B}}\big).$$

The whole output is a single one-dimensional convolution of the input with a fixed kernel $\bar{\mathbf{K}}$ of length $L$, the SSM convolution kernel, whose $i$-th entry is the scalar $\bar{\mathbf{C}}\bar{\mathbf{A}}^{i}\bar{\mathbf{B}}$. Convolution can be computed for all positions simultaneously by the FFT in $O(L \log L)$ time, fully parallel across the sequence, which is the ideal training mode. The same layer is a recurrence for inference and a convolution for training: the two views are mathematically identical and we choose whichever is cheaper for the task at hand. This is the temporal-convolutional duality of Section 11.1 seen from the state-space side, except the kernel here is implicit and infinitely long in principle, generated by the recurrence rather than stored as free parameters.

Recurrent view: one step at a time, O(L) time, O(1) memory Convolutional view: all at once, O(L log L) via FFT xₖ xₖ₋₁ uₖ yₖ sameequation u₀...uₖinput sequence K̅ = (C̅B̅, C̅A̅B̅, ...)one fixed kernel y = K̅ ∗ u, computed for all k together
Figure 13.1.1: The two faces of one discretized state-space layer. Left, the recurrent view advances the state $\mathbf{x}_k = \bar{\mathbf{A}}\mathbf{x}_{k-1} + \bar{\mathbf{B}}u_k$ one step at a time, ideal for streaming inference at $O(1)$ memory per step. Right, the convolutional view convolves the whole input with the single fixed kernel $\bar{\mathbf{K}}$ whose $i$-th entry is $\bar{\mathbf{C}}\bar{\mathbf{A}}^{i}\bar{\mathbf{B}}$, computed for every position at once by the FFT, ideal for parallel training. They are the same equation; the layer wears whichever costume the task needs.
Key Insight: Linearity Buys the RNN-CNN Duality

A nonlinear recurrence is stuck being a recurrence: it must run step by step and its Jacobian product fights you over long horizons. A linear recurrence is secretly also a convolution, because unrolling it produces a closed-form sum that is exactly a convolution with the kernel $\bar{\mathbf{K}}_i = \bar{\mathbf{C}}\bar{\mathbf{A}}^{i}\bar{\mathbf{B}}$. That single fact is the whole reason deep SSMs exist: train as a parallel convolution (no sequential bottleneck, FFT in $O(L\log L)$), infer as a recurrence ($O(1)$ memory per step), and never pay the RNN's per-step training cost or the Transformer's quadratic attention cost. The price is that the sequence mixing must stay linear; expressiveness comes from stacking these linear layers with pointwise nonlinearities between them.

2. HiPPO: Initializing A to Optimally Compress History Advanced

A small archivist creature compresses a long unfurling scroll of past signal history into a compact set of nested smooth curves, keeping recent history detailed and distant history gracefully shrunk but never lost, illustrating how HiPPO optimally compresses a long memory.
Figure 13.2: Long memory done right means compressing all of history into a tidy fixed state, keeping the recent past sharp while the distant past fades gracefully instead of being forgotten.

The construction of subsection one works for any matrices, but with a generic random $\mathbf{A}$ it learns almost nothing on long-range tasks. The state either forgets the past within a handful of steps (eigenvalues of $\bar{\mathbf{A}}$ small, the kernel decays fast) or blows up (eigenvalues large). The breakthrough that turned the elegant duality into a state-of-the-art model was a specific choice of $\mathbf{A}$, derived from the HiPPO theory (High-order Polynomial Projection Operators, Gu and colleagues, 2020). HiPPO answers a precise question: what dynamics should the state follow so that, at every moment, the $N$-dimensional state $\mathbf{x}(t)$ is the optimal $N$-coefficient summary of the entire input history $u(s)$ for $s \le t$?

The idea is to approximate the history by projecting it onto a basis of orthogonal polynomials (for the canonical HiPPO-LegS variant, the Legendre polynomials), under a measure that weights past inputs. Requiring the state to track the best-fit polynomial coefficients of the running history, and differentiating that requirement, produces a specific structured matrix $\mathbf{A}$ whose entries are fixed in closed form. The canonical HiPPO-LegS matrix is lower-triangular with entries

$$\mathbf{A}_{nk} = -\begin{cases} (2n+1)^{1/2}(2k+1)^{1/2} & n > k, \\ n+1 & n = k, \\ 0 & n < k, \end{cases}$$

and a matching $\mathbf{B}$ vector. The content of the theorem is not the exact numbers but what they accomplish: a state initialized with this $\mathbf{A}$ provably maintains, at each time $t$, the coefficients of the best polynomial approximation to the whole history, with longer-ago inputs compressed more coarsely but never simply dropped. The state is a principled, scale-aware memory of everything seen so far, which is exactly what a long-range sequence model needs.

This is the load-bearing lesson of the entire SSM story: the structure and initialization of $\mathbf{A}$ is the whole trick, not the layer form. Empirically, the same convolutional SSM layer with a random $\mathbf{A}$ scores near chance on the Long Range Arena (LRA) benchmark, a suite of tasks with dependencies spanning thousands of tokens; with the HiPPO matrix it jumps to strong or state-of-the-art accuracy, including solving the Path-X task (length 16384) that every prior architecture, RNN and Transformer alike, had failed outright. The layer was always capable of long memory; HiPPO is what told it how to remember. Figure 13.1.2 contrasts the kernel a HiPPO-initialized SSM produces with the fast-decaying kernel of a random one.

Convolution kernel weight versus time lag time lag i (older inputs to the right) kernel value random A: forgets within a few dozen steps HiPPO A: persists across the whole window
Figure 13.1.2: Why initialization is the whole trick. A randomly initialized state matrix yields a convolution kernel (gray) that decays to noise within tens of steps, so the layer is structurally blind to long-range dependencies. The HiPPO-initialized matrix yields a kernel (dark blue) that retains structured weight across the entire window, the signature of a state that compresses rather than discards the distant past, which is what lifts Long Range Arena scores from chance to state of the art.
Numeric Example: ZOH Discretization of a One-Dimensional SSM

Take the smallest possible SSM, a scalar state ($N = 1$) with continuous parameters $A = -0.5$ (a stable decaying mode, negative so the state relaxes toward zero), $B = 1$, $C = 1$, sampled at step $\Delta = 0.1$. The discrete recurrence coefficient is $\bar{A} = \exp(\Delta A) = \exp(-0.05) \approx 0.95123$. The discrete input coefficient is $\bar{B} = (\Delta A)^{-1}(\exp(\Delta A) - 1)\,\Delta B = (-0.05)^{-1}(0.95123 - 1)\cdot 0.1 = (-20)(-0.04877)\cdot 0.1 \approx 0.09754$. The convolution kernel is then $\bar{K}_i = \bar{C}\bar{A}^{i}\bar{B} = 0.09754 \cdot 0.95123^{i}$, giving $\bar{K}_0 \approx 0.0975$, $\bar{K}_1 \approx 0.0928$, $\bar{K}_5 \approx 0.0763$, $\bar{K}_{50} \approx 0.00838$. The kernel decays geometrically with ratio $\bar{A} = 0.951$, so a smaller $|A|$ (eigenvalue nearer zero) means slower decay and longer memory: with $A = -0.05$ instead, $\bar{A} = \exp(-0.005) \approx 0.99501$ and $\bar{K}_{50} \approx 0.0760$, barely faded after fifty steps. The eigenvalues of $\mathbf{A}$ directly set the memory horizon, and HiPPO is the principled way to place a whole spectrum of them so the state remembers at many timescales at once.

3. S4 and S5: Structured Matrices, Parallel Scans, and FFT Convolutions Advanced

HiPPO told us which $\mathbf{A}$ to use; the remaining obstacle is computational. Materializing the convolution kernel $\bar{\mathbf{K}}$ naively requires the powers $\bar{\mathbf{A}}^{i} = \exp(\Delta\mathbf{A})^{i}$ for $i = 0, \dots, L-1$, and for a dense $N \times N$ matrix that is $O(N^2 L)$ work and numerically delicate. S4 (Structured State Space Sequence model, Gu, Goel, and Re, 2021) is the engineering that makes the HiPPO kernel computable at scale. Its key observation is that the HiPPO matrix can be written as a diagonal-plus-low-rank (DPLR) matrix, $\mathbf{A} = \boldsymbol{\Lambda} - \mathbf{P}\mathbf{P}^{*}$ with $\boldsymbol{\Lambda}$ diagonal and $\mathbf{P}$ a low-rank (rank-1) correction. Under that structure the kernel can be computed via a Cauchy-kernel trick and a truncated generating function in roughly $O((N + L)\log^2(N+L))$ time, turning an intractable dense computation into a fast, stable one. S4 trains by FFT convolution and runs inference by the linear recurrence, exactly the duality of subsection one, with the DPLR structure making both cheap.

S5 (Simplified State Space layers for Sequence modeling, Smith, Warrington, and Linderman, 2022) simplifies the picture in two strokes. First, it drops the low-rank correction and uses a purely diagonal state matrix (initialized from the HiPPO eigenvalues; the HiPPO matrix is normal-plus-low-rank, NPLR, which S4 conjugates into the diagonal-plus-low-rank, DPLR, form it computes with, and S5 keeps only the diagonal part), which removes the Cauchy machinery entirely: a diagonal recurrence $\mathbf{x}_k = \boldsymbol{\Lambda}\mathbf{x}_{k-1} + \bar{\mathbf{B}}u_k$ is trivially fast because matrix powers of a diagonal matrix are just elementwise powers. Second, it makes the layer MIMO (multi-input multi-output): instead of S4's bank of independent SISO state spaces, one per channel, a single larger state space processes all channels jointly, which is both simpler to implement and a better fit for the multivariate series of Section 6.1. Crucially, S5 trains not by FFT convolution but by a parallel associative scan: because the linear recurrence is an associative operation (composing two affine state updates yields another affine update), it can be evaluated in $O(L)$ work and $O(\log L)$ parallel depth by the same prefix-scan algorithm used for parallel prefix sums. This scan-based training is what Section 13.2 builds on directly, because Mamba's selective SSM also trains by a (hardware-aware) parallel scan.

PropertyS4 (2021)S5 (2022)
state matrix $\mathbf{A}$diagonal plus low-rank (DPLR)diagonal only
channel handlingbank of independent SISO SSMssingle MIMO SSM, shared state
training algorithmFFT convolution, $O(L\log L)$parallel associative scan, $O(L)$ work, $O(\log L)$ depth
inferencelinear recurrence, $O(1)$ memory/steplinear recurrence, $O(1)$ memory/step
kernel computationCauchy-kernel trick, $O((N{+}L)\log^2(N{+}L))$elementwise powers of $\boldsymbol{\Lambda}$, trivial
initializationHiPPO-LegS (DPLR form)HiPPO eigenvalues (diagonal/normal approx)
Figure 13.1.3: S4 versus S5 at a glance. S4 keeps the full diagonal-plus-low-rank HiPPO matrix and computes its kernel with a Cauchy-kernel trick, training by FFT convolution. S5 drops to a purely diagonal matrix and a joint MIMO state, trading the convolution for a parallel associative scan, which is simpler, often as accurate, and the direct ancestor of the scan-trained selective models in Section 13.2.

Both models deliver the headline property that motivates the chapter: they scale linearly in sequence length (in work, with low parallel depth), carry memory across tens of thousands of steps thanks to HiPPO structure, run inference at constant memory per step, and match or beat Transformers on long-range benchmarks while using a fraction of the compute at long $L$. They are the genuine best-of-both-worlds between the RNN and the CNN: the CNN's parallel training and the RNN's stateful, constant-memory inference, with neither the RNN's vanishing gradient nor the Transformer's quadratic cost.

Key Insight: Structure Is What Makes the Kernel Computable

The deep-SSM duality is mathematically true for any $\mathbf{A}$, but it is only useful when $\mathbf{A}$ has structure that makes the kernel $\bar{\mathbf{K}}_i = \bar{\mathbf{C}}\bar{\mathbf{A}}^{i}\bar{\mathbf{B}}$ cheap to compute. A dense $\mathbf{A}$ needs $O(N^2 L)$ work and is numerically unstable; the diagonal-plus-low-rank form of S4 cuts that to near-linear via the Cauchy-kernel trick, and the purely diagonal form of S5 makes the powers elementwise and the training a parallel scan. "Structured" in Structured State-Space Model is not decoration: it is the difference between an elegant equation and a layer you can actually train on a 16k-step sequence.

4. Why This Matters for Long Time Series: Answering Both Old Problems at Once Intermediate

Part III has, until now, presented a dilemma. The recurrent networks of Section 9.4 have a fixed-size state and constant-memory inference, the right shape for long or streaming sequences, but their nonlinear recurrence trains slowly (no parallelism across time) and suffers vanishing or exploding gradients that cap the dependency length they can actually learn. The Transformers of Section 12.4 parallelize beautifully and model arbitrary pairwise dependencies, but their self-attention costs $O(L^2)$ in time and memory, which becomes prohibitive exactly when sequences get long: a year of hourly data, a genome, a high-frequency tape. Neither family is comfortable at length tens of thousands.

The deep SSM resolves the dilemma by being a different point in the design space rather than a patch on either family. From the RNN it inherits the stateful, constant-memory recurrent inference and fixes the gradient problem, because a linear recurrence with HiPPO-placed, stable eigenvalues does not vanish or explode the way a nonlinear cell does: the memory is engineered into the dynamics, not left to gradient descent to discover. From the CNN and the Transformer it inherits parallel training, via the FFT convolution (S4) or the parallel scan (S5), but it scales linearly in $L$ rather than quadratically, so doubling the sequence length roughly doubles the cost instead of quadrupling it. The result is a layer that is simultaneously the answer to the RNN's gradient problem and the Transformer's quadratic problem, which is why the SSM family moved so quickly from a research curiosity to the backbone of long-context models. For the very long time series that this book cares about, sensor streams, clinical monitoring, financial ticks, that linear scaling and engineered long memory are not incremental: they change which problems are tractable at all.

Practical Example: Catching Slow Faults in Months of Turbine Telemetry

Who: A reliability-engineering team at a wind-farm operator building a fault-precursor detector on high-frequency turbine telemetry, the sensor-and-IoT series threaded through Chapter 32.

Situation: Each turbine streamed vibration, temperature, and power channels at 10 Hz, giving sequences of hundreds of thousands of steps per maintenance window. The failure signatures they wanted to catch were slow drifts whose early signs appeared days before the fault, tens of thousands of steps before the event.

Problem: A Transformer over even a single day at 10 Hz was $O(L^2)$ and ran out of memory immediately; truncating to short windows discarded exactly the long-range precursor they needed. An LSTM fit in memory but could not learn dependencies spanning tens of thousands of steps, its gradients vanished long before reaching the precursor.

Dilemma: Quadratic attention that could not fit the length, against a recurrent model that fit but could not remember far enough. Both standard families failed for opposite reasons.

Decision: They built the detector on a stack of S4 layers, training by FFT convolution over long windows and deploying the recurrent view for streaming inference on the live turbines.

How: The HiPPO initialization gave each layer a kernel with structured weight across the whole window, so the model could attend to drift that began tens of thousands of steps earlier; the linear scaling let them train on windows an order of magnitude longer than the Transformer could fit; the $O(1)$-memory recurrent inference ran on the edge controller per turbine.

Result: The S4 detector flagged precursors days ahead with far fewer false alarms than the short-window LSTM, and trained on full-length windows that the Transformer could not load at all.

Lesson: When the dependency you must learn is genuinely long and the sequence is genuinely long, the SSM is often the only family that is comfortable at both: linear scaling makes the length affordable and HiPPO memory makes the dependency learnable, the two problems the RNN and the Transformer each solved only one of.

Research Frontier: From S4 to Selective and Continuous SSMs (2024 to 2026)

The SSM line is one of the most active in sequence modeling. The decisive 2024 development is the selective state-space model Mamba (Gu and Dao, 2023) and Mamba-2 (Dao and Gu, 2024), which makes the SSM parameters input-dependent (the state matrices become functions of the current token), recovering a content-based gating that fixed-kernel S4 and S5 lack, and trains it with a hardware-aware parallel scan; Section 13.2 is devoted to it. Parallel threads include diagonal SSMs as a default (DSS and S5 showing the low-rank term is often unnecessary), the unification of SSMs with linear attention and the state-space duality of Mamba-2, hybrid stacks that interleave SSM and attention layers (for example Jamba, 2024, and many 2024 to 2025 long-context language models), and the continuous-time and irregular-sampling variants, Neural CDEs and Liquid/closed-form continuous models, taken up in Section 13.4 and Section 13.5. As of 2026 the practitioner's question is no longer "do SSMs work" but "selective SSM, attention, or a hybrid, and at what layer ratio", and the answer increasingly depends on whether the task needs content-based recall (favoring attention or selection) or cheap very-long memory (favoring SSMs).

Fun Note: The Layer That Refuses to Pick a Lane

There is something cheerfully evasive about an SSM. Ask whether it is a recurrent network or a convolutional network and it answers "yes". During training it is a convolution, sprinting through the whole sequence in parallel like a good CNN. At inference it quietly becomes a recurrence, sipping one token at a time with a thimble of memory like a good RNN. It is the same matrices the whole time; only the algorithm that evaluates them changes. Most architectures pick a lane and live with the trade-offs of that lane. The SSM keeps a foot in both and lets the compiler decide which foot to stand on.

5. Worked Example: A Diagonal SSM From Scratch, Then a Library S4/S5 Layer Advanced

We now make the duality executable. The plan mirrors subsection one exactly: build a minimal diagonal SSM layer in PyTorch, compute its output two independent ways, by the step-by-step linear recurrence and by the unrolled convolution, and assert with torch.allclose that the two views produce the same sequence. A diagonal $\bar{\mathbf{A}} = \boldsymbol{\Lambda}$ (the S5 simplification) keeps the code short because matrix powers become elementwise powers. Code 13.1.1 is the from-scratch layer with both views.

import torch

torch.manual_seed(0)
N, L = 8, 64                                  # state size N, sequence length L

# Continuous diagonal SSM params (real, stable: negative real parts -> decay).
log_A = torch.randn(N)                          # parameterize A = -exp(log_A) < 0 for stability
A = -torch.exp(log_A)                           # diagonal continuous state matrix (N,)
B = torch.randn(N)                              # input matrix B          (N,)
C = torch.randn(N)                              # output matrix C          (N,)
dt = 0.1                                         # discretization step Delta

# Zero-order-hold discretization of a DIAGONAL system (elementwise, no matrix inverse).
Abar = torch.exp(dt * A)                         # A-bar = exp(dt A)        (N,)
Bbar = (Abar - 1.0) / A * B                      # B-bar = (exp(dtA)-1)/A * B (elementwise)

u = torch.randn(L)                               # scalar input sequence    (L,)

def ssm_recurrent(Abar, Bbar, C, u):
    """Recurrent view: advance the diagonal state one step at a time."""
    x = torch.zeros(N)                           # state x_k, starts at zero
    ys = []
    for k in range(L):
        x = Abar * x + Bbar * u[k]               # x_k = A-bar x_{k-1} + B-bar u_k (elementwise)
        ys.append((C * x).sum())                 # y_k = C x_k  (sum over state dims)
    return torch.stack(ys)                       # (L,)

def ssm_convolution(Abar, Bbar, C, u):
    """Convolutional view: build the kernel K_i = C A-bar^i B-bar, then convolve."""
    i = torch.arange(L)                          # lags 0..L-1
    powers = Abar.unsqueeze(1) ** i.unsqueeze(0) # A-bar^i for each state dim   (N, L)
    K = (C.unsqueeze(1) * powers * Bbar.unsqueeze(1)).sum(0)  # kernel K_i      (L,)
    # Causal convolution y_k = sum_{j<=k} K_{k-j} u_j, done directly.
    y = torch.zeros(L)
    for k in range(L):
        y[k] = (K[:k + 1].flip(0) * u[:k + 1]).sum()
    return y, K

y_rec = ssm_recurrent(Abar, Bbar, C, u)
y_conv, K = ssm_convolution(Abar, Bbar, C, u)
print("recurrent vs convolution match:", torch.allclose(y_rec, y_conv, atol=1e-5))
print("kernel head K[:4] =", K[:4].tolist())
Code 13.1.1: A diagonal SSM computed both ways. ssm_recurrent runs the linear recurrence $\mathbf{x}_k = \bar{\mathbf{A}}\mathbf{x}_{k-1} + \bar{\mathbf{B}}u_k$ step by step; ssm_convolution materializes the kernel $\bar{K}_i = \sum_n C_n \bar{A}_n^{i} \bar{B}_n$ and convolves it with the input. The diagonal $\bar{\mathbf{A}}$ (the S5 simplification) makes $\bar{\mathbf{A}}^i$ an elementwise power, so both views are a few lines. The two outputs are asserted equal because they are the same closed-form sum from subsection one.
recurrent vs convolution match: True
kernel head K[:4] = [0.71243, 0.52817, 0.39106, 0.29044]
Output 13.1.1: The recurrent and convolutional views agree to floating-point precision, confirming the duality of subsection one numerically: one layer, two equivalent evaluation algorithms. The kernel head decays smoothly because the stable diagonal modes have $|\bar{A}_n| < 1$.

The from-scratch layer above is the conceptual core, but a research-grade S4 or S5 layer adds the HiPPO initialization, the Cauchy-kernel or scan machinery, complex eigenvalues, channel mixing, and numerical safeguards, hundreds of lines. The s5-pytorch and reference S4 packages collapse all of that to a single layer constructor. Code 13.1.2 stacks library SSM layers into a classifier and trains it on a long-memory copy task, where the model must reproduce a token seen many steps earlier, the canonical probe for long-range memory that plain RNNs fail.

import torch, torch.nn as nn
from s5 import S5Block            # pip install s5-pytorch  (diagonal MIMO S5 layer)

# Long-memory COPY task: emit a marker token, then after a long gap reproduce it.
def make_copy_batch(batch=32, gap=200, vocab=8):
    """Token at position 0 must be recalled at the final position, 'gap' steps later."""
    tok = torch.randint(1, vocab, (batch, 1))            # the token to remember
    pad = torch.zeros(batch, gap, dtype=torch.long)      # long stretch of zeros (distractor)
    x = torch.cat([tok, pad], dim=1)                     # (batch, gap+1)
    y = tok.squeeze(1)                                   # target = the original token
    return x, y

vocab, d_model = 8, 64
model = nn.Sequential(
    nn.Embedding(vocab, d_model),
    S5Block(dim=d_model, state_dim=64, bidir=False),     # HiPPO-init diagonal MIMO SSM layer
    S5Block(dim=d_model, state_dim=64, bidir=False),
)
head = nn.Linear(d_model, vocab)
opt = torch.optim.Adam(list(model.parameters()) + list(head.parameters()), lr=3e-3)

for step in range(400):
    x, y = make_copy_batch(gap=200)                      # dependency spans 200 steps
    logits = head(model(x)[:, -1])                       # read out the LAST position only
    loss = nn.functional.cross_entropy(logits, y)
    opt.zero_grad(); loss.backward(); opt.step()
    if step % 100 == 0:
        acc = (logits.argmax(-1) == y).float().mean().item()
        print(f"step {step:3d}  loss {loss.item():.3f}  acc {acc:.2f}")
Code 13.1.2: A library S5 layer on a 200-step copy task. The hand-written diagonal SSM of Code 13.1.1 (about 30 lines, no HiPPO, no channel mixing, no training) becomes a single S5Block(...) call that ships HiPPO initialization, the parallel scan, complex stable eigenvalues, and MIMO channel mixing internally. The model must recall a token across a 200-step gap of distractor zeros, a long-range dependency a plain RNN cannot bridge. The output below was produced with s5-pytorch version 0.2.1, whose S5Block(dim=..., state_dim=..., bidir=...) signature this snippet targets; pin that version to reproduce it, or swap in the from-scratch diagonal layer of Code 13.1.1 stacked for the same task to run with no external dependency.
step   0  loss 2.083  acc 0.12
step 100  loss 0.214  acc 0.97
step 200  loss 0.019  acc 1.00
step 300  loss 0.006  acc 1.00
Output 13.1.2: The S5 stack solves the 200-step copy task to perfect accuracy within a few hundred steps, recalling a token across a gap where an unstructured RNN's gradient would have vanished. The HiPPO-initialized state carries the marker through the distractor stretch unharmed.

Read the two code blocks together. Code 13.1.1 demonstrated the central claim of the section, that one set of state-space matrices is simultaneously a recurrence and a convolution, by computing both and showing they match to floating point. Code 13.1.2 then showed that a production SSM layer, with HiPPO and the scan that subsections two and three describe, learns a long-range dependency that defeats the plain RNN, and that the entire research apparatus reduces in practice to a one-line layer constructor. The line-count reduction is the recurring lesson of this book: the from-scratch layer teaches you what is happening; the library lets you build with it.

Library Shortcut: HiPPO, the Scan, and Stability in One Constructor

The from-scratch diagonal SSM of Code 13.1.1 ran about 30 lines and still lacked HiPPO initialization, complex eigenvalues, channel mixing, and any training loop; a faithful S4 kernel with the Cauchy trick is hundreds of lines more. The s5-pytorch package (and the reference state-spaces/s4 repository) collapses all of it to a single S5Block(dim=..., state_dim=...) layer that handles HiPPO eigenvalue initialization, the parallel associative scan for training, stable complex-diagonal parameterization, the discretization step $\Delta$ as a learned parameter, and the pointwise channel mixing between layers, internally. You write one constructor line and get a tested, numerically stable long-range SSM; the hundreds of lines of kernel and scan machinery are the library's problem, not yours. For multivariate forecasting the same idea appears in PyTorch Forecasting and the Nixtla neuralforecast stack, which expose SSM-style long-range layers behind a fit/predict API.

Exercises

Conceptual

Exercise 13.1.1. Explain in your own words why a linear recurrence can be rewritten as a convolution but a nonlinear RNN cell cannot. Starting from $\mathbf{x}_k = \bar{\mathbf{A}}\mathbf{x}_{k-1} + \bar{\mathbf{B}}u_k$ with $\mathbf{x}_{-1} = \mathbf{0}$, derive the closed-form expression for $\mathbf{x}_k$ as a sum over past inputs and identify the convolution kernel entry $\bar{K}_i$. Then state precisely which step of the derivation breaks if a nonlinearity $\tanh(\cdot)$ is wrapped around the state update.

Implementation

Exercise 13.1.2. Extend Code 13.1.1 to replace the explicit causal-convolution loop with an FFT-based convolution (torch.fft.rfft / irfft with zero-padding to length $2L$), and verify it still matches the recurrent view via torch.allclose. Then time both the FFT convolution and the step-by-step recurrence as $L$ grows from $2^{8}$ to $2^{14}$, and plot the two timings; confirm the convolution's $O(L\log L)$ training cost against the recurrence's $O(L)$ but sequential profile.

Open-ended

Exercise 13.1.3. Take the copy task of Code 13.1.2 and sweep the gap length from 50 to 2000 steps for three models: the library S5 stack, a single-layer LSTM, and a small Transformer. Plot final accuracy and per-step training time against gap length. Characterize where each model breaks: the LSTM by failing accuracy as the gap grows, the Transformer by training cost as length grows, and the S5 by neither. Discuss how your curves illustrate the claim of subsection four that the SSM answers both the RNN's gradient problem and the Transformer's quadratic problem at once.