N-Dimensional Models

The solver crate supports models with arbitrary state dimension through Rust const generics.

ControlProblem<N> trait

The generic contract is [solver::models::control::ControlProblem]. It is the solver-agnostic abstraction consumed by both the BSDE regression solver and explicit finite-difference steps:

#![allow(unused)]
fn main() {
pub trait ControlProblem<const N: usize> {
    type Control;
    fn optimize(&self, t, state, derivs) -> Self::Control;
    fn running_reward(&self, t, state, control) -> f64;
    fn generator(&self, t, state, control, derivs) -> f64;
    fn driver(&self, t, state, control, derivs) -> f64;
    fn terminal(&self, state) -> f64;
    fn apply_constraint(&self, state, value) -> f64;
    fn discount_rate(&self, state) -> f64;
    fn constant_discount_rate(&self) -> Option<f64>;
    fn next_step(&self, t, state, dt, noise) -> [f64; N];
    fn is_diffusion_dimension(&self, dim) -> bool;
    fn gradient_step(&self, dim) -> f64;
}
}

StateDerivatives<N> carries first and diagonal second derivatives plus forward/backward directional differences. Continuous controls consume grad/hessian; jump controls consume fwd/bwd. For correlated diffusions it also carries the full symmetric Hessian hessian_full, whose off-diagonal entries are the mixed second derivatives d^2 V / dx_i dx_j.

Correlated diffusions and the Heston rho term

The generator of a correlated diffusion is \(\tfrac12\,\mathrm{tr}(D\, \mathrm{Hess}\, V)\) with covariance \(D = \sigma\sigma^{\top}\), so the off-diagonal entries of hessian_full are weighted by the off-diagonal covariance. The Heston model does not use this general path: its value is reduced to the coordinates \([q, v]\) by the CARA ansatz, so the spot \(S\) is not a grid dimension. The spot-variance correlation therefore appears as a closed-form drift correction

\[ \rho\,\xi\,v\,\partial_{v}\partial_{S}V = -\gamma\,q\,\rho\,\xi\,v\,\partial_{v}V, \]

folded into the variance drift. This is exact for the reduced model, not an ad hoc substitution, and it does not need hessian_full because the correlated coordinate is collapsed. The general cross term is exercised instead by models with two (or more) diffusive grid coordinates, such as [solver::models::lq_regulator::LqRegulator] with a full diffusion matrix.

The FD-specific transport contract for implicit and ADI schemes is documented in PDE Solving Methods. It is a separate trait, not part of ControlProblem.

Dimension kinds

The generic trait currently exposes two per-dimension signals:

  • is_diffusion_dimension(dim): the coordinate is driven by Brownian diffusion.
  • gradient_step(dim): physical finite-difference step for mesh-free stencils.

This is not sufficient to select a stable FD stencil. The PDE contract adds a declarative dimension_kind(dim) with three values: DiscreteJump, Diffusion, and DeterministicDrift. See PDE Solving Methods for the stencils.

Conventions

  • Dimension 0 is always inventory for market-making models.
  • The generic result carries the model's associated Control type directly; there is no inventory-specific to_spreads on the generic result.
  • Spread conversion for market-making lives in solver::models::market_making::{MarketMakingControl, SpreadResult}.

Proven: N=3 Heston-Hawkes

HestonHawkes implements ControlProblem<3> with state [q, v, lambda]:

  • dim 0 (inventory): discrete jump-controlled dimension.
  • dim 1 (variance): CIR diffusion, is_diffusion_dimension(1) = true.
  • dim 2 (intensity): deterministic mean-reverting drift.

Run the example: cargo run --release --example heston_hawkes_n3.