Paper 3 of 3 · NDVM · Native Differentiable Virtual Machine

Differentiate the Evaluator, Not the Program

An Efficient Runtime Representation for Neuro-Symbolic Learning

Keep machine-proposed programs as data, get exact gradients along the realized execution trace, and make program-and-parameter co-search practical.

Lucas Sheneman Institute for Interdisciplinary Data Sciences, University of Idaho

Abstract

Neuro-symbolic learning increasingly relies on co-search: an outer search proposes executable programs while an inner optimization calibrates their continuous parameters against data. Fitting thousands of candidate programs creates a tension. Staging each program into its own differentiable graph gives up programs-as-data, while interpreter-based approaches keep programs fluid but pay heavy overhead, so parameter calibration becomes the bottleneck. We present the Native Differentiable Virtual Machine (NDVM), a runtime representation that keeps programs as runtime data while providing exact reverse-mode gradients along the realized execution trace. By separating symbolic structure from differentiable numeric state, NDVM amortizes a single interpreter walk across large populations of parameter vectors. It cuts per-lane calibration cost by about 60× through batch amortization, scales near-linearly across CPU cores, and generalizes across front ends, including both a differentiable Scheme interpreter and a differentiable stack-bytecode VM. In a fixed-budget search over LLM-proposed programs, NDVM reaches high-quality solutions about 24× sooner in wall-clock time and explores substantially deeper.

This page is the paper's companion, the third chapter of the Neural Compiler → DMCI → NDVM program. Every chart in the Evidence section is drawn from the paper's measured results (a single CPU node; code frozen at tag paper-ndvm-arxiv). The arXiv link will be added when the paper posts.

program as data P(θ) native differentiable VM one evaluator · exact tape · batched payloads loss  L ∇θ, gradients reach the constants inside the program
Figure 1. The interpreter stays the differentiable object; NDVM makes it a fast native VM. One evaluator is built and verified once, and every program it runs is supplied as input data. Discrete structure stays scalar, numeric payloads carry the batch, and exact gradients still reach the learnable constants θ inside the program, with no per-program staging, no custom adjoints, and no branch smoothing.
What is actually new?
Staged differentiable graphs compile every candidate program
vs
NDVM one fast evaluator, programs stay data

Co-search proposes, mutates, and discards thousands of structurally distinct programs. NDVM keeps them as runtime data and makes the one differentiable evaluator fast: exact-gradient calibration becomes cheap enough to sit inside the search loop.

1 · The problem

The cost is representation, not arithmetic

Before proposing anything, the paper locks a cost model of the system it replaces: DMCI's eager PyTorch backend, profiled on one CPU core over five programs spanning a 2,300× range of cost, from a scalar expression to an 80-step Kalman-filter rollout.

85–90%
of forward time is representation: value boxing (49–61%) plus evaluator walking (25–40%)
≈1%
is raw arithmetic, including the Kalman filter's 2×2 inverses, determinants, and matrix products
<≈4%
change in forward time from B=1 to B=1024: the walk is paid once, regardless of batch width
281×
fewer allocations: one Kalman forward boxes 273,238 tagged tensors where NDVM needs 972 payload slots

Phase-0 cost model of the eager backend.

Where an interpreter's time goes

An interpreter that keeps the program as data must represent, at runtime, every intermediate value the program produces: not just numbers but tags, symbols, pairs, addresses, and closures. In an eager tensor framework the natural encoding is a small tagged tensor per value, and that encoding, not the floating-point work, is where the time goes. A single forward pass of the 80-step Kalman likelihood issues about two million value-boxing calls against roughly three thousand arithmetic calls.

The same profile shows forward time is essentially independent of how many parameter vectors are evaluated at once: widening the payload 1,024× changes forward time by under about 4%. The marginal cost of one more batch lane is the dense arithmetic and nothing else.

The diagnosis, and the target

