solver/numeric/solver.rs
1use super::result::{GridSolution, SpreadResult};
2use crate::core::grid::Grid;
3use crate::models::traits::Model;
4
5/// Common interface for all numerical HJB solvers.
6///
7/// Provides a unified API for solving the HJB equation using different numerical methods:
8/// - **Policy Iteration**: Finite difference grid method combining Howard's algorithm with operator splitting.
9/// - **BSDE**: Deep learning or regression-based Monte Carlo approach for high-dimensional problems.
10///
11/// This trait abstracts the storage medium (Grid vs Neural Net vs Monte Carlo Paths)
12/// allowing the rest of the application to just ask for solutions.
13pub trait Solver {
14 /// Solve the HJB equation and return the generic solution at a specific state.
15 ///
16 /// This is the primary method. It returns a `GridSolution` containing the
17 /// value function and raw control intensities, without any market-making
18 /// interpretation. Callers that need spreads should use `solve_with_spreads`
19 /// or call `GridSolution::to_spreads()` directly.
20 ///
21 /// # Arguments
22 /// * `grid` - The discretization grid (Optional: irrelevant for grid-free methods like BSDE)
23 /// * `model` - The model defining stochastic dynamics (drift, volatility) and objective (utility).
24 /// * `time_steps` - Number of time steps for the backward induction or simulation.
25 /// * `query_state` - The specific state vector (e.g. [Inventory, Price]) to evaluate.
26 fn solve<const N: usize, M: Model<N> + Sync>(
27 &self,
28 grid: Option<&Grid<N>>,
29 model: &M,
30 time_steps: usize,
31 query_state: &[f64; N],
32 ) -> GridSolution<N>;
33
34 /// Solve and convert to market-making spreads using the model's fill-rate parameters.
35 ///
36 /// Convenience wrapper that calls `solve` then `GridSolution::to_spreads`.
37 ///
38 /// # Returns
39 /// `SpreadResult` containing the Value Function, optimal spreads delta_pm,
40 /// and optimal intensities lambda_pm.
41 fn solve_with_spreads<const N: usize, M: Model<N> + Sync>(
42 &self,
43 grid: Option<&Grid<N>>,
44 model: &M,
45 time_steps: usize,
46 query_state: &[f64; N],
47 ) -> SpreadResult {
48 let solution = self.solve(grid, model, time_steps, query_state);
49 solution.to_spreads(model.fill_rate_base(query_state), model.fill_rate_decay())
50 }
51}