wai-quantum: a rotation's Clifford+T word takes the cheapest unit of the solver's solution, never more T gates than the reference implementation #671

Closed
dcharlot wants to merge 13 commits from wai/quantum-synth-rz-reference into main
12 changed files with 1583 additions and 49 deletions

View file

@ -13,7 +13,9 @@ name: wai-quantum resource estimation
# (quantum_arch, quantum_bicycle and the estimate job), holds every row to its
# published figure (tests/data/published_figures.tsv: the digits it is printed
# to, or a guard on ours) and the page docs/published-architectures.md to what
# they give. Its search over 4¹¹ Paulis runs in a release build only.
# they give. Its search over 4¹¹ Paulis runs in a release build only. So does
# the synthesiser's sweep against the reference implementation's T counts
# (engine::synth::rz), which every rotation's T count in an estimate comes from.
#
# In a release build the calibration test measures every point of the
# decoders' table again (the rotated surface-code memory experiment, decoded
@ -112,6 +114,20 @@ jobs:
grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/published.log" || { echo "::error::$t did not run and pass"; exit 1; }
done
cargo run --locked --release --example published_architectures --features full
- name: Each rotation's Clifford+T word against the reference implementation's T counts
shell: bash
working-directory: wai/wai-quantum
run: |
set -euo pipefail
cargo test --locked --release --features full --lib -- engine::synth::rz:: 2>&1 | tee "$RUNNER_TEMP/rz.log"
grep -qE '^test result: ok\. [1-9][0-9]* passed; 0 failed; 0 ignored' "$RUNNER_TEMP/rz.log" || { echo "::error::the synthesiser's tests did not all run and pass"; exit 1; }
for t in engine::synth::rz::tests::never_more_t_gates_than_the_reference_over_the_sweep \
engine::synth::rz::tests::the_ising_angles_take_no_more_t_gates_than_the_reference \
engine::synth::rz::tests::the_unit_search_takes_no_more_t_gates_and_at_one_count_is_no_farther \
engine::synth::rz::tests::fewer_t_gates_can_end_farther_and_one_count_can_take_another_word \
engine::synth::rz::tests::the_t_count_is_the_optimum_found_by_exhaustive_search; do
grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/rz.log" || { echo "::error::$t did not run and pass"; exit 1; }
done
- name: The engine without receipts still builds the estimate
shell: bash
working-directory: wai/wai-quantum

View file

@ -0,0 +1,25 @@
### wai-quantum: a rotation's Clifford+T word takes the cheapest unit of the solver's solution
- `engine::synth::rz` writes, for each solution `u` it finds, the four unit multiples
`ωʲ·t` of the solver's solution of the norm equation `t†t = 2ᵏ − |u|²`, and keeps the one
whose operator takes the fewest `T` gates; the solver's own unit was taken before. The
operators the units give differ by `T` gates and share a diagonal, so for one `u` the word
is exactly as near. The equation has other solutions where a prime that splits in `Z[ω]`
divides its right side; the solver returns one, and those are not tried.
- Which `u` a rotation ends on can change, since one that lost may now win: the fewest `T`
gates win, then the nearest. So no rotation takes more `T` gates than before; at an equal
`T` count it is no farther; at a lower count it can be farther, and never past its `ε`.
Over the 1,192 rows below, 350 words changed, 57 of them at an unchanged `T` count, and 87
rotations ended farther from `Rz(θ)`; the Ising program's middle angle at `ε` = 10⁻³ goes
from 29 `T` gates at 3.50·10⁻⁴ to 27 at 6.15·10⁻⁴.
- Its tests hold the `T` counts to pygridsynth 1.0.1's, the reference implementation, on
the Ising program of arXiv:2506.03094 and 128 angles at ε from 10⁻¹ to 10⁻¹³
(`tests/data/rz_gridsynth_oracle.csv`, written by
`wai/tools/quantum-rz-oracle/gridsynth_oracle.py`, which CI does not run): never more.
Before this change 157 of those 1,192 took more.
- `T` counts that move: the Ising program's four angles at 5·10⁻⁹, 79, 80, 81, 84 → 79, 80,
79, 82 (14,665,600 → 14,592,000 over the program, in the published-architecture check);
`rz(1.1)` at 5·10⁻⁵, 40 → 38, and with it the compiler's worked certificate (78 → 76 `T`
gates, 200 → 197 gates). A compiled program's output, its hash and the receipts that seal
it change wherever one of its rotations takes another word, at an unchanged `T` count
too, and a certificate's summed distances can rise with them, never past its budget.

View file

@ -0,0 +1,79 @@
#!/usr/bin/env python3
"""gridsynth_oracle.py: the reference T counts that the engine's z-rotation
synthesiser (wai/wai-quantum/src/engine/synth/rz.rs) is held to.
For each angle and precision it runs pygridsynth 1.0.1, the reference
implementation of the Ross–Selinger algorithm that arXiv:2506.03094 cites, and
prints one CSV row: the angle and the precision as the doubles both sides use
(Python's repr, which Rust parses back to the same bits), pygridsynth's
denominator exponent and its T count. The output is
wai/wai-quantum/tests/data/rz_gridsynth_oracle.csv. CI does not run this
script and nothing depends on pygridsynth: the CSV is the oracle's answer,
committed, and `engine::synth::rz`'s tests read it.
python3 -m venv /tmp/pgs && /tmp/pgs/bin/pip install "pygridsynth==1.0.1" mpmath
/tmp/pgs/bin/python gridsynth_oracle.py > rz_gridsynth_oracle.csv
The angles:
- the four rotation angles of the 10 × 10 Ising program of arXiv:2506.03094
(Appendix A.10: a fourth-order product formula, Δ = 0.25, J = g = 1), at
its ε = 5·10⁻⁹ and at every precision below;
- 128 angles spread over (−π, π) by the golden ratio, θᵢ = −π + 2π·frac(i·φ),
none within 10⁻⁶ of a multiple of π/4 (those the engine writes exactly);
at ε = 10⁻¹, 10⁻², 10⁻³, 10⁻⁴, 10⁻⁵, 10⁻⁷, 10⁻⁹, 10⁻¹¹ and 10⁻¹³.
"""
import io
import math
import multiprocessing
import contextlib
import sys
import mpmath
from pygridsynth.gridsynth import gridsynth_gates
from pygridsynth.gridsynth import gridsynth
PRECISIONS = [1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-7, 1e-9, 1e-11, 1e-13]
def ising_angles():
gamma = 1.0 / (4.0 - 4.0 ** (1.0 / 3.0))
delta = 0.25
mid = (1.0 - 4.0 * gamma) * delta
return [("ising zz", gamma * delta), ("ising x", 2.0 * gamma * delta), ("ising zz middle", mid), ("ising x middle", 2.0 * mid)]
def swept_angles(n=128):
phi = (1.0 + math.sqrt(5.0)) / 2.0
out = []
i = 1
while len(out) < n:
theta = -math.pi + 2.0 * math.pi * math.fmod(i * phi, 1.0)
q = theta / (math.pi / 4.0)
if abs(q - round(q)) > 1e-6:
out.append((f"sweep {len(out) + 1}", theta))
i += 1
return out
def run(job):
name, theta, eps = job
mpmath.mp.dps = 128
with contextlib.redirect_stdout(io.StringIO()):
u = gridsynth(theta=mpmath.mpf(theta), epsilon=mpmath.mpf(eps))
gates = gridsynth_gates(theta=mpmath.mpf(theta), epsilon=mpmath.mpf(eps))
return (name, repr(theta), repr(eps), u.k, gates.count("T"))
def main():
jobs = [(name, theta, 5e-9) for name, theta in ising_angles()]
for eps in PRECISIONS:
jobs += [(name, theta, eps) for name, theta in ising_angles() + swept_angles()]
with multiprocessing.Pool(int(sys.argv[1]) if len(sys.argv) > 1 else 8) as pool:
rows = pool.map(run, jobs, chunksize=1)
print("name,theta,epsilon,k,t_count")
for row in rows:
print(",".join(str(x) for x in row))
if __name__ == "__main__":
main()

