Neural Methods for Jump Processes
Stochastic control problems with jumps (Poisson, compound Poisson, or more general Levy processes) cannot be handled by the diffusion-only neural BSDE or DGM formulations as-is. A jump adds a nonlocal term to the backward driver and to the HJB equation. This page records the theory; measured results live in the empirical results section.
Why jumps are structurally different
For a diffusion, the infinitesimal generator is a local differential operator. For a jump-diffusion with jump measure \(\nu\), the generator gains a nonlocal integral:
\[ \mathcal{L} v = \mu \cdot \nabla v + \tfrac{1}{2}\operatorname{tr}(\sigma\sigma^\top \nabla^2 v) + \int \big[ v(x+j) - v(x) - j \cdot \nabla v\, \mathbf{1}_{|j|<1} \big] \, \nu(dj). \]
The integral connects the value at \(x\) to the value at \(x + j\) across a continuum of jump sizes. No amount of network depth or width removes it; it must be computed or sampled explicitly.
Jump architecture is two decisions, not one
The phrase "what architecture handles jumps best" conflates two independent choices. They are documented separately here because they have separate trade-offs.
Value and policy networks: represent the kinks
Jump control problems produce value functions with kinks at exercise,
continuation, and constraint boundaries. Smooth activations used by DGM and
PINNs (softplus, tanh) force global smoothness and approximate kinks
poorly, while non-smooth activations (relu, leaky_relu) cannot supply the
second derivative the residual requires. The two workable resolutions are:
- Adaptive activation functions (
tanhwith learnable scale and shift), which sharpen near kinks while remaining differentiable. - Partition-of-unity or local-basis networks, which are smooth locally while the global function is only piecewise smooth.
The jump operator: compute it, do not learn it
Once the jump measure \(\nu\) is known, the jump operator is a known, convolution-like integral. It is computed directly rather than learned:
- Finite-activity, fixed jump sizes: a finite sum over the jump grid.
- Infinite-activity Levy measures: Gauss-Laguerre quadrature, or truncation plus quadrature.
- Forward simulation: sample the jump from \(\nu\) inside the SDE; no
quadrature is needed (natural for
jax.lax.scan).
Deep BSDE with jumps
The martingale representation for a jump BSDE adds a predictable jump term \(\Gamma\) alongside the diffusion integrand \(Z\). The backward equation becomes
\[ dY_t = -f(t, X_t, Y_t, Z_t, \Gamma_t)\, dt + Z_t\, dW_t + \Gamma_t\, d\tilde N_t, \qquad Y_T = g(X_T), \]
where \(\tilde N_t\) is the compensated jump process. The neural method learns \((Y, Z, \Gamma)\) jointly; \(\Gamma\) is the jump analogue of the hedge or control and is exactly what a controlled jump problem needs.
Deep HJB (DGM) with jumps
The DGM method parameterizes \(V(t, x)\) directly and minimizes the residual of
the partial integro-differential equation (PIDE), which is the HJB equation
with the jump integral added to the generator. The jump integral is computed
by quadrature over \(\nu\) at each residual evaluation. For the jump-LQ problem
(deterministic amplitude xi) this is implemented as
neural_solver/loss.py::jump_lq_residual and validated against the closed
form; neural_solver/dgm.py::train_dgm trains the value network against that
residual.
Jump taxonomy and which method fits
| Jump structure | Deep BSDE | DGM/PIDE |
|---|---|---|
| Finite-activity, fixed sizes | sample the jump; learn \(\Gamma\) | finite sum over the grid |
| Infinite-activity Levy | sample the jump | Gauss-Laguerre quadrature |
| Bounded jump sizes | sample the jump | quadrature on a compact set |
| Heavy-tailed jump sizes | sample the jump | truncation plus quadrature |
For stochastic control specifically, the deep BSDE route is preferred: the \(\Gamma\) process is the direct control analogue, and the method scales to high state dimension without a grid. The DGM route is preferred when the full value surface on a low- or medium-dimensional domain is wanted.
Relationship to the Rust solver
The Rust solver crate already has an arbitrary jump-kernel stage
(docs/project/plan/workstreams/solver/stages/04-arbitrary-jump-processes.md)
that generalizes unit inventory jumps to arbitrary amplitudes and rates.
neural_solver reuses the same jump-kernel convention and validates its jump
BSDE against the Rust finite-difference and analytical reference values, not
only against itself.
The minimal jump benchmark implemented in neural_solver is the jump-LQ
regulator (neural_solver/src/neural_solver/models/jump_lq.py): scalar state,
a single Poisson source, and a closed-form Riccati/affine value, so the
Gamma path is validated against an exact reference rather than a sampled
one. Two Merton jump targets are also implemented where the optimal control
itself depends on the jump:
merton_jump.py: a deterministic multiplicative jump, with a closed-form quadratic policy and value, validated both against the Rust reference and by the jump deep BSDE (which recovers the value and the constantGamma).merton_jump_lognormal.py: a log-normal jump size, whose policy is the root of a transcendental first-order condition computed by Gauss-Hermite quadrature and bisection. This is a reference-only model: the deep BSDE loop does not yet sample random jump sizes, so nobsde_problemis provided.