AAAI 2027 (submitted) · arXiv preview

Paper 1 — A Differentiable Atari 2600

Two differentiable ports of the Atari 2600 — jaxtari (JAX/Python) and jutari (Julia) — run a full VCS (6507 CPU + TIA + RIOT + cartridge banking) in a bit-exact HARD mode and a differentiable SOFT mode. The SOFT forward is straight-through, so it stays bit-identical to HARD while letting gradients flow.

paper PDF · supplement PDF · Conformance code tour → · Two end-to-end differentiable ports of the xitari VCS, validated bit-for-bit

Evidence ledger

Every claim → script → command → artifact → runtime → hardware → verifying gate.

RAM byte-identical to xitari on every game 64 / 64 measured

128 B RIOT RAM, per frame, 30 frames of NOOP from the standard ALE boot (60 NOOP + 4 RESET). Max diff 0 bytes/frame on all 64 games.

Script
tools/rom_sweep/sweep_jutari_ram.py
Command
python3 tools/rom_sweep/sweep_jutari_ram.py
Artifact
tools/rom_sweep/results_jutari_ram.md
Runtime
~9–10 s / game
Hardware
M1 Max (CPU)
Verified by
PXC1 + jutari Pkg.test()
Screen pixel-identical to xitari on every game 64 / 64 measured

210×160 palette-index framebuffer, per frame, 60 frames of breakout_random_actions after the standard boot. Max diff 0 px/frame.

Script
tools/rom_sweep/sweep_jutari_screen.py
Command
python3 tools/rom_sweep/sweep_jutari_screen.py
Artifact
tools/rom_sweep/results_jutari_screen.md
Runtime
~10 s / game
Hardware
M1 Max (CPU)
Verified by
PXC-S screen conformance
Second independent port (jaxtari) also matches 64 / 64 RAM + screen measured

The JAX port is swept against xitari with the same paradigm; PXC2 then asserts jaxtari ≡ jutari frame-by-frame.

Script
tools/rom_sweep/sweep_jaxtari.py
Command
python3 tools/rom_sweep/sweep_jaxtari.py
Artifact
tools/rom_sweep/results_jaxtari_ram.md
Runtime
minutes / game (JAX eager)
Hardware
M1 Max (CPU)
Verified by
PXC2 cross-check
SOFT forward is bit-exact to HARD (Theorem 1) byte-identical measured

The executed straight-through SOFT path is byte-identical to HARD: with relaxation off (the default), soft_rom_peek / soft_ram_peek equal the original one-hot dot product over 5,000 random peeks, and toggling a relaxed run on and back off leaves RAM and the rendered frame unchanged (no state leak). The 4-panel video only illustrates HARD ≡ SOFT-STE while a relaxed (α,T) path drifts — the proof is the regression check, not the video.

Script
tools/relaxation_study/verify_soft_ste.jl
Command
cd jutari && julia --project=. ../tools/relaxation_study/verify_soft_ste.jl
Artifact
tools/relaxation_study/video_out/divergence_si.mp4
Input data
Runtime
seconds (check)
Hardware
M1 Max (CPU)
Verified by
verify_soft_ste.jl (RAM + frame byte-identical) + the 64/64 screen sweep

The mp4 is an illustration, generated by the two input scripts. The bit-exactness is proved by the script in this row (verify_soft_ste.jl), not by the video.

GPU throughput — forward, soft mode (Pong, batched) 2.95M / 3.12M env-steps/s measured

Peak forward throughput: 2,947,553 env-steps/s on GTX 1080 Ti (batch 4096) and 3,119,115 on Quadro RTX 5000. 3000 CPU instructions/rollout, 10 repeats, batch sweep 1→65536.

Script
tools/bench_jaxtari_gpu.py
Command
python3 tools/bench_jaxtari_gpu.py --rom pong.bin
Artifact
results/gpu/gtx1080ti.json
Runtime
~10–80 s / batch config
Hardware
GTX 1080 Ti / Quadro RTX 5000 · JAX 0.10.1
Verified by
raw JSON env block (device, jax version, per-batch wall time)
GPU throughput — forward + gradient 2.80M / 2.91M env-steps/s measured

Peak forward+backward (jax.grad) throughput: 2,799,870 env-steps/s on GTX 1080 Ti and 2,911,069 on Quadro RTX 5000 (batch 4096).

Script
tools/plot_gpu_throughput.py
Command
python3 tools/plot_gpu_throughput.py
Artifact
jutari_paper/paper/figures/gpu_throughput.pdf
Input data
Runtime
plot from cached JSON
Hardware
GTX 1080 Ti / Quadro RTX 5000
Verified by
results/gpu/{gtx1080ti,q5000}.json

