xad-rs
Exact automatic differentiation for Rust — forward-mode, reverse-mode, first- and second-order, with named variable support for ergonomic gradient readback.
Unofficial Rust port of the C++ XAD library. Not affiliated with the upstream project.
Choosing a mode
The forward-mode types are named after k-jets — Taylor-coefficient
bundles from differential geometry. The number is the order, and the
Vec suffix means the bundle is propagated against a multi-variable
tangent vector (full gradient / full Hessian) rather than a single
seeded direction.
| Type | Mode | Order | Best for |
|---|---|---|---|
Jet1<T> |
Forward, single direction | 1st | 1 input direction, many outputs |
Jet1Vec |
Forward, multi-var | 1st | full gradient in one pass |
Jet2<T> |
Forward, single direction | 1st + 2nd | diagonal Hessian / gamma |
Jet2Vec |
Forward, multi-var (dense) | 1st + 2nd | full n × n Hessian, n ≲ 50 |
AReal<T> + Tape |
Reverse (adjoint) | 1st | many inputs, scalar output |
Every mode also has a named variant (NamedJet1Vec, NamedTape, etc.)
that lets you read gradients by variable name instead of positional index.
Installation
[]
= "0.3"
MSRV: 1.85 (Rust edition 2024).
Quick start
Reverse mode
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;
println!; // 2xy + cos(x)
println!; // x^2
Forward mode (full gradient)
use Jet1Vec;
let = ;
let f = & * &y; // x^2 * y
assert_eq!; // df/dx = 2xy
assert_eq!; // df/dy = x^2
Second-order derivatives
use Jet2;
let x = variable;
let y = x * x * x; // x^3
assert_eq!; // 3x^2
assert_eq!; // 6x
Named variables
Access derivatives by name — useful in financial models with many risk factors:
use ;
let mut ft = new;
let spot_h = ft.declare_jet1vec;
let strike_h = ft.declare_jet1vec;
let scope: NamedForwardScope = ft.into_scope;
let spot = scope.jet1vec;
let strike = scope.jet1vec;
let ratio = spot / strike;
assert!;
Named reverse mode returns gradients as IndexMap<String, f64>:
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!;
Jacobian and Hessian
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;
Dense full Hessian (Jet2Vec)
use Jet2Vec;
let x = variable;
let y = variable;
let f = & + &;
assert_eq!; // d2f/dx2 = 2y
assert_eq!; // d2f/dxdy = 2x
assert_eq!; // d2f/dy2 = 6y
Per-op cost is O(n^2). For n > ~50, prefer seeded Jet2<T> with n passes.
Crate structure
src/
forward/ Jet1, Jet1Vec, Jet2, Jet2Vec + Named wrappers
reverse/ AReal, NamedAReal, NamedTape
ops/ compute_jacobian_*, compute_hessian, compute_full_hessian
math.rs AD-aware transcendentals (sin, exp, erf, norm_cdf, ...)
tape.rs Reverse-mode tape and thread-local active-tape slot
scalar.rs Scalar trait bound (f32, f64)
registry.rs VarRegistry — ordered name-to-index map
forward_tape.rs NamedForwardTape / NamedForwardScope setup
Examples
| 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 |
fixed_rate_bond.rs |
YTM / duration / convexity |
jacobian.rs |
4x4 Jacobian (reverse mode) |
hessian.rs |
4x4 Hessian with analytic cross-check |
adjoint_first_order.rs |
First-order adjoint mode — full 4-input gradient in a single reverse sweep |
fwd_adj_second_order.rs |
Forward-over-adjoint 2nd order — gradient + Hessian row via Jet2Vec |
Design notes
- Tape storage is thread-local. One
Tape<T>per thread;NamedTapeis!Send. - Forward mode is allocation-light.
Jet1Veckeeps tangents in a singleVec<f64>with fused, autovectorizable loops. - Zero-alloc operator fast paths. Every
ARealbinary op uses fixed-arityTape::push_binary/push_unary— no intermediateVecper op.
Tests
165 tests covering operator correctness, transcendentals, second-order derivatives, Jacobian/Hessian helpers, named variable readback, and cross-mode consistency.
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.
num-traitsfor generic scalar plumbing.