If 85–90% of the cost is how values and control are represented, and batching is nearly free, then the right move is not to compile each program away into its own graph. It is to make the interpreter itself fast, keep programs as data, and let one structural walk carry an entire population of parameter vectors.

2 · The idea

Split structure from numbers

Discrete structure is never differentiated, so it becomes native scalar data. Numbers are the only differentiable quantities, so they get dense buffers that carry the batch axis. Control flow stays discrete and exact; the reverse pass records payloads only.

eager backend: boxed tagged tensor every value = one [B × 14] tensor lane 0 lane 1 ⋮ ⋮ B lanes, on every value ⋮ tag one-hot (10) payload (4) a symbol, an address, a boolean: each still allocates a full tagged tensor 49–61% of forward time is this boxing vs NDVM: structural / numeric split structural value = one scalar record tag aux pid type · symbol / address / closure id payload index dense payload table, leading axis B primal [B] adjoint [B] tags, symbols, addresses stay scalar; only numbers pay for the batch one structural walk serves all B lanes control flow = the exact realized trace · no branch smoothing · per-lane masks when lanes diverge
Figure 2. The structural/numeric split. Left: the eager backend boxes every runtime value, numeric or not, as a [B × 14] tagged tensor. Right: an NDVM value is a scalar record 〈tag, aux, pid〉; only numeric values point (via pid) into a dense payload table whose leading axis is the batch, with separate primal and adjoint buffers. Non-numeric values allocate no tensor at all.

Structural values, scalar

Tags, interned symbols, heap addresses, closures, and environments are native scalar data. The heap is a write-once arena (the modeled subset excludes mutation): cons appends a cell, car/cdr are direct loads. None of it is differentiable; none of it allocates tensors.

Control: the exact realized trace

Branch predicates, tag tests, and dispatch are discrete routing decisions, never smoothed. Gradients are exact on the trace that actually executed; when lanes of a batch diverge at a numeric branch, per-lane masks keep every lane's result correct. A parameter that appears only in a predicate honestly receives no gradient through it.

Reverse pass: a payload-only tape

The forward pass appends a tape node only for differentiable numeric primitives (add, multiply, exp, matmul, reduce, and so on). Symbol lookups, tag tests, allocation, and branch dispatch emit nothing. Tape size tracks the numeric work actually done, not program size or interpreter recursion depth.

The defining invariant

Make the interpreter fast without compiling away the interpreted program. NDVM unrolls the evaluator's instruction stream, never the object program: the runtime memoizes decoding and variable lookups but never residualizes a program into its own graph. That is what separates it from staging and partial evaluation, and it is why any program the search proposes inherits gradients immediately.

3 · The payoff

Co-search: an LLM proposes, NDVM calibrates

In program-and-parameter co-search, an outer loop such as OpenEvolve (Sharma, 2025), an open-source implementation of DeepMind's AlphaEvolve approach (Novikov et al., 2025), proposes discrete program structures, and an inner loop calibrates each candidate's continuous constants by exact gradients. The program page introduces the concept; this section measures what NDVM changes: the inner loop stops being the bottleneck.

discrete structure search continuous parameter search LLM / OpenEvolve propose program structure NDVM exact-gradient calibration evaluate held-out skill program as data fitted constants fitness → select best structure, refine, repeat
Figure 3. The co-search loop with NDVM as the inner engine. Because gradients are exact on either backend, a candidate fits to the same parameters on NDVM as on the eager backend; the speedup is the same optimization run faster, not a change in what each fit finds.
8,144.1×
one Kalman MLE calibration: DMCI 211,277.2 ms → NDVM 25.94 ms, bit-identical NLL trajectory
138,769
calibrations per CPU-hour on NDVM, against 17 on the eager backend
23.8×
frontier shift on the scalar task: 42,289 vs 1,778 calibrations in a fixed 900 s budget
339.8×
frontier shift on the recurrence-heavy task: 39,759 vs 117; the eager backend never reaches a successful fit

Discovery frontier and per-calibration throughput, measured on a single CPU node.

