← learnModule 0 · Orientation: one sweep, every Greek3 min read

A map of the engine

Five layers, one tape: where record-once/replay-twice actually lives in the codebase, before you write a line of it.

The last page was the idea. This page is where that idea actually lives — one picture of the whole codebase, so that when a later module drops you into nablatensor-quant or nablatensor-risk, you already know which floor of the building you're on.

The whole story

A map of the engine: nablatensor-core records ADouble operations onto a tape; six interchangeable engines (cpu, cpu-jit, simd, vulkan, rocm, cuda) replay that tape; nablatensor-quant turns a replay into a price; nablatensor-risk turns many prices into one number; the regulatory layer turns that into the number a bank files.

Did you know?

Every GPU backend compiles and links whether or not its toolchain is even installed, then gates itself at runtime through AadEngine.isAvailable() — none of them is a build- or test-time dependency of the default cpu-jit path. That's why mvn -o test is green offline, on a laptop with no GPU and no native library installed: every GPU engine politely reports itself unavailable instead of failing anything.

Five layers, bottom to top

The core: ADouble and the tape

nablatensor-core holds the ADouble type from the last page, the AadRecorder that builds a tape as your code runs, and the AadTape that results. Nothing here knows what an option or a bank is — it only knows how to record arithmetic and replay it, forwards or backwards.

Six engines, one tape

The tape doesn't care which engine replays it. cpu is the scalar interpreter — slow, dependency-free, and treated as the oracle every other engine is checked against. cpu-jit compiles the tape into straight-line JVM bytecode and is the default. simd replays it across the JDK's Vector API lanes. vulkan, rocm, and cuda each compile the tape into a fused GPU kernel — GLSL→SPIR-V, HIP via HIPRTC, and CUDA via NVRTC, respectively — and only run if that vendor's driver is actually present. Same recording, six different ways of running it; the choice is one string, .on("cpu-jit") or similar, not a rewrite.

Did you know?

Those six engines aren't the same code recompiled six times — they're three genuinely different compilers pointed at the same tape. cpu-jit emits JVM bytecode through the Class-File API; Vulkan hands the same tape to a GLSL→SPIR-V compute shader pipeline, the kind a game engine uses; ROCm generates HIP C++ and compiles it with HIPRTC while the JVM is already running. cpu-jit reproduces the scalar oracle bit-for-bit; the fp32 GPU paths agree with it to five decimal places.

Quant: turning a replay into a price

nablatensor-quant is where finance enters: EquityMarket, Products, MonteCarlo, model families like HestonModel and SabrModel, and a gradient-based Calibrator. This is the layer Module 1 through Module 8 mostly live in — payoffs, models, calibration.

Risk: turning many prices into one number

nablatensor-risk takes the sensitivities that fall out of one trade's tape and combines them across a book: RiskFactor, Sensitivities, Portfolio, and NestedAggregation — the same √(ΣK² + Σγ·SS)-shaped aggregation both FRTB and ISDA SIMM specify. Module 9 lives here.

Regulatory: the number a bank actually files

The top of the map isn't a separate module in the source tree — it's nablatensor-quant and nablatensor-risk composed to match a specific regulation's text: FRTB capital, SA-CVA, ISDA SIMM, SA-CCR, and the rest of Module 10. NablaTensor computes the arithmetic a regulation asks for; as its own README puts it, "sign-off is yours."

Try it yourself

Open ADouble.java and count how many arithmetic methods it exposes — add, mul, exp, and so on. Every one of them is a node type the reverse sweep in Module 1 knows how to differentiate. There's nothing hidden past what you can see in that one file.

▶️ Run it

Still nothing to run — Module 1 is next, and it starts with the file you just opened.

⚠️ What this doesn't do

This map skips the seams — custom ops, hooks like antithetic sampling, the scenario DSL, netting — the places you can extend or reconfigure one layer without touching the others. Those show up alongside the modules that actually use them, not here.

What's next

→ Deeper: the engine's own README lists every module in the box, in more detail than fits on one page. → Next: ADouble, the number that remembers, where the code starts.


Questions or corrections? open an issue