open-standards/wai/wai-quantum/examples/tracker_ole.rs
Transaction Science 72145ce6f9
All checks were successful
WAI conformance / does this change touch it (push) Has been skipped
WAI conformance / cargo-class corpora · linux (push) Has been skipped
WAI conformance / cargo-class corpora · linux-arm64 (push) Has been skipped
WAI conformance / cargo-class corpora · macos (push) Has been skipped
WAI conformance / cargo-class corpora · windows (push) Has been skipped
WAI conformance / fast integer kernels, every x86_64 kernel set (AVX-512 silicon) (push) Has been skipped
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (push) Has been skipped
WAI conformance / faces from keypoints under wasm32-wasip2 (wasmtime) (push) Has been skipped
WAI conformance / v2 vocabulary · manifests validate as stated (push) Has been skipped
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (push) Has been skipped
WAI conformance / independent verifiers · every verifier step, each corpus's Rust side (push) Has been skipped
WAI conformance / each feature of the independent verifiers' steps compiles alone (push) Has been skipped
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (push) Has been skipped
WAI conformance / cross-arch byte-equality · linux (push) Has been skipped
WAI conformance / cross-arch byte-equality · linux-arm64 (push) Has been skipped
WAI conformance / cross-arch byte-equality · macos (push) Has been skipped
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (push) Has been skipped
WAI conformance / C2PA manifest emission · signed, read back, validated (push) Has been skipped
WAI conformance / independent verifiers · each needs= is what a run without packages shows (nightly) (push) Has been skipped
WAI operation catalogue / does this change touch it (push) Successful in 1m1s
wai-quantum pulse and dynamics / does this change touch it (push) Successful in 1m20s
wai-quantum OpenQASM reader / does this change touch it (push) Successful in 1m22s
wai-quantum resource estimation / does this change touch it (push) Successful in 1m22s
wai-quantum for JavaScript / does this change touch it (push) Successful in 1m23s
wai-quantum docs, course and locales / does this change touch it (push) Successful in 1m23s
wai-audit collector and player integration / does this change touch it (push) Successful in 1m37s
wai-quantum other formats / does this change touch it (push) Successful in 1m25s
wai-quantum for Python / does this change touch it (push) Successful in 1m18s
wai-quantum contract / does this change touch it (push) Successful in 2m50s
wai-quantum service / does this change touch it (push) Successful in 1m40s
wai-quantum extension points / does this change touch it (push) Successful in 1m44s
wai-quantum command line / does this change touch it (push) Successful in 3m8s
wai-quantum studio and desktop / does this change touch it (push) Successful in 1m46s
wai-quantum variational and algorithm library / does this change touch it (push) Successful in 1m46s
wai-quantum verdicts and repairs / does this change touch it (push) Successful in 1m47s
wai-quantum error correction and mitigation / does this change touch it (push) Successful in 1m53s
wai-quantum views in agent hosts / does this change touch it (push) Successful in 1m47s
WAI Studio / does this change touch it (push) Successful in 59s
wai-sink-android native sink library / does this change touch it (push) Successful in 1m55s
wai-quantum clippy / does this change touch it (push) Successful in 4m26s
wai-quantum editors / does this change touch it (push) Successful in 5m18s
wai-quantum pulse and dynamics / the same bits · macos (push) Successful in 3m34s
wai-sink-swift native sink package / does this change touch it (push) Successful in 4m43s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 2m20s
wai-quantum command line / command line · macos (push) Successful in 3m20s
wai-quantum service / service energy · linux packages (push) Successful in 8m59s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 14s
WAI examples / WAI examples · does this change touch them (push) Successful in 14s
wai-quantum wasmQ / does this change touch it (push) Successful in 12s
WAI conformance / a push to main · corpus provenance and sidecars, signer ids, the registry export (push) Successful in 1m4s
wai-quantum service / service · macos (push) Successful in 8m12s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 5m33s
wai-quantum pulse and dynamics / reader, simulator and pulse jobs under wasm32-wasip2 (wasmtime) (push) Successful in 3m0s
wai-quantum pulse and dynamics / the same bits · linux-arm64 (push) Successful in 7m42s
wai-quantum editors / editors · macos (push) Successful in 1m59s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 10m31s
wai-quantum OpenQASM reader / corpus under wasm32-wasip2 (wasmtime) (push) Successful in 1m52s
wai-quantum pulse and dynamics / reader, simulator and pulse jobs · linux, release (push) Successful in 4m5s
wai-quantum docs, course and locales / the Studio's words in every locale · linux (push) Successful in 13s
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux-arm64, release (push) Successful in 4m10s
wai-quantum OpenQASM reader / reader and corpus · linux (push) Successful in 5m9s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 8m44s
wai-quantum for Python / python · macos (push) Successful in 14m49s
wai-quantum other formats / the set under wasm32-wasip2 (wasmtime) (push) Successful in 2m46s
wai-audit collector and player integration / collector · linux (push) Successful in 5m8s
wai-quantum contract / the policy is linked, and the deprecations page reads (push) Successful in 17s
wai-quantum docs, course and locales / the course and the command line's languages · linux (push) Successful in 8m34s
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · macos (push) Successful in 5m51s
wai-quantum other formats / readers, writers and the set · linux (push) Successful in 8m34s
wai-quantum for JavaScript / javascript · linux (push) Successful in 11m31s
WAI Studio / Studio in Chromium and Firefox · macos (push) Successful in 15m31s
wai-quantum extension points / the registry under wasm32-wasip2 (wasmtime) (push) Successful in 5m22s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 17m18s
wai-quantum contract / API compatibility · linux (push) Successful in 8m40s
wai-quantum for Python / python · linux (push) Successful in 11m36s
wai-quantum extension points / the registry and the example · linux-arm64 (push) Successful in 22m27s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 21m15s
wai-quantum verdicts and repairs / the intent set and the verdict under wasm32-wasip2 (wasmtime) (push) Successful in 3m51s
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux, release (push) Successful in 4m6s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 1m14s
WAI examples / WAI examples · android-app · linux-arm64 (push) Successful in 19m9s
wai-quantum studio and desktop / studio · browser (push) Successful in 7m37s
wai-quantum verdicts and repairs / verdicts, repairs and the intent set · linux (push) Successful in 6m50s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 21m21s
wai-quantum extension points / the registry and the example · linux (push) Successful in 13m41s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 12m53s
wai-quantum resource estimation / estimation and calibration · linux, release (push) Successful in 21m40s
wai-quantum wasmQ / the reference modules rebuild to their modules of record · linux (push) Successful in 48s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 10m7s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 3m58s
wai-quantum views in agent hosts / views · the page and its engine (push) Successful in 8m43s
wai-quantum views in agent hosts / views · a scripted host (push) Successful in 8m26s
wai-quantum error correction and mitigation / codes, decoders, texts and mitigation · linux, release (push) Successful in 9m18s
wai-quantum clippy / clippy, warnings denied, every feature set · linux (push) Successful in 6m3s
wai-quantum contract / schemas and the committed tool lists · linux (push) Successful in 19m32s
wai-quantum editors / editors · linux (push) Successful in 7m22s
wai-quantum service / service · linux (push) Successful in 20m11s
wai-quantum wasmQ / interpreter and vectors under wasm32-wasip2 (wasmtime) (push) Successful in 6m34s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 11m33s
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · linux (push) Successful in 10m43s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (push) Successful in 32m24s
wai-quantum command line / command line · linux (push) Successful in 34m57s
WAI Studio / Studio in WebKit · linux (push) Successful in 28m32s
WAI examples / WAI examples · portable · linux (push) Successful in 28m33s
wai-quantum docs, course and locales / every command and snippet in the docs · linux (push) Successful in 53m22s
WAI Quantum: the tracker's 49-qubit operator Loschmidt echo corrected loop by loop around belief propagation, and the four fast receipts sealed with the operator's key again
quantum_bptn::clusters (written from J. Gray, G. Park, G. Evenbly,
N. Pancotti, E. F. Kjonstad and G. K.-L. Chan 2025, and S. Midha and
Y. F. Zhang 2025): Tns::expect_region_bp contracts any region exactly with
belief propagation's messages on its boundary, which is the loop series
restricted to the region summed to every order. Each piece is contracted
from the leaves of a spanning tree to a root, the bonds the tree leaves out
cut and summed over their ket and bra indices; every set of cuts that
leaves a spanning tree (up to 20,000) is tried with every root against an
estimate of the work and of the tables' memory, and the cheapest whose
tables fit in 16 GiB is taken (RegionPlan). On the 49x648 echo at chi = 64
that halves the largest three-ring region's work (1.0e15 -> 4.9e14) and
cuts another's by 4.5 (8.3e13 -> 1.8e13) against cutting the smallest bonds
of a spanning tree of the largest. Combinations are summed as they come,
each sum in a fixed order and each rescaling by a power of two: the same
bits at any worker count and on every platform. Also loop_weight (a ring's
own correction Z_l, the loop correlation check), counting_numbers and
loop_cluster_terms (Gray et al.'s Algorithm 1), cluster_combine (product
and sum formulas), short_cycles and cell_unions.

