//! What the published-instance reproductions share: the pinned sources, a //! SHA-256 check of every input read, the compaction of a device-wide register //! to the qubits a circuit touches, the energy reading around a run, and the //! signed receipt each run writes. //! //! The instances come from a public tracker of quantum-advantage candidates, //! licensed Apache-2.0 (see `tracker/NOTICE` beside this file). Its circuits and //! Hamiltonians are fetched by the reader at the commit below and checked //! against the hashes here; only the small fixtures the tests need are kept in //! this repository, under `tests/data/tracker/`, with the licence notice. #![allow(dead_code)] use std::path::Path; use std::time::Instant; use serde_json::{Value, json}; use wai_quantum::ed25519_dalek::SigningKey; use wai_quantum::quantum_spd::{Op, Pauli, PauliString, RotCircuit}; /// The tracker's repository and the commit every input is read at. pub const REPOSITORY: &str = "https://github.com/quantum-advantage-tracker/quantum-advantage-tracker.github.io"; // allow-name: a repository URL pub const COMMIT: &str = "4d27f882d55028162206c4f12b5b6fc6a63868e7"; /// Every input a reproduction reads, by its path in the repository at /// [`COMMIT`], and the SHA-256 of its bytes there. pub const SOURCES: &[(&str, &str)] = &[ ("LICENSE", "6a50c5923c736b5d160cc6dc8737ef6bb998f885bedfa2c036f6c0b0e6117848"), ("data/observable-estimations/submissions.json", "82258f5ee279eea6ba487df1f014bf3a3e3dcd2e0888cc5bc5a24e846a09f61c"), ("data/classically-verifiable-problems/submissions.json", "055846dbca163b516eb4a4e53b7d0a1d6f56d9bad5abf067bdef1f4752046992"), ("data/variational-problems/submissions.json", "639e7beade574e5e9a8ad259a93f30775021cb0950dd921c9b1d37199f837bcc"), ( "data/observable-estimations/circuit-models/operator_loschmidt_echo/49Q_OLE_circuit_L_3_b_0.25_delta0.15.qasm", "4aae5089337253921cd70df470dc52b5243e0c8410b36a6bcbb43497db48db29", ), ( "data/observable-estimations/circuit-models/operator_loschmidt_echo/49Q_OLE_circuit_L_6_b_0.25_delta0.15.qasm", "3748e2c026c118f9d6c7499093ea43e41a45251b6bf8d3adb6fb056f718f6cc0", ), ( "data/observable-estimations/circuit-models/operator_loschmidt_echo/70Q_OLE_circuit_L_6_b_0.25_delta0.15.qasm", "7bb359cd6a6270856819780f410336ecefe52f082cd14af2d95539a681bf9843", ), ("data/observable-estimations/circuit-models/su2_hadron_dynamics_lsh/x_100_meson.qasm", "28b3d82a2572dac60110c94a0f58a945a117d414e94446866e0d87cc5121b4f9"), ("data/observable-estimations/circuit-models/su2_hadron_dynamics_lsh/x_100_SCV.qasm", "af269dd7aeacfe6c9fef00bdab3bd1d0a641f5ee99be67c56ebf73a15791b6da"), ( "data/classically-verifiable-problems/circuit-models/peaked_circuit/peaked_circuit_heavy_hex_49x4020.qasm", "ef92424a8e365905037e2a610a50ec8cd46b032a0fb01fd12b80d2d8ed0f112f", ), ( "data/classically-verifiable-problems/circuit-models/peaked_circuit/peaked_circuit_heavy_hex_49x5072.qasm", "a9c2409bad096273b64c722a29cf493f0dd621a80760e87f4b778f0bbb70ddc9", ), ( "data/classically-verifiable-problems/circuit-models/peaked_circuit/peaked_circuit_P9_Hqap_56x1917.qasm", "f043c6cdf9e1a1ba9b3e68ea3b893277e8acacab80319d6a8524cc022886a3f9", ), ( "data/variational-problems/hamiltonians/guided_sparse_ground_state_problem/49Q_v1/49Q_v1_hamiltonian.npy", "c15ad8d74b5a41508a7cf99c389ad8a45ac50206a0eb7a992a72a3e11bf07566", ), ( "data/variational-problems/hamiltonians/guided_sparse_ground_state_problem/49Q_v1/49Q_v1_initial_state_index.npy", "dcdb99c48ad035351f3ba0361d02e3fc8c6f6a02b47200796b293c47f1f3ad4b", ), ]; /// The pinned SHA-256 of `path`, as hex. pub fn pinned(path: &str) -> &'static str { SOURCES.iter().find(|(p, _)| *p == path).map(|(_, h)| *h).unwrap_or_else(|| panic!("{path} is not a pinned source")) } /// The bytes of `path` under the checkout `root`, refused unless their SHA-256 /// is the pinned one. pub fn read_pinned(root: &Path, path: &str) -> Vec { let bytes = std::fs::read(root.join(path)).unwrap_or_else(|e| panic!("reading {path} under {}: {e}", root.display())); let got = hex(&sha256(&bytes)); assert_eq!(got, pinned(path), "{path}: SHA-256 {got} is not the pinned one; fetch the tracker at {COMMIT}"); bytes } /// The checkout of the tracker: the first argument, or `TRACKER_ROOT`. pub fn tracker_root(arg: Option) -> std::path::PathBuf { arg.or_else(|| std::env::var("TRACKER_ROOT").ok()) .unwrap_or_else(|| panic!("give the tracker checkout ({REPOSITORY} at {COMMIT}) as the first argument or TRACKER_ROOT")) .into() } /// What a receipt names as its input: the repository, the commit, the path /// and its hash. pub fn source(path: &str) -> Value { json!({ "repository": REPOSITORY, "commit": COMMIT, "path": path, "sha256": pinned(path) }) } pub fn hex(b: &[u8]) -> String { b.iter().map(|x| format!("{x:02x}")).collect() } /// SHA-256 (FIPS 180-4). #[allow(clippy::needless_range_loop)] pub fn sha256(data: &[u8]) -> [u8; 32] { const K: [u32; 64] = [ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, ]; let mut h: [u32; 8] = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]; let mut msg = data.to_vec(); msg.push(0x80); while msg.len() % 64 != 56 { msg.push(0); } msg.extend_from_slice(&((data.len() as u64) * 8).to_be_bytes()); for block in msg.chunks(64) { let mut w = [0u32; 64]; for i in 0..16 { w[i] = u32::from_be_bytes([block[4 * i], block[4 * i + 1], block[4 * i + 2], block[4 * i + 3]]); } for i in 16..64 { let s0 = w[i - 15].rotate_right(7) ^ w[i - 15].rotate_right(18) ^ (w[i - 15] >> 3); let s1 = w[i - 2].rotate_right(17) ^ w[i - 2].rotate_right(19) ^ (w[i - 2] >> 10); w[i] = w[i - 16].wrapping_add(s0).wrapping_add(w[i - 7]).wrapping_add(s1); } let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut hh] = h; for i in 0..64 { let s1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25); let ch = (e & f) ^ (!e & g); let t1 = hh.wrapping_add(s1).wrapping_add(ch).wrapping_add(K[i]).wrapping_add(w[i]); let s0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22); let maj = (a & b) ^ (a & c) ^ (b & c); let t2 = s0.wrapping_add(maj); hh = g; g = f; f = e; e = d.wrapping_add(t1); d = c; c = b; b = a; a = t1.wrapping_add(t2); } for (x, y) in h.iter_mut().zip([a, b, c, d, e, f, g, hh]) { *x = x.wrapping_add(y); } } let mut out = [0u8; 32]; for (i, x) in h.iter().enumerate() { out[4 * i..4 * i + 4].copy_from_slice(&x.to_be_bytes()); } out } // --------------------------------------------------------------------------- // Circuits // --------------------------------------------------------------------------- /// The qubits a gate acts on. fn qubits(op: &Op) -> Vec { match op { Op::H(q) | Op::S(q) | Op::Sdg(q) | Op::SX(q) | Op::SXdg(q) | Op::X(q) | Op::Y(q) | Op::Z(q) => vec![*q], Op::CX(a, b) | Op::CZ(a, b) | Op::Swap(a, b) => vec![*a, *b], Op::Rot { axis, .. } | Op::QuarterRot { axis, .. } => axis.iter().map(|(q, _)| *q).collect(), } } /// `op` with its qubits renamed by `f`. fn renamed(op: &Op, f: &impl Fn(u32) -> u32) -> Op { let s = |axis: &PauliString| axis.iter().map(|(q, p)| (f(*q), *p)).collect::(); match op { Op::H(q) => Op::H(f(*q)), Op::S(q) => Op::S(f(*q)), Op::Sdg(q) => Op::Sdg(f(*q)), Op::SX(q) => Op::SX(f(*q)), Op::SXdg(q) => Op::SXdg(f(*q)), Op::X(q) => Op::X(f(*q)), Op::Y(q) => Op::Y(f(*q)), Op::Z(q) => Op::Z(f(*q)), Op::CX(a, b) => Op::CX(f(*a), f(*b)), Op::CZ(a, b) => Op::CZ(f(*a), f(*b)), Op::Swap(a, b) => Op::Swap(f(*a), f(*b)), Op::Rot { axis, theta } => Op::Rot { axis: s(axis), theta: *theta }, Op::QuarterRot { axis, k } => Op::QuarterRot { axis: s(axis), k: *k }, } } /// A rotation through a whole number of quarter turns, as written (`pi/2`, /// `-pi/2`, `pi`, read as the doubles nearest them), held as the exact /// quarter-turn gate it means; every other angle is kept as read. fn exact_quarters(op: Op) -> Op { use std::f64::consts::{FRAC_PI_2, PI}; match op { Op::Rot { axis, theta } => { let k = [(FRAC_PI_2, 1u8), (PI, 2), (-FRAC_PI_2, 3), (-PI, 2)].iter().find(|(a, _)| a.to_bits() == theta.to_bits()).map(|(_, k)| *k); match k { Some(k) => Op::QuarterRot { axis, k }, None => Op::Rot { axis, theta }, } } other => other, } } /// The circuit on the qubits it touches, renumbered in increasing order, with /// each quarter turn held exactly; and the device qubit of each new index. pub fn compact(c: &RotCircuit) -> (RotCircuit, Vec) { let mut used: Vec = c.ops.iter().flat_map(qubits).collect(); used.sort_unstable(); used.dedup(); let at = |q: u32| used.binary_search(&q).expect("a qubit the circuit uses") as u32; let ops = c.ops.iter().map(|op| exact_quarters(renamed(op, &at))).collect(); (RotCircuit { n: used.len() as u32, ops }, used) } /// A product of `Z`s on device qubits, on the compacted register. pub fn z_string(device: &[u32], map: &[u32]) -> PauliString { device.iter().map(|q| (map.binary_search(q).expect("a qubit the circuit uses") as u32, Pauli::Z)).collect() } /// The pairs the circuit's two-qubit gates act on, each once, smaller first, /// in the order they first appear. pub fn coupling(c: &RotCircuit) -> Vec<(u32, u32)> { let mut out: Vec<(u32, u32)> = Vec::new(); for op in &c.ops { if let [a, b] = qubits(op)[..] { let e = (a.min(b), a.max(b)); if !out.contains(&e) { out.push(e); } } } out } /// The echo `2⁻ⁿ Tr(O · W† O W)` of a circuit `W` on `n` qubits as one state /// on `2n`: each qubit `q` paired with an ancilla `n + q` in a Bell state (the /// purification of the maximally mixed state), `W` on the qubits, and, for `O` /// the `Z`s on `sites`, each ancilla's `Z` folded onto its qubit by a `CX`. /// Then `2⁻ⁿ Tr(O W† O W) = ⟨Π_{q ∈ sites} Z_q⟩` in that state, since /// `(I ⊗ O)` on the ancillas commutes with `W` and `O` is diagonal. Returns the /// circuit and its coupling graph: the qubits' own, and an edge to each ancilla. pub fn purified_echo(w: &RotCircuit, sites: &[u32]) -> (RotCircuit, Vec<(u32, u32)>) { let n = w.n; let mut edges = coupling(w); edges.extend((0..n).map(|q| (q, n + q))); let mut c = RotCircuit::new(2 * n); for q in 0..n { c.push(Op::H(q)).push(Op::CX(q, n + q)); } c.ops.extend(w.ops.iter().cloned()); for &q in sites { c.push(Op::CX(n + q, q)); } (c, edges) } /// The loop through `sites` on the graph `edges`: the shortest path from each /// site to the next (breadth first, neighbours in increasing order), joined; /// `None` unless the joined paths make one simple cycle. pub fn loop_through(edges: &[(u32, u32)], sites: &[u32]) -> Option> { let n = edges.iter().map(|&(a, b)| a.max(b) + 1).max()? as usize; let mut adj = vec![Vec::new(); n]; for &(a, b) in edges { adj[a as usize].push(b); adj[b as usize].push(a); } for a in &mut adj { a.sort_unstable(); } let path = |s: u32, t: u32| -> Option> { let mut prev = vec![u32::MAX; n]; prev[s as usize] = s; let mut queue = std::collections::VecDeque::from([s]); while let Some(v) = queue.pop_front() { if v == t { break; } for &w in &adj[v as usize] { if prev[w as usize] == u32::MAX { prev[w as usize] = v; queue.push_back(w); } } } if prev[t as usize] == u32::MAX { return None; } let mut p = vec![t]; while *p.last()? != s { p.push(prev[*p.last()? as usize]); } p.reverse(); Some(p) }; let mut ring = Vec::new(); for i in 0..sites.len() { let p = path(sites[i], sites[(i + 1) % sites.len()])?; ring.extend_from_slice(&p[..p.len() - 1]); } let mut seen = ring.clone(); seen.sort_unstable(); seen.dedup(); (seen.len() == ring.len() && ring.len() >= 3).then_some(ring) } /// The qubits in breadth-first order through the coupling graph `edges`, from /// qubit 0, each vertex's neighbours in increasing order: a chain on which /// coupled qubits sit near each other. pub fn bfs_chain(n: u32, edges: &[(u32, u32)]) -> Vec { let mut adj = vec![Vec::new(); n as usize]; for &(a, b) in edges { adj[a as usize].push(b); adj[b as usize].push(a); } for a in &mut adj { a.sort_unstable(); a.dedup(); } let mut seen = vec![false; n as usize]; let mut order = Vec::with_capacity(n as usize); for start in 0..n { if seen[start as usize] { continue; } seen[start as usize] = true; let mut queue = std::collections::VecDeque::from([start]); while let Some(v) = queue.pop_front() { order.push(v); for &w in &adj[v as usize] { if !seen[w as usize] { seen[w as usize] = true; queue.push_back(w); } } } } order } /// The circuit a QASM text describes, as Pauli rotations and Clifford gates. pub fn rotations(src: &str) -> RotCircuit { wai_quantum::qasm::parse(src).unwrap_or_else(|e| panic!("the circuit does not read: {e}")).rotations() } // --------------------------------------------------------------------------- // Energy, time and receipts // --------------------------------------------------------------------------- /// Run `f`, timing it and reading an energy counter around it: the result, the /// wall time in seconds, and the energy figure (or why there is none). On macOS /// the counter is this process's own CPU energy; on Linux, the processor /// packages' counters, which count every process on the host (the figure says /// so, and gives the host's load when the run began). pub fn metered(f: impl FnOnce() -> T) -> (T, f64, Value) { if cfg!(target_os = "linux") { return metered_packages(f); } metered_process(f) } fn metered_packages(f: impl FnOnce() -> T) -> (T, f64, Value) { use std::sync::Mutex; use std::sync::atomic::{AtomicBool, Ordering}; use wai_quantum::engine::energy::{Accumulated, Packages, package_figure}; let load = std::fs::read_to_string("/proc/loadavg").ok().and_then(|s| s.split_whitespace().next().map(str::to_string)); let packages = match Packages::open() { Ok(p) => p, Err(why) => { let started = Instant::now(); let out = f(); return (out, started.elapsed().as_secs_f64(), json!({ "unmetered": why })); } }; let Some(first) = packages.read() else { let started = Instant::now(); let out = f(); return (out, started.elapsed().as_secs_f64(), json!({ "unmetered": "a package counter did not read" })); }; let acc = Mutex::new(Accumulated::new(&packages, first)); let done = AtomicBool::new(false); let started = Instant::now(); let (out, ok) = std::thread::scope(|s| { // Read every 250 ms, so that no counter wraps between two reads. s.spawn(|| { while !done.load(Ordering::Relaxed) { std::thread::sleep(std::time::Duration::from_millis(250)); let _ = acc.lock().unwrap().read(); } }); let out = f(); done.store(true, Ordering::Relaxed); let ok = acc.lock().unwrap().read().is_some(); (out, ok) }); let secs = started.elapsed().as_secs_f64(); let mut figure = if ok { package_figure(Some(&acc.lock().unwrap().reading(0)), "") } else { json!({ "unmetered": "a package counter did not read at the end of the run" }) }; if figure.get("joules_micro").is_some() { figure["covers"] = json!("the energy of the host's processor packages over the run: every process on the host in that window, this one among them, and the packages' idle draw"); figure["source"] = json!("powercap energy_uj of every package zone, read before the run, every 250 ms during it and after it, each wrap corrected at the zone's max_energy_range_uj"); figure["host_load_1m_at_start"] = json!(load); // Other work on the host is not counted in jobs here: the load says it. if let Some(m) = figure.as_object_mut() { m.remove("concurrent_jobs"); } } (out, secs, figure) } fn metered_process(f: impl FnOnce() -> T) -> (T, f64, Value) { use wai_quantum::engine::energy::own; let before = own(); let started = Instant::now(); let out = f(); let secs = started.elapsed().as_secs_f64(); let after = own(); let figure = match (before, after) { (Some(a), Some(b)) => { let nj = |r: &wai_quantum::engine::energy::Reading| r.energy_nj.saturating_add(r.billed_nj).saturating_sub(r.serviced_nj); let delta = nj(&b).saturating_sub(nj(&a)); let joules_micro = delta.saturating_add(500) / 1000; if joules_micro == 0 { json!({ "unmetered": "the process's energy counter did not advance over the run" }) } else { json!({ "joules_micro": joules_micro, "energy_provenance": "OnChipCounter", "energy_counter_filtering": "Unknown", "attribution": "process", "coverage": "partial", "covers": "the CPU energy of this process's own threads over the run, with what system services billed to it", "excludes": ["memory", "the host's idle draw", "energy of threads still on a core at the second read"], "cpu_ms": b.cpu_ns.saturating_sub(a.cpu_ns) / 1_000_000, "source": "proc_pid_rusage ri_energy_nj + ri_billed_energy − ri_serviced_energy of this process, read before and after the run", }) } } _ => json!({ "unmetered": "this platform gives no per-process energy counter here" }), }; (out, secs, figure) } /// The signing key: 64 hex digits in the file `WAI_TRACKER_KEY` names, or, with /// none, a key every reader knows, which the receipt then says it was sealed /// with. pub fn signing_key() -> (SigningKey, &'static str) { match std::env::var("WAI_TRACKER_KEY") { Ok(path) => { let text = std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("reading the key {path}: {e}")); let text = text.trim(); assert_eq!(text.len(), 64, "the key file holds 64 hex digits"); let mut b = [0u8; 32]; for (i, x) in b.iter_mut().enumerate() { *x = u8::from_str_radix(&text[2 * i..2 * i + 2], 16).expect("hex digits"); } (SigningKey::from_bytes(&b), "the operator's key") } Err(_) => (SigningKey::from_bytes(&[42u8; 32]), "a demonstration key every reader knows (set WAI_TRACKER_KEY to sign with your own)"), } } /// Seal `result` of `request` and write the three, as one JSON document, to /// `out` (when given). Returns the document. pub fn seal(request: Value, mut result: Value, out: Option<&Path>) -> Value { let (key, which) = signing_key(); result["signed_with"] = json!(which); let receipt = wai_quantum::engine::receipt::seal(&key, &request, &result); let doc = json!({ "request": request, "result": result, "receipt": receipt }); if let Some(path) = out { if let Some(dir) = path.parent() { std::fs::create_dir_all(dir).unwrap_or_else(|e| panic!("creating {}: {e}", dir.display())); } std::fs::write(path, serde_json::to_string_pretty(&doc).unwrap() + "\n").unwrap_or_else(|e| panic!("writing {}: {e}", path.display())); } doc } /// Whether a written receipt document's seal holds over its request and result. pub fn verifies(doc: &Value) -> bool { wai_quantum::engine::receipt::verify(&doc["request"], &doc["result"], &doc["receipt"]) } /// Where a run's receipt goes: `RECEIPTS_DIR` (default `receipts`) / `name`. pub fn receipt_path(name: &str) -> std::path::PathBuf { Path::new(&std::env::var("RECEIPTS_DIR").unwrap_or_else(|_| "receipts".into())).join(name) } /// The number as its exact bits, for a reader that must get the same double back. pub fn bits(x: f64) -> String { format!("{:016x}", x.to_bits()) } /// The process's peak resident memory so far, in bytes: `VmHWM` on Linux, /// `ru_maxrss` (bytes there) on macOS; `None` elsewhere or if it does not read. pub fn peak_rss_bytes() -> Option { #[cfg(target_os = "linux")] { let s = std::fs::read_to_string("/proc/self/status").ok()?; let kb: u64 = s.lines().find(|l| l.starts_with("VmHWM:"))?.split_whitespace().nth(1)?.parse().ok()?; Some(kb * 1024) } #[cfg(target_os = "macos")] { // `struct rusage` from ``: two `timeval`s (16 bytes // each), then `ru_maxrss` and thirteen more `long`s. #[repr(C)] struct Rusage { times: [i64; 4], maxrss: i64, rest: [i64; 13], } unsafe extern "C" { fn getrusage(who: i32, usage: *mut Rusage) -> i32; } let mut r = Rusage { times: [0; 4], maxrss: 0, rest: [0; 13] }; // SAFETY: `r` is a writable `struct rusage` for the call; RUSAGE_SELF is 0. let rc = unsafe { getrusage(0, &mut r) }; (rc == 0 && r.maxrss > 0).then_some(r.maxrss as u64) } #[cfg(not(any(target_os = "linux", target_os = "macos")))] { None } }