open-standards/wai/wai-quantum/examples/landscape_solution.rs
Transaction Science 68e4c1fe0a
Some checks failed
WAI operation catalogue / does this change touch it (push) Successful in 29s
wai-audit collector and player integration / does this change touch it (push) Successful in 38s
wai-quantum contract / does this change touch it (push) Successful in 26s
wai-quantum resource estimation / does this change touch it (push) Successful in 22s
wai-quantum pulse and dynamics / does this change touch it (push) Successful in 18s
wai-quantum for Python / does this change touch it (push) Successful in 19s
wai-quantum error correction and mitigation / does this change touch it (push) Successful in 17s
wai-quantum qudit jobs / does this change touch it (push) Successful in 18s
wai-quantum extension points / does this change touch it (push) Successful in 19s
wai-quantum studio and desktop / does this change touch it (push) Successful in 20s
wai-quantum service / does this change touch it (push) Successful in 22s
wai-quantum variational and algorithm library / does this change touch it (push) Successful in 20s
wai-quantum verdicts and repairs / does this change touch it (push) Successful in 13s
wai-quantum views in agent hosts / does this change touch it (push) Successful in 12s
wai-quantum on Windows / does this change touch it (push) Successful in 17s
wai-sink-android native sink library / does this change touch it (push) Successful in 17s
wai-sink-swift native sink package / does this change touch it (push) Successful in 14s
WAI Studio / does this change touch it (push) Successful in 13s
wai-quantum command line / does this change touch it (push) Successful in 3m43s
wai-quantum editors / does this change touch it (push) Successful in 3m33s
wai-quantum-landscape-fpga reference design / does this change touch it (push) Successful in 3m34s
wai-quantum for JavaScript / does this change touch it (push) Successful in 3m34s
wai-quantum clippy / does this change touch it (push) Successful in 3m44s
wai-quantum OpenQASM reader / does this change touch it (push) Successful in 3m35s
wai-quantum docs, course and locales / does this change touch it (push) Successful in 3m36s
wai-quantum other formats / does this change touch it (push) Successful in 3m35s
wai-quantum service / service energy · linux packages (push) Successful in 2m52s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 10s
wai-quantum wasmQ / does this change touch it (push) Successful in 11s
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 12s
WAI examples / WAI examples · does this change touch them (push) Successful in 13s
wai-quantum contract / the policy is linked, and the deprecations page reads (push) Successful in 5s
wai-quantum pulse and dynamics / reader, simulator and pulse jobs under wasm32-wasip2 (wasmtime) (push) Successful in 1m27s
wai-quantum pulse and dynamics / reader, simulator and pulse jobs · linux, release (push) Successful in 2m29s
wai-audit collector and player integration / collector · linux (push) Successful in 6m7s
wai-quantum qudit jobs / the module and the conformance set under wasm32-wasip2 (wasmtime) (push) Successful in 1m48s
wai-quantum resource estimation / estimation and calibration · linux, release (push) Successful in 7m12s
wai-quantum contract / API compatibility · linux (push) Successful in 6m59s
wai-quantum extension points / the registry under wasm32-wasip2 (wasmtime) (push) Successful in 2m14s
wai-quantum for Python / python · linux (push) Failing after 5m58s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 2m5s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 10m15s
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux, release (push) Successful in 3m21s
wai-quantum verdicts and repairs / the intent set and the verdict under wasm32-wasip2 (wasmtime) (push) Successful in 3m13s
wai-quantum error correction and mitigation / codes, decoders, texts and mitigation · linux, release (push) Successful in 6m26s
wai-quantum views in agent hosts / views · the page and its engine (push) Successful in 5m13s
wai-quantum verdicts and repairs / verdicts, repairs and the intent set · linux (push) Successful in 6m21s
wai-quantum extension points / the registry and the example · linux (push) Successful in 8m14s
wai-quantum studio and desktop / studio · browser (push) Successful in 9m29s
wai-quantum views in agent hosts / views · a scripted host (push) Successful in 7m51s
wai-quantum contract / schemas and the committed tool lists · linux (push) Successful in 14m47s
wai-quantum qudit jobs / the module, the job, the conformance set, the referee and the verb · linux (push) Successful in 13m7s
wai-quantum pulse and dynamics / the same bits · linux-arm64 (push) Successful in 3m9s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 12m40s
wai-quantum editors / editors · linux (push) Successful in 5m22s
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux-arm64, release (push) Successful in 2m56s
wai-quantum other formats / the set under wasm32-wasip2 (wasmtime) (push) Successful in 3m6s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Failing after 7m1s
wai-quantum clippy / clippy, warnings denied, every feature set · linux (push) Successful in 6m10s
wai-quantum docs, course and locales / the Studio's words in every locale · linux (push) Successful in 22s
wai-quantum OpenQASM reader / corpus under wasm32-wasip2 (wasmtime) (push) Successful in 1m19s
wai-quantum extension points / the registry and the example · linux-arm64 (push) Successful in 5m48s
wai-quantum OpenQASM reader / reader and corpus · linux (push) Successful in 3m5s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 5m32s
wai-quantum service / service · linux (push) Successful in 18m53s
wai-quantum-landscape-fpga reference design / the board's code on the board's processor's architecture · linux-arm64, release (push) Successful in 4m54s
WAI Studio / Studio in WebKit · linux (push) Successful in 18m56s
wai-quantum other formats / readers, writers and the set · linux (push) Successful in 9m34s
wai-quantum docs, course and locales / the course and the command line's languages · linux (push) Successful in 7m1s
wai-quantum for JavaScript / javascript · linux (push) Successful in 10m34s
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 25m59s
wai-quantum pulse and dynamics / the same bits · macos (push) Successful in 2m11s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 2m53s
wai-quantum qudit jobs / the same bits · macos (push) Successful in 2m5s
wai-quantum for Python / python · macos (push) Failing after 3m24s
wai-quantum command line / command line · linux (push) Successful in 36m45s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 5m33s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 6m10s
wai-quantum service / service · macos (push) Successful in 7m38s
WAI examples / WAI examples · android-app · linux-arm64 (push) Successful in 11m6s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 13m49s
wai-quantum command line / command line · macos (push) Successful in 3m22s
wai-quantum docs, course and locales / every command and snippet in the docs · linux (push) Successful in 38m41s
wai-quantum editors / editors · macos (push) Successful in 1m45s
WAI Studio / Studio in Chromium and Firefox · macos (push) Successful in 12m35s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 14m16s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 3m33s
wai-quantum wasmQ / the reference modules rebuild to their modules of record · linux (push) Successful in 46s
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · linux (push) Successful in 4m28s
wai-quantum wasmQ / interpreter and vectors under wasm32-wasip2 (wasmtime) (push) Successful in 3m35s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 10m6s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 12m17s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 15m17s
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 21m16s
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · macos (push) Successful in 2m17s
WAI examples / WAI examples · portable · linux (push) Successful in 21m41s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 7m1s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (push) Successful in 21m57s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 12m58s
wai-quantum on Windows / engine · windows (push) Failing after 16m11s
wai-quantum on Windows / command line · windows (push) Failing after 5m53s
wai-quantum on Windows / job service · windows (push) Failing after 4m47s
wai-quantum on Windows / python · windows (push) Failing after 10m36s
wai-quantum: energy to solution for the landscape emulator, registered before the table is run
The harness, its tuned baselines and its exact solver, with the instance list, the metrics and
the decision rule fixed in the repository before the full table is run for the first time. The
table, its data, the script that rebuilds them and the CI job come in the next commit.