View file

@ -58,24 +58,57 @@ pub fn load(given: Option<&Path>, demo: bool) -> Result<Key, String> {
None => user_path().ok_or("no HOME to keep a key in: pass --key FILE")?,
};
match std::fs::read_to_string(&path) {
Ok(text) => {
let seed = parse(&text).ok_or_else(|| format!("{}: a key file holds 64 hex digits", path.display()))?;
Ok(Key { key: SigningKey::from_bytes(&seed), path: Some(path), made: false })
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound && named.is_none() => {
let mut seed = [0u8; 32];
getrandom::fill(&mut seed).map_err(|e| format!("no random source for a new key: {e}"))?;
if let Some(dir) = path.parent() {
std::fs::create_dir_all(dir).map_err(|e| format!("{}: {e}", dir.display()))?;
}
let text: String = seed.iter().map(|b| format!("{b:02x}")).collect();
write_private(&path, &format!("{text}\n")).map_err(|e| format!("{}: {e}", path.display()))?;
Ok(Key { key: SigningKey::from_bytes(&seed), path: Some(path), made: true })
Ok(text) => key_from(&path, &text),
Err(e) if e.kind() == std::io::ErrorKind::NotFound && named.is_none() => make(&path),
Err(e) => Err(format!("{}: {e}", path.display())),
}
}
fn key_from(path: &Path, text: &str) -> Result<Key, String> {
let seed = parse(text).ok_or_else(|| format!("{}: a key file holds 64 hex digits", path.display()))?;
Ok(Key { key: SigningKey::from_bytes(&seed), path: Some(path.to_path_buf()), made: false })
}
/// This user's key, made at `path` from the operating system's random source.
/// Two processes may make it at once, as two agents starting `wai-quantum mcp`
/// on a new machine do: the file is never seen partly written, and the one
/// that comes second signs with the first's key rather than failing.
fn make(path: &Path) -> Result<Key, String> {
let mut seed = [0u8; 32];
getrandom::fill(&mut seed).map_err(|e| format!("no random source for a new key: {e}"))?;
if let Some(dir) = path.parent() {
std::fs::create_dir_all(dir).map_err(|e| format!("{}: {e}", dir.display()))?;
}
let text: String = seed.iter().map(|b| format!("{b:02x}")).collect();
match publish_private(path, &format!("{text}\n")) {
Ok(()) => Ok(Key { key: SigningKey::from_bytes(&seed), path: Some(path.to_path_buf()), made: true }),
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => {
let text = std::fs::read_to_string(path).map_err(|e| format!("{}: {e}", path.display()))?;
key_from(path, &text)
}
Err(e) => Err(format!("{}: {e}", path.display())),
}
}
/// `text` at `path`, readable by its owner only and never seen partly
/// written: it goes to a new file beside `path`, which is then linked in under
/// `path`'s name. The link fails when `path` exists, so of two writers one
/// wins and the other is told (`AlreadyExists`). A file system with no links
/// takes the text in place, as `write_private` gives it.
fn publish_private(path: &Path, text: &str) -> std::io::Result<()> {
let mut tag = [0u8; 8];
getrandom::fill(&mut tag).map_err(|e| std::io::Error::other(e.to_string()))?;
let name = path.file_name().and_then(|n| n.to_str()).unwrap_or("key");
let beside = path.with_file_name(format!(".{name}.{}.{:016x}", std::process::id(), u64::from_le_bytes(tag)));
write_private(&beside, text)?;
let linked = std::fs::hard_link(&beside, path);
let _ = std::fs::remove_file(&beside);
match linked {
Err(e) if e.kind() != std::io::ErrorKind::AlreadyExists => write_private(path, text),
done => done,
}
}
fn write_private(path: &Path, text: &str) -> std::io::Result<()> {
use std::io::Write as _;
let mut f = std::fs::OpenOptions::new();
@ -132,4 +165,36 @@ mod tests {
}
let _ = std::fs::remove_dir_all(&dir);
}
/// Sixteen processes' worth of first uses at once, as when two agents start
/// `wai-quantum mcp` on a new machine: each gets a key, all the same one,
/// one of them made it, and nothing else is left beside it.
#[test]
fn keys_made_at_once_are_one_key() {
let dir = std::env::temp_dir().join(format!("wai-quantum-cli-key-race-{}", std::process::id()));
let path = dir.join("wai").join("quantum-key");
for round in 0..25 {
let _ = std::fs::remove_dir_all(&dir);
let start = std::sync::Arc::new(std::sync::Barrier::new(16));
let threads: Vec<_> = (0..16)
.map(|_| {
let (path, start) = (path.clone(), start.clone());
std::thread::spawn(move || {
start.wait();
make(&path).map(|k| (k.key.to_bytes(), k.made))
})
})
.collect();
let got: Vec<([u8; 32], bool)> = threads.into_iter().map(|t| t.join().unwrap()).collect::<Result<_, _>>().unwrap_or_else(|e| panic!("round {round}: {e}"));
assert!(got.windows(2).all(|w| w[0].0 == w[1].0), "round {round}: more than one key");
assert_eq!(got.iter().filter(|g| g.1).count(), 1, "round {round}: one of them made it");
assert_eq!(std::fs::read_dir(path.parent().unwrap()).unwrap().count(), 1, "round {round}: only the key is left");
assert_eq!(load_from_file(&path), got[0].0, "round {round}: the file holds that key");
}
let _ = std::fs::remove_dir_all(&dir);
}
fn load_from_file(path: &Path) -> [u8; 32] {
key_from(path, &std::fs::read_to_string(path).unwrap()).unwrap().key.to_bytes()
}
}

