Core mechanism
Backend code generation translates the same primitive operations and adjoint rules into device kernels. Results are compared to the CPU reference before performance is considered.
Java prices the CPU reference from the editable tape inputs. The four GPU kernel languages and precision requirements are shown for comparison; their runtimes are unavailable in this browser build, so no GPU result or parity is invented.
CPU reference defaults to 20,000 scenarios for an interactive browser run.
This exact source runs in TeaVM. Form changes update its Java literals and reset manual edits.
import com.nablatensor.quant.EquityMarket;
import com.nablatensor.quant.MonteCarlo;
import com.nablatensor.quant.Products;
public final class GpuPortabilityReferenceRiskStudio {
private GpuPortabilityReferenceRiskStudio() {}
public static void main(String[] args) {
EquityMarket market = EquityMarket.of()
.spot(100.0)
.strike(100.0)
.vol(0.20)
.rate(0.03)
.maturity(1.0)
.build();
int steps = 64;
long scenarios = 20000L, seed = 42L;
try (MonteCarlo<EquityMarket> mc = MonteCarlo.of(Products.asianCall())
.market(market)
.steps(steps)
.fp64()
.greeks()
.on("cpu")
.build()) {
var value = mc.run(scenarios, seed);
System.out.println("RESULT|" + mc.nodes() + "|" + value.price() + "|" + value.greek(EquityMarket::spot)
+ "|" + value.scenariosPerSecond());
}
}
}
GPU targets differ in kernel language and runtime, but a recorded tape gives them a common computational contract.
Backend code generation translates the same primitive operations and adjoint rules into device kernels. Results are compared to the CPU reference before performance is considered.
Verify device discovery and numerical parity, profile transfer and kernel costs separately, keep driver/runtime versions observable, and maintain a tested CPU fallback.
*Keywords: asian option monte carlo java, gpu monte carlo greeks, java vector api monte carlo, adjoint aad asian option*
An arithmetic-average Asian call has no closed form, so its risk is normally a bump-and-revalue grid. Here it is one recording, one adjoint sweep, replayed on every backend the machine has — same tape, same seed, same numbers to Monte-Carlo noise; only throughput changes.
Every engine agrees on price and Greeks to the digits shown; cpu-jit reproduces the scalar cpu oracle bit-for-bit (see validation). This box has an AMD APU, so rocm runs a real HIP GPU kernel at fp64; on an APU that is only ~1.2× the SIMD path — a discrete card, or the fp32 shaders below, is where the GPU pulls ahead.
The AadEngines.available(...) filter above is fp64, so vulkan and cuda (both fp32-only) don't appear. At fp32 the picture on this box:
cuda has no device on this box. On a Colab Tesla T4, notebooks/engine-benchmark.ipynb — a heavier workload (a 4057-node barrier tape, not this 1536-node Asian) — runs cuda at 1.3×10⁷ value+5-Greeks scenarios/s (≈ 1.4× the same T4's opencl), i.e. in the vulkan / rocm tier. Not directly comparable to the rows above; re-run the notebook on a GPU runtime for the exact figure.
A common graph does not eliminate platform differences. Hardware capability, precision support and deployment constraints remain backend-specific.