combinatorial_optimization
Concept Overview
Section titled “Concept Overview”AFML Chapter 21 tooling for discrete, path-dependent problems, built around keeping the integer structure explicit rather than relaxing it away. DecisionSchema describes an integer decision space and solve_exact enumerates it. TradingTrajectorySchema describes a trading path — per-step trade bounds, inventory limits, an optional terminal inventory — and enumerate_trading_paths produces every feasible trajectory, which evaluate_trading_path scores against expected returns, risk aversion, market impact and a fixed per-ticket cost.
When to Use
Section titled “When to Use”Use exact enumeration on small instances as a correctness oracle: compare_exact_and_adapter exists precisely so a heuristic or external solver can be validated against ground truth before it is trusted at scale. The decision space grows exponentially in horizon and dimension and max_paths will stop you — treat that as the signal to move to an adapter, not to raise the cap. The fixed ticket cost is what makes the problem genuinely combinatorial; without it a continuous relaxation would do.
Mathematical Foundations
Section titled “Mathematical Foundations”Finite Integer Program
Section titled “Finite Integer Program”
Path-Dependent Objective
Section titled “Path-Dependent Objective”
Adapter Gap vs Exact
Section titled “Adapter Gap vs Exact”
Usage Examples
Section titled “Usage Examples”Exact trajectory search with fixed ticket costs
Section titled “Exact trajectory search with fixed ticket costs”use openquant::combinatorial_optimization::{ TradeBounds, TradingTrajectoryObjectiveConfig, TradingTrajectoryPath, TradingTrajectorySchema, enumerate_trading_paths, evaluate_trading_path,};
let schema = TradingTrajectorySchema { initial_inventory: 0, inventory_min: -2, inventory_max: 2, step_trade_bounds: vec![ TradeBounds { min_trade: -1, max_trade: 1 }, TradeBounds { min_trade: -1, max_trade: 1 }, TradeBounds { min_trade: -1, max_trade: 1 }, ], terminal_inventory: Some(0), max_paths: 50_000,};let cfg = TradingTrajectoryObjectiveConfig { expected_returns: vec![0.01, -0.015, 0.012], risk_aversion: 0.001, impact_coefficients: vec![0.0005, 0.0005, 0.0005], fixed_ticket_cost: 0.002, terminal_inventory_target: 0, terminal_inventory_penalty: 0.05,};
let best = enumerate_trading_paths(&schema)? .into_iter() .map(|path| { let score = evaluate_trading_path(&path, &cfg)?; Ok::<(TradingTrajectoryPath, f64), openquant::combinatorial_optimization::CombinatorialOptimizationError>((path, score)) }) .collect::<Result<Vec<_>, _>>()? .into_iter() .max_by(|a, b| a.1.total_cmp(&b.1)) .expect("at least one feasible path");
println!("best objective: {:.6}", best.1);println!("trades: {:?}", best.0.trades);API Reference
Section titled “API Reference”Rust API
Section titled “Rust API”DecisionSchemaIntegerVariableIntegerObjectivesolve_exactSolverAdaptersolve_with_adaptercompare_exact_and_adapterTradingTrajectorySchemaenumerate_trading_pathsevaluate_trading_pathsolve_trading_trajectory_exact
Risk Notes and Caveats
Section titled “Risk Notes and Caveats”- Exact enumeration scales exponentially in decision dimension/horizon; treat it as a correctness baseline and regression oracle.
- Use adapter interfaces to compare heuristic/external solvers against exact solutions on small calibration instances before production deployment.