Some checks failed
wai-audit collector and player integration / does this change touch it (push) Successful in 34s
WAI operation catalogue / does this change touch it (push) Successful in 26s
wai-quantum command line / does this change touch it (push) Successful in 24s
wai-quantum clippy / does this change touch it (push) Successful in 42s
wai-quantum contract / does this change touch it (push) Successful in 32s
wai-quantum docs, course and locales / does this change touch it (push) Successful in 48s
wai-quantum other formats / does this change touch it (push) Successful in 31s
wai-quantum editors / does this change touch it (push) Successful in 1m27s
wai-quantum for JavaScript / does this change touch it (push) Successful in 59s
wai-quantum-landscape-fpga reference design / does this change touch it (push) Successful in 48s
wai-quantum resource estimation / does this change touch it (push) Successful in 1m19s
wai-quantum OpenQASM reader / does this change touch it (push) Successful in 49s
wai-quantum pulse and dynamics / does this change touch it (push) Successful in 40s
wai-quantum service / does this change touch it (push) Successful in 19s
wai-quantum for Python / does this change touch it (push) Successful in 36s
wai-quantum views in agent hosts / does this change touch it (push) Successful in 28s
wai-quantum verdicts and repairs / does this change touch it (push) Successful in 40s
wai-quantum on Windows / does this change touch it (push) Successful in 32s
wai-quantum extension points / does this change touch it (push) Successful in 2m14s
wai-quantum error correction and mitigation / does this change touch it (push) Successful in 2m26s
WAI Studio / does this change touch it (push) Successful in 1m43s
wai-sink-android native sink library / does this change touch it (push) Successful in 1m59s
wai-quantum variational and algorithm library / does this change touch it (push) Successful in 2m9s
wai-quantum studio and desktop / does this change touch it (push) Successful in 2m14s
wai-quantum qudit jobs / does this change touch it (push) Successful in 2m25s
wai-sink-swift native sink package / does this change touch it (push) Successful in 1m49s
wai-quantum service / service energy · linux packages (push) Failing after 6s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Has been cancelled
WAI Studio / Studio in Chromium and Firefox · macos (push) Has been cancelled
WAI Studio / Studio in WebKit · linux (push) Has been cancelled
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Has been cancelled
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Has been cancelled
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Has been cancelled
wai-quantum wasmQ / does this change touch it (push) Has been cancelled
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · linux (push) Has been cancelled
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · macos (push) Has been cancelled
wai-quantum wasmQ / the reference modules rebuild to their modules of record · linux (push) Has been cancelled
wai-quantum wasmQ / interpreter and vectors under wasm32-wasip2 (wasmtime) (push) Has been cancelled
wai-quantum views in agent hosts / views · the page and its engine (push) Has been cancelled
wai-quantum views in agent hosts / views · a scripted host (push) Has been cancelled
wai-quantum verdicts and repairs / verdicts, repairs and the intent set · linux (push) Has been cancelled
wai-quantum verdicts and repairs / the intent set and the verdict under wasm32-wasip2 (wasmtime) (push) Has been cancelled
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux, release (push) Has been cancelled
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux-arm64, release (push) Has been cancelled
wai-quantum studio and desktop / studio · browser (push) Has been cancelled
wai-quantum studio and desktop / desktop app · macos (push) Has been cancelled
wai-quantum studio and desktop / desktop app · linux (push) Has been cancelled
wai-quantum studio and desktop / desktop app · windows (push) Has been cancelled
wai-quantum extension points / the registry and the example · linux (push) Has been cancelled
wai-quantum extension points / the registry and the example · linux-arm64 (push) Has been cancelled
wai-quantum extension points / the registry under wasm32-wasip2 (wasmtime) (push) Has been cancelled
wai-quantum error correction and mitigation / codes, decoders, texts and mitigation · linux, release (push) Has been cancelled
wai-quantum for Python / python · linux (push) Has been cancelled
wai-quantum for Python / python · macos (push) Has been cancelled
wai-quantum pulse and dynamics / reader, simulator and pulse jobs · linux, release (push) Has been cancelled
wai-quantum pulse and dynamics / the same bits · linux-arm64 (push) Has been cancelled
wai-quantum pulse and dynamics / the same bits · macos (push) Has been cancelled
wai-quantum pulse and dynamics / reader, simulator and pulse jobs under wasm32-wasip2 (wasmtime) (push) Has been cancelled
wai-quantum OpenQASM reader / reader and corpus · linux (push) Has been cancelled
wai-quantum OpenQASM reader / corpus under wasm32-wasip2 (wasmtime) (push) Has been cancelled
wai-quantum energy-landscape jobs / does this change touch it (push) Has been cancelled
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Has been cancelled
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Has been cancelled
wai-quantum energy-landscape jobs / the same bits · macos (push) Has been cancelled
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Has been cancelled
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Has been cancelled
wai-quantum for JavaScript / javascript · linux (push) Has been cancelled
wai-quantum other formats / readers, writers and the set · linux (push) Has been cancelled
wai-quantum other formats / the set under wasm32-wasip2 (wasmtime) (push) Has been cancelled
wai-quantum resource estimation / estimation and calibration · linux, release (push) Has been cancelled
wai-quantum editors / editors · linux (push) Has been cancelled
wai-quantum editors / editors · macos (push) Has been cancelled
wai-quantum docs, course and locales / every command and snippet in the docs · linux (push) Has been cancelled
wai-quantum docs, course and locales / the course and the command line's languages · linux (push) Has been cancelled
wai-quantum docs, course and locales / the Studio's words in every locale · linux (push) Has been cancelled
wai-quantum contract / API compatibility · linux (push) Has been cancelled
wai-quantum contract / schemas and the committed tool lists · linux (push) Has been cancelled
wai-quantum contract / the policy is linked, and the deprecations page reads (push) Has been cancelled
wai-quantum clippy / clippy, warnings denied, every feature set · linux (push) Has been cancelled
wai-quantum command line / command line · linux (push) Has been cancelled
wai-quantum command line / command line · macos (push) Has been cancelled
WAI examples / WAI examples · does this change touch them (push) Has been cancelled
WAI examples / WAI examples · portable · linux (push) Has been cancelled
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (push) Has been cancelled
WAI examples / WAI examples · android-app · linux-arm64 (push) Has been cancelled
WAI operation catalogue / the catalogue and every door · linux (push) Has been cancelled
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Has been cancelled
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Has been cancelled
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Has been cancelled
wai-audit collector and player integration / collector · linux (push) Has been cancelled
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Has been cancelled
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Has been cancelled
wai-quantum landscape energy to solution / does this change touch it (push) Successful in 11s
wai-quantum landscape stage 0, the sampler against the exact law / does this change touch it (push) Successful in 11s
wai-quantum qudit jobs / the module and the conformance set under wasm32-wasip2 (wasmtime) (push) Successful in 2m12s
wai-quantum qudit jobs / the module, the job, the conformance set, the referee and the verb · linux (push) Successful in 6m28s
wai-quantum-landscape-fpga reference design / the board's code on the board's processor's architecture · linux-arm64, release (push) Successful in 2m20s
wai-quantum service / service · linux (push) Successful in 15m18s
wai-quantum landscape energy to solution / the small tier, to the byte · linux (push) Successful in 2m22s
wai-quantum landscape stage 0, the sampler against the exact law / the small tier, to the byte · linux (push) Successful in 55s
wai-quantum qudit jobs / the same bits · macos (push) Successful in 2m30s
wai-quantum-landscape-fpga reference design / the member against the model of the logic, and the logic against the model · linux, release (push) Successful in 40m33s
wai-quantum service / service · macos (push) Successful in 7m59s
wai-quantum on Windows / engine · windows (push) Failing after 19m8s
wai-quantum landscape stage 0, the sampler against the exact law / the small tier, to the byte · macos (push) Successful in 57s
wai-quantum landscape energy to solution / the small tier, to the byte · macos (push) Successful in 2m7s
wai-quantum on Windows / command line · windows (push) Failing after 5m28s
wai-quantum on Windows / job service · windows (push) Failing after 4m3s
wai-quantum on Windows / python · windows (push) Failing after 9m44s
A peaked circuit is built as R, a block U and its approximate inverse U† (re-angled, re-synthesised in patches, on all-to-all hardware moved by hidden permutations), and P trained to peak R (arXiv:2510.25838). Forward, the middle is as hard as any random circuit of its depth; grown outward from the junction between U and U†, the circuit's operator stays near the identity until R and P. The published classical solutions use that (arXiv:2604.21908). quantum_peaked (new feature and module): - Layered: the circuit as layers of two-qubit blocks. - scan / best_centre / probe: every centre (a cut, or a layer alone) probed by growing the operator a few layers each way; the smallest marks the junction. - cancel / cancel_unswapping: the whole circuit as an operator on the graph its gates build (rows after the centre, columns before it), bonds made and dropped as gates join qubits, each side layered by its distance from the junction; simple-update truncation; optional unswapping that keeps a SWAP shrinking a bond as a relabelling of rows or columns. - Operator::peak (marginals by exact contraction) and Operator::amplitude (<s|C|0...0> with the scale carried through every update). quantum_bptn: gate_of, Gate, svd_rows visible to the crate, unchanged. Results (tracker_peaked structure / verify, receipts in tests/data/tracker): - 49x5072: junction at block layer 138.5 (probe log size 2.8, median 105); the operator is the identity from the 10th to the 130th layer a side; peak 1001100011100000001010100001011111111011110010110 (qubit 48 first), the published string, |<s|C|0>|^2 = 0.709. 6-19 s, < 75 MB. - 49x4020: junction at 109.5, bonds <= 4; peak 0110011000010000100101000110001101000000100001001 (qubit 48 first), 0.694. - verify: the string's amplitude in the whole circuit at cutoffs 1e-2..1e-3 from two centres: 0.7089-0.7094 and 0.6934-0.6997. - P9_Hqap_56x1917: not found; no centre stands out and the operator reaches 237 bonds and 1e7 numbers by 14 layers a side. tests/tracker_peaked.rs re-runs both heavy-hex recoveries from the circuits, now kept as fixtures (unmodified, Apache-2.0), and checks the receipts. Co-Authored-By: Claude Opus 5.5 <[email protected]>
317 lines
17 KiB
Rust
317 lines
17 KiB
Rust
//! The peaked circuits read through the structure they were built with
|
||
//! (`quantum_peaked`): the junction found by probing, the operator grown
|
||
//! outward from it, the peak read by exact contraction, and each string's
|
||
//! amplitude in the whole circuit at a sweep of truncations.
|
||
|
||
#![allow(dead_code)]
|
||
|
||
use serde_json::{Value, json};
|
||
use wai_quantum::quantum_peaked::{Layered, Truncation, Unswap, best_centre, cancel, cancel_unswapping, probe, scan, scan_unswapping};
|
||
use wai_quantum::quantum_spd::RotCircuit;
|
||
|
||
/// The peaks the tracker's classical submissions published, as printed there,
|
||
/// with where each was printed. The 49×5072 string is printed qubit 48 first;
|
||
/// the 56×1917 string as the submission's notebook gives it, compared here in
|
||
/// both orders.
|
||
pub const PUBLISHED: &[(&str, &str, &str)] = &[
|
||
(
|
||
"49x5072",
|
||
"1001100011100000001010100001011111111011110010110",
|
||
"tracker issue #105 (TNO + iterative cancellation), the string as submitted",
|
||
),
|
||
(
|
||
"P9_Hqap_56x1917",
|
||
"01101110111001100000100000001010011100101101010111110111",
|
||
"the notebook issue #106 links (MPO + unswapping), the string it checks its sample against",
|
||
),
|
||
];
|
||
|
||
/// The published string for `name`, if one was printed, and its source.
|
||
pub fn published(name: &str) -> Option<(&'static str, &'static str)> {
|
||
PUBLISHED.iter().find(|(n, _, _)| *n == name).map(|(_, s, w)| (*s, *w))
|
||
}
|
||
|
||
fn bits(s: &str) -> Vec<u8> {
|
||
s.bytes().map(|b| u8::from(b == b'1')).collect()
|
||
}
|
||
|
||
fn text(b: &[u8]) -> String {
|
||
b.iter().map(|&x| if x == 1 { '1' } else { '0' }).collect()
|
||
}
|
||
|
||
/// The arguments after the mode, as `key=value`.
|
||
fn arg<T: std::str::FromStr>(args: &[String], key: &str, default: T) -> T {
|
||
args.iter()
|
||
.find_map(|a| a.strip_prefix(&format!("{key}=")).map(|v| v.parse().unwrap_or_else(|_| panic!("{key}={v} does not read"))))
|
||
.unwrap_or(default)
|
||
}
|
||
|
||
/// Bits in the string for qubit order `q = 0, 1, …` from a string printed
|
||
/// either way, and which way matched (the order with the larger amplitude).
|
||
pub fn orient(printed: &str) -> [(Vec<u8>, &'static str); 2] {
|
||
let fwd = bits(printed);
|
||
let mut rev = fwd.clone();
|
||
rev.reverse();
|
||
[(fwd, "as printed, first character qubit 0"), (rev, "reversed, last character qubit 0")]
|
||
}
|
||
|
||
/// `structure`: scan every centre, grow the operator from the smallest, read
|
||
/// the peak; then the string's amplitude in that operator, and the published
|
||
/// string's when there is one. Writes a receipt.
|
||
pub fn structure(circuit: &RotCircuit, map: &[u32], name: &str, path: &str, args: &[String]) {
|
||
let window: usize = arg(args, "window", 4);
|
||
let chi: usize = arg(args, "chi", 16);
|
||
let cutoff: f64 = arg(args, "cutoff", 1e-2);
|
||
let probe_chi: usize = arg(args, "probe_chi", 8);
|
||
let read_chi: usize = arg(args, "read_chi", 8);
|
||
let read_cutoff: f64 = arg(args, "read_cutoff", 1e-2);
|
||
let limit: usize = arg(args, "limit", 1 << 26);
|
||
let forced: Option<usize> = args.iter().find_map(|a| a.strip_prefix("centre=").map(|v| v.parse().expect("a centre")));
|
||
// unswap=T: unswapping wherever a bond reaches T (0: none), rounds=R passes a step.
|
||
let threshold: usize = arg(args, "unswap", 0);
|
||
let rounds: usize = arg(args, "rounds", 4);
|
||
let unswap = (threshold > 0).then_some(Unswap { threshold, rounds });
|
||
let trunc = Truncation { chi, cutoff };
|
||
let ((layered, probes, centre, op, peak, amp, pub_amps), secs, energy) = super::common::metered(|| {
|
||
let layered = Layered::new(circuit).expect("one- and two-qubit gates");
|
||
let probe = Truncation { chi: probe_chi, cutoff };
|
||
// scan=0 with a centre given: no scan.
|
||
let centres: Vec<usize> = if forced.is_some() && arg(args, "scan", 1) == 0 { Vec::new() } else { (0..=2 * layered.depth()).collect() };
|
||
let probes = match unswap {
|
||
Some(u) => scan_unswapping(&layered, centres, window, probe, u),
|
||
None => scan(&layered, centres, window, probe),
|
||
}
|
||
.expect("centres in range");
|
||
let centre = forced.unwrap_or_else(|| best_centre(&layered, &probes).expect("a centre"));
|
||
let op = match unswap {
|
||
Some(u) => cancel_unswapping(&layered, centre, trunc, 1, u),
|
||
None => cancel(&layered, centre, trunc, 1),
|
||
}
|
||
.expect("the centre");
|
||
let peak = op.peak(Truncation { chi: read_chi, cutoff: read_cutoff }, 2, limit).expect("a readout within the limit");
|
||
let amp = op.amplitude(&peak.string, limit).expect("the amplitude");
|
||
let pub_amps: Vec<(String, f64, &'static str)> = published(name)
|
||
.map(|(s, _)| orient(s).into_iter().map(|(b, how)| (text(&b), op.amplitude(&b, limit).expect("the amplitude").probability, how)).collect())
|
||
.unwrap_or_default();
|
||
(layered, probes, centre, op, peak, amp, pub_amps)
|
||
});
|
||
let mut ranked = probes.clone();
|
||
ranked.sort_by(|a, b| a.step.log_size.total_cmp(&b.step.log_size).then(a.centre.cmp(&b.centre)));
|
||
println!("layers {} block layers, {} blocks, {} two-qubit gates", layered.depth(), layered.blocks(), layered.two_qubit_gates());
|
||
println!("scan {} centres, window {window}, χ {probe_chi}, cutoff {cutoff:e}", probes.len());
|
||
for p in ranked.iter().take(5) {
|
||
println!(
|
||
" centre {:>4} (layer {:>6.1}) log size {:>7.3} max bond {:>3} bonds {:>3} discarded {:.3e}",
|
||
p.centre,
|
||
p.centre as f64 / 2.0,
|
||
p.step.log_size,
|
||
p.step.max_bond,
|
||
p.step.bonds,
|
||
p.step.discarded
|
||
);
|
||
}
|
||
let median = {
|
||
let mut v: Vec<f64> = probes.iter().map(|p| p.step.log_size).collect();
|
||
v.sort_by(f64::total_cmp);
|
||
v.get(v.len() / 2).copied().unwrap_or(0.0)
|
||
};
|
||
println!(" median log size over every centre {median:.3}");
|
||
let peak_bond = op.steps().iter().map(|s| s.max_bond).max().unwrap_or(1);
|
||
let peak_elems = op.steps().iter().map(|s| s.elements).max().unwrap_or(0);
|
||
println!("centre {centre} (layer {:.1}), χ {chi}, cutoff {cutoff:e}", centre as f64 / 2.0);
|
||
let n = op.steps().len();
|
||
for (i, s) in op.steps().iter().enumerate() {
|
||
if i % 10 == 0 || i + 1 == n {
|
||
println!(
|
||
" step {:>4} rows {:>4} cols {:>4} max bond {:>3} bonds {:>3} elements {:>7} discarded {:.3e}",
|
||
i, s.right, s.left, s.max_bond, s.bonds, s.elements, s.discarded
|
||
);
|
||
}
|
||
}
|
||
let weakest = peak.marginals.iter().map(|p| (p - 0.5).abs() * 2.0).fold(f64::INFINITY, f64::min);
|
||
println!("peak {} (bit q = qubit q)", text(&peak.string));
|
||
println!(" printed qubit {} first: {}", circuit.n - 1, text(&peak.string.iter().rev().copied().collect::<Vec<_>>()));
|
||
println!("probability {:.6} in the read state (bond {}), weakest bit margin {weakest:.3}", peak.probability, peak.max_bond);
|
||
println!("amplitude |⟨s|C|0⟩|² = {:.6e}, ‖C|0⟩‖² = {:.6e} in the operator, ratio {:.6}", amp.probability, amp.norm, amp.probability / amp.norm);
|
||
for (s, p, how) in &pub_amps {
|
||
let same = *s == text(&peak.string);
|
||
println!("published {s} ({how}): |⟨s|C|0⟩|² = {p:.6e}{}", if same { " = the peak read here" } else { "" });
|
||
}
|
||
println!(
|
||
"time {secs:.1} s, discarded {:.3e}, largest bond {peak_bond}, most elements {peak_elems}, swaps kept {}",
|
||
op.discarded(),
|
||
op.swaps()
|
||
);
|
||
let request = json!({
|
||
"instance": format!("peaked_circuit_{}", instance(name)),
|
||
"source": super::common::source(path),
|
||
"method": "quantum_peaked: the circuit as layers of two-qubit blocks; every centre probed by growing the circuit's operator a few layers each way (the smallest operator marks where a block meets its approximate inverse); the whole circuit grown outward from that centre as an operator on the graph its gates build (rows after the centre, columns before it), simple-update truncation; the peak read on |0…0⟩ by exact contraction of the network",
|
||
"window": window,
|
||
"probe_chi": probe_chi,
|
||
"chi": chi,
|
||
"cutoff": cutoff,
|
||
"read_chi": read_chi,
|
||
"read_cutoff": read_cutoff,
|
||
"unswap": unswap.map(|u| json!({"threshold": u.threshold, "rounds": u.rounds})),
|
||
"qubits": map,
|
||
});
|
||
let result = json!({
|
||
"block_layers": layered.depth(),
|
||
"blocks": layered.blocks(),
|
||
"two_qubit_gates": layered.two_qubit_gates(),
|
||
"scan_best": ranked.iter().take(5).map(|p| json!({"centre": p.centre, "log_size": p.step.log_size, "max_bond": p.step.max_bond, "bonds": p.step.bonds, "discarded": p.step.discarded})).collect::<Vec<_>>(),
|
||
"scan_median_log_size": median,
|
||
"centre": centre,
|
||
"steps": op.steps().iter().map(|s| json!([s.right, s.left, s.max_bond, s.bonds, s.elements, s.discarded])).collect::<Vec<_>>(),
|
||
"steps_columns": ["rows", "cols", "max_bond", "bonds", "elements", "discarded"],
|
||
"discarded": op.discarded(),
|
||
"swaps_kept": op.swaps(),
|
||
"string": text(&peak.string),
|
||
"string_order": "bit q is qubit q of the register as compacted (the device qubit map[q])",
|
||
"marginals_one": peak.marginals,
|
||
"probability_read": peak.probability,
|
||
"amplitude": { "re": amp.re, "im": amp.im, "probability": amp.probability, "norm": amp.norm },
|
||
"published": pub_amps.iter().map(|(s, p, how)| json!({"string": s, "order": how, "probability": p})).collect::<Vec<_>>(),
|
||
"published_source": published(name).map(|(_, w)| w),
|
||
"wall_seconds": secs,
|
||
"energy_figure": energy,
|
||
});
|
||
let out = super::common::receipt_path(&format!("peaked_{name}_structure_chi{chi}.json"));
|
||
assert!(super::common::verifies(&super::common::seal(request, result, Some(&out))));
|
||
println!("receipt {}", out.display());
|
||
}
|
||
|
||
/// `profile centre=H [steps=…] [chi=…] [cutoff=…] [unswap=T]`: the operator
|
||
/// grown from one centre for each number of steps in `steps=` (default
|
||
/// 2,4,8,16,32), each printed as it finishes, so a run that will not finish
|
||
/// shows where it grows.
|
||
pub fn profile(circuit: &RotCircuit, args: &[String]) {
|
||
let layered = Layered::new(circuit).expect("one- and two-qubit gates");
|
||
let centre: usize = args.iter().find_map(|a| a.strip_prefix("centre=").map(|v| v.parse().expect("a centre"))).unwrap_or(layered.depth());
|
||
let chi: usize = arg(args, "chi", 16);
|
||
let cutoff: f64 = arg(args, "cutoff", 1e-2);
|
||
let threshold: usize = arg(args, "unswap", 0);
|
||
let unswap = (threshold > 0).then_some(Unswap { threshold, rounds: arg(args, "rounds", 4) });
|
||
let steps: Vec<usize> = args
|
||
.iter()
|
||
.find_map(|a| a.strip_prefix("steps=").map(|v| v.split(',').map(|x| x.parse().expect("a step count")).collect()))
|
||
.unwrap_or_else(|| vec![2, 4, 8, 16, 32]);
|
||
println!("layers {} block layers, {} blocks; centre {centre}, χ {chi}, cutoff {cutoff:e}, unswap {threshold}", layered.depth(), layered.blocks());
|
||
for k in steps {
|
||
let started = std::time::Instant::now();
|
||
match probe(&layered, centre, k, Truncation { chi, cutoff }, unswap) {
|
||
Ok(op) => {
|
||
let s = op.steps().last().copied();
|
||
if let Some(s) = s {
|
||
println!(
|
||
" {k:>3} steps rows {:>3} cols {:>3} max bond {:>3} bonds {:>4} elements {:>9} log size {:>8.2} swaps {:>4} {:.1} s",
|
||
s.right,
|
||
s.left,
|
||
s.max_bond,
|
||
s.bonds,
|
||
s.elements,
|
||
s.log_size,
|
||
op.swaps(),
|
||
started.elapsed().as_secs_f64()
|
||
);
|
||
}
|
||
}
|
||
Err(e) => println!(" {k:>3} steps {e} {:.1} s", started.elapsed().as_secs_f64()),
|
||
}
|
||
}
|
||
}
|
||
|
||
/// `junction [window=2] [chi=8] [cutoff=…] [unswap=T]`: the scan alone, every
|
||
/// centre's probe printed in order, then the ten smallest.
|
||
pub fn junction(circuit: &RotCircuit, args: &[String]) {
|
||
let layered = Layered::new(circuit).expect("one- and two-qubit gates");
|
||
let window: usize = arg(args, "window", 2);
|
||
let trunc = Truncation { chi: arg(args, "chi", 8), cutoff: arg(args, "cutoff", 1e-2) };
|
||
let threshold: usize = arg(args, "unswap", 0);
|
||
let started = std::time::Instant::now();
|
||
let probes = match threshold {
|
||
0 => scan(&layered, 0..=2 * layered.depth(), window, trunc),
|
||
t => scan_unswapping(&layered, 0..=2 * layered.depth(), window, trunc, Unswap { threshold: t, rounds: arg(args, "rounds", 4) }),
|
||
}
|
||
.expect("centres in range");
|
||
for p in &probes {
|
||
println!("centre {:>4} log size {:>8.2} max bond {:>3} bonds {:>4}", p.centre, p.step.log_size, p.step.max_bond, p.step.bonds);
|
||
}
|
||
let mut ranked = probes.clone();
|
||
ranked.sort_by(|a, b| a.step.log_size.total_cmp(&b.step.log_size).then(a.centre.cmp(&b.centre)));
|
||
println!("smallest:");
|
||
for p in ranked.iter().take(10) {
|
||
println!(" centre {:>4} log size {:>8.2} max bond {:>3} bonds {:>4}", p.centre, p.step.log_size, p.step.max_bond, p.step.bonds);
|
||
}
|
||
println!("{} centres in {:.1} s", probes.len(), started.elapsed().as_secs_f64());
|
||
}
|
||
|
||
/// The instance's file stem after `peaked_circuit_`.
|
||
pub fn instance(name: &str) -> String {
|
||
if name.starts_with('P') { name.to_string() } else { format!("heavy_hex_{name}") }
|
||
}
|
||
|
||
/// `verify STRING`: the string's amplitude `⟨s|C|0⟩` in the whole circuit,
|
||
/// the operator grown from `centre=` (default the scan's) at each cutoff in
|
||
/// `cutoffs=` with bond cap `chi=`, the network closed and contracted exactly.
|
||
/// A cutoff of 0 truncates nothing below the cap.
|
||
pub fn verify(circuit: &RotCircuit, map: &[u32], name: &str, path: &str, string: &str, args: &[String]) -> Value {
|
||
let chi: usize = arg(args, "chi", 64);
|
||
let limit: usize = arg(args, "limit", 1 << 26);
|
||
let cutoffs: Vec<f64> = args
|
||
.iter()
|
||
.find_map(|a| a.strip_prefix("cutoffs=").map(|v| v.split(',').map(|x| x.parse().expect("a cutoff")).collect()))
|
||
.unwrap_or_else(|| vec![1e-2, 1e-3, 1e-4]);
|
||
let layered = Layered::new(circuit).expect("one- and two-qubit gates");
|
||
let centre: usize = args.iter().find_map(|a| a.strip_prefix("centre=").map(|v| v.parse().expect("a centre"))).unwrap_or_else(|| {
|
||
let probes = scan(&layered, 0..=2 * layered.depth(), 4, Truncation { chi: 8, cutoff: 1e-2 }).expect("centres");
|
||
best_centre(&layered, &probes).expect("a centre")
|
||
});
|
||
let b = bits(string);
|
||
assert_eq!(b.len(), circuit.n as usize, "a string of {} bits", circuit.n);
|
||
let mut rows = Vec::new();
|
||
for &cut in &cutoffs {
|
||
let (res, secs, energy) = super::common::metered(|| {
|
||
let op = cancel(&layered, centre, Truncation { chi, cutoff: cut }, 1).expect("the centre");
|
||
let amp = op.amplitude(&b, limit);
|
||
// The largest bond over the first nine tenths of the steps (the
|
||
// cancelled middle) and over the rest (the outer layers).
|
||
let n = op.steps().len();
|
||
let split = n - n / 10;
|
||
let middle = op.steps()[..split].iter().map(|s| s.max_bond).max().unwrap_or(1);
|
||
let outer = op.steps()[split..].iter().map(|s| s.max_bond).max().unwrap_or(1);
|
||
(op.discarded(), middle.max(outer), (middle, outer), amp)
|
||
});
|
||
let (discarded, bond, (middle, outer), amp) = res;
|
||
match amp {
|
||
Ok(a) => {
|
||
println!(
|
||
"cutoff {cut:<8e} χ ≤ {chi:<4} bond {middle:>3} middle, {outer:>3} outer |⟨s|C|0⟩|² = {:.6e} ‖C|0⟩‖² = {:.6e} ratio {:.6} discarded {discarded:.3e} {secs:.1} s",
|
||
a.probability,
|
||
a.norm,
|
||
a.probability / a.norm
|
||
);
|
||
rows.push(json!({"cutoff": cut, "chi": chi, "largest_bond": bond, "middle_bond": middle, "outer_bond": outer, "re": a.re, "im": a.im, "probability": a.probability, "norm": a.norm, "discarded": discarded, "wall_seconds": secs, "energy_figure": energy}));
|
||
}
|
||
Err(e) => {
|
||
println!("cutoff {cut:<8e} χ ≤ {chi:<4} largest bond {bond:>4} the closing contraction: {e} {secs:.1} s");
|
||
rows.push(json!({"cutoff": cut, "chi": chi, "largest_bond": bond, "refused": e.to_string(), "discarded": discarded, "wall_seconds": secs, "energy_figure": energy}));
|
||
}
|
||
}
|
||
}
|
||
let request = json!({
|
||
"instance": format!("peaked_circuit_{}", instance(name)),
|
||
"source": super::common::source(path),
|
||
"method": "the amplitude ⟨s|C|0…0⟩ of the given string in the whole circuit: its operator grown outward from the centre (quantum_peaked::cancel) at each cutoff, closed with ⟨s| on the rows and |0⟩ on the columns and contracted exactly, the scale carried through every update; no readout, no marginals",
|
||
"string": string,
|
||
"string_order": "bit q is qubit q of the register as compacted (the device qubit map[q])",
|
||
"centre": centre,
|
||
"qubits": map,
|
||
});
|
||
let result = json!({ "sweep": rows });
|
||
let out = super::common::receipt_path(&format!("peaked_{name}_verify_centre{centre}_chi{chi}.json"));
|
||
let doc = super::common::seal(request, result, Some(&out));
|
||
assert!(super::common::verifies(&doc));
|
||
println!("receipt {}", out.display());
|
||
doc
|
||
}
|