tracker_ole mode loops: the arc through the observable's sites (order 0),
then order k = the observable's ring F joined with every connected set of
k - 1 other rings, closed under intersection and counted; regions past the
run's work or memory budget are left out and named, and the order over the
regions read is reported beside it.

49x648, chi = 64, 96, 128, 160, 192, 256, 320 (summed discarded weight
0.088 to 0.0015): order 1 (F exact) is the fast sweep's loop readout, the
arc its arc bit for bit. Order 2 (F joined with D and with E, the two rings
sharing a path with it) adds +0.0019, +0.0026, +0.0031, +0.0034, +0.0036,
+0.0039, +0.0040, growing with chi, a nineteenth to a twelfth of what order
1 adds to the arc; at chi = 320 it reads 0.8235. On a line in the discarded
weight through the last three chi (residual 3e-6) order 2 meets none
discarded at 0.82251 (order 1: 0.81845, as before). The ring D gives almost
all of it (DF over F +0.20 % at chi 64, +0.46 % at 320). Each ring's own
Z_l is at most 2.8e-4 in size and falls with chi.

Order 3 not reached: of its five three-ring regions only BDF fits the
budgets run (6e12 to 2e13 multiply-adds), and it moves the value by at most
2e-10; at chi = 64 the others need 1.8e13 to 4.9e14 multiply-adds (ADF's
tables 309 GB, past every host's cap), above chi = 64 1.4e14 to 1.2e16.
Error estimate, with its assumption: if each order adds the same fraction
of the one before as order 2 does of order 1 (Aitken's delta-squared on
arc, order 1, order 2), the orders not run add 1.0e-4 at chi = 64 and
3.5e-4 at chi = 320, and the estimate extrapolates to 0.82287. That is an
estimate, not a bound, and it is not tested against a third order here.
Published: device 0.824, belief-propagation tensor networks 0.8203 (bond
192) and 0.8217 (bond 512), single-path Monte Carlo 0.808.

49x1296 and 70x1872: not converged (summed discarded weight 13 to 29), and
order 2 there needs 6e13 to 1e14 multiply-adds at chi = 32, 1.6e15 at 48
and 1.6e16 at 64 (plan-only runs); the expansion corrects contraction, not
truncation, so it cannot make those readings bound the echo.

At chi = 96 all 24 numbers of the expansion have the same bits on Linux
x86_64 (32 workers) and macOS arm64 (16 workers).

Receipts: 49x648 loops at chi 96 and 128 sealed with the operator's key on
Linux x86_64; chi 64, 160, 192, 256 and 320 with the demonstration key on
macOS arm64. The four fast receipts cb44dd4a8 re-sealed with the
demonstration key (49x648 chi 64 and 96, 49x1296 and 70x1872 chi 64) are
sealed with the operator's key again: re-run on Linux x86_64 in their
committed settings, each request equal to the committed one and every
number in each result the committed bits.

Tests: clusters unit tests (a region holding every loop is exact whatever
its cuts; worker-count bits; the cuts chosen cost no more than the largest
bonds' tree's); tracker_reference: on a ladder of three squares order 2 is
nearer the network's exact contraction than order 1 in four trials of six
(summed distances: arc 3.43e-3, order 1 2.89e-3, order 2 1.85e-3), and the
49x648 loops receipts pinned.

Change note: wai/changes/2026-11-14-wai-quantum-ole-loop-cluster-expansion.md.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-14 08:34:52 -05:00

443 lines
27 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! The tracker's operator-Loschmidt-echo instances by sparse Pauli dynamics,
//! against the device values and the classical values published for them.
//!
//! `cargo run --release --example tracker_ole --features quantum_engine,quantum_receipt,quantum_spd_receipt,quantum_bptn,quantum_mpsim -- <tracker checkout> <instance> <method> [setting ...]`
//!
//! `instance` is `49x648`, `49x1296` or `70x1872`. Each circuit `W` is written
//! `U · V · U†` on a 156-qubit register, `U` the Trotterised Ising evolution of
//! the instance and `V` the perturbation; its echo is
//! `f = 2⁻ⁿ Σ_z ⟨z|O|z⟩ ⟨z|W† O W|z⟩` for `O = Z₅₂ Z₅₉ Z₇₂`, which the device
//! estimates from random basis states. Two methods, each swept:
//!
//! - `spd [threshold ...]`: sparse Pauli dynamics ([`echo`]) carries `O`
//! through the last third only and takes the overlap after the
//! perturbation, an exact identity, so each value comes with a bound on what
//! truncation moved.
//! - `bptn [χ ...]` and `bptn-gauged [χ ...]`: the echo as one state on twice
//! the qubits (each qubit's ancilla in a Bell pair with it, `W` on the
//! qubits, the ancillas' `Z`s folded onto theirs), evolved as a tensor
//! network on the coupling graph by simple update (`bptn-gauged` re-gauges
//! into the belief-propagation gauge after every layer), and read as `Z₅₂ Z₅₉
//! Z₇₂` with the 12-qubit loop that holds the three contracted exactly.
//!
//! - `mpo [χ ...]`: the circuit's operator as a matrix-product state on row
//! and column sites, grown outward from the perturbation's centre, so that
//! it starts as `V` (a product, near the identity) and grows only by `V`'s
//! dressing; the echo is `⟨⟨W|(O ⊗ O)|W⟩⟩` on it.
//!
//! - `fast [χ ...]`: `bptn` with the dense blocked linear algebra
//! (`Tns::with_blocked_linalg`), for bonds in the hundreds; read around the
//! loop (while its bonds are small enough), and along the loop's arc through
//! the three sites with belief propagation's environment and with the bond
//! weights'. `fast-zero` is the same circuit without its middle, whose exact
//! echo is 1: the divisor of the published "rescaled" values.
//!
//! Settings for these two, from the environment: `OLE_THREADS` (workers),
//! `OLE_BP_SWEEPS` and `OLE_BP_TOL` (the readout's belief propagation; 0
//! sweeps reads with the bond weights alone), `OLE_LOOP_MAX` (the largest
//! bond the loop readout is run at).
//!
//! A value is converged only where its sweep stops moving it.
//!
//! Each run writes a signed receipt to `RECEIPTS_DIR` (default `receipts`).
#[path = "tracker/common.rs"]
mod common;
#[path = "tracker/echo.rs"]
mod echo_net;
#[path = "tracker/operator.rs"]
mod operator;
use serde_json::json;
use wai_quantum::quantum_bptn::Tns;
use wai_quantum::quantum_spd::{Pauli, SpdConfig, echo, echo_split};
/// Published values: (what produced it, the value, the tracker submission it is from).
type Published = &'static [(&'static str, f64, u32)];
const INSTANCES: &[(&str, &str, Published)] = &[
(
"49x648",
"data/observable-estimations/circuit-models/operator_loschmidt_echo/49Q_OLE_circuit_L_3_b_0.25_delta0.15.qasm",
&[
("device, global rescaling", 0.824, 38),
("belief-propagation tensor network, bond 192", 0.8202512915, 15),
("belief-propagation tensor network, bond 512", 0.821658489, 18),
("single-path Monte Carlo", 0.808, 63),
],
),
(
"49x1296",
"data/observable-estimations/circuit-models/operator_loschmidt_echo/49Q_OLE_circuit_L_6_b_0.25_delta0.15.qasm",
&[
("device, global rescaling", 0.662, 37),
("device, second layout", 0.657, 77),
("second device", 0.649, 78),
("belief-propagation tensor network, bond 512", 0.88157984, 19),
("the same, rescaled", 0.94257142, 20),
("single-path Monte Carlo", 0.619, 64),
],
),
(
"70x1872",
"data/observable-estimations/circuit-models/operator_loschmidt_echo/70Q_OLE_circuit_L_6_b_0.25_delta0.15.qasm",
&[
("device, global rescaling", 0.673, 36),
("belief-propagation tensor network, bond 512", 0.873827508, 21),
("the same, rescaled", 0.95247989, 22),
("single-path Monte Carlo", 0.614, 65),
],
),
];
/// The observable every instance measures, on the device's qubits.
const OBSERVABLE: [u32; 3] = [52, 59, 72];
fn main() {
let mut args = std::env::args().skip(1);
let root = common::tracker_root(args.next());
let name = args.next().unwrap_or_else(|| "49x648".into());
let method = args.next().unwrap_or_else(|| "spd".into());
let settings: Vec<String> = args.collect();
let (_, path, published) = INSTANCES.iter().find(|(n, ..)| *n == name).unwrap_or_else(|| panic!("no instance {name}"));
let src = String::from_utf8(common::read_pinned(&root, path)).expect("UTF-8");
let (circuit, map) = common::compact(&common::rotations(&src));
let (tail, middle) = echo_split(&circuit).expect("the circuit is written U · V · U†");
let circuit_hash = common::hex(
&wai_quantum::quantum_spd_receipt::SpdJob { circuit: circuit.clone(), observable: vec![], ones: vec![], config: SpdConfig::default() }.circuit_hash(),
);
let threads = std::thread::available_parallelism().map_or(1, |t| t.get());
println!("instance operator_loschmidt_echo_{name}");
println!("qubits {} of the device's register", circuit.n);
println!("gates {} ({} in the tail, {} in the middle)", circuit.ops.len(), tail.ops.len(), middle.ops.len());
println!("circuit hash {circuit_hash}");
for (label, value, issue) in published.iter() {
println!("published {value:<12} {label} (submission {issue})");
}
let request = |extra: serde_json::Value| {
let mut r = json!({
"instance": format!("operator_loschmidt_echo_{name}"),
"source": common::source(path),
"observable": OBSERVABLE.iter().map(|q| format!("Z{q}")).collect::<Vec<_>>(),
"circuit_hash": circuit_hash,
"threads": threads,
"published": published.iter().map(|(label, value, issue)| json!({ "label": label, "value": value, "submission": issue })).collect::<Vec<_>>(),
});
for (k, v) in extra.as_object().expect("an object") {
r[k] = v.clone();
}
r
};
let joules = |e: &serde_json::Value| e.get("joules_micro").map_or("unmetered".to_string(), |j| format!("{:.1} J", j.as_u64().unwrap_or(0) as f64 / 1e6));
match method.as_str() {
"spd" => {
let obs = common::z_string(&OBSERVABLE, &map);
let thresholds: Vec<f64> = settings.iter().map(|a| a.parse().expect("a threshold")).collect();
for threshold in if thresholds.is_empty() { vec![1e-3, 3e-4, 1e-4] } else { thresholds } {
let cfg = SpdConfig { threshold, max_weight: None };
let (r, secs, energy) = common::metered(|| echo(&circuit, &[(1.0, obs.clone())], &cfg, threads).expect("a valid circuit"));
println!(
"threshold {threshold:<8e} f = {:.6} bound {:.3e} A {} terms peak {} final {} dropped {:.3e} + {:.3e} {secs:.1} s {}",
r.value, r.truncation_bound, r.tail_terms, r.peak_terms, r.final_terms, r.tail_dropped, r.middle_dropped, joules(&energy),
);
let req = request(json!({
"method": "sparse Pauli dynamics, echo overlap (quantum_spd::echo)",
"threshold": threshold,
"threshold_bits": common::bits(threshold),
}));
let result = json!({
"value": r.value,
"value_bits": common::bits(r.value),
"truncation_bound": r.truncation_bound,
"tail_terms": r.tail_terms,
"peak_terms": r.peak_terms,
"final_terms": r.final_terms,
"term_updates": r.term_updates,
"tail_dropped": r.tail_dropped,
"middle_dropped": r.middle_dropped,
"wall_seconds": secs,
"energy_figure": energy,
});
let out = common::receipt_path(&format!("ole_{name}_spd_t{threshold:e}.json"));
assert!(common::verifies(&common::seal(req, result, Some(&out))));
println!("receipt {}", out.display());
}
}
"bptn" | "bptn-gauged" => {
let sites: Vec<u32> = common::z_string(&OBSERVABLE, &map).iter().map(|(q, _)| *q).collect();
let (purified, edges) = common::purified_echo(&circuit, &sites);
let ring = common::loop_through(&common::coupling(&circuit), &sites).expect("the observable's qubits lie on one loop");
println!("loop {:?} (device qubits)", ring.iter().map(|&q| map[q as usize]).collect::<Vec<_>>());
let chis: Vec<usize> = settings.iter().map(|a| a.parse().expect("a bond dimension")).collect();
for chi in if chis.is_empty() { vec![8, 16, 32] } else { chis } {
let ((f, discarded, bond, sweeps, residual), secs, energy) = common::metered(|| {
let mut t = Tns::new(purified.n, &edges, chi).expect("the graph");
if method == "bptn" {
t.run(&purified).expect("gates on the graph");
} else {
t.run_gauged(&purified, 50, 1e-10).expect("gates on the graph");
}
let env = t.belief_propagation(500, 1e-12);
let ops: Vec<(u32, Pauli)> = sites.iter().map(|&q| (q, Pauli::Z)).collect();
let f = t.expect_loop_bp(&env, &ring, &ops).expect("a loop");
(f, t.discarded(), t.max_bond(), env.sweeps, env.residual)
});
println!(
"chi {chi:<5} f = {f:.6} discarded {discarded:.3e} bond {bond} belief propagation {sweeps} sweeps, residual {residual:.1e} {secs:.1} s {}",
joules(&energy),
);
let req = request(json!({
"method": if method == "bptn" {
"tensor network on the coupling graph by simple update, the echo purified (quantum_bptn::Tns::run), read with the observable's loop contracted exactly (expect_loop_bp)"
} else {
"tensor network on the coupling graph by simple update re-gauged after every layer, the echo purified (quantum_bptn::Tns::run_gauged), read with the observable's loop contracted exactly (expect_loop_bp)"
},
"chi": chi,
"loop": ring.iter().map(|&q| map[q as usize]).collect::<Vec<_>>(),
}));
let result = json!({
"value": f,
"value_bits": common::bits(f),
"discarded": discarded,
"max_bond": bond,
"bp_sweeps": sweeps,
"bp_residual": residual,
"wall_seconds": secs,
"energy_figure": energy,
});
let out = common::receipt_path(&format!("ole_{name}_{method}_chi{chi}.json"));
assert!(common::verifies(&common::seal(req, result, Some(&out))));
println!("receipt {}", out.display());
}
}
"mpo" => {
let sites: Vec<u32> = common::z_string(&OBSERVABLE, &map).iter().map(|(q, _)| *q).collect();
let edges = common::coupling(&circuit);
// V's centre: the middle of the gates the split leaves between U and U†.
let mid = tail.ops.len() + middle.ops.len() / 2;
let chis: Vec<usize> = settings.iter().map(|a| a.parse().expect("a bond dimension")).collect();
for chi in if chis.is_empty() { vec![16, 32, 64] } else { chis } {
let ((f, report), secs, energy) = common::metered(|| operator::echo_by_operator(&circuit, &edges, chi, mid, &sites));
println!(
"chi {chi:<5} f = {f:.6} discarded {:.3e} fidelity estimate {:.4} bond {} updates {} {secs:.1} s {}",
report.discarded,
report.fidelity_estimate,
report.max_bond_used,
report.updates,
joules(&energy),
);
let req = request(json!({
"method": "the circuit's operator, a matrix-product state on row and column sites grown outward from the perturbation's centre (quantum_mpsim::Chain), read as ⟨⟨W|(O ⊗ O)|W⟩⟩",
"chi": chi,
"junction": mid,
}));
let result = json!({
"value": f,
"value_bits": common::bits(f),
"discarded": report.discarded,
"fidelity_estimate": report.fidelity_estimate,
"max_bond": report.max_bond_used,
"updates": report.updates,
"truncations": report.truncations,
"wall_seconds": secs,
"energy_figure": energy,
});
let out = common::receipt_path(&format!("ole_{name}_mpo_chi{chi}.json"));
assert!(common::verifies(&common::seal(req, result, Some(&out))));
println!("receipt {}", out.display());
}
}
"fast" | "fast-zero" => {
let sites: Vec<u32> = common::z_string(&OBSERVABLE, &map).iter().map(|(q, _)| *q).collect();
let head_len = circuit.ops.len() - tail.ops.len() - middle.ops.len();
let parts = echo_net::purified(&circuit, head_len, middle.ops.len(), &sites);
let env_usize = |k: &str, d: usize| std::env::var(k).ok().and_then(|v| v.parse().ok()).unwrap_or(d);
let workers = env_usize("OLE_THREADS", threads);
let bp_sweeps = env_usize("OLE_BP_SWEEPS", 30);
let bp_tol: f64 = std::env::var("OLE_BP_TOL").ok().and_then(|v| v.parse().ok()).unwrap_or(1e-9);
let loop_max = env_usize("OLE_LOOP_MAX", 64);
println!("path {:?} (device qubits)", parts.path.iter().map(|&q| map[q as usize]).collect::<Vec<_>>());
let chis: Vec<usize> = settings.iter().map(|a| a.parse().expect("a bond dimension")).collect();
for chi in if chis.is_empty() { vec![16, 32, 64] } else { chis } {
let (phases_before, _) = wai_quantum::quantum_svd::phases();
let steps_before = wai_quantum::quantum_bptn::blocked_phases();
let ((r, evolve_seconds), secs, energy) = common::metered(|| {
let (net, evolve) = echo_net::whole(&parts, chi, workers, method == "fast");
(echo_net::read(&net, &parts, bp_sweeps, bp_tol, loop_max), evolve)
});
let peak = common::peak_rss_bytes();
// Where the dense routines spent their time (summed over calls).
let (phases_after, _) = wai_quantum::quantum_svd::phases();
let phases: Vec<(String, f64)> = phases_after.iter().zip(&phases_before).map(|((n, a), (_, b))| (n.to_string(), a - b)).collect();
// The headline: the loop closed exactly where it was run, else the arc.
let value = r.bp_loop.or(r.bp_path).unwrap_or(r.vidal_path);
let show = |x: Option<f64>| x.map_or("-".to_string(), |x| format!("{x:.6}"));
println!(
"chi {chi:<5} f = {value:.6} (BP loop {}, BP arc {}, simple-update arc {:.6}) discarded {:.3e} bond {} BP {} sweeps {:.1e} {secs:.1} s peak {} MB {}",
show(r.bp_loop),
show(r.bp_path),
r.vidal_path,
r.discarded,
r.max_bond,
r.bp_sweeps,
r.bp_residual,
peak.map_or(0, |b| b >> 20),
joules(&energy),
);
println!(" evolution {evolve_seconds:.1} s, readout {:.1} s; loop bonds {:?}", r.seconds, r.loop_bonds);
let steps: Vec<(String, f64)> = wai_quantum::quantum_bptn::blocked_phases().iter().zip(&steps_before).map(|((n, a), (_, b))| (n.to_string(), a - b)).collect();
println!(" steps (summed over threads): {}", steps.iter().map(|(n, t)| format!("{n} {t:.1} s")).collect::<Vec<_>>().join(", "));
println!(" inside the SVDs: {}", phases.iter().map(|(n, t)| format!("{n} {t:.1} s")).collect::<Vec<_>>().join(", "));
let method_text = if method == "fast" {
"the purified echo |W⟩⟩ on the coupling graph with an ancilla on every qubit, evolved in the circuit's order by simple update with the dense blocked linear algebra (Tns::with_blocked_linalg); read around the observable's loop with belief propagation's environment off it (expect_loop_bp), along its arc (expect_path_bp) with that environment and with the bond weights'"
} else {
"as fast, with the middle left out, so that the exact echo is 1: the divisor of a rescaled value"
};
let req = request(json!({
"method": method_text,
"chi": chi,
"workers": workers,
"bp_sweeps_max": bp_sweeps,
"bp_tolerance": bp_tol,
"loop_readout_max_bond": loop_max,
"arc": parts.path.iter().map(|&q| map[q as usize]).collect::<Vec<_>>(),
"loop": parts.ring.iter().map(|&q| map[q as usize]).collect::<Vec<_>>(),
}));
let opt = |x: Option<f64>| x.map_or(json!(null), |x| json!(x));
let opt_bits = |x: Option<f64>| x.map_or(json!(null), |x| json!(common::bits(x)));
let result = json!({
"value": value,
"value_bits": common::bits(value),
"bp_loop": opt(r.bp_loop),
"bp_loop_bits": opt_bits(r.bp_loop),
"bp_arc": opt(r.bp_path),
"bp_arc_bits": opt_bits(r.bp_path),
"simple_update_arc": r.vidal_path,
"simple_update_arc_bits": common::bits(r.vidal_path),
"bp_sweeps": r.bp_sweeps,
"bp_residual": if r.bp_residual.is_finite() { json!(r.bp_residual) } else { json!(null) },
"discarded": r.discarded,
"max_bond": r.max_bond,
"loop_bonds": r.loop_bonds,
"evolve_seconds": evolve_seconds,
"readout_seconds": r.seconds,
"wall_seconds": secs,
"peak_rss_bytes": peak,
"energy_figure": energy,
"step_seconds": steps.iter().map(|(n, t)| json!({ "step": n, "seconds": t })).collect::<Vec<_>>(),
"svd_phase_seconds": phases.iter().map(|(n, t)| json!({ "phase": n, "seconds": t })).collect::<Vec<_>>(),
});
let out = common::receipt_path(&format!("ole_{name}_{method}_chi{chi}.json"));
assert!(common::verifies(&common::seal(req, result, Some(&out))));
println!("receipt {}", out.display());
}
}
"loops" | "loops-zero" => {
let sites: Vec<u32> = common::z_string(&OBSERVABLE, &map).iter().map(|(q, _)| *q).collect();
let head_len = circuit.ops.len() - tail.ops.len() - middle.ops.len();
let parts = echo_net::purified(&circuit, head_len, middle.ops.len(), &sites);
let env_usize = |k: &str, d: usize| std::env::var(k).ok().and_then(|v| v.parse().ok()).unwrap_or(d);
let workers = env_usize("OLE_THREADS", threads);
let bp_sweeps = env_usize("OLE_BP_SWEEPS", 30);
let bp_tol: f64 = std::env::var("OLE_BP_TOL").ok().and_then(|v| v.parse().ok()).unwrap_or(1e-9);
let max_cells = env_usize("OLE_CLUSTER_CELLS", 3);
let max_work: f64 = std::env::var("OLE_CLUSTER_WORK").ok().and_then(|v| v.parse().ok()).unwrap_or(1e13);
let max_bytes: f64 = std::env::var("OLE_CLUSTER_BYTES").ok().and_then(|v| v.parse().ok()).unwrap_or(32e9);
let ring_len = 12;
let dev = |v: u32| map[v as usize];
let chis: Vec<usize> = settings.iter().map(|a| a.parse().expect("a bond dimension")).collect();
for chi in if chis.is_empty() { vec![64] } else { chis } {
let (((x, bp_arc, bp_loop, env_sweeps, env_residual, bonds, readout), evolve_seconds, net_discarded, net_bond), secs, energy) = common::metered(|| {
let (net, evolve) = echo_net::whole(&parts, chi, workers, method == "loops");
let started = std::time::Instant::now();
let env = net.belief_propagation(bp_sweeps, bp_tol);
let ops: Vec<(u32, Pauli)> = sites.iter().map(|&q| (q, Pauli::Z)).collect();
let bp_arc = net.expect_path_bp(&env, &parts.path, &ops).expect("the arc");
let bp_loop = net.expect_loop_bp(&env, &parts.ring, &ops).expect("the loop");
println!("chi {chi:<5} arc readout {bp_arc:.6} loop readout {bp_loop:.6} discarded {:.3e} bond {} BP {} sweeps {:.1e} evolution {evolve:.1} s", net.discarded(), net.max_bond(), env.sweeps, env.residual);
let lam = net.bond_weights();
let bonds: Vec<(u32, u32, usize)> = parts.edges.iter().enumerate().filter(|(_, (a, b))| *a < parts.n && *b < parts.n).map(|(e, &(a, b))| (dev(a), dev(b), lam[e].len())).collect();
println!(" bonds {:?}", bonds);
let x = echo_net::clusters(&net, &env, &parts, ring_len, max_cells, max_work, max_bytes);
let readout = started.elapsed().as_secs_f64();
((x, bp_arc, bp_loop, env.sweeps, env.residual, bonds, readout), evolve, net.discarded(), net.max_bond())
});
let echo_net::Expansion { cells, orders, reads, weights } = x;
let peak = common::peak_rss_bytes();
let devs = |r: &[u32]| r.iter().map(|&v| dev(v)).collect::<Vec<_>>();
let best = orders.iter().rev().find_map(|o| o.product);
println!(" {secs:.1} s peak {} MB {}", peak.map_or(0, |b| b >> 20), joules(&energy));
let opt = |x: Option<f64>| x.map_or(json!(null), |x| json!(x));
let opt_bits = |x: Option<f64>| x.map_or(json!(null), |x| json!(common::bits(x)));
let req = request(json!({
"method": if method == "loops" {
"the purified echo |W⟩⟩ evolved as in fast; read by the loop cluster expansion around belief propagation (Gray, Park, Evenbly, Pancotti, Kjønstad and Chan 2025, Eq. 7 and Algorithm 1): the regions are the observable's ring joined with connected sets of the graph's other rings, closed under intersection with counting numbers c(r) = 1 − Σ_{a ⊋ r} c(a), each contracted exactly (Tns::expect_region_bp: its loops cut where the estimated work is least) with belief propagation's messages on its boundary; also the arc through the observable's sites (expect_path_bp, the tree below order 1) and each ring's own correction (Midha and Zhang 2025, Eq. 9)"
} else {
"as loops, with the middle left out, so that the exact echo is 1"
},
"chi": chi,
"workers": workers,
"bp_sweeps_max": bp_sweeps,
"bp_tolerance": bp_tol,
"ring_length": ring_len,
"max_cells": max_cells,
"max_work": max_work,
"max_table_bytes": max_bytes,
"arc": devs(&parts.path),
"loop": devs(&parts.ring),
}));
let result = json!({
"value": opt(best),
"value_bits": opt_bits(best),
"bp_arc": bp_arc,
"bp_arc_bits": common::bits(bp_arc),
"bp_loop": bp_loop,
"bp_loop_bits": common::bits(bp_loop),
"orders": orders.iter().map(|o| json!({
"cells": o.cells,
"terms": o.terms.iter().map(|(r, c)| json!({ "region": devs(r), "count": c })).collect::<Vec<_>>(),
"product": opt(o.product),
"product_bits": opt_bits(o.product),
"sum": opt(o.sum),
"sum_bits": opt_bits(o.sum),
"partial": o.partial.as_ref().map_or(json!(null), |q| json!({
"left_out": q.left_out.iter().map(|r| devs(r)).collect::<Vec<_>>(),
"terms": q.terms.iter().map(|(r, c)| json!({ "region": devs(r), "count": c })).collect::<Vec<_>>(),
"product": opt(q.product),
"product_bits": opt_bits(q.product),
"sum": opt(q.sum),
"sum_bits": opt_bits(q.sum),
})),
})).collect::<Vec<_>>(),
"regions": reads.iter().map(|r| json!({
"region": devs(&r.region),
"cells": r.cells,
"cuts": r.cuts.iter().map(|&(a, b, d)| json!([dev(a), dev(b), d])).collect::<Vec<_>>(),
"combinations": r.combinations,
"work": r.work,
"table_bytes": r.bytes,
"value": opt(r.value),
"value_bits": opt_bits(r.value),
"norm_ratio": opt(r.norm_ratio),
"seconds": r.seconds,
})).collect::<Vec<_>>(),
"rings": cells.iter().zip(&weights).map(|(c, w)| json!({ "ring": devs(c), "norm_ratio": opt(*w), "norm_ratio_bits": opt_bits(*w) })).collect::<Vec<_>>(),
"bonds": bonds.iter().map(|&(a, b, d)| json!([a, b, d])).collect::<Vec<_>>(),
"bp_sweeps": env_sweeps,
"bp_residual": env_residual,
"discarded": net_discarded,
"max_bond": net_bond,
"evolve_seconds": evolve_seconds,
"readout_seconds": readout,
"wall_seconds": secs,
"peak_rss_bytes": peak,
"energy_figure": energy,
});
let out = common::receipt_path(&format!("ole_{name}_{method}_chi{chi}.json"));
assert!(common::verifies(&common::seal(req, result, Some(&out))));
println!("receipt {}", out.display());
}
}
other => panic!("spd, bptn, bptn-gauged, mpo, fast, fast-zero, loops or loops-zero, not {other}"),
}
}