View file

@ -91,14 +91,17 @@ fn json_output_is_json_on_every_kind_of_job() {
/// One request to the MCP server on standard input and output.
fn mcp(tool: &str, arguments: Value) -> Value {
let mut child = Command::new(BIN).arg("mcp").env_remove("WAI_QUANTUM_KEY").stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::null()).spawn().unwrap();
let mut child = Command::new(BIN).arg("mcp").env_remove("WAI_QUANTUM_KEY").stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn().unwrap();
let mut stdin = child.stdin.take().unwrap();
writeln!(stdin, "{}", json!({ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": { "name": "test", "version": "0" } } })).unwrap();
writeln!(stdin, "{}", json!({ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": tool, "arguments": arguments } })).unwrap();
drop(stdin);
let out = child.wait_with_output().unwrap();
let text = String::from_utf8_lossy(&out.stdout);
let answer: Value = text.lines().filter_map(|l| serde_json::from_str::<Value>(l).ok()).find(|v| v["id"] == 2).unwrap_or_else(|| panic!("{text}"));
// A server that answers nothing says why on its standard error, which the panic keeps.
let answer: Value = text.lines().filter_map(|l| serde_json::from_str::<Value>(l).ok()).find(|v| v["id"] == 2).unwrap_or_else(|| {
panic!("{tool}: no answer from the server ({}): standard output {text:?}, standard error {:?}", out.status, String::from_utf8_lossy(&out.stderr))
});
answer["result"]["structuredContent"].clone()
}

View file

@ -104,8 +104,8 @@ For `h q[0]; rz(0.3) q[0]; cx q[0], q[1]; ry(1.1) q[1];` at `--epsilon 1e-4`
"level": 1,
"source": { "hash": "3088646d…", "qubits": 2,
"counts": { "gates": 4, "cnots": 1, "t_count": 0, "rotations": 2, "depth": 4, "…": "…" } },
"output": { "hash": "65e0c256…",
"counts": { "gates": 200, "cnots": 1, "t_count": 78, "rotations": 0, "depth": 200, "…": "…" } },
"output": { "hash": "a6aff9b0…",
"counts": { "gates": 197, "cnots": 1, "t_count": 76, "rotations": 0, "depth": 197, "…": "…" } },
"epsilon": { "budget": 0.0001, "rotations": 2, "each": 5e-05, "bound": 7.453429548248133e-05 },
"passes": [
{ "pass": "simplify", "before": { "…": "…" }, "after": { "…": "…" },
@ -114,16 +114,16 @@ For `h q[0]; rz(0.3) q[0]; cx q[0], q[1]; ry(1.1) q[1];` at `--epsilon 1e-4`
"check": { "how": "each kind of gate against its decomposition, on its own qubits", "verdict": "exact", "checked": 1, "distance": 5.551115123125783e-17 } },
{ "pass": "approximate", "…": "…",
"check": { "how": "each rotation's Clifford+T word multiplied out in exact ring arithmetic, and its operator-norm distance to the rotation recomputed from the word in fixed point and rounded up",
"verdict": "approximate", "rotations": 2, "epsilon_each": 5e-05, "t_count": 78, "distance": 7.453429548248133e-05 } },
"verdict": "approximate", "rotations": 2, "epsilon_each": 5e-05, "t_count": 76, "distance": 7.453429548248133e-05 } },
{ "pass": "phase_fold", "…": "…",
"check": { "how": "the phase polynomial recomputed: … in whole eighths of a turn", "verdict": "proof", "merged": 41 } },
"check": { "how": "the phase polynomial recomputed: … in whole eighths of a turn", "verdict": "proof", "merged": 39 } },
{ "…": "…" }
],
"rotations": [
{ "angle": 0.3, "t_count": 38, "distance": 3.77439802702028e-05, "k": 20 },
{ "angle": 1.1, "t_count": 40, "distance": 3.679031521227853e-05, "k": 20 }
{ "angle": 1.1, "t_count": 38, "distance": 3.679031521227853e-05, "k": 20 }
],
"whole": { "how": "the dense unitaries of the whole program and the whole output", "distance": 7.123665880156653e-05, "verdict": "approximate" },
"whole": { "how": "the dense unitaries of the whole program and the whole output", "distance": 7.269652454265581e-05, "verdict": "approximate" },
"verdict": "approximate",
"reading": "The output equals the program up to a global phase to within 7.453429548248133e-5 in the operator norm (the budget was 1e-4). …"
}

View file

@ -84,7 +84,9 @@ Ising program. Its other differences are explained in their rows:
capability at 10⁻³ (its own row).
- Its Ising program takes 15,542,400 T gates in its tables and 19,036,800 in
its text and Fig. 1. pygridsynth 1.0.1, the version it cites, gives the
15,542,400 exactly.
15,542,400 exactly. Our synthesiser also searches the rotations one global
phase away and takes 6.1% fewer, and no more than pygridsynth on any of the
angles and precisions its tests compare.
- Its gross Ising machine of 4,817 qubits takes the adapter of the 10⁻³
factory beside the 10⁻⁴ factory it names (4,801).
- The Ising program's inter-module measurements match its 946,800 with the
@ -268,8 +270,8 @@ its own formula, and so on. Its Toffoli count comes back.
| in-module measurements `N_M`, two-gross | arXiv:2506.03094 Table 9, source files | 4,238,828 | 4,148,800 | -2.12% | our limit | Ours removes no repeated in-module measurement, which theirs does (§4), and takes sites in order, which it does not print. Its counts also carry the compile section's action of a shift on Z̄, which puts its gross below its two-gross; ours has them the other way round. |
| automorphisms `N_U`, gross | arXiv:2506.03094 Table 9, source files | 2,270,400 | 2,728,800 | +20.19% | our limit | Ours takes the fewest shifts on a path of fewest measurements, and merges none; theirs is a compiler's. |
| automorphisms `N_U`, two-gross | arXiv:2506.03094 Table 9, source files | 2,294,400 | 2,368,000 | +3.21% | our limit | Ours takes the fewest shifts on a path of fewest measurements, and merges none; theirs is a compiler's. |
| T injections `N_T` | arXiv:2506.03094 Table 9, source files | 15,542,400 | 14,665,600 | -5.64% | their model | pygridsynth 1.0.1, the version the source cites, run on the program's four angles at ε = 5·10⁻⁹, gives 86, 80, 84 and 82 T gates, which make 15,542,400 exactly; it approximates the rotation itself. Ours, the same Ross–Selinger method, gives 79, 80, 81 and 84, and also searches the class one global phase e^(iπ/8) away, which a rotation of the pivot allows. |
| T injections as §4 and Fig. 1(b) state | arXiv:2506.03094 §4; Fig. 1(b), source files | 1.9·10⁷ (Fig. 1(b): 19,036,800) | 14,665,600 | -22.96% | their numbers | §4 says N_T = 1.9·10⁷ and Fig. 1(b) plots 19,036,800. Table 9 and every failure probability of Table 10 take 15,542,400, which the row above compares ours with. |
| T injections `N_T` | arXiv:2506.03094 Table 9, source files | 15,542,400 | 14,592,000 | -6.11% | their model | pygridsynth 1.0.1, the version the source cites, run on the program's four angles at ε = 5·10⁻⁹, gives 86, 80, 84 and 82 T gates, which make 15,542,400 exactly; it approximates the rotation itself. Ours, the same Ross–Selinger method, gives 79, 80, 79 and 82: it also searches the class one global phase e^(iπ/8) away, which a rotation of the pivot allows, and of the solver's solution of the norm equation and its unit multiples it keeps the one whose operator takes the fewest T gates. It takes no more than the reference on any of 1,192 angles and precisions (engine::synth::rz's tests). |
| T injections as §4 and Fig. 1(b) state | arXiv:2506.03094 §4; Fig. 1(b), source files | 1.9·10⁷ (Fig. 1(b): 19,036,800) | 14,592,000 | -23.35% | their numbers | §4 says N_T = 1.9·10⁷ and Fig. 1(b) plots 19,036,800. Table 9 and every failure probability of Table 10 take 15,542,400, which the row above compares ours with. |
| idles `N_I`, two-gross, from its `N_T` | arXiv:2506.03094 Table 9, source files | 41,636,714,298 | 42,100,476,000 | +1.11% | our limit | Ours: every module idles while the factory works, and otherwise never. Theirs counts the idles of its schedule. |
| failure probability, gross, p = 10⁻³, its counts | arXiv:2506.03094 Table 10 | 3.33·10⁴ | 3.331e4 | +0.03% | agrees | Table 9's counts at our evaluation of Table 6's fits (Eq. (26)); the band moves the fits' parameters by their last printed digit. |
| failure probability, gross, p = 10⁻⁴, its counts | arXiv:2506.03094 Table 10 | 7.97·10⁻¹ | 7.977e-1 | +0.09% | agrees | Table 9's counts at our evaluation of Table 6's fits (Eq. (26)); the band moves the fits' parameters by their last printed digit. |

View file

@ -19,31 +19,41 @@ fn hx(b: &[u8]) -> String {
/// (`formats::jeff`), so that column moves with every release of wai-quantum:
/// taken at 0.8.1, it was written again at 0.9.0 from the engine's own export,
/// which at 0.8.1 still gives the values taken then.
///
/// Since the synthesiser keeps the cheapest unit multiple of the norm
/// equation's solution (`engine::synth::rz`), a rotation's word can take fewer
/// `T` gates, so the compile's output and the estimate's counts of the rows
/// with such rotations are what it gives now, every one with fewer `T` gates:
/// the compile of c3z 1080 → 1059, c3x 1080 → 1061, c3y 1079 → 1063, c3h
/// 1081 → 1065, c2u 1066 → 1058, c2sx 483 → 476, ccu 1078 → 1065, c2swap
/// 1080 → 1061 and grover6 10080 → 9828; the estimate's rotation `T` of c2rx,
/// c2ry and c2rzz 460 → 450, c2u 1647 → 1631, c2sx 624 → 611, ccu 1807 →
/// 1791, c2swap 720 → 705, c2gphase 117 → 114 and cp 114 → 108.
#[rustfmt::skip]
#[allow(clippy::type_complexity)]
const BEFORE: &[(&str, &str, usize, &str, &str, &str, &str, &str, &str)] = &[
("c3z", "qubit[5] q;\nh q;\nctrl(3) @ z q[0], q[1], q[2], q[3];\n", 34, "29718f9ab500304a", "181acaa4aad01230", "f23087907c80c69d", "c8c5157978bce0e3", "65bc71cbed38d1a8", "747ea02fde8aeaca"),
("c3x", "qubit[5] q;\nh q;\nctrl(3) @ x q[0], q[1], q[2], q[3];\n", 36, "7a786cc271f2501b", "8a504be7fc0299e8", "19be6f5bfc085d84", "0c304a3bc21ab20d", "daf3f611f19ea19a", "d7c18a0142c206a0"),
("c3y", "qubit[5] q;\nh q;\nt q[1];\nctrl(3) @ y q[0], q[1], q[2], q[3];\n", 39, "83dfa98a747a790d", "fbc90dbfada344a4", "263ae5be1f8ed271", "3248786655ef4b22", "2e406a5884783142", "9fd8aa3d94545ea2"),
("c3h", "qubit[5] q;\nh q;\nt q[1];\nctrl(3) @ h q[0], q[1], q[2], q[3];\n", 37, "d6da69225d63f4a2", "f9fd9fa5547c7200", "de15875954d42157", "b2d92db2f0938d25", "5537e974bf7a9789", "744da0841af0f928"),
("c3z", "qubit[5] q;\nh q;\nctrl(3) @ z q[0], q[1], q[2], q[3];\n", 34, "29718f9ab500304a", "181acaa4aad01230", "d6ac65a5d000432d", "c8c5157978bce0e3", "65bc71cbed38d1a8", "747ea02fde8aeaca"),
("c3x", "qubit[5] q;\nh q;\nctrl(3) @ x q[0], q[1], q[2], q[3];\n", 36, "7a786cc271f2501b", "8a504be7fc0299e8", "d67b92d5f3fdb9cf", "0c304a3bc21ab20d", "daf3f611f19ea19a", "d7c18a0142c206a0"),
("c3y", "qubit[5] q;\nh q;\nt q[1];\nctrl(3) @ y q[0], q[1], q[2], q[3];\n", 39, "83dfa98a747a790d", "fbc90dbfada344a4", "55221950a66c19b9", "3248786655ef4b22", "2e406a5884783142", "9fd8aa3d94545ea2"),
("c3h", "qubit[5] q;\nh q;\nt q[1];\nctrl(3) @ h q[0], q[1], q[2], q[3];\n", 37, "d6da69225d63f4a2", "f9fd9fa5547c7200", "0c3cd36f5611ac6d", "b2d92db2f0938d25", "5537e974bf7a9789", "744da0841af0f928"),
("c2p", "qubit[4] q;\nh q;\nctrl(2) @ p(pi / 8) q[0], q[1], q[2];\n", 17, "b076ca7327b88b22", "13346662e1739d87", "18407afca6242403", "82518b8435656332", "fac0bb93925ec89d", "0da1476c3de0dffa"),
("c2rz", "qubit[4] q;\nh q;\nctrl(2) @ rz(pi / 4) q[0], q[1], q[2];\n", 18, "ade98300c7a91bea", "ca049c0c8dd637ed", "a4f6414c00826c92", "0f6065ef438dadba", "967d0020dc595ca1", "d2f07d8d123fa85a"),
("c2rx", "qubit[4] q;\nh q;\nctrl(2) @ rx(pi / 2) q[0], q[1], q[2];\n", 20, "6ae6ae2309534fbb", "3eab347bbdb8b27c", "5a664df2c0c8b771", "4dc76727674b23fa", "c938f52de02329e6", "d992c105de67f83c"),
("c2ry", "qubit[4] q;\nh q;\nctrl(2) @ ry(pi / 2) q[0], q[1], q[2];\n", 22, "27369425f1ce33f2", "94f7f25bde25caef", "947dd07eb6275558", "27aeedd8797a64c3", "baccb437d38345c8", "b75ea5448c736963"),
("c2u", "qubit[4] q;\nh q;\nctrl(2) @ u(pi / 2, pi / 4, pi / 8) q[0], q[1], q[2];\n", 51, "0032cafc1cf71c51", "7c43ae072ebd46be", "e8f8bdd2fd064d70", "529d746a02266c75", "2bfcec998fd6fbc9", "94c720252c873ede"),
("c2sx", "qubit[4] q;\nh q;\nctrl(2) @ sx q[0], q[1], q[2];\n", 21, "3011642a37dab1c8", "378d6c6c3635da01", "e65547fe84b0d8cf", "8a53373f168fcddd", "45331d3739d29283", "c3e8535f252e0170"),
("c2rx", "qubit[4] q;\nh q;\nctrl(2) @ rx(pi / 2) q[0], q[1], q[2];\n", 20, "6ae6ae2309534fbb", "3eab347bbdb8b27c", "5a664df2c0c8b771", "4dc76727674b23fa", "c938f52de02329e6", "04e354bedaac05f0"),
("c2ry", "qubit[4] q;\nh q;\nctrl(2) @ ry(pi / 2) q[0], q[1], q[2];\n", 22, "27369425f1ce33f2", "94f7f25bde25caef", "947dd07eb6275558", "27aeedd8797a64c3", "baccb437d38345c8", "d06687536842afbb"),
("c2u", "qubit[4] q;\nh q;\nctrl(2) @ u(pi / 2, pi / 4, pi / 8) q[0], q[1], q[2];\n", 51, "0032cafc1cf71c51", "7c43ae072ebd46be", "528d9ce71320056f", "529d746a02266c75", "2bfcec998fd6fbc9", "d52535001b3fd082"),
("c2sx", "qubit[4] q;\nh q;\nctrl(2) @ sx q[0], q[1], q[2];\n", 21, "3011642a37dab1c8", "378d6c6c3635da01", "8054090c33152d4e", "8a53373f168fcddd", "45331d3739d29283", "f1b22819c6f6d640"),
("neg", "qubit[4] q;\nh q;\nnegctrl(2) @ ctrl @ s q[0], q[1], q[2], q[3];\n", 37, "64475caf52138761", "77667386517f1f09", "1c755ad6249197a1", "e46c16636e80eebd", "ae0ea2e1a600fe8c", "e42f39af5237beca"),
("ccu", "qubit[4] q;\nh q;\nctrl @ cu(pi / 2, pi / 4, pi / 8, pi / 16) q[0], q[1], q[2];\n", 52, "a9f7955f0864db33", "fa538ea89cfe5c9a", "0ba490c2dda2780c", "c40db1252b470677", "9af7de5cf84e3975", "b27c6c0bb9082d58"),
("c2swap", "qubit[4] q;\nh q;\nctrl(2) @ swap q[0], q[1], q[2], q[3];\n", 37, "90d28cfbf2beef6c", "7982dfa1bd563330", "76fee435a36b077d", "f1554f2143fd5485", "3eac44e71c6e6884", "fe16b8d3921fa66b"),
("c2rzz", "qubit[4] q;\nh q;\nctrl(2) @ rzz(pi / 2) q[0], q[1], q[2], q[3];\n", 20, "169448464ac572eb", "b537afe5c235346c", "c0df4fdb5cb39f1a", "e7c473ac7aced773", "7b9403a68c4191c1", "d992c105de67f83c"),
("c2gphase", "qubit[3] q;\nh q;\nctrl(2) @ gphase(pi / 4) q[0], q[1];\n", 4, "613a1f7f53c2c634", "0e065cabc1032cc6", "eb75b70b655bedca", "87c33623c70c4586", "2f5443784c488a78", "709224f43ac6c30e"),
("ccu", "qubit[4] q;\nh q;\nctrl @ cu(pi / 2, pi / 4, pi / 8, pi / 16) q[0], q[1], q[2];\n", 52, "a9f7955f0864db33", "fa538ea89cfe5c9a", "4cddec462306adfb", "c40db1252b470677", "9af7de5cf84e3975", "2cb9eefc64e918ec"),
("c2swap", "qubit[4] q;\nh q;\nctrl(2) @ swap q[0], q[1], q[2], q[3];\n", 37, "90d28cfbf2beef6c", "7982dfa1bd563330", "827673a89608715b", "f1554f2143fd5485", "3eac44e71c6e6884", "869908729c2e89a4"),
("c2rzz", "qubit[4] q;\nh q;\nctrl(2) @ rzz(pi / 2) q[0], q[1], q[2], q[3];\n", 20, "169448464ac572eb", "b537afe5c235346c", "c0df4fdb5cb39f1a", "e7c473ac7aced773", "7b9403a68c4191c1", "04e354bedaac05f0"),
("c2gphase", "qubit[3] q;\nh q;\nctrl(2) @ gphase(pi / 4) q[0], q[1];\n", 4, "613a1f7f53c2c634", "0e065cabc1032cc6", "eb75b70b655bedca", "87c33623c70c4586", "2f5443784c488a78", "f161950ccab25f70"),
("invc3t", "qubit[4] q;\nh q;\ninv @ ctrl(3) @ t q[0], q[1], q[2], q[3];\n", 33, "6d8735fa38b73015", "8ac349a04bd30ca8", "389140fbf3231c9f", "cfc33faa8c2f6e40", "2483f0a54b74abf8", "b0d2a886a160dcc2"),
("grover6", "qubit[6] q;\nh q;\nctrl(5) @ z q[0], q[1], q[2], q[3], q[4], q[5];\nh q;\nx q;\nctrl(5) @ z q[0], q[1], q[2], q[3], q[4], q[5];\nx q;\nh q;\n", 280, "71390b8e8200400a", "9e5c239c034ba374", "9b7fb2311b984049", "384c13c05764b82d", "b31d63424bc43e4e", "d164abfb32a62b0a"),
("grover6", "qubit[6] q;\nh q;\nctrl(5) @ z q[0], q[1], q[2], q[3], q[4], q[5];\nh q;\nx q;\nctrl(5) @ z q[0], q[1], q[2], q[3], q[4], q[5];\nx q;\nh q;\n", 280, "71390b8e8200400a", "9e5c239c034ba374", "a14f0c960297a237", "384c13c05764b82d", "b31d63424bc43e4e", "d164abfb32a62b0a"),
("ccx", "qubit[4] q;\nh q;\nt q[0];\nctrl(2) @ x q[0], q[1], q[2];\n", 6, "542e1352d6cd7c2e", "bc16012d7e5c98a8", "99b450e817595855", "6645931b4b759afb", "3bb1330f3ba2a9d6", "d370a78cc7e92248"),
("ccz", "qubit[4] q;\nh q;\nt q[0];\nctrl(2) @ z q[0], q[1], q[2];\n", 6, "32cc8ef799a35dc2", "b357eae18a404904", "f3b4c56a4b8d0c9d", "7a9c51e72904ac4a", "580547bf20c7c3e4", "d370a78cc7e92248"),
("c2y", "qubit[4] q;\nh q;\nt q[0];\nctrl(2) @ y q[0], q[1], q[2];\n", 8, "2c326695e1bde126", "59d46a5019e4d87c", "dacf9a1398e3e043", "a9ff98ce426f905d", "5e943acf949d0ebd", "551165238caa42d2"),
("c2h", "qubit[4] q;\nh q;\nt q[0];\nctrl(2) @ h q[0], q[1], q[2];\n", 8, "ae920e55c106966c", "e61608a2117a83aa", "58443259e04d5f16", "7e9d2678d90ccadc", "f17c81d581143ea0", "d76ade781f528b10"),
("cp", "qubit[3] q;\nh q;\nctrl @ p(pi / 8) q[0], q[1];\n", 4, "48ca258d13245d56", "cddd783aad2071d2", "e062f8754960a2d9", "ed65712144049bea", "9293396e5fad806a", "0e28272539b04b2a"),
("cp", "qubit[3] q;\nh q;\nctrl @ p(pi / 8) q[0], q[1];\n", 4, "48ca258d13245d56", "cddd783aad2071d2", "e062f8754960a2d9", "ed65712144049bea", "9293396e5fad806a", "ce8fbc7d4e31cb46"),
("cswap", "qubit[3] q;\nh q;\nctrl @ swap q[0], q[1], q[2];\n", 4, "2a5e8a545c769f54", "70fe25ec22008f86", "27282765b5abf030", "e85d174f9e4e97da", "adc56410e186e7cf", "694084d5478b13ed"),
("plain", "qubit[3] q;\nh q;\ncx q[0], q[1];\nrz(pi / 4) q[2];\n", 5, "8103a71b8f08fb58", "92dbd1cf0f4ce0e1", "275c3c9040292ce0", "2bd714b375f08ed0", "35d1172993ba3e67", "68eebfa353685fb7"),
];

View file

@ -14,7 +14,23 @@
//! grid problem ([`super::grid`]), each tested exactly; for each, `t†t =
//! 2ᵏ − |u|²` is solved ([`super::dioph`]); the first `k` with a solution
//! gives the operator, which [`super::ring::synthesize`] writes as the word
//! with the fewest `T` gates. The `T` count is about `3·log₂(1/ε)`.
//! with the fewest `T` gates. Every unit multiple `ωʲ·t` of the solver's `t`
//! solves the equation too, and the operators they give differ by `T` gates,
//! so each is written and the fewest kept. (The equation has other solutions
//! where a prime that splits in `Z[ω]` divides `2ᵏ − |u|²`; the solver returns
//! one, and those are not tried.) The `T` count is about `3·log₂(1/ε)`.
//!
//! Of the words within `ε` at that `k`, the fewest `T` gates win, then the
//! nearest. So what the unit search does to a rotation is this: it never takes
//! more `T` gates than the solver's own unit would; at an equal count it is no
//! farther; at a lower count it can be farther, because a `u` that lost may now
//! win with its own distance, but never past `ε`. Its word can change at an
//! equal count too.
//!
//! The tests hold the `T` counts to pygridsynth 1.0.1's, the reference
//! implementation, on 1,192 angles and precisions
//! (`tests/data/rz_gridsynth_oracle.csv`, written by
//! `wai/tools/quantum-rz-oracle/gridsynth_oracle.py`): never more.
//!
//! What is returned has been checked twice over: the word multiplies back,
//! exactly, to the operator found, and its distance to `Rz(θ)` is computed
@ -84,6 +100,30 @@ pub fn word_distance(gates: &[Kind], theta: f64) -> f64 {
d + d * 1e-15 + f64::MIN_POSITIVE
}
/// The operator `(1/√2ᵏ)·[[u, −t'†ωˡ], [t', u†ωˡ]]` with the fewest `T` gates,
/// over the unit multiples `t' = ωʲ·t` of the solver's solution of the norm
/// equation, as a word.
///
/// Each `ωʲ·t` solves `t†t = 2ᵏ − |u|²`, and the operators they give differ by
/// `T` gates: `t' = ω·t` is `T·U·T†` with `ω` taken into the second column's
/// phase. Their diagonals are the same, so for this `u` each is as near
/// `Rz(θ)`. `j` and `j + 4` give operators conjugate by `Z`, a Clifford, with
/// one `T` count, so `j < 4` covers them. The solver's own `t` comes first and
/// is kept on a tie.
fn fewest_t_completion(u: &Zw, t: &Zw, l: i64, k: u32) -> Result<super::ring::Word, String> {
let wl = Zw::omega(l);
let mut best: Option<super::ring::Word> = None;
for j in 0..4 {
let tj = t.mul_omega(j);
let op = Mat2::new([u.clone(), tj.adj().mul(&wl).neg(), tj, u.adj().mul(&wl)], k);
let word = synthesize(&op)?;
if best.as_ref().is_none_or(|b| word.t_count < b.t_count) {
best = Some(word);
}
}
Ok(best.expect("four completions were written"))
}
/// The word for `Rz(mπ/4)` up to a phase: `T^m`.
fn quarter_word(m: i64) -> Vec<Kind> {
match m.rem_euclid(8) {
@ -102,6 +142,11 @@ fn quarter_word(m: i64) -> Vec<Kind> {
/// search finds at the least denominator exponent; refused for `ε` outside
/// [`MIN_EPSILON`, `MAX_EPSILON`].
pub fn rz(theta: f64, epsilon: f64) -> Result<Rotation, String> {
rz_by(theta, epsilon, fewest_t_completion)
}
/// [`rz`], each `u`'s operator written by `complete`.
fn rz_by(theta: f64, epsilon: f64, complete: fn(&Zw, &Zw, i64, u32) -> Result<super::ring::Word, String>) -> Result<Rotation, String> {
if !theta.is_finite() {
return Err(format!("the angle {theta} is not a number"));
}
@ -165,9 +210,7 @@ pub fn rz(theta: f64, epsilon: f64) -> Result<Rotation, String> {
equations += 1;
let mut budget = FACTOR_BUDGET;
let Some(t) = dioph::solve(&xi, &mut budget) else { continue };
let wl = Zw::omega(*l);
let op = Mat2::new([u.clone(), t.adj().mul(&wl).neg(), t, u.adj().mul(&wl)], k);
let word = synthesize(&op)?;
let word = complete(u, &t, *l, k)?;
let distance = word_distance(&word.gates, theta);
if distance <= epsilon {
found.push((word.gates, word.t_count, distance));
@ -340,4 +383,102 @@ mod tests {
assert!(rz(0.3, 0.6).is_err());
assert!(rz(f64::NAN, 1e-3).is_err());
}
/// The reference T counts: pygridsynth 1.0.1, run by
/// `wai/tools/quantum-rz-oracle/gridsynth_oracle.py` on the four angles of
/// the Ising program of arXiv:2506.03094 and on 128 angles over (−π, π),
/// at ε from 10⁻¹ to 10⁻¹³. Rows: name, θ, ε, its exponent, its T count.
fn oracle() -> Vec<(String, f64, f64, usize)> {
include_str!("../../../tests/data/rz_gridsynth_oracle.csv")
.lines()
.skip(1)
.map(|line| {
let f: Vec<&str> = line.split(',').collect();
(f[0].to_string(), f[1].parse().unwrap(), f[2].parse().unwrap(), f[4].parse().unwrap())
})
.collect()
}
#[test]
fn the_ising_angles_take_no_more_t_gates_than_the_reference() {
// At ε = 5·10⁻⁹ the reference takes 86, 80, 84 and 82: 15,542,400 over
// the program. Here the third took 81 and the fourth 84 while the
// solver's own unit was taken.
let rows: Vec<_> = oracle().into_iter().filter(|r| r.0.starts_with("ising") && r.2 == 5e-9).collect();
assert_eq!(rows.iter().map(|r| r.3).collect::<Vec<_>>(), [86, 80, 84, 82]);
let ours: Vec<usize> = rows.iter().map(|r| rz(r.1, r.2).unwrap().t_count).collect();
for (r, t) in rows.iter().zip(&ours) {
assert!(*t <= r.3, "{}: {t} T gates, the reference {}", r.0, r.3);
}
assert_eq!(ours, [79, 80, 79, 82]);
}
#[test]
#[cfg_attr(debug_assertions, ignore = "about twelve hundred syntheses: release only")]
fn never_more_t_gates_than_the_reference_over_the_sweep() {
let rows = oracle();
assert_eq!(rows.len(), 1192);
let (mut fewer, mut equal, mut saved) = (0, 0, 0);
let mut worse = Vec::new();
for (name, theta, eps, reference) in &rows {
let r = rz(*theta, *eps).unwrap();
assert!(r.distance <= *eps, "{name}, ε {eps}: distance {}", r.distance);
match r.t_count.cmp(reference) {
std::cmp::Ordering::Less => {
fewer += 1;
saved += reference - r.t_count;
}
std::cmp::Ordering::Equal => equal += 1,
std::cmp::Ordering::Greater => worse.push(format!("{name} θ {theta} ε {eps}: {} against {reference}", r.t_count)),
}
}
eprintln!("against the reference: {fewer} fewer ({saved} T gates in all), {equal} equal, {} more", worse.len());
assert!(worse.is_empty(), "{} rows take more T gates than the reference: {worse:#?}", worse.len());
}
/// The operator as the solver's own `t` gives it, as [`rz`] once took it.
fn the_solver_s_own_unit(u: &Zw, t: &Zw, l: i64, k: u32) -> Result<crate::engine::synth::ring::Word, String> {
let wl = Zw::omega(l);
synthesize(&Mat2::new([u.clone(), t.adj().mul(&wl).neg(), t.clone(), u.adj().mul(&wl)], k))
}
/// Each `u` keeps its distance whatever the unit, but the search is over
/// every `u`, and one that lost may now win: fewer `T` gates can end
/// farther, and one count can take another word.
#[test]
fn fewer_t_gates_can_end_farther_and_one_count_can_take_another_word() {
// The Ising program's zz middle angle at ε = 10⁻³.
let (theta, eps) = (-0.1644907717943757, 1e-3);
let (now, before) = (rz(theta, eps).unwrap(), rz_by(theta, eps, the_solver_s_own_unit).unwrap());
assert_eq!((before.t_count, now.t_count), (29, 27));
assert!(now.distance > before.distance && now.distance <= eps, "{} against {}", now.distance, before.distance);
// rz(0.1) at ε = 10⁻⁹: 89 T gates both ways, another word, nearer.
let (now, before) = (rz(0.1, 1e-9).unwrap(), rz_by(0.1, 1e-9, the_solver_s_own_unit).unwrap());
assert_eq!((before.t_count, now.t_count), (89, 89));
assert_ne!(now.gates, before.gates);
assert!(now.distance < before.distance, "{} against {}", now.distance, before.distance);
}
/// What the unit search can do to a rotation, over the oracle's rows:
/// never more `T` gates, no farther at an equal count, always within `ε`.
#[test]
#[cfg_attr(debug_assertions, ignore = "about twenty-four hundred syntheses: release only")]
fn the_unit_search_takes_no_more_t_gates_and_at_one_count_is_no_farther() {
let (mut changed, mut at_one_count, mut farther) = (0, 0, 0);
for (name, theta, eps, _) in &oracle() {
let (now, before) = (rz(*theta, *eps).unwrap(), rz_by(*theta, *eps, the_solver_s_own_unit).unwrap());
assert!(now.t_count <= before.t_count, "{name}, ε {eps}: {} T gates, {} before", now.t_count, before.t_count);
assert!(now.distance <= *eps, "{name}, ε {eps}: distance {}", now.distance);
if now.t_count == before.t_count {
assert!(now.distance <= before.distance, "{name}, ε {eps}: {} against {}", now.distance, before.distance);
}
if now.gates != before.gates {
changed += 1;
at_one_count += usize::from(now.t_count == before.t_count);
}
farther += usize::from(now.distance > before.distance);
}
eprintln!("the unit search: {changed} words changed, {at_one_count} of them at one T count; {farther} rotations farther");
assert_eq!((changed, at_one_count, farther), (350, 57, 87));
}
}

View file

@ -506,7 +506,7 @@ fn ising(gross: &PauliCosts, two: &PauliCosts) -> Result<Section, String> {
F::I,
Class::TheirModel,
format!(
"pygridsynth 1.0.1, the version the source cites, run on the program's four angles at ε = 5·10⁻⁹, gives 86, 80, 84 and 82 T gates, which make 15,542,400 exactly; it approximates the rotation itself. Ours, the same Ross–Selinger method, gives {}, {}, {} and {}, and also searches the class one global phase e^(iπ/8) away, which a rotation of the pivot allows.",
"pygridsynth 1.0.1, the version the source cites, run on the program's four angles at ε = 5·10⁻⁹, gives 86, 80, 84 and 82 T gates, which make 15,542,400 exactly; it approximates the rotation itself. Ours, the same Ross–Selinger method, gives {}, {}, {} and {}: it also searches the class one global phase e^(iπ/8) away, which a rotation of the pivot allows, and of the solver's solution of the norm equation and its unit multiples it keeps the one whose operator takes the fewest T gates. It takes no more than the reference on any of 1,192 angles and precisions (engine::synth::rz's tests).",
counts[0], counts[1], counts[2], counts[3]
),
);
@ -874,7 +874,7 @@ mod tests {
assert!(rows["fig9.chosen.gross"].why.contains("bicycle_cliffords 0.1.0"));
assert!(rows["fig10a.gross_e4_5k.nt"].why.contains("bicycle_compiler 0.1.0"));
let all: String = sections.iter().flat_map(|s| &s.rows).map(|r| format!("{} {} {}\n", r.quantity, r.source, r.why)).collect();
for gone in ["not released", "Fig. 16", "shortfall", "press release", "announced", "every R ≠ I"] {
for gone in ["not released", "Fig. 16", "shortfall", "press release", "announced", "every R ≠ I", "norm equation's solutions"] {
assert!(!all.contains(gone), "{gone}");
}
assert!(rows["fig10a.gross_e3_5k.nt"].why.contains("Fig. 17") || rows["fig10a.gross_e3_5k.nt_undivided"].why.contains("Fig. 17"));
@ -907,8 +907,8 @@ mod tests {
/// The Ising row's text names these.
#[test]
fn the_ising_angles_take_these_t_counts() {
assert_eq!(ising_t_counts(5e-9).unwrap(), [79, 80, 81, 84]);
assert_eq!(ising_t_count(5e-9).unwrap(), 14_665_600);
assert_eq!(ising_t_counts(5e-9).unwrap(), [79, 80, 79, 82]);
assert_eq!(ising_t_count(5e-9).unwrap(), 14_592_000);
// pygridsynth 1.0.1's counts on the same angles give the source's total.
assert_eq!(80 * (4 * (360 * 86 + 100 * 80) + 360 * 84 + 100 * 82), 15_542_400);
}

View file

@ -104,8 +104,8 @@ table9.gross.nm arXiv:2506.03094 Table 9, source files 4,215,240 4215240 guard 4
table9.two.nm arXiv:2506.03094 Table 9, source files 4,238,828 4238828 guard 4.149e6
table9.gross.nu arXiv:2506.03094 Table 9, source files 2,270,400 2270400 guard 2.729e6
table9.two.nu arXiv:2506.03094 Table 9, source files 2,294,400 2294400 guard 2.368e6
table9.nt arXiv:2506.03094 Table 9, source files 15,542,400 15542400 guard 1.467e7
s4.nt arXiv:2506.03094 §4; Fig. 1(b), source files 1.9·10⁷ (Fig. 1(b): 19,036,800) 19036800 guard 1.467e7
table9.nt arXiv:2506.03094 Table 9, source files 15,542,400 15542400 guard 1.459e7
s4.nt arXiv:2506.03094 §4; Fig. 1(b), source files 1.9·10⁷ (Fig. 1(b): 19,036,800) 19036800 guard 1.459e7
table9.two.ni arXiv:2506.03094 Table 9, source files 41,636,714,298 41636714298 guard 4.210e10
table10.fail.gross.1e-3 arXiv:2506.03094 Table 10 3.33·10⁴ 33300.0 band 100.0
table10.fail.gross.1e-4 arXiv:2506.03094 Table 10 7.97·10⁻¹ 0.797 band 0.001

1 id source printed value rule
104 table9.two.nm arXiv:2506.03094 Table 9, source files 4,238,828 4238828 guard 4.149e6
105 table9.gross.nu arXiv:2506.03094 Table 9, source files 2,270,400 2270400 guard 2.729e6
106 table9.two.nu arXiv:2506.03094 Table 9, source files 2,294,400 2294400 guard 2.368e6
107 table9.nt arXiv:2506.03094 Table 9, source files 15,542,400 15542400 guard 1.467e7 guard 1.459e7
108 s4.nt arXiv:2506.03094 §4; Fig. 1(b), source files 1.9·10⁷ (Fig. 1(b): 19,036,800) 19036800 guard 1.467e7 guard 1.459e7
109 table9.two.ni arXiv:2506.03094 Table 9, source files 41,636,714,298 41636714298 guard 4.210e10
110 table10.fail.gross.1e-3 arXiv:2506.03094 Table 10 3.33·10⁴ 33300.0 band 100.0
111 table10.fail.gross.1e-4 arXiv:2506.03094 Table 10 7.97·10⁻¹ 0.797 band 0.001

File diff suppressed because it is too large Load diff