- quantum_landscape::tuned: simulated annealing, parallel tempering and tabu search as runs of a
  stated length, seeded and the same on every platform, written to be fast (running fields,
  thresholds from a table, two states only for a cell whose cost is below 0).
- quantum_landscape::exact: an exact dynamic programme over a frontier, which proves the lowest
  energy of instances too large to enumerate where an order keeps the frontier within 13 cells.
- quantum_landscape::solution: the instances (the worked examples of both protocol versions,
  constraint problems at several sizes, random three-state and two-state instances with fixed
  seeds, and a structured family of blocks), the tuning procedure and its grids, the success
  probability with its Wilson interval, the runs for a 99 in 100 chance, and the rule for ahead,
  tied and behind. Operations are counted; the host's seconds and joules are measured where it
  has a meter and stated unmetered where it has none; the emulator's priced joules are kept apart
  from both, and cover the deterministic kernel only.
- examples/landscape_solution.rs: list, program, run and render; the macOS per-process counter
  and the Linux package counters as the host's meters.
- quantum-conformance/landscape/energy-to-solution/PREREGISTRATION.md and the two instance lists.

Only the small tier was run before this commit, to test the harness.

Co-Authored-By: Claude Fable 5.2 <[email protected]>
2026-11-11 10:24:37 -05:00