The Amdahl honesty

The inner fit is 96.8% of per-candidate wall-clock on the eager backend; NDVM drops that share to 0.654, so calibration stops being the bottleneck and the model-proposal step becomes the next floor. With a live LLM at 0.5 s per candidate the end-to-end gain is 405× (108× at 2.0 s): the loop becomes LLM-bound. The paper reports calibration throughput as the headline and the end-to-end number as Amdahl-bounded, not as an unbounded discovery speedup.

Scope of the measurement

Both fixed-budget searches replay offline-cached streams of LLM-proposed programs, compile-validated on both backends in advance, so the proposing model is out of the timed loop and the two backends see the identical candidate stream. Each candidate has a distinct structural skeleton, the regime where per-candidate staging would have to restage every one.

The science case studies of this research program, battery capacity-fade knee recovery, the LIM-ENSO Kalman-filter MLE, and the FluZoo negative result, are results of the DMCI paper, not of NDVM: see co-search on the DMCI page. NDVM's claim is narrower and mechanical: the same calibrations, orders of magnitude cheaper.

4 · Evidence

Measured results

All charts are drawn from the paper's committed results (a single CPU node, float32, code at tag paper-ndvm-arxiv). Hover for exact values.

1Throughput becomes discovery

Same candidate stream, same 900-second budget, two backends. NDVM reaches its first held-out R² > 0.9 at 12.2 s on the scalar task (the eager backend needs 288.2 s) and finishes at R² 0.9962 vs 0.9691. On the recurrence-heavy task the eager backend completes only 117 calibrations and never reaches a successful fit.

Discovery frontier: best held-out R² vs wall-clock
loading…

2One walk carries the population; cores carry the candidates

Batch-native execution keeps the structural walk scalar and widens only the payloads, so per-lane cost falls as B grows: about 60× on the native path from B=1 to B=256, and about 21× when measured through the PyTorch autograd boundary, as plotted here. Independent candidates additionally fan out across cores near-linearly.

Batch amortization: cost vs batch size B
80-step Kalman NLL, forward + gradient, through the autograd boundary · log-log
Multicore strong scaling
candidate-level parallelism, byte-identical to serial · 14.92× on 16 cores (93.3% efficiency); the 64-thread point uses SMT logical threads on the 32-core node

3The inner loop, as throughput

The robust, schedule-independent headline is how many candidate programs a fixed compute budget can calibrate. Both backends run the same 30-step Adam fit to a bit-identical NLL trajectory; the difference is purely runtime representation and native execution.

Calibrations per CPU-hour, log scale
Kalman/LIM maximum-likelihood fit, 30 Adam steps

What the one big number conflates

The raw forward speedup of the native runtime over the eager backend mixes two effects. A tuned-eager baseline disentangles them: removing the boxed representation alone is worth about 4–5× in eager Python, and native execution is the residual, about 8× to 2,133× on top, growing with rollout depth. The clean claims are exact-gradient equivalence, the batch multiplier, and this decomposed speedup.

Correctness is checked continuously: the native runtime reproduces the frozen reference backend's forward outputs and per-parameter gradients across the program suite, including the 80-step Kalman rollout's noise-covariance gradients through the matrix-adjoint path.

5 · Generality

Two independent clients, one runtime

NDVM is a runtime representation, not a faster DMCI. Two clients with different dispatch models share the same 120-line value and autodiff interface: the DMCI tree-walking evaluator, and a differentiable stack-bytecode VM that adds only 219 lines of its own.

A differentiable stack-bytecode VM

The second client is a linear instruction stream with an explicit operand stack and 15 opcodes:

PUSH LOAD ADD SUB MUL DIV NEG EXP LOG SIN COS DUP LOOP BRANCH DOT

It contains no DMCI parser or evaluator code; it imports only the structural/numeric-split value box. Against a naive baseline that fuses every stack value into a single tagged tensor, the split is 1.77–3.34× faster single-lane, and because one walk over the instruction stream serves all lanes, per-lane cost falls about 240× from B=1 to B=256. Gradients are bit-identical to reverse-mode autodiff and agree with central finite differences on every leaf.