plot_gpu_throughput.py only reads the committed JSON and draws the curve — every plotted number traces to a measured wall time in results/gpu/*.json.

Exact-forward region in the (α, T) relaxation plane α≥6, T≤0.14 measured

The heatmap is a per-step likelihood model, Pstep(α,T) = p_read(T)ρ · p_branch(α)f_b. Its inputs are measured by running the real soft simulator (soft_step) on the Space Invaders ROM for 3,000 steps: ρ (mean instruction length), f_b (branch fraction), the actual branch-offset set and the fetched-address histogram. dump_profiles.jl writes those profiles; make_relax_heatmap.py renders the outer combination. The operating point α=6, T=0.14 is independently bit-exact-verified by verify_soft_ste.jl.

Script
tools/relaxation_study/dump_profiles.jl
Command
cd jutari && julia --project=. ../tools/relaxation_study/dump_profiles.jl
Artifact
tools/relaxation_study/relax_profiles.txt
Input data
Runtime
seconds
Hardware
M1 Max (CPU)
Verified by
relax_profiles.txt (measured); plotted by make_relax_heatmap.py

The heatmap is a model, not a per-cell brute-force scan: the closed-form p_read/p_branch are evaluated over statistics measured from a real 3,000-step soft run on the SI ROM (dump_profiles.jl). The operating point α=6, T=0.14 is separately bit-exact-verified by verify_soft_ste.jl.

XAI demo — joystick gradient recovers “push RIGHT” ±35.7 L/R · 0 up/down measured

The inverse ∂(move-right)/∂joystick is computed by Zygote autodiff through the paper's bilinear sampler: −35.73 for left, +35.73 for right, 0 for up/down — identical across all three soft variants (Theorem 1), while the naive integer-index path gives 0 in every direction. The forward ∂screen/∂RIGHT is a finite-difference directional derivative through the sampler and lights up the cannon edges. The values live in the committed ji_grad.txt; si_joystick_fig.py only plots them — it computes nothing.

Script
tools/xai_si_gradient/si_joystick_gradient.jl
Command
cd jutari && julia --project=. ../tools/xai_si_gradient/si_joystick_gradient.jl
Artifact
tools/xai_si_gradient/out/ji_grad.txt
Runtime
seconds
Hardware
M1 Max (CPU)
Verified by
ji_grad.txt identical across the 3 soft variants; figure si_joystick_gradient.pdf

The gradients are computed here, not in the figure script. Input is the real space_invaders.bin ROM (not redistributed; obtained via AutoROM), stepped to the 35 s scene for the cannon footprint. Zygote.gradient differentiates the sampler objective; the forward saliency is a central finite difference on the joystick. Outputs land in out/ji_grad.txt (committed) and out/ji_*.raw (regenerable).

XAI joystick figure (plot of the computed gradients) 2×2 panel measured

Reads the committed gradient fields/values from tools/xai_si_gradient/out/ and draws the 2×2 figure (scene, sampler saliency, naive≡0, inverse bar chart). A plotting step only — no computation. Listed separately so the figure script is not mistaken for the source of the numbers.

Script
tools/xai_si_gradient/si_joystick_fig.py
Command
python3 tools/xai_si_gradient/si_joystick_fig.py
Artifact
tools/xai_si_gradient/out/si_joystick_gradient.pdf
Input data
Runtime
seconds
Hardware
M1 Max (CPU)
Verified by
inputs from si_joystick_gradient.jl (ji_grad.txt, ji_*.raw)

Pure plotting — no data is computed here. The bar heights in panel (d) are read from ji_grad.txt; the constant wbar = 0.26 (si_joystick_fig.py:73) is only the matplotlib bar width / side-by-side offset (3 bars × 0.26 ≈ 0.78 of the unit spacing), not a data value.

Implementation-effort timeline (from git history) 769 commits on main measured

Cumulative commits / active sessions / calendar days computed directly from the repo git log up to the implementation cutoff.

Script
jutari_paper/paper/make_figures.py
Command
python3 jutari_paper/paper/make_figures.py
Artifact
jutari_paper/paper/figures/fig_timeline.pdf
Runtime
seconds
Hardware
any
Verified by
git log (public history)

Figures

Rasterised from the paper’s committed PDFs; click to enlarge.

VCS architecture

VCS architecture

CPU / TIA / RIOT / cartridge block diagram (schematic).

HARD / SOFT / STE pipeline

HARD / SOFT / STE pipeline

Dual execution paths joined by the straight-through estimator.

GPU throughput scaling

GPU throughput scaling

Env-steps/s vs batch size, two GPUs, forward & forward+grad. Built from results/gpu/*.json.

Relaxation (α, T) heatmap

Relaxation (α, T) heatmap

Per-step likelihood; the bit-exact corner and operating point marked.

XAI joystick gradient

XAI joystick gradient

Real scene, sampler ∂screen/∂RIGHT, naive≡0, inverse bar chart.

Effort timeline

Effort timeline

Cumulative commits & active sessions from git history.

Conformance gallery

Each clip is three panels — xitari (reference C++) · jutari (our port) · per-pixel difference. The difference panel stays black for the whole clip (only the “DIFFERENCE” header label is lit): byte-for-byte identical output. Verified across the full length of all 64 games; a representative selection follows.

Space Invaders

Pong

Breakout

Ms. Pac-Man

Q*bert

Seaquest

Enduro

Pitfall!

Montezuma's Revenge

River Raid

Beam Rider

Kangaroo

All 64 games render pixel-exact — see the screen sweep.

Videos

The supplement divergence clip and the narrated overview.

Supplement: HARD vs SOFT-STE vs relaxed (4-panel)

HARD | SOFT-STE | SOFT-relaxed(α,T) | diff. The HARD and SOFT-STE panels are pixel-identical (Theorem 1); the relaxed panel drifts.

Paper 1 — narrated overview

Project talk (transcoded for web).