wai-quantum-service: two worked examples that measure in the middle #338

Merged
dcharlot merged 1 commit from wai/quantum-dynamic-examples into main 2026-10-19 20:26:18 -04:00
2 changed files with 33 additions and 0 deletions

View file

@ -58,6 +58,18 @@ pub fn examples() -> Value {
"shows": "The same pair with gate errors and readout flips: 01 and 10 appear, and ⟨Z0 Z1⟩ falls below 1. With noise on few qubits the exact density matrix runs.",
"job": { "qasm": ghz(2), "shots": 4000, "observables": ["Z0 Z1"], "noise": { "depolarizing_1q": 0.01, "depolarizing_2q": 0.03, "readout": 0.02 } }
},
{
"name": "teleport",
"title": "Teleporting a qubit",
"shows": "ry(0.7) on q0 arrives on q2: two qubits are measured in the middle, and if applies the corrections they select. ⟨Z2⟩ = cos 0.7 and ⟨X2⟩ = sin 0.7 exactly, weighed over all four branches; the shots split at each measurement as independent runs would.",
"job": { "qasm": "OPENQASM 3.0;\nqubit[3] q;\nbit[3] c;\nry(0.7) q[0];\nh q[1];\ncx q[1], q[2];\ncx q[0], q[1];\nh q[0];\nc[0] = measure q[0];\nc[1] = measure q[1];\nif (c[1]) x q[2];\nif (c[0]) z q[2];\nc[2] = measure q[2];", "shots": 1000, "observables": ["Z2", "X2"] }
},
{
"name": "bit-flip-code",
"title": "A bit flip found and undone",
"shows": "The three-qubit bit-flip code holding |+⟩, with a flip on the middle qubit. Two ancillas, measured in the middle, name the flip (the syndrome reads 11 on every shot), and if undoes it, so ⟨X0⟩ = 1 after decoding. Every gate is Clifford, so the stabilizer tableau runs.",
"job": { "qasm": "OPENQASM 3.0;\nqubit[5] q;\nbit[2] s;\nbit r;\nh q[0];\ncx q[0], q[1];\ncx q[0], q[2];\nx q[1];\ncx q[0], q[3];\ncx q[1], q[3];\ncx q[1], q[4];\ncx q[2], q[4];\ns[0] = measure q[3];\ns[1] = measure q[4];\nif (s == 1) x q[0];\nif (s == 3) x q[1];\nif (s == 2) x q[2];\ncx q[0], q[1];\ncx q[0], q[2];\nr = measure q[0];", "shots": 1000, "observables": ["X0"] }
},
{
"name": "ghz-1000",
"title": "A thousand-qubit GHZ state",
@ -196,6 +208,8 @@ mod tests {
("rotation", "statevector"),
("qaoa-ring", "statevector"),
("noisy-bell", "density_matrix"),
("teleport", "statevector"),
("bit-flip-code", "stabilizer"),
("ghz-1000", "stabilizer"),
("noisy-ghz-500", "stabilizer"),
("chain-100-dynamics", "pauli"),

View file

@ -866,6 +866,25 @@ mod tests {
}
}
/// The two worked examples that measure in the middle do what their
/// `shows` says.
#[test]
fn the_measuring_examples_show_what_they_say() {
let ex = crate::discovery::examples();
let job = |name: &str| ex.as_array().unwrap().iter().find(|e| e["name"] == name).unwrap()["job"].clone();
let t = go(job("teleport"));
assert_eq!(t["method"], "statevector", "{t}");
assert!((t["expectations"][0]["value"].as_f64().unwrap() - 0.7f64.cos()).abs() < 1e-12, "{t}");
assert!((t["expectations"][1]["value"].as_f64().unwrap() - 0.7f64.sin()).abs() < 1e-12, "{t}");
assert_eq!(t["dynamic"]["branches_weighed"], 4, "{t}");
let b = go(job("bit-flip-code"));
assert_eq!(b["method"], "stabilizer", "{b}");
assert_eq!(b["expectations"][0]["value"], 1.0, "{b}");
let counts = b["counts"].as_object().unwrap();
assert!(counts.keys().all(|k| k.ends_with("11")), "the syndrome names the middle qubit on every shot: {b}");
assert_eq!(counts.values().map(|v| v.as_u64().unwrap()).sum::<u64>(), 1000);
}
#[test]
fn dynamic_runs_repeat_with_their_seed() {
let qasm = TELEPORT.replace("THETA", "1.1");