All checks were successful
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 3s
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 / jcp-rs (pull_request) Successful in 1m26s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m11s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m10s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m38s
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 8m58s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 4m28s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 12s
standards workspaces build + test / aac-rs (pull_request) Successful in 3m39s
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 23s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 42s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 1m14s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 3m26s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 58s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m2s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 1m27s
standards workspaces build + test / map-rs (pull_request) Successful in 1m56s
standards workspaces build + test / mesh-rs (pull_request) Successful in 1m11s
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Successful in 3m52s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 1m44s
standards workspaces build + test / openpay (pull_request) Successful in 7m55s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 6m50s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 51s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 2m12s
standards workspaces build + test / arl-rs (pull_request) Successful in 18m6s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 44m33s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 47m38s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1h25m12s
standards workspaces build + test / sense-rs (pull_request) Successful in 13m25s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 12m25s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 13m43s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 1m9s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 3m0s
Optimisation is the claim made most often for quantum hardware, and each such claim is a comparison with a classical solver. quantum_qio is that solver, deterministic and re-checkable: - Ising problems (sparse symmetric J, fields h) and Max-Cut (J = -w), a G-set reader, and the +-1 all-to-all spin glass. - Simulated bifurcation from its published update rules: symplectic Euler, perfectly inelastic walls, ballistic (f = Jx) and discrete (f = J sgn x) forces, and both heated (arXiv:2203.08361), with c0 = c1 / (rms(J) sqrt N). Fields ride on an extra spin fixed at +1. - Eight trials advance per pass over the couplings; each trial's arithmetic is unchanged, so a batched run leaves the same final positions bit for bit as one trial at a time. The test fails on a 1e-15 change to one lane. - Simulated annealing (single-spin Metropolis, linear beta), single-flip descent, an exact Gray-code referee up to 34 spins (threaded), and step-to-solution S = N_s ln 0.01 / ln(1 - P). Checked: - every variant and annealing reach the exact ground state on 20-spin glasses; - G-set best-known cuts reached (seed 1): G1 11624 (39% of 2,000-step trials), G2 11620, G3 11622, G11 564, G14 3064 (annealing; bifurcation stops at 3062), G22 13359, G43 6660; G55 reaches 10292 of 10299; - the published dense-glass step (1.1) is unstable on sparse Max-Cut graphs: the stiffest mode has w^2 = a0(a0 - c0 mu_min) and mu_min = -degree, so G1's limit is near 0.88; documented, with the settings that work. CLI: wai-quantum qio (--gset FILE | --sk N) --method dsb|bsb|hdsb|hbsb|sa|exact [--descend --target --spins --json]. Example: qio_gset. Pinned bit for bit natively and under wasm32-wasip2 (16 pins); CLI output byte-identical across the two, threaded or not, G-set files included. Co-Authored-By: Claude Opus 5.5 <[email protected]>
74 lines
3.9 KiB
Rust
74 lines
3.9 KiB
Rust
//! Solve a G-set Max-Cut instance with simulated bifurcation and report the
|
|
//! best cut, how often the target is reached, and the steps to reach it with
|
|
//! 99% probability.
|
|
//!
|
|
//! ```text
|
|
//! cargo run --release --example qio_gset --features quantum_qio -- FILE VARIANT STEPS TRIALS [TARGET] [DT] [C1] [GAMMA] [THREADS]
|
|
//! ```
|
|
//! VARIANT is bsb, dsb, hbsb or hdsb. Omitted settings take the published values.
|
|
use wai_quantum::quantum_qio::{descend, read_gset, simulated_annealing, simulated_bifurcation, step_to_solution, SaConfig, SbConfig, Variant};
|
|
|
|
fn main() {
|
|
let a: Vec<String> = std::env::args().collect();
|
|
let g = read_gset(&std::fs::read_to_string(&a[1]).expect("read")).expect("parse");
|
|
let polish = a[2].ends_with("+ls");
|
|
let name = a[2].trim_end_matches("+ls");
|
|
if name == "sa" {
|
|
// STEPS sweeps; DT and C1 slots carry beta0 and beta1.
|
|
let sweeps: u32 = a[3].parse().unwrap();
|
|
let trials: usize = a[4].parse().unwrap();
|
|
let target: Option<f64> = a.get(5).and_then(|x| x.parse().ok());
|
|
let beta0 = a.get(6).and_then(|x| x.parse().ok()).unwrap_or(0.1);
|
|
let beta1 = a.get(7).and_then(|x| x.parse().ok()).unwrap_or(3.0);
|
|
let threads: usize = a.get(9).map_or(8, |x| x.parse().unwrap());
|
|
let t0 = std::time::Instant::now();
|
|
let run = simulated_annealing(&g.ising(), &SaConfig { sweeps, beta0, beta1, trials, seed: 1 }, threads);
|
|
let cuts: Vec<f64> = run.trials.iter().map(|t| g.cut(&t.spins)).collect();
|
|
let best = cuts.iter().cloned().fold(f64::MIN, f64::max);
|
|
print!("SA beta {beta0}->{beta1} sweeps={sweeps} trials={trials} best {best} mean {:.1}", cuts.iter().sum::<f64>() / cuts.len() as f64);
|
|
if let Some(t) = target {
|
|
let p = cuts.iter().filter(|&&c| c >= t).count() as f64 / cuts.len() as f64;
|
|
print!(" P(≥{t}) {p:.4} S99 {:?}", step_to_solution(p, f64::from(sweeps)).map(|s| s.round()));
|
|
}
|
|
println!(" {:.1}s", t0.elapsed().as_secs_f64());
|
|
return;
|
|
}
|
|
let v = match name {
|
|
"bsb" => Variant::Ballistic,
|
|
"dsb" => Variant::Discrete,
|
|
"hbsb" => Variant::HeatedBallistic(0.0),
|
|
"hdsb" => Variant::HeatedDiscrete(0.0),
|
|
other => panic!("variant {other}"),
|
|
};
|
|
let steps: u32 = a[3].parse().unwrap();
|
|
let trials: usize = a[4].parse().unwrap();
|
|
let mut cfg = SbConfig::published(v, steps, trials, 1);
|
|
let target: Option<f64> = a.get(5).and_then(|x| x.parse().ok());
|
|
if let Some(dt) = a.get(6).and_then(|x| x.parse().ok()) {
|
|
cfg.dt = dt;
|
|
}
|
|
if let Some(c1) = a.get(7).and_then(|x| x.parse().ok()) {
|
|
cfg.c1 = c1;
|
|
}
|
|
if let Some(gamma) = a.get(8).and_then(|x| x.parse::<f64>().ok()) {
|
|
cfg.variant = match cfg.variant {
|
|
Variant::HeatedBallistic(_) => Variant::HeatedBallistic(gamma),
|
|
Variant::HeatedDiscrete(_) => Variant::HeatedDiscrete(gamma),
|
|
other => other,
|
|
};
|
|
}
|
|
let threads: usize = a.get(9).map_or(8, |x| x.parse().unwrap());
|
|
let t0 = std::time::Instant::now();
|
|
let run = simulated_bifurcation(&g.ising(), &cfg, threads);
|
|
let dt = t0.elapsed().as_secs_f64();
|
|
let ising = g.ising();
|
|
let cuts: Vec<f64> = run.trials.iter().map(|t| if polish { g.cut(&descend(&ising, &t.spins).spins) } else { g.cut(&t.spins) }).collect();
|
|
let best = cuts.iter().cloned().fold(f64::MIN, f64::max);
|
|
let mean = cuts.iter().sum::<f64>() / cuts.len() as f64;
|
|
print!("n={} edges={} {}{:?} dt={} c1={} steps={} trials={} best {} mean {:.1}", g.n, g.edges.len(), if polish { "+descent " } else { "" }, cfg.variant, cfg.dt, cfg.c1, steps, trials, best, mean);
|
|
if let Some(t) = target {
|
|
let p = cuts.iter().filter(|&&c| c >= t).count() as f64 / cuts.len() as f64;
|
|
print!(" P(≥{t}) {p:.4} S99 {:?}", step_to_solution(p, f64::from(steps)).map(|s| s.round()));
|
|
}
|
|
println!(" {:.1}s ({:.2} ms/trial-thread)", dt, 1e3 * dt * threads as f64 / trials as f64);
|
|
}
|