Some checks failed
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 13m15s
standards workspaces build + test / aac-rs (pull_request) Successful in 2m9s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 1m31s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 1m6s
standards workspaces build + test / map-rs (pull_request) Successful in 1m31s
standards workspaces build + test / mesh-rs (pull_request) Successful in 46s
standards workspaces build + test / openpay (pull_request) Successful in 4m18s
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 4s
no-vanity-metrics / WAI public text names no company or product (pull_request) Successful in 3s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m8s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m55s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m28s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m13s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 15m40s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m9s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 50s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m12s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m11s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 3m14s
wai-pack / wai-pack · linux-arm64 (pull_request) Failing after 19s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m5s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m39s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 6m17s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 14s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 12m30s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 11m44s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 9s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 24s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 46s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 1m41s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 1m1s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 2m22s
wai-pack / wai-pack · linux (pull_request) Failing after 3m40s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Failing after 2m29s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 21s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 20m47s
wai-pack / wai-pack · dependency licences (pull_request) Failing after 3m41s
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Successful in 4m23s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 1m59s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 25m42s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 1m9s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 6m43s
wai-pack / wai-pack · macos (pull_request) Failing after 5s
Symmetry projects a network, Psi(s) = sum_g chi(g) psi(g.s), over a lattice's translations (ring or torus, momentum 0 or pi along each direction) and optionally the global spin flip (even or odd parity). - Ratios and log-derivatives become weighted averages over the transformed configurations, held in a cache that Metropolis moves keep exact. - A configuration the symmetry forbids (its sum below the rounding of its terms) is treated as zero. Biases now start random as well as weights. With zero biases the network is exactly even under the global flip, and training keeps it even, which is what trapped 10-site rings in 0.3.37. SR falls back to an eigendecomposition (cutoff 1e-12) when Cholesky loses a pivot. A projected network started near even drives its metric to 1e12, and the factorisation produced NaN there. Rings in their sector reach exact energies to rounding: 10 sites at pi, 7e-14; 12 sites at 0, even, 1e-15. The frustrated 4x4 torus at J2 = 0.5 comes within 7.7e-3 (2000 steps; 3.6% unprojected). The NQS pin covers a projected machine through the fallback; all 22 pins pass natively and under wasm32-wasip2. The nqs CLI gains --project, --kpi and --odd, byte-identical under WASI. Co-Authored-By: Claude Opus 5.5 <[email protected]>
572 lines
23 KiB
Rust
572 lines
23 KiB
Rust
//! The crate promises identical results natively, in the browser and at the
|
||
//! edge. Before every transcendental moved in-crate, four of these layers gave
|
||
//! different bits natively and under `wasm32-wasip2`. These digests were taken
|
||
//! natively and confirmed under `wasm32-wasip2`; any platform whose math
|
||
//! differs fails here, not in a user's diff.
|
||
//!
|
||
//! `CARGO_TARGET_WASM32_WASIP2_RUNNER=wasmtime cargo test --release --target wasm32-wasip2 --features full`
|
||
#![cfg(all(
|
||
feature = "quantum",
|
||
feature = "quantum_vml",
|
||
feature = "quantum_phasor",
|
||
feature = "quantum_qfhrr",
|
||
feature = "quantum_kernel",
|
||
feature = "quantum_mps",
|
||
feature = "quantum_pauli",
|
||
feature = "quantum_spd",
|
||
feature = "quantum_bptn",
|
||
feature = "quantum_resource",
|
||
feature = "quantum_frame",
|
||
feature = "quantum_tn",
|
||
feature = "quantum_gbs",
|
||
feature = "quantum_sv",
|
||
feature = "quantum_arch",
|
||
feature = "quantum_ldpc",
|
||
feature = "quantum_qio",
|
||
feature = "quantum_uf",
|
||
feature = "quantum_noisy",
|
||
feature = "quantum_dmrg",
|
||
feature = "quantum_tdvp",
|
||
feature = "quantum_chem",
|
||
feature = "quantum_nqs"
|
||
))]
|
||
|
||
use wai_quantum::*;
|
||
|
||
/// FNV-1a over every value's IEEE-754 bits.
|
||
fn digest(xs: &[f64]) -> u64 {
|
||
let mut h: u64 = 0xcbf2_9ce4_8422_2325;
|
||
for x in xs {
|
||
for b in x.to_bits().to_le_bytes() {
|
||
h = (h ^ u64::from(b)).wrapping_mul(0x100_0000_01b3);
|
||
}
|
||
}
|
||
h
|
||
}
|
||
|
||
fn trained() -> quantum_vml::BornFit {
|
||
quantum_vml::train_born(&quantum_vml::parity_target(3), 3, 2, 40, 0.1, 7)
|
||
}
|
||
|
||
#[test]
|
||
fn born_machine_training() {
|
||
let fit = trained();
|
||
let mut v = fit.params.clone();
|
||
v.extend(&fit.loss_curve);
|
||
v.extend(&fit.final_probs);
|
||
v.push(fit.final_kl);
|
||
assert_eq!(digest(&v), 0xd8e5_bd02_2201_2e5d);
|
||
}
|
||
|
||
#[test]
|
||
fn phasor_bridge() {
|
||
let p = quantum_phasor::random_params(3, 5);
|
||
let (a, b, c, d) = quantum_phasor::compare(3, &p, 64);
|
||
let mut v = a;
|
||
v.extend(b);
|
||
v.extend(c);
|
||
v.push(d);
|
||
assert_eq!(digest(&v), 0x08be_30dd_7ce1_9561);
|
||
}
|
||
|
||
#[test]
|
||
fn qfhrr_born_machine() {
|
||
let fit = trained();
|
||
let mut v = quantum_qfhrr::born_probs(3, 2, &fit.params, 4);
|
||
v.push(quantum_qfhrr::tv_vs_exact(3, 2, &fit.params, 4));
|
||
assert_eq!(digest(&v), 0x5407_7c4d_1be0_d985);
|
||
}
|
||
|
||
#[test]
|
||
fn phasor_kernel() {
|
||
let (x, y) = quantum_kernel::circles(200, 3);
|
||
let rff = quantum_kernel::sample_rff(2, 64, 1.0, 9);
|
||
let w = quantum_kernel::fit_ridge(&rff, &x, &y, 1e-3);
|
||
let mut v: Vec<f64> = x.iter().flatten().copied().collect();
|
||
v.extend(&w);
|
||
assert_eq!(digest(&v), 0x58ba_1666_5ef6_fd9e);
|
||
}
|
||
|
||
fn brickwork() -> quantum::Circuit {
|
||
let mut c = quantum::Circuit::new(8);
|
||
for l in 0..4u8 {
|
||
for q in 0..8 {
|
||
c.h(q);
|
||
c.t(q);
|
||
}
|
||
for q in (l % 2..7).step_by(2) {
|
||
c.cx(q, q + 1);
|
||
}
|
||
}
|
||
c
|
||
}
|
||
|
||
#[test]
|
||
fn mps_truncation() {
|
||
let c = brickwork();
|
||
let (mps, _) = quantum_mps::run(&c, 4).unwrap();
|
||
assert_eq!(digest(&[quantum_mps::fidelity(&mps, &c.simulate().unwrap())]), 0xa807_44ca_a97f_bff8);
|
||
}
|
||
|
||
#[test]
|
||
fn sparse_pauli_propagation() {
|
||
let (e, _) = quantum_pauli::expect_z(&brickwork(), 3, 1e-6).unwrap();
|
||
assert_eq!(digest(&[e]), 0x8cc6_5829_1fb1_8909);
|
||
}
|
||
|
||
#[test]
|
||
fn sparse_pauli_dynamics() {
|
||
let chain: Vec<(u32, u32)> = (0..29).map(|q| (q, q + 1)).collect();
|
||
let circuit = quantum_spd::kicked_ising(30, &chain, 0.5, 6);
|
||
let cfg = quantum_spd::SpdConfig { threshold: 1e-6, max_weight: None };
|
||
let r = quantum_spd::expect_z(&circuit, 7, &cfg).unwrap();
|
||
assert_eq!(digest(&[r.value, r.truncation_bound]), 0xfc44_f4b6_0e70_68b2);
|
||
}
|
||
|
||
#[test]
|
||
fn tensor_network_evolution() {
|
||
// Every qubit's ⟨Z⟩ and the discarded weight after three steps on the
|
||
// 127-qubit lattice at χ = 8: QR, the converged SVD and the parallel
|
||
// layers all feed these bits.
|
||
let edges = quantum_spd::heavy_hex_127();
|
||
let mut t = quantum_bptn::Tns::new(127, &edges, 8).unwrap();
|
||
t.run(&quantum_spd::kicked_ising(127, &edges, 0.6, 3)).unwrap();
|
||
let mut v: Vec<f64> = (0..127).map(|q| t.expect1(q, quantum_spd::Pauli::Z).unwrap()).collect();
|
||
v.push(t.discarded());
|
||
assert_eq!(digest(&v), 0x0e51_33ff_7987_aa26);
|
||
}
|
||
|
||
/// Every figure of the factoring and chemistry estimates on all six reference
|
||
/// qubits: distances, factory rounds, qubit counts, times and error rates.
|
||
/// The rotation T-count goes through the in-crate logarithm.
|
||
#[test]
|
||
fn resource_estimates() {
|
||
use quantum_resource::*;
|
||
let programs = [
|
||
(LogicalCounts { qubits: 12_581, measurements: 1_080_000_000, rotations: 12, rotation_depth: 12, t_gates: 12, ccz: 3_730_000_000 }, 1.0 / 3.0),
|
||
(LogicalCounts { qubits: 1318, measurements: 1_370_000_000, rotations: 206_000_000, rotation_depth: 205_000_000, t_gates: 55_300_000, ccz: 135_000_000_000 }, 0.01),
|
||
];
|
||
let mut v = Vec::new();
|
||
for (c, eps) in programs {
|
||
for q in PhysicalQubit::presets() {
|
||
let e = estimate_best(&c, &q, &EstimateConfig::new(eps)).unwrap();
|
||
v.extend([e.distance as f64, e.steps as f64, e.runtime_ns, e.logical_error, e.t_target]);
|
||
v.extend([e.factories as f64, e.physical_qubits as f64, e.isa.t_per_rotation as f64]);
|
||
for r in &e.factory.unwrap().rounds {
|
||
v.extend([r.distance as f64, r.copies as f64, r.duration_ns, r.failure, r.output_error]);
|
||
}
|
||
}
|
||
}
|
||
assert_eq!(digest(&v), 0xce9d_43b2_d498_f379);
|
||
}
|
||
|
||
/// Detection counts of a sampled surface-code run, the failures its decoding
|
||
/// leaves, and the code model fitted from a small grid: the sampler's random
|
||
/// stream, its logarithm-driven skips, the matching and the fit's `exp`.
|
||
#[test]
|
||
fn frame_sampling_and_matching() {
|
||
use quantum_frame::{parse, sample, surface_code_memory};
|
||
use quantum_match::{fit_code_model, memory_experiment};
|
||
let c = parse(&surface_code_memory(3, 3, 0.01)).unwrap();
|
||
let s = sample(&c, 10_000, 5);
|
||
let mut v: Vec<f64> = (0..s.detectors).map(|d| s.count(d) as f64).collect();
|
||
let mut pts = Vec::new();
|
||
for d in [3, 5] {
|
||
for p in [0.004, 0.008] {
|
||
let t = memory_experiment(d, d, p, 4_000, 9).unwrap();
|
||
v.push(t.failures as f64);
|
||
v.push(t.per_round());
|
||
pts.push(t);
|
||
}
|
||
}
|
||
let f = fit_code_model(&pts).unwrap();
|
||
v.extend([f.prefactor, f.threshold]);
|
||
assert_eq!(digest(&v), 0xcbb3_99f9_6d5c_e8f0);
|
||
}
|
||
|
||
/// A contraction plan found by the seeded hyper-optimiser, and the amplitude
|
||
/// its sliced, threaded contraction gives: the search's random stream and
|
||
/// logarithms, and the fixed-order complex arithmetic.
|
||
#[test]
|
||
fn tensor_network_plan_and_amplitude() {
|
||
use quantum_tn::{complex, contract_plan, find_path, Families, Gate, Network, PathOptions};
|
||
// A 3 × 4 grid, ten layers of fixed two-qubit gates and phased rotations.
|
||
let (w, h) = (4u32, 3u32);
|
||
let mut gates = Vec::new();
|
||
let mut k = 0.0f64;
|
||
for layer in 0..10u32 {
|
||
for q in 0..w * h {
|
||
k += 0.37;
|
||
let (c, s) = (1.0 / (1.0 + k * k).sqrt(), k / (1.0 + k * k).sqrt());
|
||
gates.push(Gate { qubits: vec![q], matrix: vec![complex(c, 0.0), complex(0.0, -s), complex(0.0, -s), complex(c, 0.0)] });
|
||
}
|
||
let horizontal = layer % 2 == 0;
|
||
for y in 0..h {
|
||
for x in 0..w {
|
||
let (a, b) = if horizontal { (y * w + x, y * w + x + 1) } else { (y * w + x, (y + 1) * w + x) };
|
||
let ok = if horizontal { x + 1 < w && (x + layer / 2) % 2 == 0 } else { y + 1 < h && (y + layer / 2) % 2 == 0 };
|
||
if ok {
|
||
// An iSWAP-like gate with a controlled phase.
|
||
let z = complex(0.0, 0.0);
|
||
let one = complex(1.0, 0.0);
|
||
let mi = complex(0.0, -1.0);
|
||
let ph = complex(0.5, -0.866_025_403_784_438_6);
|
||
gates.push(Gate { qubits: vec![a, b], matrix: vec![one, z, z, z, z, z, mi, z, z, mi, z, z, z, z, z, ph] });
|
||
}
|
||
}
|
||
}
|
||
}
|
||
let n = w * h;
|
||
let bits: Vec<u8> = (0..n).map(|q| (q % 3 == 1) as u8).collect();
|
||
let mut net = Network::amplitude(n, &gates, &bits, &[]).unwrap();
|
||
net.simplify();
|
||
let shape = net.shape();
|
||
let free = find_path(&shape, &net.dims, &net.open, &PathOptions { trials: 12, seed: 5, max_size: None, reconfigure: 6, families: Families::Both });
|
||
let cap = free.per_slice.max_size / 8.0;
|
||
let plan = find_path(&shape, &net.dims, &net.open, &PathOptions { trials: 12, seed: 5, max_size: Some(cap), reconfigure: 6, families: Families::Both });
|
||
let amp = contract_plan(&net, &plan).unwrap().data[0];
|
||
let steps: Vec<f64> = plan.path.steps.iter().flat_map(|&(a, b)| [a as f64, b as f64]).collect();
|
||
let mut v = vec![amp.re, amp.im, plan.per_slice.flops, plan.per_slice.max_size, plan.slices];
|
||
v.extend(steps);
|
||
assert_eq!(digest(&v), 0x8954_0c3a_d1fc_a04d);
|
||
}
|
||
|
||
/// A 24 × 24 hafnian and a 14-click torontonian (both summed in fixed chunks,
|
||
/// threaded natively and sequential under WASI), lossy-state probabilities,
|
||
/// exact samples and marginals.
|
||
#[test]
|
||
fn gaussian_boson_sampling() {
|
||
use quantum_gbs::{hafnian, random_unitary, GaussianState, Mat, C};
|
||
let u = random_unitary(24, 5);
|
||
let mut m = Mat::zeros(24);
|
||
for i in 0..24 {
|
||
for j in 0..24 {
|
||
let (x, y) = (u.at(i, j), u.at(j, i));
|
||
m.a[i * 24 + j] = C { re: x.re + y.re, im: x.im + y.im };
|
||
}
|
||
}
|
||
let h = hafnian(&m);
|
||
let r: Vec<f64> = (0..16).map(|i| 0.3 + 0.04 * i as f64).collect();
|
||
let st = GaussianState::squeezed(&r, &random_unitary(16, 6), 0.7).unwrap();
|
||
let pattern: Vec<bool> = (0..16).map(|i| i % 8 != 3).collect();
|
||
let mut v = vec![h.re, h.im, st.click_probability(&pattern).unwrap()];
|
||
let small = GaussianState::squeezed(&[0.8, 0.5, 0.6, 0.4, 0.7], &random_unitary(5, 7), 0.6).unwrap();
|
||
v.push(small.photon_probability(&[2, 0, 1, 1, 0]).unwrap());
|
||
for s in small.sample_clicks(300, 9) {
|
||
v.push(s.iter().enumerate().map(|(i, &b)| if b { (1u32 << i) as f64 } else { 0.0 }).sum());
|
||
}
|
||
let (p1, p2) = small.click_marginals();
|
||
v.extend(p1);
|
||
v.extend(p2);
|
||
assert_eq!(digest(&v), 0x039d_e851_06c3_567d);
|
||
}
|
||
|
||
/// A 16-qubit random circuit at fusion widths 0, 2 and 3: every kernel path
|
||
/// (block-parallel, split by the top bit, split into quarters, general fused,
|
||
/// diagonal), threaded natively and sequential under WASI, and the chunked
|
||
/// reductions (norm, expectation, samples).
|
||
#[test]
|
||
fn dense_state_vector() {
|
||
use gates::Gate;
|
||
use quantum_sv::StateVector;
|
||
let n = 16u32;
|
||
let mut g = Vec::new();
|
||
let mut a = 0.1f64;
|
||
for layer in 0..6u32 {
|
||
for q in 0..n {
|
||
a += 0.731;
|
||
g.push(match (q + layer) % 5 {
|
||
0 => Gate::rx(q, a),
|
||
1 => Gate::ry(q, a),
|
||
2 => Gate::rz(q, a),
|
||
3 => Gate::sqrt_w(q),
|
||
_ => Gate::t(q),
|
||
});
|
||
}
|
||
let mut q = layer % 2;
|
||
while q + 1 < n {
|
||
g.push(if q % 3 == 0 { Gate::fsim(q, q + 1, a, 0.5 * a) } else { Gate::cz(q, q + 1) });
|
||
q += 2;
|
||
}
|
||
g.push(Gate::iswap(0, n - 1));
|
||
}
|
||
let mut v = Vec::new();
|
||
for width in [0usize, 2, 3] {
|
||
let mut sv = StateVector::zero(n).unwrap();
|
||
sv.run(&g, width).unwrap();
|
||
v.extend(sv.re.iter().step_by(97).copied());
|
||
v.extend(sv.im.iter().step_by(89).copied());
|
||
v.push(sv.norm2());
|
||
v.push(sv.expectation(&[(0.5, vec![(0, 'Z'), (7, 'X')]), (1.5, vec![(3, 'Y'), (15, 'Y')])]));
|
||
v.extend(sv.sample(64, width as u64).into_iter().map(|x| x as f64));
|
||
}
|
||
assert_eq!(digest(&v), 0xd0df_e437_5b28_903f);
|
||
}
|
||
|
||
|
||
/// Storage layouts under every fit set, cultivation interpolation (in-crate
|
||
/// `ln` and `exp`), the threshold-to-storage conversion, and the whole factoring
|
||
/// machine at three key sizes.
|
||
#[test]
|
||
fn architecture_estimates() {
|
||
use quantum_arch::*;
|
||
let mut v = Vec::new();
|
||
for model in [StorageModel::si1000(), StorageModel::uniform(), StorageModel::uniform_refit()] {
|
||
for target in [1e-9, 3.7e-13, 1e-15] {
|
||
for b in [
|
||
best_block(&model, Storage::Cold, Yoke::Rows, target, 250),
|
||
best_block(&model, Storage::Hot, Yoke::Rows, target, 250),
|
||
grid_block(&model, 16, target),
|
||
]
|
||
.into_iter()
|
||
.flatten()
|
||
{
|
||
v.push(f64::from(b.distance));
|
||
v.push(b.qubits_per_logical());
|
||
v.push(b.error_per_logical_round);
|
||
}
|
||
}
|
||
}
|
||
for (p, t) in [(5e-4, 3.3e-9), (1e-3, 1e-7), (1e-3, 4.4e-6), (2e-3, 2.2e-5)] {
|
||
let c = cultivate(p, t).unwrap();
|
||
v.push(c.volume);
|
||
v.push(c.error);
|
||
}
|
||
let f = StorageFit::flat_from_threshold(0.023, 0.0100, 1e-3);
|
||
v.push(f.suppression);
|
||
v.push(f.per_patch_round(17, 1, 1));
|
||
for bits in [1024, 2048, 4096] {
|
||
let e = factoring_estimate(&FactoringParams::published(bits).unwrap(), &Machine::published()).unwrap();
|
||
v.push(e.physical_qubits() as f64);
|
||
v.push(e.ccz_rounds);
|
||
v.push(e.hours_per_shot);
|
||
v.push(e.hours_per_shot_rounded);
|
||
v.push(e.shot_survival);
|
||
v.push(e.days);
|
||
v.push(e.toffolis_per_shot);
|
||
}
|
||
assert_eq!(digest(&v), 0xd166_b4c6_c731_7a52);
|
||
}
|
||
|
||
/// A bivariate-bicycle memory: the circuit's error model (probabilities from
|
||
/// the independent-channel conversion), BP over it with in-crate logarithms,
|
||
/// and OSD on the shots BP leaves unexplained.
|
||
#[test]
|
||
fn qldpc_memory_decoding() {
|
||
use quantum_frame::{error_model, parse, sample, Basis};
|
||
use quantum_ldpc::*;
|
||
let c = parse(&memory_circuit(&BbCode::bb72(), 3, 0.005, Basis::Z)).unwrap();
|
||
let model = error_model(&c).unwrap();
|
||
let dec = BpOsd::new(&model, BpOsdConfig { max_iter: 40, ..BpOsdConfig::default() });
|
||
let det = sample(&c, 192, 11);
|
||
let mut v: Vec<f64> = model.mechanisms.iter().step_by(37).map(|m| m.probability).collect();
|
||
let mut osd = 0;
|
||
for s in 0..192 {
|
||
let d = dec.decode(&det.fired(s));
|
||
osd += u32::from(!d.converged);
|
||
v.push(d.observables as f64);
|
||
v.push(f64::from(d.iterations));
|
||
v.push(det.flips(s) as f64);
|
||
}
|
||
assert!(osd > 0, "the sample must exercise OSD");
|
||
assert_eq!(digest(&v), 0x5479_ebe5_f648_b739);
|
||
}
|
||
|
||
/// Optimisation: every simulated-bifurcation variant (batched, with fields
|
||
/// riding on an extra spin), annealing with in-crate `exp`, single-flip
|
||
/// descent, and the exact referee.
|
||
#[test]
|
||
fn quantum_inspired_optimisation() {
|
||
use quantum_qio::*;
|
||
let p = Ising::sk(40, 3);
|
||
let mut v = Vec::new();
|
||
for var in [Variant::Ballistic, Variant::Discrete, Variant::HeatedBallistic(0.0), Variant::HeatedDiscrete(0.0)] {
|
||
for t in simulated_bifurcation(&p, &SbConfig::published(var, 300, 11, 9), 3).trials {
|
||
v.push(t.energy);
|
||
v.extend(t.spins.iter().map(|&s| f64::from(s)));
|
||
}
|
||
}
|
||
let q = Ising::new(9, &[(0, 4, 0.75), (4, 8, -1.5), (1, 2, 1.0), (2, 6, 0.25)], &[0.5, 0.0, -0.3, 0.0, 0.1, 0.0, 0.0, 0.0, -0.9]).unwrap();
|
||
for t in simulated_bifurcation(&q, &SbConfig::published(Variant::Discrete, 200, 5, 2), 2).trials {
|
||
v.push(t.energy);
|
||
}
|
||
for t in simulated_annealing(&p, &SaConfig { sweeps: 200, beta0: 0.1, beta1: 2.5, trials: 6, seed: 4 }, 3).trials {
|
||
v.push(t.energy);
|
||
v.push(descend(&p, &t.spins).energy);
|
||
}
|
||
let g = ground_state(&Ising::sk(18, 5), 4).unwrap();
|
||
v.push(g.energy);
|
||
v.extend(g.spins.iter().map(|&s| f64::from(s)));
|
||
assert_eq!(digest(&v), 0xc01a_7afa_39c0_c487);
|
||
}
|
||
|
||
/// Union-find decoding: event-driven growth on the radix heap, merges and
|
||
/// peeling, over a sampled surface-code memory, with a reused workspace.
|
||
#[test]
|
||
fn union_find_decoding() {
|
||
use quantum_frame::{error_model, parse, sample, surface_code_memory};
|
||
let c = parse(&surface_code_memory(7, 7, 0.006)).unwrap();
|
||
let g = quantum_match::MatchingGraph::from_model(&error_model(&c).unwrap()).unwrap();
|
||
let uf = quantum_uf::UnionFind::new(&g);
|
||
let mut ws = uf.workspace();
|
||
let det = sample(&c, 512, 21);
|
||
let v: Vec<f64> = (0..512).map(|s| uf.decode(&det.fired(s), &mut ws).unwrap() as f64).collect();
|
||
assert!(v.iter().any(|&x| x != 0.0), "the sample must include flips");
|
||
assert_eq!(digest(&v), 0xe43c_2ad4_9244_3118);
|
||
}
|
||
|
||
/// Noisy circuits: trajectories under every channel (Pauli branches, damping
|
||
/// jumps with renormalisation, readout flips), the exact density matrix and
|
||
/// both cross-entropy figures.
|
||
#[test]
|
||
fn noisy_circuits() {
|
||
use gates::Gate;
|
||
use quantum_noisy::*;
|
||
let n = 6u32;
|
||
let mut g = Vec::new();
|
||
let mut a = 0.3f64;
|
||
for layer in 0..5u32 {
|
||
for q in 0..n {
|
||
a += 0.917;
|
||
g.push(if (q + layer) % 2 == 0 { Gate::rx(q, a) } else { Gate::ry(q, a) });
|
||
}
|
||
let mut q = layer % 2;
|
||
while q + 1 < n {
|
||
g.push(Gate::cz(q, q + 1));
|
||
q += 2;
|
||
}
|
||
}
|
||
let noise = NoiseModel { depol1: 0.01, depol2: 0.03, damping: 0.02, dephasing: 0.01, readout: 0.02 };
|
||
let obs = vec![vec![(1.0, vec![(0, 'Z')])], vec![(1.0, vec![(1, 'X'), (4, 'Y')])]];
|
||
let run = trajectories(&g, n, &noise, &obs, 40, 6, 3).unwrap();
|
||
let mut v: Vec<f64> = run.expectations.iter().flat_map(|e| [e.mean, e.stderr]).collect();
|
||
v.extend(run.samples.iter().map(|&x| x as f64));
|
||
let rho = DensityMatrix::run(&g, n, &noise).unwrap();
|
||
v.extend(obs.iter().map(|o| rho.expectation(o)));
|
||
v.push(rho.trace());
|
||
let mut ideal = quantum_sv::StateVector::zero(n).unwrap();
|
||
ideal.run(&g, 0).unwrap();
|
||
v.push(exact_xeb(&ideal, &rho, noise.readout));
|
||
let x = linear_xeb(&ideal, &run.samples);
|
||
v.push(x.mean);
|
||
v.push(x.stderr);
|
||
v.push(digital_fidelity(&g, n, &noise));
|
||
assert_eq!(digest(&v), 0x78b2_ddfb_e7c3_6bea);
|
||
}
|
||
|
||
/// DMRG: the symmetric eigensolver, Lanczos with re-orthogonalisation,
|
||
/// density-matrix truncation and entropies (in-crate `ln`), on two chains;
|
||
/// the free-fermion Ising energy; and exact diagonalisation.
|
||
#[test]
|
||
fn dmrg_ground_states() {
|
||
use quantum_dmrg::*;
|
||
let mut v = Vec::new();
|
||
let cfg = DmrgConfig { max_bond: 16, sweeps: 2, ..DmrgConfig::default() };
|
||
for chain in [Chain::heisenberg(10, 1.0, 0.8, 0.1), Chain::ising(12, 1.0, 0.9)] {
|
||
let r = dmrg(&chain, &cfg);
|
||
v.extend(r.sweep_energies);
|
||
v.push(r.discarded);
|
||
v.extend(r.entropies);
|
||
v.push(exact_ground_energy(&chain).unwrap());
|
||
}
|
||
v.push(ising_exact_energy(40, 1.0, 0.7));
|
||
let a: Vec<f64> = (0..36).map(|k| ((k * 7 % 11) as f64 - 5.0) / (1.0 + (k % 6) as f64)).collect();
|
||
let sym: Vec<f64> = (0..36).map(|k| a[k] + a[(k % 6) * 6 + k / 6]).collect();
|
||
let (vals, vecs) = symmetric_eigen(&sym, 6);
|
||
v.extend(vals);
|
||
v.extend(vecs.iter().map(|x| x.abs()));
|
||
assert_eq!(digest(&v), 0xcdd9_d9fb_5ba6_d71c);
|
||
}
|
||
|
||
#[test]
|
||
fn tdvp_time_evolution() {
|
||
use quantum_dmrg::{Chain, Mps, Op, Scalar, C};
|
||
use quantum_tdvp::*;
|
||
let mut v = Vec::new();
|
||
// A truncated Heisenberg quench from the Néel state, and the Ising quench
|
||
// with its free-fermion referee.
|
||
let n = 10;
|
||
let neel = Mps::basis(&(0..n).map(|i| i % 2 == 1).collect::<Vec<_>>());
|
||
let mut ev = Evolution::new(&Chain::heisenberg(n, 1.0, 0.7, 0.1), &neel, TdvpConfig { dt: 0.1, max_bond: 6, threads: 1, ..TdvpConfig::default() });
|
||
for _ in 0..6 {
|
||
v.push(ev.step().discarded);
|
||
}
|
||
v.extend(ev.expect(Op::z()));
|
||
v.extend(ev.bond_expect(Op::sz(), Op::sz()));
|
||
v.extend(ev.entropies());
|
||
v.push(ev.energy());
|
||
let o = ev.overlap(&neel);
|
||
v.extend([o.re, o.im]);
|
||
let plus = Mps::product(&vec![[C::ONE, C::ONE]; 8]);
|
||
let mut ev = Evolution::new(&Chain::ising(8, 1.0, 0.9), &plus, TdvpConfig { dt: 0.2, max_bond: 16, cutoff: 0.0, threads: 1, ..TdvpConfig::default() });
|
||
for _ in 0..3 {
|
||
ev.step();
|
||
}
|
||
v.extend(ev.expect(Op::x()));
|
||
let ff = ising_quench(8, 1.0, 0.9, ev.time());
|
||
v.extend(ff.x);
|
||
v.extend(ff.zz);
|
||
v.push(ff.echo);
|
||
assert_eq!(digest(&v), 0xe1b4_fd28_af23_50cd);
|
||
}
|
||
|
||
#[test]
|
||
fn chemistry_by_dmrg() {
|
||
use quantum_chem::*;
|
||
let mut v = Vec::new();
|
||
let fd = read_fcidump(include_str!("data/lih.fcidump")).unwrap();
|
||
v.push(fci(&fd).unwrap().energy);
|
||
v.push(hartree_fock_energy(&fd));
|
||
let r = ground_state(&fd, &ChemConfig { max_bond: 10, sweeps: 1, threads: 1, ..ChemConfig::default() });
|
||
v.extend(r.sweep_energies);
|
||
v.push(r.discarded);
|
||
v.extend(r.entropies);
|
||
let mpo = molecular_mpo(&fd, &ChemConfig::default());
|
||
v.extend(mpo.dims.iter().map(|&d| d as f64));
|
||
assert_eq!(digest(&v), 0xe955_a4ff_7eda_9960);
|
||
}
|
||
|
||
#[test]
|
||
fn neural_quantum_states() {
|
||
use quantum_nqs::*;
|
||
let mut v = Vec::new();
|
||
let n = 8;
|
||
let model = SpinModel::heisenberg(n, &chain_edges(n, false), 1.0);
|
||
v.push(model.exact_ground_energy(Some(0)).unwrap());
|
||
let rbm = Rbm::new(n, 2, 0.05, 1).with_marshall_sign(checkerboard(n, 1));
|
||
// Exact expectations, then sampled ones, a few steps each.
|
||
let mut exact = Vmc::new(model.clone(), rbm.clone(), VmcConfig { exact: true, magnetisation: Some(0), lr: 0.1, threads: 1, ..VmcConfig::default() });
|
||
for _ in 0..5 {
|
||
let e = exact.step();
|
||
v.extend([e.energy, e.variance]);
|
||
}
|
||
let mut sampled = Vmc::new(SpinModel::ising(n, &chain_edges(n, false), 1.0, 0.8), Rbm::new(n, 1, 0.1, 2), VmcConfig { samples: 200, chains: 4, threads: 1, ..VmcConfig::default() });
|
||
for _ in 0..3 {
|
||
let e = sampled.step();
|
||
v.extend([e.energy, e.variance, e.error, e.acceptance]);
|
||
}
|
||
v.extend(&sampled.rbm.w);
|
||
// A complex machine on the Majumdar–Ghosh ring, which has no sign rule:
|
||
// complex exponentials, logarithms and arctangents in every step.
|
||
let mg = SpinModel::j1j2(n, &chain_edges(n, true), &chain_next_nearest(n, true), 1.0, 0.5);
|
||
let mut cplx = Vmc::new(mg, Rbm::complex(n, 2, 0.05, 3), VmcConfig { exact: true, magnetisation: Some(0), lr: 0.1, threads: 1, ..VmcConfig::default() });
|
||
for _ in 0..4 {
|
||
let e = cplx.step();
|
||
v.extend([e.energy, e.variance]);
|
||
}
|
||
v.extend(cplx.rbm.w.iter().flat_map(|c| [c.re, c.im]));
|
||
// A projected machine on a 10-site ring (momentum π, odd), started near
|
||
// even: the metric goes singular and the eigendecomposition takes over.
|
||
let ring = SpinModel::heisenberg(10, &chain_edges(10, true), 1.0);
|
||
let rbm = Rbm::complex(10, 1, 0.01, 7).with_symmetry(Symmetry::ring(10, true).with_spin_flip(true));
|
||
let mut proj = Vmc::new(ring, rbm, VmcConfig { exact: true, magnetisation: Some(0), lr: 0.1, threads: 1, ..VmcConfig::default() });
|
||
for k in 0..60 {
|
||
let e = proj.step();
|
||
if k % 10 == 9 {
|
||
v.extend([e.energy, e.variance]);
|
||
}
|
||
}
|
||
v.extend(proj.rbm.b.iter().flat_map(|c| [c.re, c.im]));
|
||
assert_eq!(digest(&v), 0x834c_988e_b34e_814f);
|
||
}
|
||
|