open-standards/wai/wai-quantum/examples/sv_run.rs
Transaction Science 38a205ee33
Some checks failed
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 3s
no-vanity-metrics / WAI public text names no comparison (pull_request) Successful in 4s
no-vanity-metrics / WAI public text names no company or product (pull_request) Successful in 3s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m55s
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 3m14s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m31s
standards workspaces build + test / aac-rs (pull_request) Successful in 1m50s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m13s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 1m20s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 50s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m10s
standards workspaces build + test / map-rs (pull_request) Successful in 59s
standards workspaces build + test / mesh-rs (pull_request) Successful in 44s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m38s
standards workspaces build + test / openpay (pull_request) Successful in 3m11s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 3m56s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 13s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 5m6s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 2m11s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 24s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 38s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 44s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 1m13s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 2m7s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 57s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m2s
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Successful in 3m57s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 1m44s
standards workspaces build + test / arl-rs (pull_request) Successful in 23m30s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 28m45s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 23m46s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 22m26s
standards workspaces build + test / sense-rs (pull_request) Successful in 18m49s
standards workspaces build + test / macOS energy backends (pull_request) Failing after 13m54s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 25m26s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 1m17s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 12m58s
wai-quantum 0.3.28: the dense state vector at any angle, the same bits threaded or not
The byte-exact simulator is fixed-point and dyadic by design. quantum_sv is
the general state vector for everything else (arbitrary rotations, sqrt W,
fSim, random unitaries), and the ground truth approximate methods are
measured against, up to about 30 qubits.

- Split real and imaginary arrays; qubit 0 most significant, as in the
  tensor networks.
- Kernels: unrolled one- and two-qubit, general k-qubit, and a diagonal
  fast path.
- Fusion around multi-qubit gates: pending one-qubit gates join the next
  multi-qubit gate on their qubit, trailing ones the last, and above width 2
  adjacent multi-qubit gates merge. Each move only crosses gates on other
  qubits.
- Threads, with no unsafe code: block-aligned slices, and for gates on the
  top qubits a split at the top target bit, or into four quarters for
  adjacent pairs.
- Every path computes each amplitude through one row sum in one order, so
  threading never changes a bit. The native-vs-WASI pin caught a path whose
  sum ran in a different order; the fix is the shared row_dot, and a test
  now forces 1/2/3/8/32 threads and demands identical states (falsified by
  reversing one kernel's sum).
- Reductions (norm, Pauli expectations, sorted-uniform sampling) are summed
  in fixed chunks.

gates: Gate moves here from quantum_tn (re-exported there), with the
standard gates by name: H, X, Y, Z, S, T, sqrt X/Y/W, RX/RY/RZ, phase, CX,
CZ, SWAP, iSWAP, CPhase, RZZ, fSim.

Checked:
- final states of random circuits on 8, 12 and 16 qubits agree with an
  independent simulator to 2e-16 at fusion widths 0, 2 and 4;
- tensor-network amplitudes equal the state vector's to 1e-12 on 18 qubits
  (tests/tn_vs_sv.rs);
- a 26-qubit, depth-20, 770-gate circuit runs in about 9 s at width 2, in
  double precision.

CLI: wai-quantum sv --file CIRCUIT.jsonl [--fuse --top --sample --expect
--json]; tn shares its circuit reader. Byte-identical natively and under
wasm32-wasip2.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-04 17:01:39 -04:00

35 lines
1.5 KiB
Rust

//! Run a circuit (JSON lines, one gate per line: {"q":[a,b],"m":[re,im,…]}) on
//! the dense state vector and print the final state, or time it.
//!
//! ```text
//! cargo run --release --example sv_run --features quantum_sv -- CIRCUIT N WIDTH [--state | --time]
//! ```
use wai_quantum::gates::{complex, Gate};
use wai_quantum::quantum_sv::StateVector;
fn main() {
let a: Vec<String> = std::env::args().collect();
let text = std::fs::read_to_string(&a[1]).expect("read circuit");
let n: u32 = a[2].parse().unwrap();
let width: usize = a[3].parse().unwrap();
let gates: Vec<Gate> = text
.lines()
.filter(|l| !l.trim().is_empty())
.map(|l| {
let v: serde_json::Value = serde_json::from_str(l).unwrap();
let qubits = v["q"].as_array().unwrap().iter().map(|x| x.as_u64().unwrap() as u32).collect();
let m: Vec<f64> = v["m"].as_array().unwrap().iter().map(|x| x.as_f64().unwrap()).collect();
Gate { qubits, matrix: m.chunks(2).map(|c| complex(c[0], c[1])).collect() }
})
.collect();
let mut sv = StateVector::zero(n).unwrap();
let t0 = std::time::Instant::now();
sv.run(&gates, width).unwrap();
let dt = t0.elapsed().as_secs_f64();
if a.iter().any(|x| x == "--state") {
let amps: Vec<String> = (0..sv.re.len()).map(|x| format!("[{:e},{:e}]", sv.re[x], sv.im[x])).collect();
println!("[{}]", amps.join(","));
} else {
println!("{n} qubits, {} gates, width {width}: {dt:.3} s, norm {:.15}", gates.len(), sv.norm2());
}
}