xad-rs
Exact automatic differentiation for Rust. Forward and reverse mode, first and second order, with name-keyed gradient readback for quant-finance workloads. No finite-difference error, no symbolic manipulation — just the chain rule, applied to your program as it runs.
Unofficial Rust port of the C++ XAD library. Not affiliated with the upstream project.
Documentation
- Theory — derivations and decision-tree guidance:
docs/README.md. - API — generated rustdoc: docs.rs/xad-rs.
- Examples — runnable, cross-checked against analytic answers:
examples/.
How it works
Write your numerical code once against the trait Real.
Instantiate it at the call site against the concrete mode that matches your
problem shape — f64 for no-AD, Jet1 for one directional derivative, Jet1Vec
for a full gradient in one forward pass, AReal + Tape for a gradient over many
inputs, Jet2/Jet2Vec for second order.
use *;
let v_passive = quadratic; // primal, no AD
let v_jet1 = quadratic; // forward, 1st order
let v_jet2 = quadratic; // forward, 1st + 2nd
// Reverse mode: build inside an active Tape (see below).
Pick a mode
| Your problem | Mode | Read more |
|---|---|---|
| Just the value, no derivatives | f64 |
01 — AD as a discipline |
| One input direction, any number of outputs | Jet1<T> |
02 — Forward mode & dual numbers |
| Full gradient in one forward pass (n small) | Jet1Vec |
02 — Forward mode & dual numbers |
| Full gradient, n ≫ 4 inputs, scalar output | Tape + AReal<T> |
03 — Reverse mode & taped adjoints |
| Gamma / diagonal Hessian along one direction | Jet2<T> |
04 — Second-order & k-jets |
| Full n × n Hessian, n ≲ 50 | Jet2Vec via compute_full_hessian |
04 — Second-order & k-jets |
| Greeks by name (delta, vega, ...) instead of by index | Any mode's Named* variant |
05 — Named variables & quant use cases |
Reverse mode breaks even with forward around n ≈ 4 inputs. For n ≫ 4 (e.g. a 30-input swap pricer), reverse is dramatically faster.
Real is implemented for f64, AReal<f64>, Jet1<f64>, and Jet2<f64>.
Jet1Vec / Jet2Vec lack the impl because the trait's From<f64> requires
knowing the tangent length; use them directly when you want a full gradient or
Hessian in one pass.
By mode — quick recipes
Reverse (gradient via tape)
use ;
let mut tape = new;
tape.activate;
let mut x = new;
let mut y = new;
register_input;
register_input;
// f(x, y) = x^2 * y + sin(x)
let mut f = & * &y + sin;
register_output;
f.set_adjoint;
tape.compute_adjoints;
assert!;
assert_eq!;
Forward (full gradient in one pass)
use Jet1Vec;
let = ;
let f = & * &y; // x^2 * y
assert_eq!; // df/dx = 2xy
assert_eq!; // df/dy = x^2
Second order (gamma along one direction)
use Jet2;
let x = variable;
let y = x * x * x; // x^3
assert_eq!; // 3x^2
assert_eq!; // 6x
For the full dense Hessian in one pass, use Jet2Vec via compute_full_hessian
(see examples/hessian.rs and the chapter 04 cost
model).
Named (greeks by name)
Forward, declare-and-scope:
use ;
let mut ft = new;
let spot_h = ft.declare_jet1vec;
let strike_h = ft.declare_jet1vec;
let scope: = ft.into_scope;
let spot = scope.jet1vec;
let strike = scope.jet1vec;
let ratio = spot / strike;
assert!;
Reverse, with a name-keyed gradient as an IndexMap:
use NamedTape;
let mut tape = new;
let x = tape.input;
let y = tape.input;
let _registry = tape.freeze;
let f = & * &y + x.sin;
let grad = tape.gradient;
assert!;
assert!;
Composite Jacobian / Hessian helpers
use ;
// f: R^2 -> R^2, f(x, y) = [x*y, x + y]
let _jac = compute_jacobian_rev;
// g: R^2 -> R, g(x, y) = x^2 * y + y^3
let _hess = compute_hessian;
For the exact Hessian (machine precision, one forward pass instead of n reverse
sweeps), reach for compute_full_hessian — it returns a NamedHessian with the
value, gradient, and full ndarray::Array2<f64> Hessian.
Examples
Run with cargo run --release --example <name>.
| Example | What it demonstrates |
|---|---|
swap_pricer.rs |
30-input IRS DV01 and gamma via reverse, Jet1Vec, and Jet2 |
fx_option.rs |
Garman–Kohlhagen FX option greeks, three AD modes cross-checked against analytic |
fixed_rate_bond.rs |
YTM, duration, convexity |
jacobian.rs |
4×4 Jacobian via reverse mode |
hessian.rs |
4×4 Hessian via compute_full_hessian with analytic cross-check |
adjoint_first_order.rs |
Full 4-input gradient in one reverse sweep |
fwd_adj_second_order.rs |
Forward-over-adjoint: gradient + Hessian row via Jet2Vec |
License
AGPL-3.0-or-later, matching the upstream XAD project. See LICENSE.md.
Acknowledgements
- The C++ XAD library — architectural inspiration and source of the financial examples.
- QuantLibAAD — the XAD-instrumented QuantLib build; reference for the AAD-on-quant-finance patterns the financial examples in this crate are modelled after.
num-traits,indexmap, andndarrayfor the underlying primitives.