180 lines
8.6 KiB
Rust

//! Energy to solution: the landscape emulator against tuned classical methods
//! (`wai_quantum::quantum_landscape::solution`).
//!
//! ```text
//! landscape_solution list --tier full|small
//! The instance list of a tier, as JSON: what is pre-registered.
//! landscape_solution program ID
//! The program of one instance, by the name the list gives it.
//! landscape_solution run --tier full|small --out DIR [--measure] [--window SECONDS] [--threads N] [--host LABEL]
//! Tune and grade the tier, and write DIR/results.json: counts only, the same
//! bytes on every machine. With --measure, then time every cell on one thread
//! and read this host's energy meter around it, and write DIR/measured.json.
//! landscape_solution render --results FILE [--measured FILE]
//! The table as a document, from the result files.
//! ```
//!
//! The joules of `--measure` are this computer's, running software: one process
//! on macOS, the whole processor packages on Linux, and stated unmetered
//! anywhere the host has no meter this reads. They are never a device's energy.
use serde_json::{Value, json};
use std::time::{Duration, Instant};
use wai_quantum::engine::energy;
use wai_quantum::quantum_landscape::solution::{self, Meter, Tier, Unmetered};
/// The operating system's count of this process's CPU energy.
struct Process {
before: Option<energy::Reading>,
}
/// A thread's energy is added to its process when the thread leaves a core, so
/// the thread sleeps before each read.
const SETTLE: Duration = Duration::from_millis(2);
impl Meter for Process {
fn describe(&self) -> Value {
json!({
"kind": "measured",
"meter": "the operating system's per-process CPU energy counter (proc_pid_rusage: ri_energy_nj, with what system services billed to the process)",
"class": "OnChipCounter",
"scope": "whole process: this process and nothing else",
"covers": "the CPU energy of this process's own threads over each window, as the processor's own accounting gives it, with no calibration behind it",
"excludes": "memory, the host's idle draw, every other process, and everything outside the processor (supplies, cooling, storage, display)",
"note": "read while the process runs; the thread sleeps 2 ms before each read so that its energy is posted",
})
}
fn start(&mut self) {
std::thread::sleep(SETTLE);
self.before = energy::own();
}
fn stop(&mut self) -> Result<f64, String> {
std::thread::sleep(SETTLE);
let (Some(before), Some(after)) = (self.before.take(), energy::own()) else {
return Err("this process's energy counter did not read: it is not live on this host".into());
};
let joules = after.joules() - before.joules();
if joules > 0.0 { Ok(joules) } else { Err("this process's energy counter did not advance over a window: it is not live on this host".into()) }
}
}
/// The processor packages' energy counters.
struct Package {
packages: energy::Packages,
before: Option<energy::PackageSnapshot>,
}
impl Meter for Package {
fn describe(&self) -> Value {
json!({
"kind": "measured",
"meter": "the processor packages' own energy counters, as the kernel's power-capping interface publishes them (/sys/class/powercap)",
"class": "OnChipCounter",
"scope": "whole package: every process on every processor package of this host, this table's among them",
"covers": "the packages' energy over each window, their idle draw and every other process's work included; none of it is attributed to this table's process",
"excludes": "memory and devices outside the package, supplies, cooling, storage",
"update_ns": self.packages.probe.update_ns,
})
}
fn start(&mut self) {
self.before = self.packages.read();
}
fn stop(&mut self) -> Result<f64, String> {
let (Some(before), Some(after)) = (self.before.take(), self.packages.read()) else {
return Err("a package's energy counter did not read".into());
};
let reading = self.packages.between(&before, &after, 0).ok_or("a package's energy counter gave no difference over a window")?;
if reading.energy_uj > 0 { Ok(reading.energy_uj as f64 / 1e6) } else { Err("the packages' energy counters did not advance over a window".into()) }
}
}
fn meter() -> Box<dyn Meter> {
if cfg!(target_os = "macos") {
return match energy::own() {
Some(_) => Box::new(Process { before: None }),
None => Box::new(Unmetered("this process's energy counter does not read on this host".into())),
};
}
if cfg!(target_os = "linux") {
return match energy::Packages::open() {
Ok(packages) => Box::new(Package { packages, before: None }),
Err(why) => Box::new(Unmetered(why)),
};
}
Box::new(Unmetered("no energy counter is read on this operating system".into()))
}
fn usage() -> ! {
eprintln!("usage: landscape_solution list --tier full|small");
eprintln!(" landscape_solution program ID");
eprintln!(" landscape_solution run --tier full|small --out DIR [--measure] [--window SECONDS] [--threads N] [--host LABEL]");
eprintln!(" landscape_solution render --results FILE [--measured FILE]");
std::process::exit(2)
}
fn value(args: &[String], flag: &str) -> Option<String> {
args.iter().position(|a| a == flag).map(|k| args.get(k + 1).cloned().unwrap_or_else(|| usage()))
}
fn pretty(v: &Value) -> String {
let mut s = serde_json::to_string_pretty(v).expect("a value is written");
s.push('\n');
s
}
fn read(path: &str) -> Value {
let text = std::fs::read_to_string(path).unwrap_or_else(|e| {
eprintln!("{path}: {e}");
std::process::exit(1)
});
serde_json::from_str(&text).unwrap_or_else(|e| {
eprintln!("{path}: {e}");
std::process::exit(1)
})
}
fn main() {
let args: Vec<String> = std::env::args().skip(1).collect();
let tier = || value(&args, "--tier").and_then(|t| Tier::from_name(&t)).unwrap_or_else(|| usage());
match args.first().map(String::as_str) {
Some("list") => print!("{}", pretty(&solution::list(tier()))),
Some("program") => match args.get(1).and_then(|id| solution::program_by_id(id)) {
Some(text) => print!("{text}"),
None => {
eprintln!("no instance has that name; `list` gives every name");
std::process::exit(1)
}
},
Some("run") => {
let tier = tier();
let out = std::path::PathBuf::from(value(&args, "--out").unwrap_or_else(|| usage()));
let threads = value(&args, "--threads").map_or(0, |t| t.parse().unwrap_or_else(|_| usage()));
std::fs::create_dir_all(&out).expect("the output folder is made");
let began = Instant::now();
let evaluated = solution::evaluate(tier, threads, &|line| eprintln!("{:8.1} s {line}", began.elapsed().as_secs_f64()));
let results = evaluated.to_json();
std::fs::write(out.join("results.json"), pretty(&results)).expect("results.json is written");
eprintln!("{:8.1} s results.json written", began.elapsed().as_secs_f64());
if args.iter().any(|a| a == "--measure") {
let window = value(&args, "--window").map_or(0.25, |w| w.parse().unwrap_or_else(|_| usage()));
let cores = std::thread::available_parallelism().map_or(1, |p| p.get());
let label = value(&args, "--host").unwrap_or_else(|| format!("{} {}, {cores} logical cores", std::env::consts::OS, std::env::consts::ARCH));
let host = json!({ "label": label, "os": std::env::consts::OS, "arch": std::env::consts::ARCH, "logical_cores": cores, "threads_used": 1 });
let mut meter = meter();
let measured = solution::measure(&evaluated, meter.as_mut(), &|| began.elapsed().as_secs_f64(), window, &host, &|line| eprintln!("{:8.1} s {line}", began.elapsed().as_secs_f64()));
std::fs::write(out.join("measured.json"), pretty(&measured)).expect("measured.json is written");
eprintln!("{:8.1} s measured.json written: energy {}", began.elapsed().as_secs_f64(), if measured["energy_unmetered"].is_null() { "measured" } else { "unmetered" });
}
}
Some("render") => {
let results = read(&value(&args, "--results").unwrap_or_else(|| usage()));
let measured = value(&args, "--measured").map(|p| read(&p));
print!("{}", solution::render(&results, measured.as_ref()));
}
_ => usage(),
}
}