Measured January 2026 on the AADC 1.x licensed build; thread counts are stated per row. Re-runs on the current release are scheduled.
Python AAD Benchmark

625x Faster Greeks
Than XAD. 14x Faster Than Enzyme.

MatLogica AADC delivers the fastest Greeks computation for Python Monte Carlo, dramatically outperforming XAD, Enzyme-AD, JAX, PyTorch, and Autograd.

All benchmarks use 100 trades × 10,000 scenarios × 252 timesteps on identical hardware with 4-thread execution for fair comparison.

625x
Faster than XAD
14x
Faster than Enzyme-AD
34%
Greeks overhead only
68 MB
Memory usage

Greeks Computation Time

100 trades × 1,000 scenarios × 252 timesteps (single-threaded)

AADC BEST
1.34s
625x vs XAD
Enzyme-AD
14.37s
58x vs XAD
JAX
7.1s
118x vs XAD
PyTorch
20.5s
41x vs XAD
Autograd
55.3s
15x vs XAD
XAD
~840s
1x
Bump & Revalue (baseline)
44s
1x

* PyTorch time includes JIT compilation; per-path AD takes 1361s

Why AADC Wins

Different approaches to automatic differentiation have vastly different performance characteristics

⚡

MatLogica AADC

1.34s Greeks time (10K scenarios)
  • JIT-compiled AAD kernels
  • AVX2/AVX-512 SIMD vectorisation
  • Greeks add only +34% overhead
  • Record once, evaluate all scenarios
  • Works with existing Python loops
🔬

Enzyme-AD (LLVM)

14.37s Greeks time (10K scenarios)
  • LLVM-level differentiation
  • Integrates with JAX
  • Greeks add +330% overhead
  • Requires JAX-compatible code
  • 14x slower than AADC
🐌

XAD (Tape-Based)

~840s Greeks time (10K scenarios)
  • New tape for EVERY scenario
  • Python interpreter overhead
  • Greeks add +12,800% overhead
  • Slower than bump-and-revalue!
  • 625x slower than AADC

Integration Effort

Lines of code changed and model rewrite requirements

AADC ✓ No rewrite
~10 lines
XAD ✓ No rewrite
~15 lines
Autograd ~ Partial
~10 lines
JAX ✗ Yes - Complete
~50 lines
Enzyme-AD ✗ Yes - Complete
~50 lines
PyTorch ✗ Yes - Vectorised
~60 lines

Key JAX/PyTorch Integration Issue

JAX does not support native Python control flow inside JIT-compiled functions:

  • for loops must be replaced with jax.lax.fori_loop
  • if/else must be replaced with jax.lax.cond
  • Existing models require significant restructuring

Memory Usage

Peak memory consumption during Greeks computation

XAD
32 MB
Autograd
46 MB
AADC
68 MB
JAX
187 MB
PyTorch
241 MB
Enzyme-AD
344 MB

Key insight: AADC uses 3-5x less memory than JIT-based alternatives (JAX, PyTorch, Enzyme-AD) while delivering faster performance.

Library Comparison

Strengths and considerations for each AAD library

#2

Enzyme-AD

LLVM-based differentiation

14.37s Greeks time
330% Greeks overhead
344 MB Memory

Strengths

  • Open source (Apache 2.0)
  • LLVM-level differentiation
  • Can differentiate C++ code
  • GPU support via JAX

Considerations

  • 14x slower than AADC for Greeks
  • Requires JAX-compatible code (no Python loops)
  • Complex setup and dependencies
  • 5x higher memory than AADC
SLOW

XAD

Tape-based AAD

~840s Greeks time
12,800% Greeks overhead
32 MB Memory

Strengths

  • Open source (AGPL)
  • Simple tape-based API
  • Minimal memory overhead
  • Easy to understand

Considerations

  • 625x slower than AADC for Greeks
  • Per-scenario tape is catastrophic for Monte Carlo
  • Slower than bump-and-revalue!
  • Not suitable for production
#3

Google JAX

XLA-compiled differentiation

7.1s Greeks time
~500% Greeks overhead
187 MB Memory

Strengths

  • Open source (Apache 2.0)
  • XLA compilation for optimisation
  • Good ecosystem and documentation
  • GPU support out of the box

Considerations

  • 5x slower than AADC for Greeks
  • Model rewrite required: Must use jax.lax.fori_loop
  • 3x more memory (187 MB vs 68 MB)
  • Compilation overhead on first run

Why XAD is Slow

The fundamental problem: XAD creates a new tape for every Monte Carlo path

AADC - Record Once
# AADC: Record kernel once, evaluate all scenarios
funcs.start_recording()
S0_v = aadc.idouble(0.0)
S0_arg = S0_v.mark_as_input()

# Standard Python loop - NO REWRITE!
for t in range(num_timesteps):
    price = price * np.exp(drift + vol * Z[t])

payoff_res = payoff.mark_as_output()
funcs.stop_recording()

# Evaluate ALL scenarios + Greeks in ONE call
results = aadc.evaluate(funcs, request, inputs)
XAD - New Tape Per Scenario
# XAD: New tape for EVERY scenario - catastrophic!
for scenario in range(10000):  # 10,000 iterations!
    with xadj.Tape() as tape:  # New tape each time
        tape.registerInput(S0_ad)
        tape.newRecording()

        # Simulate single path
        payoff = simulate_path(S0_ad, ...)

        tape.registerOutput(payoff)
        payoff.derivative = 1.0
        tape.computeAdjoints()  # Backward pass

        delta_sum += S0_ad.derivative

The Key Difference

AADC records the computation graph once and evaluates all 10,000 scenarios in parallel using SIMD vectorisation. XAD creates, records, and computes adjoints for a new tape on every single path - that's 10,000 tape operations instead of 1.

Ready to Accelerate Your Greeks?

See how AADC can deliver 625x faster Greeks computation than XAD for your Python Monte Carlo models with minimal code changes.

Hardware Specification

All benchmarks executed on identical hardware for fair comparison

System Configuration

CPUIntel Xeon Platinum 8280L @ 2.70GHz
Cores28 cores/socket, 2 sockets, 112 threads
OSLinux 6.1.0-13-amd64 (Debian)

Test Parameters

Trades100
Scenarios10,000
Timesteps252
Threads4 (fair comparison)

Asian Option Monte Carlo with GBM dynamics