Some checks failed
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 23s
WAI examples / WAI examples · does this change touch them (push) Successful in 29s
wai-quantum for JavaScript / does this change touch it (push) Successful in 41s
wai-quantum docs, course and locales / does this change touch it (push) Successful in 45s
wai-audit collector and player integration / does this change touch it (push) Successful in 59s
wai-quantum resource estimation / does this change touch it (push) Successful in 46s
wai-quantum docs, course and locales / the Studio's words in every locale · linux (push) Successful in 21s
wai-quantum wasmQ / does this change touch it (push) Successful in 1m19s
WAI operation catalogue / does this change touch it (push) Successful in 1m20s
wai-quantum for Python / does this change touch it (push) Successful in 40s
wai-quantum error correction and mitigation / does this change touch it (push) Successful in 41s
wai-quantum service / does this change touch it (push) Successful in 41s
wai-quantum extension points / does this change touch it (push) Successful in 42s
wai-quantum pulse and dynamics / does this change touch it (push) Successful in 1m41s
wai-quantum editors / does this change touch it (push) Successful in 2m8s
wai-quantum command line / does this change touch it (push) Successful in 2m11s
wai-quantum other formats / does this change touch it (push) Successful in 2m12s
wai-quantum clippy / does this change touch it (push) Successful in 2m12s
wai-quantum contract / does this change touch it (push) Successful in 2m12s
wai-quantum OpenQASM reader / does this change touch it (push) Successful in 2m13s
wai-quantum studio and desktop / does this change touch it (push) Successful in 53s
wai-quantum wasmQ / the reference modules rebuild to their modules of record · linux (push) Successful in 56s
wai-quantum variational and algorithm library / does this change touch it (push) Successful in 53s
wai-quantum verdicts and repairs / does this change touch it (push) Successful in 59s
wai-sink-android native sink library / does this change touch it (push) Successful in 57s
wai-quantum views in agent hosts / does this change touch it (push) Successful in 59s
WAI Studio / does this change touch it (push) Successful in 55s
wai-sink-swift native sink package / does this change touch it (push) Successful in 1m25s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 2m40s
wai-quantum pulse and dynamics / the same bits · macos (push) Successful in 1m46s
wai-audit collector and player integration / collector · linux (push) Successful in 4m6s
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · macos (push) Successful in 3m38s
wai-quantum for Python / python · macos (push) Successful in 3m48s
wai-quantum pulse and dynamics / the same bits · linux-arm64 (push) Successful in 3m59s
wai-quantum editors / editors · macos (push) Successful in 2m28s
wai-quantum pulse and dynamics / reader, simulator and pulse jobs under wasm32-wasip2 (wasmtime) (push) Successful in 4m52s
wai-quantum docs, course and locales / the course and the command line's languages · linux (push) Successful in 5m56s
wai-quantum service / service energy · linux packages (push) Successful in 5m23s
wai-quantum command line / command line · macos (push) Successful in 3m24s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 8m10s
wai-quantum wasmQ / interpreter and vectors under wasm32-wasip2 (wasmtime) (push) Successful in 7m52s
wai-quantum contract / the policy is linked, and the deprecations page reads (push) Successful in 10s
wai-quantum service / service · macos (push) Successful in 8m1s
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux-arm64, release (push) Successful in 7m32s
wai-quantum pulse and dynamics / reader, simulator and pulse jobs · linux, release (push) Successful in 8m36s
wai-quantum editors / editors · linux (push) Successful in 8m4s
wai-quantum extension points / the registry under wasm32-wasip2 (wasmtime) (push) Successful in 8m53s
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · linux (push) Successful in 9m7s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 8m4s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 7m29s
wai-quantum OpenQASM reader / corpus under wasm32-wasip2 (wasmtime) (push) Successful in 1m18s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Failing after 12m8s
wai-quantum contract / API compatibility · linux (push) Successful in 5m16s
wai-quantum for JavaScript / javascript · linux (push) Successful in 11m27s
wai-quantum extension points / the registry and the example · linux-arm64 (push) Successful in 12m6s
WAI examples / WAI examples · android-app · linux-arm64 (push) Successful in 13m41s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 9m15s
wai-quantum service / service · linux (push) Successful in 12m53s
wai-quantum resource estimation / estimation and calibration · linux, release (push) Successful in 14m1s
wai-quantum verdicts and repairs / verdicts, repairs and the intent set · linux (push) Successful in 3m10s
wai-quantum verdicts and repairs / the intent set and the verdict under wasm32-wasip2 (wasmtime) (push) Successful in 3m22s
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux, release (push) Successful in 4m10s
wai-quantum error correction and mitigation / codes, decoders, texts and mitigation · linux, release (push) Successful in 14m45s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 1m9s
WAI Studio / Studio in Chromium and Firefox · macos (push) Successful in 11m39s
wai-quantum extension points / the registry and the example · linux (push) Successful in 15m22s
wai-quantum for Python / python · linux (push) Successful in 15m45s
wai-quantum other formats / the set under wasm32-wasip2 (wasmtime) (push) Successful in 7m23s
wai-quantum clippy / clippy, warnings denied, every feature set · linux (push) Successful in 11m15s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 17m27s
wai-quantum other formats / readers, writers and the set · linux (push) Successful in 10m16s
wai-quantum views in agent hosts / views · the page and its engine (push) Successful in 5m18s
wai-quantum OpenQASM reader / reader and corpus · linux (push) Successful in 10m1s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 10m56s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (push) Successful in 21m33s
wai-quantum views in agent hosts / views · a scripted host (push) Successful in 7m1s
wai-quantum studio and desktop / studio · browser (push) Successful in 13m47s
WAI examples / WAI examples · portable · linux (push) Successful in 24m8s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 17m57s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 29m1s
WAI Studio / Studio in WebKit · linux (push) Successful in 16m2s
wai-quantum contract / schemas and the committed tool lists · linux (push) Successful in 25m13s
wai-quantum command line / command line · linux (push) Successful in 28m51s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 28m15s
wai-quantum docs, course and locales / every command and snippet in the docs · linux (push) Successful in 36m16s
The surface-code memory example (examples/qec_memory) gains what a paired comparison with the published decoders needs: - survey --skip K decodes shots K to K + N of each experiment (K even, so every shot keeps its parity and the model that parity picks), and scores the published decoders on the same shots: shots a decoder's settings were never chosen on. - survey --predictions DIR now also writes the published decoders' predictions on the same shots and the record's own flips, one byte a shot, beside this crate's. - Every receipt records its first shot, and per experiment, for each of this crate's decoders against each published decoder, the shots only one of the two got wrong. - qec_memory pairs SET KEY@RECEIPT... tests those counts: the exact two-sided McNemar test per distance and over every distance given, the fitted rates and Lambda of both, and a paired bootstrap (every fitted experiment's shots drawn again with the two decoders' outcomes on a shot kept together, each replicate from its own seed) of each distance's rate ratio and of the difference in Lambda. No receipt changes here; the runs that use it follow. Co-Authored-By: Claude Opus 5.5 <[email protected]>
230 lines
12 KiB
Rust
230 lines
12 KiB
Rust
//! The two published record sets, read as they unpack.
|
||
|
||
use std::path::{Path, PathBuf};
|
||
use wai_quantum::quantum_frame::ErrorModel;
|
||
use wai_quantum::quantum_memory::{Shots, fit_priors, read_01, read_b8};
|
||
use wai_quantum::quantum_qec_text::parse_dem;
|
||
|
||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||
pub enum Set {
|
||
/// doi:10.5281/zenodo.6804040: distance 3 (four patches) and 5, rounds
|
||
/// 1 to 25, 50,000 shots an experiment.
|
||
Y2023,
|
||
/// doi:10.5281/zenodo.13273331, the 105-qubit set: distance 3 (nine
|
||
/// patches), 5 (four) and 7 (one), rounds 1 to 250.
|
||
Y2024,
|
||
}
|
||
|
||
impl Set {
|
||
pub fn parse(s: &str) -> Option<Set> {
|
||
match s {
|
||
"2023" => Some(Set::Y2023),
|
||
"2024" => Some(Set::Y2024),
|
||
_ => None,
|
||
}
|
||
}
|
||
pub fn name(self) -> &'static str {
|
||
match self {
|
||
Set::Y2023 => "2023",
|
||
Set::Y2024 => "2024",
|
||
}
|
||
}
|
||
/// The experiment, as cited.
|
||
pub fn citation(self) -> &'static str {
|
||
match self {
|
||
Set::Y2023 => "Google Quantum AI, Suppressing quantum errors by scaling a surface code logical qubit, Nature 614, 676 (2023), doi:10.1038/s41586-022-05434-1 (allow-name: the citation and CC BY 4.0 credit the record's licence requires)",
|
||
Set::Y2024 => "Google Quantum AI and Collaborators, Quantum error correction below the surface code threshold, Nature 638, 920 (2025), doi:10.1038/s41586-024-08449-y (allow-name: the citation and CC BY 4.0 credit the record's licence requires)",
|
||
}
|
||
}
|
||
/// The record, pinned.
|
||
pub fn source(self) -> serde_json::Value {
|
||
match self {
|
||
Set::Y2023 => serde_json::json!({
|
||
"doi": "10.5281/zenodo.6804040",
|
||
"url": "https://zenodo.org/api/records/6804040/files/google_qec3v5_experiment_data.zip/content", // allow-name: the record's own file name and its CC BY 4.0 credit
|
||
"file": "google_qec3v5_experiment_data.zip", "bytes": 315_490_804u64, // allow-name: the record's own file name and its CC BY 4.0 credit
|
||
"md5": "a7fd8b481c3087090093106382dc217d",
|
||
"sha256": "ef569742126b305e163cc7fccbf6275e03bdd54d090dffb1aef12a78af0a74c4",
|
||
"licence": "CC BY 4.0", "by": "Google Quantum AI", // allow-name: the record's own file name and its CC BY 4.0 credit
|
||
}),
|
||
Set::Y2024 => serde_json::json!({
|
||
"doi": "10.5281/zenodo.13273331",
|
||
"url": "https://zenodo.org/api/records/13273331/files/google_105Q_surface_code_d3_d5_d7.zip/content", // allow-name: the record's own file name and its CC BY 4.0 credit
|
||
"file": "google_105Q_surface_code_d3_d5_d7.zip", "bytes": 5_716_907_033u64, // allow-name: the record's own file name and its CC BY 4.0 credit
|
||
"md5": "21fa6ad35b395d838ebcdbc92e364a12",
|
||
"sha256": "1e8e3b4f5f35ba4fd9b4a8448473f37a7090b404fd6eff0c00188092876070dd",
|
||
"licence": "CC BY 4.0", "by": "Google Quantum AI", // allow-name: the record's own file name and its CC BY 4.0 credit
|
||
}),
|
||
}
|
||
}
|
||
/// The fit, as the receipt states it.
|
||
pub fn fit_rule(self) -> &'static str {
|
||
match self {
|
||
Set::Y2023 => "per patch and basis, a weighted least-squares line through ln(1 − 2p) over rounds 3 to 25 (binomial weights; σ scaled by √(χ²/dof) when above one); ε averaged over patches and bases; Λ = ε₃/ε₅",
|
||
Set::Y2024 => "per patch and basis, a weighted least-squares line through ln(1 − 2p) over rounds 10 to 250 less the 13-round calibration experiments (binomial weights; σ scaled by √(χ²/dof) when above one); ε averaged over patches and bases; Λ from a weighted line through ln ε_d against (d + 1)/2",
|
||
}
|
||
}
|
||
/// Whether a publication's fits use an experiment of `rounds` rounds:
|
||
/// from round 3 (2023); from round 10 (2024), less the 13-round
|
||
/// experiments, which calibrated the optimized prior and carry no
|
||
/// ensembled-synthesis predictions.
|
||
pub fn fitted(self, rounds: u32) -> bool {
|
||
match self {
|
||
Set::Y2023 => rounds >= 3,
|
||
Set::Y2024 => rounds >= 10 && rounds != 13,
|
||
}
|
||
}
|
||
}
|
||
|
||
/// One experiment of a set.
|
||
#[derive(Clone, Debug)]
|
||
pub struct Experiment {
|
||
pub name: String,
|
||
pub dir: PathBuf,
|
||
pub distance: u32,
|
||
pub basis: String,
|
||
pub rounds: u32,
|
||
pub patch: String,
|
||
pub shots: usize,
|
||
pub detectors: usize,
|
||
}
|
||
|
||
fn kv(text: &str, key: &str) -> Option<String> {
|
||
text.lines().find_map(|l| l.strip_prefix(key).and_then(|r| r.strip_prefix(':')).map(|v| v.trim().to_string()))
|
||
}
|
||
|
||
/// Every surface-code experiment of the set under `dir`, in name order.
|
||
pub fn list(set: Set, dir: &Path) -> Vec<Experiment> {
|
||
let mut out = Vec::new();
|
||
match set {
|
||
Set::Y2023 => {
|
||
let mut names: Vec<String> = std::fs::read_dir(dir).unwrap().map(|e| e.unwrap().file_name().into_string().unwrap()).filter(|n| n.starts_with("surface_code_")).collect();
|
||
names.sort();
|
||
for n in names {
|
||
let d = dir.join(&n);
|
||
let p = std::fs::read_to_string(d.join("properties.yml")).unwrap();
|
||
let num = |k: &str| kv(&p, k).unwrap_or_else(|| panic!("{n}: no {k}")).parse::<usize>().unwrap();
|
||
let (row, col) = (num("center_data_qubit_row"), num("center_data_qubit_col"));
|
||
out.push(Experiment {
|
||
name: n.clone(),
|
||
dir: d.clone(),
|
||
distance: num("distance") as u32,
|
||
basis: kv(&p, "basis").unwrap(),
|
||
rounds: num("rounds") as u32,
|
||
patch: format!("{row}_{col}"),
|
||
shots: num("shots"),
|
||
detectors: num("circuit_detectors"),
|
||
});
|
||
}
|
||
}
|
||
Set::Y2024 => {
|
||
let root = dir.join("google_105Q_surface_code_d3_d5_d7"); // allow-name: the record's own file name and its CC BY 4.0 credit
|
||
let mut patches: Vec<String> = std::fs::read_dir(&root).unwrap().map(|e| e.unwrap().file_name().into_string().unwrap()).filter(|n| n.starts_with('d') && n.contains("_at_")).collect();
|
||
patches.sort();
|
||
for patch in patches {
|
||
for basis in ["X", "Z"] {
|
||
let bdir = root.join(&patch).join(basis);
|
||
if !bdir.is_dir() {
|
||
continue;
|
||
}
|
||
let mut rs: Vec<String> = std::fs::read_dir(&bdir).unwrap().map(|e| e.unwrap().file_name().into_string().unwrap()).filter(|n| n.starts_with('r')).collect();
|
||
rs.sort();
|
||
for r in rs {
|
||
let d = bdir.join(&r);
|
||
let meta: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(d.join("metadata.json")).unwrap()).unwrap();
|
||
let get = |k: &str| meta.get(k).and_then(serde_json::Value::as_u64).unwrap_or_else(|| panic!("{}: metadata has no {k}: {meta}", d.display())) as usize;
|
||
// The circuit is written out round by round, one
|
||
// DETECTOR line a detector.
|
||
let circuit = std::fs::read_to_string(d.join("circuit_ideal.stim")).unwrap();
|
||
assert!(!circuit.contains("REPEAT"), "{}: a circuit with blocks", d.display());
|
||
let detectors = circuit.lines().filter(|l| l.starts_with("DETECTOR")).count();
|
||
out.push(Experiment {
|
||
name: format!("{patch}/{basis}/{r}"),
|
||
dir: d.clone(),
|
||
distance: patch[1..].split('_').next().unwrap().parse().unwrap(),
|
||
basis: basis.to_string(),
|
||
rounds: r[1..].parse().unwrap(),
|
||
patch: patch.split("_at_").nth(1).unwrap().to_string(),
|
||
shots: get("shots"),
|
||
detectors,
|
||
});
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
out
|
||
}
|
||
|
||
/// The experiment's detection events and observable flips.
|
||
pub fn shots(set: Set, e: &Experiment) -> Shots {
|
||
let det = std::fs::read(e.dir.join("detection_events.b8")).unwrap();
|
||
let obs = match set {
|
||
Set::Y2023 => read_01(&std::fs::read_to_string(e.dir.join("obs_flips_actual.01")).unwrap(), 1, e.shots).unwrap(),
|
||
Set::Y2024 => read_b8(&std::fs::read(e.dir.join("obs_flips_actual.b8")).unwrap(), 1, e.shots).unwrap(),
|
||
};
|
||
Shots::from_b8(det, e.detectors, obs, 1).unwrap_or_else(|err| panic!("{}: {err}", e.name))
|
||
}
|
||
|
||
/// The published decoders' predictions for the experiment's shots `skip` to
|
||
/// `skip + n`: each decoder's name and its predictions on those shots, shot
|
||
/// `skip` first.
|
||
pub fn published(set: Set, e: &Experiment, skip: usize, n: usize) -> Vec<(String, Vec<u64>)> {
|
||
let mut out = Vec::new();
|
||
let cut = |pred: Vec<u64>| -> Vec<u64> { pred[skip..skip + n].to_vec() };
|
||
match set {
|
||
Set::Y2023 => {
|
||
for name in ["pymatching", "correlated_matching", "belief_matching", "tensor_network_contraction"] {
|
||
let f = e.dir.join(format!("obs_flips_predicted_by_{name}.01"));
|
||
if let Ok(t) = std::fs::read_to_string(&f) {
|
||
out.push((name.to_string(), cut(read_01(&t, 1, e.shots).unwrap())));
|
||
}
|
||
}
|
||
}
|
||
Set::Y2024 => {
|
||
let dr = e.dir.join("decoding_results");
|
||
if let Ok(rd) = std::fs::read_dir(&dr) {
|
||
let mut names: Vec<String> = rd.map(|x| x.unwrap().file_name().into_string().unwrap()).collect();
|
||
names.sort();
|
||
for name in names {
|
||
let f = dr.join(&name).join("obs_flips_predicted.b8");
|
||
if let Ok(b) = std::fs::read(&f) {
|
||
out.push((name, cut(read_b8(&b, 1, e.shots).unwrap())));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
out
|
||
}
|
||
|
||
fn read_model(path: &Path) -> ErrorModel {
|
||
let t = std::fs::read_to_string(path).unwrap_or_else(|e| panic!("{}: {e}", path.display()));
|
||
parse_dem(&t).unwrap_or_else(|e| panic!("{}: {e}", path.display())).to_model().unwrap_or_else(|e| panic!("{}: {e}", path.display()))
|
||
}
|
||
|
||
/// The models a prior names, one per shot residue: shot `s` is decoded with
|
||
/// model `s mod len`.
|
||
pub fn models(set: Set, e: &Experiment, prior: &str, shots: &Shots) -> Vec<ErrorModel> {
|
||
// This crate's fit, over a published model's structure: even shots
|
||
// decoded with the model fitted to the odd ones, and odd with even.
|
||
let fitted = |structure: ErrorModel| -> Vec<ErrorModel> {
|
||
let (for_even, a) = fit_priors(&structure, &shots.select(|s| s % 2 == 1), true, 200);
|
||
let (for_odd, b) = fit_priors(&structure, &shots.select(|s| s % 2 == 0), true, 200);
|
||
eprintln!("{}: fitted {} symptom sets to {} parities ({} and {} sweeps, residual {:.3e} → {:.3e})", e.name, a.unknowns, a.equations, a.sweeps, b.sweeps, a.residual.0, a.residual.1);
|
||
vec![for_even, for_odd]
|
||
};
|
||
match (set, prior) {
|
||
(Set::Y2023, "fit") => fitted(read_model(&e.dir.join("circuit_detector_error_model.dem"))),
|
||
(Set::Y2023, "fitpij") => fitted(read_model(&e.dir.join("pij_from_even_for_odd.dem"))),
|
||
(Set::Y2024, "fit") => fitted(read_model(&e.dir.join("decoding_results/correlated_matching_decoder_with_si1000_prior/error_model.dem"))),
|
||
(Set::Y2024, "fitrl") => fitted(read_model(&e.dir.join("decoding_results/correlated_matching_decoder_with_rl_optimized_prior/error_model.dem"))),
|
||
// Even shots with the model fitted to the odd ones, and odd shots
|
||
// with the model fitted to the even ones.
|
||
(Set::Y2023, "pij") => vec![read_model(&e.dir.join("pij_from_odd_for_even.dem")), read_model(&e.dir.join("pij_from_even_for_odd.dem"))],
|
||
(Set::Y2023, "circuit") => vec![read_model(&e.dir.join("circuit_detector_error_model.dem"))],
|
||
(Set::Y2024, "si1000") => vec![read_model(&e.dir.join("decoding_results/correlated_matching_decoder_with_si1000_prior/error_model.dem"))],
|
||
(Set::Y2024, "rl") => vec![read_model(&e.dir.join("decoding_results/correlated_matching_decoder_with_rl_optimized_prior/error_model.dem"))],
|
||
_ => panic!("no prior {prior} for set {}", set.name()),
|
||
}
|
||
}
|