Table 1. Second client, forward + backward median wall time (a single CPU node).
workloadfused eager, B=1 (ms)split, B=1 (ms)split per-lane, B=256 (µs)speedup
W1 scalar expression0.2970.1240.5122.39×
W2 counted loop1.3870.4301.7753.23×
W3 branch0.1360.0760.3081.77×
W4 matrix-vector0.6680.2000.8243.34×

Randomized differential testing

A randomized differential tester compares the native runtime against the frozen reference backend over the supported language surface, gating forward outputs, gradients, and central finite differences: 600/600 checks pass at the primary seed and 1500/1500 on a second seed. The same tester documents the precise boundary of the supported subset.

6 · Scope

When NDVM wins, and when it does not

The paper states its own crossover points. NDVM is the right tool in the co-search regime; outside it, other engines are.

NDVM wins when, together:

  • Many structurally distinct candidate programs run through one fixed evaluator, so nothing can be staged and reused.
  • Each candidate is fitted for only a handful of gradient steps before it is mutated or discarded.
  • Representation and control dominate the numeric work, as the Phase-0 model measures (85–90% of forward time; arithmetic about 1%).

It does not win when:

  • A fixed program is reused for thousands of optimizer steps: per-candidate staging amortizes and overtakes NDVM after roughly 213 to 42,000 steps per candidate (co-search does far fewer). Cached-template staging overtakes only above about 80 constant-only reuses per skeleton.
  • Control diverges heavily across the population: lane masking stays correct, but each side of a divergent branch is walked under its active lanes, so the single-walk amortization erodes toward per-lane cost.
  • Dense numeric kernels dominate: high-dimensional, throughput-bound work belongs in numeric libraries and accelerators, not in the VM.
  • The program needs features outside the supported surface: the heap is a write-once arena, with no mutation, no exceptions, and no first-class continuations.
7 · Roadmap

What is measured, and what is future work

The gap between what is measured and what remains designed is the most important thing for a reader to calibrate.

scope All interpreter results are CPU

The measured workload is allocation- and control-bound, the regime where a latency-optimized core beats a throughput-optimized accelerator. NDVM is a CPU-native runtime by design; a GPU appears only as a forward-only numeric-ceiling proof of concept in an appendix, with no interpreter dispatch, heap, tape, or gradient.

future GPU interpreter

The persistent-kernel evaluator that would run the structural walk on the device under warp-ballot lane masks is designed, not built. Its branchy structural walk is the real risk on a GPU, so the paper gates the claim behind that measurement rather than making it.

future MLIR / Enzyme lowering

An optional compiler lowering of the evaluator through MLIR or Enzyme is named as future work. The baseline semantics must keep working without it: programs remain runtime data.

future Formal gradient-correctness proof

Property 1 (trace-constant gradients) is stated as intended semantics and validated empirically against the frozen reference backend across the program suite; it is not a machine-checked theorem. A formal operational semantics and proof are planned.

Resources

Read it, run it, cite it

The code, the profiling harness, the differential tester, and the second-client demonstrations are released; paper-ndvm/REPRODUCE.md maps every figure and table to a script. The paper is on arXiv at arXiv:2607.03574.

See the full Neural Compiler → DMCI → NDVM lineage on the program page.

Cite this paper

@article{sheneman2026ndvm,
  title         = {Differentiate the Evaluator, Not the Program:
                   An Efficient Runtime Representation for Neuro-Symbolic Learning},
  author        = {Sheneman, Lucas},
  year          = {2026},
  journal       = {arXiv preprint arXiv:2607.03574},
  eprint        = {2607.03574},
  archivePrefix = {arXiv},
  primaryClass  = {cs.LG},
  doi           = {10.48550/arXiv.2607.03574}
}
Brainstorm