HUGR engine overhaul: work-queue interpreter with full control flow#336
Closed
ciaranra wants to merge 394 commits into
Closed
HUGR engine overhaul: work-queue interpreter with full control flow#336ciaranra wants to merge 394 commits into
ciaranra wants to merge 394 commits into
Conversation
…ejections so a sourceless .classical()+neo reports the missing source, not the classical-override rejection
…rement-count tests to the circuit's num_measurements
…st to match the native DEM path
…tegrate-cliff-def-handoff-twirl
…liff-def-handoff-twirl
… (default Helios)
…red GateDefinitions decompositions (gate on has_decomposition in both dispatch chains) so explicit decompositions are not silently bypassed at Clifford angles
…on/module accuracy caveat (the multi-level estimator biases upward; deep-rare-event estimates are approximate), per Codex review of the remaining-work doc
…ens like the other parsers, and the two algorithm-decoder bindings return PyErr instead of panicking on empty segments or missing boundary-gate fields
…64 in the descriptor bindings (+ debug_assert and obs_bits helper at the apply site), and correct the predecoder zero-alloc docstring
… default to a single unbiased level and require explicit .allow_biased_multilevel() to engage the (biased) multi-level path, fail-fast at build otherwise; mirrored in the Python binding
…imulation: descending-sorted scores must take the survivor threshold at index p0*n (keep top p0), not (1-p0)*n (which kept the bottom and made each level's conditional ~1-p0 instead of ~p0); add a discriminating threshold test plus the previously-missing analytical-unbiasedness guard for the multi-level path
…ors on >64 observables (observable_dem_output_mask returns Result) instead of silently dropping ids >=64, and the per-shot truth-mask helper takes the validated mask
… case expansion, TailLoop expand/continue, Call frames) onto one two-phase ContainerActivation mechanism that structurally enforces reset-before-readiness
…ation reset current_block and transitions mid-flight)
…es queue at expansion (CFGs gated on readiness like Calls), body/case completion waits for them, and completed loops/CFGs run their parent-container hooks
…ed container region must be processed or provably inert, catching starvation invisible to queue bookkeeping; Call-frame resets invalidate the previous invocation's records
…ed variants (Euclidean q,r pair; m=0 faults unchecked and error-Sums checked), and itobool/ifrombool, pinned by a builder-driven executor test
… values store canonically sign-extended per width, unsigned reads mask, shifts drop past-width bits, rotates/popcnt/clz/ctz work within N bits, and widen_u zero-extends from the source width
…rame machinery for both CFG and plain-dataflow function bodies, with LoadFunction producing first-class FuncRef values), parse result labels from typed String args instead of Debug scraping, and flip conditional_x to assert clean completion with its captured result array
…driver/engine batch disagreement) instead of silently dropping them
… for pure-classical programs (results key 'return' / 'return_N'), un-xfailing the two return-capture tests
…arity, array comprehensions with literal sizes, measure_array instead of move-out-of-subscript) -- the guppy tree now has zero xfails
…rams checked against a plain-Python reference evaluator via the X-anchor trick
…ns no longer execute or clobber returns), symmetric Call/scan frame ownership with cross wake-ups, unsigned width conversions reinterpret canonical storage at the source width (iwiden_u/inarrow_u/imin_u/imax_u), and error Sums carry the spec's error payload
…oop control resolution gates on body completion, nodes_inside_cases rebuilds on reset, poison surfaces at loop entry, bare DFG containers fault loudly, pending_conditionals is a set, pending_func_calls is a deduped FIFO, dead Tag audit exemption removed
…, RandomInt/RandomIntBounded store canonically at int<5> with unsigned bound reads, RandomAdvance faults on backtracking and unboundedly large deltas, result_uint/result_array_uint bit-reinterpret canonical storage, and unresolved symbolic angles fault instead of defaulting to identity
…s not-ready (one-shot input copiers no longer fire early), case payload offsets derive from the type row, loop-continue clears stale just-input wires, LoadConstant children count in block emptiness/completion with extra pending-branch wake-ups, and empty-block/scan-passthrough chains iterate instead of recursing
…anned functions resolve load_nat), trunc_s/u range-check and canonicalize at the op's width, iu_to_s/is_to_u fault out of range per spec, shadowed divergent arms deleted (float comparisons, convert aliases, nonexistent bit-count ops) with fmax/fmin/fpow confirmed live, prelude.exit faults explicitly, and ConstUsize/ConstError constants parse
…onditional/QFT/Hadamard tests assert real distributions, backend-unavailable skips honestly, Bell/Grover pins exact), the two skip-marker constructs un-skipped (RUS while loop reports via result(), deep circuit passes), interference test pins the correct 50/50 physics, and the Python-vs-HUGR divergent regimes (negative divisors, logical shifts, past-width shifts) pinned with spec-derived expectations
… every deferred op kind, not just bool reads) and document pending_conditionals accurately
…ins, dedup on push) and the loaded Hugr lives behind an Arc so per-round and per-wave handles stop deep-cloning the graph -- guppy tree wall time drops ~60%
…utures resolve to Int (preserving leak values) instead of collapsing to Bool
…near over GF(2), so advancement is a 64x64 bit-matrix power and backtracking uses the 2^64-1 period -- the step ceiling and backtracking fault are gone, pinned by jump-vs-stepping and round-trip tests
…dispatch, naming the op and capacity instead of failing opaquely inside the simulator
…ead now validates each consumed command's qubits, via a shared check_qubit_capacity helper on both dispatchers
…fore block-output propagation (stale-iteration values starve loudly), block/CFG payload offsets derive from type-level arity, unknown transition successors poison instead of spinning past the ceiling, extension Faults skip the completion cascades, synchronously-completed scans no longer re-park as false stalls, NewRNGContext reads the seed's canonical bit pattern, pass-through ops defer on missing inputs, DFG containers flatten explicitly, and impossible scan-launch states fault loudly
…ence (bool-encoded: int result reporting is unlinked locally, and hugr-core's ishr const-folder breaks on constant past-width shifts -- both noted)
…(processed and no active container owns it) backs readiness and all four completion checks, and all_predecessors_ready becomes a method, ending the map-threading at eleven call sites
… qubit tracing: a DFG node's outputs resolve at its Output child, its Input node at the outer wires), closing the documented classical-DFG residual with a nested-DFG pinning test
…th purge-on-reactivation retention and post-replay resolver re-runs, the classical executor resolves inputs through the tracing layer (pinned end-to-end: a nested-DFG op previously deferred forever), qubit tracing crosses DFG boundaries with depth-capped recursion, Call arguments and conditional virtual payloads clear stale state before rewrite, and the fail-loud edges close (Engine::process with pending quantum work, gate modifiers, the gate-emitter catch-all, the empty-queue stall check, port-keyed return capture, global_phase deferral) with capacity-guard dispatcher tests replacing the vacuous allocation test
…ad through the DFG-tracing layer (a gate on a DFG output ran on a phantom qubit), conditional Sum payloads move to a dedicated map ending the real-port aliasing, TailLoop/Call inputs clear stale state and gain fill-only post-measurement repair, block re-activation resets descend flattened DFG interiors, replay edges carry cascade ids so within-cascade chains survive purging and only the latest cascade refills, return capture is positional at collection with signature-derived arity, and batch scheduling counts builder messages so handler-emitted commands are never dropped
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Rebuilds the HUGR engine (
crates/pecos-hugr) into a work-queue interpreter that executes guppy-compiled HUGR programs directly: CFGs (including loop cycles), Conditionals, TailLoops, function Calls, higher-order scans, and flattened DFGs, with measurement round-trips overByteMessage.Highlights
HandlerOutcome/ClassicalOutcome(Processed / Defer / Fault) with fail-loud semantics throughout — starved nodes surface in a completion-time stall report, faults poison execution, and completion runs a reachability audit (executed_containers).node_settledpredicate backing readiness and all completion checks, iterative CFG transitions with cascade-tagged measurement-replay edges (fill-only, purge-on-reactivation), and fill-only post-measurement repair for Call arguments and TailLoop initial inputs.ConstInt::value_s), Euclidean div/mod with unsigned divisors per the HUGR spec, structural DFG-boundary tracing for classical values and qubits with depth caps, and a dedicated conditional-payload map (ends virtual-port aliasing of real output ports).WorkQueue,Arc<Hugr>(guppy test tree 91s → 34s), O(log δ) xorshift64 RNG jump-ahead via GF(2) matrix powers (bidirectional).Verification
Eleven adversarial review rounds (blind multi-arm panels: Codex cross-model + fresh subagents, fused by merit), each folded in with gates:
cargo fmt,clippy -D warnings(both feature configs), full workspace tests, guppy pytest tree, repo-wide lint. Final battery: 3,918 Python tests + 10,479 workspace Rust tests, zero failures (local cuQuantum excluded — 5 environmental failures reproduce identically on dev; CI is authoritative there).Notes for reviewers
StateVecEngineauto-grows by recreating the simulator instead of routing through the guarded dispatchers (pre-existing dev behavior; documented inqubit_capacity_test.rs). A mid-session grow would silently reset quantum state — flagged for a separate decision/PR.ishl/ishrraw shifts past width); PECOS's QIS compile path inherits it until a version bump, the engine's runtime path is unaffected.🤖 Generated with Claude Code