From 52923e0acc618621dd19ea5338c30677fc0cb963 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Thu, 5 Nov 2026 18:23:50 -0500 Subject: [PATCH 01/42] wip: planner contract (a working commit, before falsifying) --- .../schemas/local-tools.v1.json | 47 + wai/wai-quantum-cli/src/main.rs | 230 ++- wai/wai-quantum-cli/src/mcp.rs | 44 +- wai/wai-quantum-cli/src/providers.rs | 189 ++- wai/wai-quantum-cli/tests/providers.rs | 103 ++ wai/wai-quantum-qpu/src/job.rs | 441 +++++- wai/wai-quantum-qpu/src/ledger.rs | 6 + wai/wai-quantum-qpu/tests/clients.rs | 45 + .../schemas/service-tools.v1.json | 3 + wai/wai-quantum-service/src/http.rs | 35 +- wai/wai-quantum-service/src/jobs.rs | 34 +- wai/wai-quantum-service/src/mcp.rs | 6 +- wai/wai-quantum-service/tests/contract.rs | 133 ++ wai/wai-quantum/docs/job-refusals.md | 5 + wai/wai-quantum/schemas/job-request.v1.json | 71 + wai/wai-quantum/schemas/job-result.v1.json | 596 +++++++ wai/wai-quantum/schemas/plan.v1.json | 5 +- wai/wai-quantum/src/engine/catalog.rs | 31 +- wai/wai-quantum/src/engine/job.rs | 16 + wai/wai-quantum/src/engine/mod.rs | 9 + wai/wai-quantum/src/engine/planner.rs | 1373 +++++++++++++++++ wai/wai-quantum/src/engine/planner/tests.rs | 900 +++++++++++ wai/wai-quantum/src/engine/provider.rs | 21 +- wai/wai-quantum/src/engine/refusal.rs | 7 + wai/wai-quantum/src/engine/registry/mod.rs | 5 + wai/wai-quantum/src/engine/run.rs | 3 + wai/wai-quantum/src/engine/sets.rs | 9 + 27 files changed, 4293 insertions(+), 74 deletions(-) create mode 100644 wai/wai-quantum-service/tests/contract.rs create mode 100644 wai/wai-quantum/src/engine/planner.rs create mode 100644 wai/wai-quantum/src/engine/planner/tests.rs diff --git a/wai/wai-quantum-cli/schemas/local-tools.v1.json b/wai/wai-quantum-cli/schemas/local-tools.v1.json index 63cb70dcc..debb8d853 100644 --- a/wai/wai-quantum-cli/schemas/local-tools.v1.json +++ b/wai/wai-quantum-cli/schemas/local-tools.v1.json @@ -24,6 +24,28 @@ "null" ], "description": "The signing key, 32 bytes in hex." + }, + "planner": { + "type": "object", + "description": "For a job under a contract, what its reasoning says: the route chosen, the class wanted and given, what was kept, and the shadow." + }, + "recheck": { + "type": "object", + "description": "With recheck: whether the routes priced again and the shadow run again are what the job sealed.", + "properties": { + "holds": { + "type": "boolean" + }, + "engine": { + "type": "object" + }, + "priced": { + "type": "object" + }, + "shadow": { + "type": "object" + } + } } } }, @@ -443,6 +465,31 @@ "confirm": { "type": "string", "description": "What the person reads before confirming a run that is not free." + }, + "planner": { + "$ref": "https://git.transaction.science/Transaction-Science/open-standards/raw/branch/main/wai/wai-quantum/schemas/job-result.v1.json#/$defs/planner" + } + } + }, + "routed": { + "type": "object", + "description": "Every route a job could take under its contract, each with its price or why it was rejected, and the route chosen: nothing submitted, nothing spent.", + "required": [ + "dry_run", + "planner" + ], + "properties": { + "dry_run": { + "const": true + }, + "planner": { + "$ref": "https://git.transaction.science/Transaction-Science/open-standards/raw/branch/main/wai/wai-quantum/schemas/job-result.v1.json#/$defs/planner" + }, + "plan": { + "$ref": "https://git.transaction.science/Transaction-Science/open-standards/raw/branch/main/wai/wai-quantum/schemas/plan.v1.json" + }, + "provider_plan": { + "$ref": "#/$defs/provider_estimate" } } } diff --git a/wai/wai-quantum-cli/src/main.rs b/wai/wai-quantum-cli/src/main.rs index d96aec0b9..94ffa9891 100644 --- a/wai/wai-quantum-cli/src/main.rs +++ b/wai/wai-quantum-cli/src/main.rs @@ -315,6 +315,9 @@ enum Command { /// One job a line, each judged as a job's receipt, one JSON verdict a line; the status is 1 when any is not valid #[arg(long, conflicts_with = "history")] lines: bool, + /// For a job under a contract, also run again what can be: its routes priced again at the job's memory, held to the digest it sealed, and its shadow, held to its counts bit for bit + #[arg(long, conflicts_with = "lines")] + recheck: bool, }, /// Show the key this user signs receipts with Key { @@ -556,6 +559,50 @@ struct Job { /// Where the state vector runs (the statevector method): auto (the default: on a member only where the committed measurements show it faster than this host's CPU for the job's size and fusion, otherwise the CPU; `wai-quantum fabric` states the rule and the numbers), cpu, accelerator (the first certified accelerator member that holds the state), or a member's id or key (`wai-quantum fabric` lists them); for a pauli job, accelerator or a member's id or key runs its sum of terms on that member, with the CPU's answers; repeated, the state is split by its top qubits into one partition on each member named, a power of two of them. A member certified bit-exact gives the CPU's answers; a placement this host cannot honour is refused (J013) #[arg(long = "fabric", value_name = "PLACEMENT")] fabric: Vec, + /// The class the answer must be of: bit-exact, exact, single, bounded, estimate, heuristic; measured (a processor's counts), simulated (a provider's simulator's), or any. Under a contract (this, --max-cost, --deadline, --max-joules or --allow-providers) the planner prices every route it can see, runs the cheapest that meets it, and seals its reasoning in the receipt; with nothing to meet it, it refuses with each route's reason (J071), and nothing falls back. Without a class the job keeps the class auto would give + #[arg(long, value_name = "CLASS")] + exactness: Option, + /// The most the run may cost, as 0.50:USD: a route with an unknown cost, or priced in another currency, does not meet it. It confirms nothing: a run that is not free still takes --yes + #[arg(long, value_name = "AMOUNT:CURRENCY", value_parser = max_cost_arg)] + max_cost: Option, + /// When the run must be done by, in seconds: a route whose time is not known does not meet it, and the receipt says whether it was kept (exit 4 when it was not) + #[arg(long = "deadline", value_name = "SECONDS")] + deadline: Option, + /// The most energy the run may take, in joules: a route whose energy is not known does not meet it, and this command estimates none, so here every route is refused; the job service estimates from what it has metered + #[arg(long, value_name = "JOULES")] + max_joules: Option, + /// Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods here: each is asked to estimate the job, and nothing is sent unless one is chosen. A device is chosen only when --exactness measured or any asks for its class. On the job service, which reaches no provider, it changes nothing + #[arg(long)] + allow_providers: bool, + /// The contract itself, as JSON or a file of it: exactness, max_cost, deadline_seconds, max_joules and providers; the options above are set over it + #[arg(long, value_name = "JSON|FILE", value_parser = contract_arg)] + contract: Option, +} + +impl Job { + /// Whether the command line was given a contract, so that a program given on + /// standard input is read once. + fn asks_a_contract(&self) -> bool { + self.contract.is_some() || self.exactness.is_some() || self.max_cost.is_some() || self.deadline.is_some() || self.max_joules.is_some() || self.allow_providers + } +} + +/// `0.50:USD`: an amount in decimals and its currency. +fn max_cost_arg(s: &str) -> Result { + match s.split_once(':') { + Some((amount, currency)) if wai_quantum::engine::planner::is_decimal(amount) && !currency.is_empty() => Ok(json!({ "amount": amount, "currency": currency })), + _ => Err("give an amount in decimals and its currency, as 0.50:USD".into()), + } +} + +/// A contract as JSON, or the file that holds it. +fn contract_arg(s: &str) -> Result { + let text = if s.trim_start().starts_with('{') { s.to_string() } else { std::fs::read_to_string(s).map_err(|e| format!("{s}: {e}"))? }; + let v: Value = serde_json::from_str(&text).map_err(|e| format!("a contract is a JSON object: {e}"))?; + if !v.is_object() { + return Err("a contract is a JSON object, as {\"exactness\": \"exact\"}".into()); + } + Ok(v) } /// `name=v1,v2,…`: each value a whole number if it reads as one, else a number. @@ -866,11 +913,37 @@ fn request(job: &Job, qasm: String) -> Value { [one] => r["fabric"] = json!(one), many => r["fabric"] = json!(many), } + let mut contract = job.contract.clone(); + let mut set = |k: &str, v: Value| { + contract.get_or_insert_with(|| json!({}))[k] = v; + }; + if let Some(e) = &job.exactness { + set("exactness", json!(e)); + } + if let Some(c) = &job.max_cost { + set("max_cost", c.clone()); + } + if let Some(d) = job.deadline { + set("deadline_seconds", json!(d)); + } + if let Some(j) = job.max_joules { + set("max_joules", json!(j)); + } + if job.allow_providers { + set("providers", json!("allowed")); + } + if let Some(c) = contract { + r["contract"] = c; + } r } /// What a result says of its energy: the command line does not meter a run. -const UNMETERED: &str = "the command line does not meter a run's energy"; +pub(crate) const UNMETERED: &str = "the command line does not meter a run's energy"; + +/// The exit status of a run that kept not all its contract asked: a deadline, a +/// ceiling on energy or on cost, as the result states. Its answer is sealed. +pub(crate) const CONTRACT_MISSED: i32 = 4; /// The job body `run` gives, as the service gives it: the request, the plan, /// and the result sealed with `key` ([`job::run`]). @@ -1081,12 +1154,72 @@ fn print_job(body: &Value, top: usize) { if let Some(ms) = r.get("elapsed_ms") { println!("time {ms} ms"); } + if let Some(p) = r.get("planner") { + print_planner(p); + } + if let Some(sh) = r.get("shadow") { + print_shadow(sh); + } if let Some(key) = r.pointer("/receipt/key").and_then(Value::as_str) { let ok = job::verify(body).map(|(ok, _)| ok).unwrap_or(false); println!("receipt {}, signed by {}", if ok { "verifies" } else { "DOES NOT VERIFY" }, job::did_of(key).unwrap_or_else(|| key.to_string())); } } +/// A planner's reasoning as a person reads it: what was wanted, each route's +/// price or why it was rejected, and the choice. +pub(crate) fn print_planner(p: &Value) { + let s = |v: &Value| v.as_str().map(str::to_string).unwrap_or_else(|| v.to_string()); + let from = match p["wanted_from"].as_str() { + Some("contract") => "the contract's", + Some("named") => "the route the job names", + Some("auto") => "what auto would give", + _ => "none named", + }; + println!("contract wants {} ({from}): {}", p["wanted"].as_str().unwrap_or("no class"), s(&p["why"])); + for r in p["routes"].as_array().into_iter().flatten().filter(|r| r["rejected"]["code"] != "not_named") { + let price = &r["price"]; + let time = price["time"]["seconds"].as_f64().map_or_else(|| "time unknown".to_string(), |t| format!("about {t:.3e} s ({})", s(&price["time"]["basis"]))); + let money = if price["money"]["free"] == true { "free".to_string() } else if let Some(a) = price["money"]["amount"].as_str() { format!("{a} {}", s(&price["money"]["currency"])) } else { "cost unknown".to_string() }; + let priced = if price.is_null() { String::new() } else { format!(" — {money}, {time}") }; + let left = price["leaves_out"].as_array().filter(|a| !a.is_empty()).map(|a| format!("; leaves out {}", a.iter().map(|x| s(x)).collect::>().join(", "))).unwrap_or_default(); + let outcome = if let Some(c) = r["rejected"]["code"].as_str() { format!("rejected ({c}: {})", s(&r["rejected"]["why"])) } else { s(&r["outcome"]) }; + println!(" {:<28} {} {}{priced}{left}", s(&r["route"]), s(&r["class"]), outcome); + } + if p["choice"].is_string() { + println!("stable {}", if p["stable"]["choice"] == true { "this choice depends on nothing of this host" } else { "this choice depends on this host (its providers, a GPU, or its energy estimate)" }); + } + if let Some(sh) = p.get("shadow").filter(|sh| sh["route"].is_null()) { + println!("shadow none possible: {}", s(&sh["why"])); + } else if let Some(sh) = p.get("shadow").filter(|_| p.get("kept").is_none()) { + println!("shadow {} will run beside it ({})", s(&sh["route"]), s(&sh["class"])); + } + for (k, v) in p["kept"].as_object().into_iter().flatten() { + let held = match v["kept"].as_bool() { + Some(true) => "kept".to_string(), + Some(false) => "MISSED".to_string(), + None => "not known".to_string(), + }; + println!("kept {k}: {held}"); + } +} + +/// A shadow as a person reads it. +pub(crate) fn print_shadow(sh: &Value) { + let s = |v: &Value| v.as_str().map(str::to_string).unwrap_or_else(|| v.to_string()); + if sh["ran"] == true { + let d = &sh["distance"]; + let said = if d["computed"] == true { + format!("total variation {:.4} from the provider's counts (these shots alone leave about {:.4}); Hellinger fidelity {:.4}", d["total_variation"].as_f64().unwrap_or(f64::NAN), d["sampling_tvd_expected"].as_f64().unwrap_or(f64::NAN), d["hellinger_fidelity"].as_f64().unwrap_or(f64::NAN)) + } else { + format!("no distance: {}", s(&d["why"])) + }; + println!("shadow {} ({}): {said}", s(&sh["route"]), s(&sh["accuracy"]["class"])); + } else { + println!("shadow none: {} ({})", s(&sh["why"]), s(&sh["code"])); + } +} + fn load_key(k: &KeyArgs) -> keys::Key { let key = keys::load(k.key.as_deref(), k.demo_key).unwrap_or_else(|e| die(&e)); keys::notes(&key); @@ -1180,7 +1313,7 @@ fn main() { let _ = FROM.set(cli.from); match cli.command { #[cfg(feature = "providers")] - Command::Run { job, out, key, provider } if provider.provider.is_some() => providers::run(&job, &out, &key, &provider), + Command::Run { job, out, key, provider } if provider.provider.is_some() || job.allow_providers => providers::run(&job, &out, &key, &provider), Command::Run { job, out, key, .. } => { let req = job_request(&job).unwrap_or_else(|e| die(&e)); let k = load_key(&key); @@ -1210,13 +1343,19 @@ fn main() { Some(items) => items.iter().map(|i| i.pointer("/result/verdict/holds").and_then(Value::as_bool)).collect(), None => vec![body.pointer("/result/verdict/holds").and_then(Value::as_bool)], }; - std::process::exit(if holds.contains(&Some(false)) { + let status = if holds.contains(&Some(false)) { 1 } else if holds.iter().all(|h| *h == Some(true)) { 0 } else { 2 - }); + }; + if status != 0 { + std::process::exit(status); + } + } + if wai_quantum::engine::planner::missed(&body["result"]) { + std::process::exit(CONTRACT_MISSED); } } Command::Plan { job, json } if !job.programs.is_empty() || !job.sweep.is_empty() => { @@ -1235,6 +1374,29 @@ fn main() { } } } + #[cfg(feature = "providers")] + Command::Plan { job, json } if job.allow_providers => providers::plan(&job, json), + Command::Plan { job, json } if job.asks_a_contract() => { + use wai_quantum::engine::{planner, refusal, registry::Registry}; + let req = job_request(&job).unwrap_or_else(|e| die(&e)); + let c = planner::consider(Registry::builtins(), &req, &planner::Host::new(job.memory_gb << 30)).unwrap_or_else(|e| die(&e)); + if json { + let mut v = c.plan.as_ref().map_or_else(|| json!({}), |p| serde_json::to_value(p).unwrap_or(Value::Null)); + if let Some(e) = &c.refusal { + v["refused"] = refusal::refusal_json(e); + } + v["planner"] = c.reasoning.clone(); + println!("{v}"); + } else { + print_planner(&c.reasoning); + if let Some(p) = &c.plan { + println!("memory {:.1} MiB at most", p.memory_bytes as f64 / (1u64 << 20) as f64); + } + } + if let Some(e) = &c.refusal { + die(e); + } + } Command::Plan { job, json } => { let req = job_request(&job).unwrap_or_else(|e| die(&e)); let p = catalog::plan(&req, job.memory_gb << 30).unwrap_or_else(|e| die(&e)); @@ -1391,7 +1553,7 @@ fn main() { } #[cfg(feature = "service")] Command::Task { cmd, args } => task::main(cmd, &args), - Command::Verify { file, history: hist, json: as_json, lines } => { + Command::Verify { file, history: hist, json: as_json, lines, recheck } => { let bytes = read_bytes(file.as_deref()).unwrap_or_else(|e| die(&e)); let src = match String::from_utf8(bytes) { Ok(s) => s, @@ -1448,15 +1610,33 @@ fn main() { } } else if as_json || (v.get("request").is_some() && v.get("result").is_some()) { let c = job::check_text(&src); + let again = recheck.then(|| wai_quantum::engine::planner::recheck(wai_quantum::engine::registry::Registry::builtins(), &v).unwrap_or_else(|e| die(&e))); if as_json { - println!("{}", c.to_json()); - if !c.valid() { + let mut said = c.to_json(); + if let Some(a) = &again { + said["recheck"] = a.clone(); + } + println!("{said}"); + if !c.valid() || again.as_ref().is_some_and(|a| a["holds"] != true) { std::process::exit(1); } return; } let mut ok = c.valid(); print_check(&c); + if let Some(a) = &again { + let said = |x: &Value| match (x["checked"].as_bool(), x["same"].as_bool()) { + (Some(true), Some(true)) => "the same".to_string(), + (Some(true), _) => "NOT THE SAME".to_string(), + _ => format!("not checked: {}", x["why"].as_str().unwrap_or("")), + }; + println!("priced again {}", said(&a["priced"])); + println!("shadow again {}", said(&a["shadow"])); + if a["engine"]["same"] != true { + println!("engine sealed by {}, rechecked by {}: a price may differ between them", a["engine"]["sealed_by"].as_str().unwrap_or("another"), a["engine"]["this"].as_str().unwrap_or("")); + } + ok &= a["holds"] == true; + } if let Some(c) = v["request"].get("history") { let hands: Vec = c["gates"].as_object().into_iter().flatten().map(|(h, n)| format!("{n} {}", h.replace('_', " "))).collect(); println!("history {}: {} of {} gates", c["version"].as_str().unwrap_or("?"), hands.join(", "), c["of"]["gates"]); @@ -1602,6 +1782,18 @@ fn print_check(c: &job::Check) { if broken.is_empty() { println!("rules {}", if rules.is_empty() { "every rule a verifier checks holds (wai/extensions/quantum-providers.md section 8.4)".to_string() } else { format!("BROKEN: {}", rules.join(", ")) }); } + if let Some(p) = &c.planner { + let s = |v: &Value| v.as_str().map(str::to_string).unwrap_or_else(|| v.to_string()); + println!("contract wanted {}, given {}, by {}", p["wanted"].as_str().unwrap_or("no class"), s(&p["class"]), s(&p["choice"])); + for (k, v) in p["kept"].as_object().into_iter().flatten() { + println!("kept {k}: {}", match v["kept"].as_bool() { Some(true) => "kept", Some(false) => "MISSED", None => "not known" }); + } + if p["shadow_ran"] == true { + println!("shadow total variation {} from a classical method's counts", s(&p["shadow_total_variation"])); + } else if p["shadow_ran"] == false { + println!("shadow none could be run; the result says why"); + } + } let Some(p) = &c.provider else { return }; let s = |v: &Value| v.as_str().map(str::to_string).unwrap_or_else(|| v.to_string()); let class = s(&p["class"]); @@ -1687,7 +1879,7 @@ mod tests { fn job(qasm: &str) -> (Job, String) { ( - Job { file: None, shots: None, seed: None, method: None, observables: vec![], amplitudes: vec![], noise: vec![], options: vec![], memory_gb: 1, history: None, compile: None, target: None, intent: vec![], verdict: false, repair: false, max_iterations: None, programs: vec![], sweep: vec![], mitigate: None, pulse: None, params: vec![], fabric: vec![] }, + Job { file: None, shots: None, seed: None, method: None, observables: vec![], amplitudes: vec![], noise: vec![], options: vec![], memory_gb: 1, history: None, compile: None, target: None, intent: vec![], verdict: false, repair: false, max_iterations: None, programs: vec![], sweep: vec![], mitigate: None, pulse: None, params: vec![], fabric: vec![], exactness: None, max_cost: None, deadline: None, max_joules: None, allow_providers: false, contract: None }, qasm.to_string(), ) } @@ -1825,6 +2017,28 @@ mod tests { } assert!(Cli::try_parse_from(["wai-quantum", "debug", "p.qasm", "--branches", "--to", "3"]).is_err()); assert!(matches!(Cli::try_parse_from(["wai-quantum", "dap"]).unwrap().command, Command::Dap)); + // A contract, from its options, set over a contract given whole. + match Cli::try_parse_from(["wai-quantum", "run", "p.qasm", "--exactness", "exact", "--max-cost", "0.50:USD", "--deadline", "30", "--max-joules", "5", "--allow-providers", "--contract", "{\"exactness\": \"any\", \"deadline_seconds\": 1}"]).unwrap().command { + Command::Run { job, .. } => { + assert!(job.asks_a_contract()); + let r = request(&job, "qubit q;".into()); + assert_eq!(r["contract"], json!({ "exactness": "exact", "max_cost": { "amount": "0.50", "currency": "USD" }, "deadline_seconds": 30.0, "max_joules": 5.0, "providers": "allowed" }), "{r}"); + } + _ => panic!("not run"), + } + match Cli::try_parse_from(["wai-quantum", "run", "p.qasm"]).unwrap().command { + Command::Run { job, .. } => assert!(!job.asks_a_contract() && request(&job, "qubit q;".into()).get("contract").is_none()), + _ => panic!("not run"), + } + assert!(Cli::try_parse_from(["wai-quantum", "run", "p.qasm", "--max-cost", "0.50"]).is_err(), "a ceiling has its currency"); + assert!(Cli::try_parse_from(["wai-quantum", "run", "p.qasm", "--max-cost", "1e3:USD"]).is_err(), "an amount in decimals"); + assert!(Cli::try_parse_from(["wai-quantum", "run", "p.qasm", "--contract", "[]"]).is_err(), "a contract is an object"); + #[cfg(feature = "providers")] + { + assert!(Cli::try_parse_from(["wai-quantum", "run", "p.qasm", "--dry-run"]).is_err(), "a dry run of what"); + assert!(Cli::try_parse_from(["wai-quantum", "run", "p.qasm", "--yes", "--allow-providers"]).is_ok()); + assert!(Cli::try_parse_from(["wai-quantum", "plan", "p.qasm", "--allow-providers"]).is_ok()); + } match Cli::try_parse_from(["wai-quantum", "run", "p.qasm", "--target", "synthetic-line-5"]).unwrap().command { Command::Run { job, .. } => assert_eq!(job.target.as_deref(), Some("synthetic-line-5")), _ => panic!("not run"), diff --git a/wai/wai-quantum-cli/src/mcp.rs b/wai/wai-quantum-cli/src/mcp.rs index d685c6dbb..25213b162 100644 --- a/wai/wai-quantum-cli/src/mcp.rs +++ b/wai/wai-quantum-cli/src/mcp.rs @@ -60,7 +60,7 @@ pub(crate) fn schemas() -> &'static Registry { /// The schema each tool's answer follows, by its file and place. fn output_of(tool: &str) -> Option<&'static str> { Some(match tool { - "run_quantum_circuit" | "run_on_provider" => "job.v1.json", + "run_quantum_circuit" | "run_on_provider" | "run_routed" => "job.v1.json", "get_provider_job" | "cancel_provider_job" => "local-tools.v1.json#/$defs/provider_job", "list_provider_jobs" => "local-tools.v1.json#/$defs/provider_jobs", "plan_quantum_circuit" => "plan.v1.json", @@ -102,6 +102,7 @@ fn output_of(tool: &str) -> Option<&'static str> { "taste_next" => "local-tools.v1.json#/$defs/taste_next", "providers_list" => "local-tools.v1.json#/$defs/providers_list", "provider_estimate" => "local-tools.v1.json#/$defs/provider_estimate", + "plan_routes" => "local-tools.v1.json#/$defs/routed", "qec_code" | "qec_decode" | "qec_threshold" => "qec.v1.json", "pulse_schedule" | "pulse_check" => "pulse.v1.json", "gradient_qasm" | "optimize_qasm" | "vqe_ground_state" | "qaoa_maxcut" | "build_algorithm" => "algorithms.v1.json", @@ -131,7 +132,8 @@ fn job_schema() -> Value { "repair": { "description": "Repair the program first, on the lines its diagnostics flag alone (as repair_qasm does): true, or the choices {\"max_iterations\": N, \"dyadic_bits\": K, \"sizes\": {\"q\": 3}}. The result's \"repaired\" holds the program that ran and each repair." }, "mitigate": wai_quantum::engine::mitigate::schema(), "pulse": wai_quantum::engine::pulse::options_schema(), - "params": { "type": "object", "additionalProperties": { "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." } + "params": { "type": "object", "additionalProperties": { "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." }, + "contract": wai_quantum::engine::planner::contract_schema() } }) } @@ -264,13 +266,13 @@ fn core_tools() -> Value { { "name": "run_quantum_circuit", "title": "Run a quantum program here", - "description": "Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more.", + "description": "Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `contract` (the class wanted, a deadline) and the planner prices every method here, runs the cheapest that meets it, seals its reasoning under `planner`, and refuses (J071) rather than fall back to less; this tool reaches no provider, and plan_routes and run_routed do. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more.", "inputSchema": job_schema(), }, { "name": "plan_quantum_circuit", "title": "Plan a quantum program", - "description": "The method a program would run on and why, the memory and work it would take, without running it.", + "description": "The method a program would run on and why, the memory and work it would take, without running it. With a contract, every route's price or reason for rejection under planner, or the refusal (J071) when no route meets it.", "inputSchema": job_schema(), }, { @@ -352,8 +354,8 @@ fn core_tools() -> Value { { "name": "verify_quantum_result", "title": "Check a result's receipt", - "description": "Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and which key signed it.", - "inputSchema": { "type": "object", "required": ["job"], "properties": { "job": { "type": "object", "description": "The job: {\"request\": ..., \"result\": ...}, the result carrying its receipt." } } }, + "description": "Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and which key signed it; for a job under a contract, every route's outcome and the choice recomputed from what it states, and with recheck its routes priced again and its shadow run again.", + "inputSchema": { "type": "object", "required": ["job"], "properties": { "job": { "type": "object", "description": "The job: {\"request\": ..., \"result\": ...}, the result carrying its receipt." }, "recheck": { "type": "boolean", "description": "For a job under a contract: its routes priced again at the job's memory, held to the digest it sealed, and its shadow run again, held to its counts bit for bit." } } }, }, { "name": "discover_evaluate", @@ -593,7 +595,11 @@ fn call(name: &str, args: &Value, memory_gb: u64, key: &SigningKey, client: &Cli } "plan_quantum_circuit" => { qasm()?; - catalog::plan(&with_target()?, memory_gb << 30).map(|p| serde_json::to_value(p).unwrap_or(Value::Null)) + let req = with_target()?; + if wai_quantum::engine::planner::has_contract(&req) { + return wai_quantum::engine::planner::plan_value(wai_quantum::engine::registry::Registry::builtins(), &req, memory_gb << 30); + } + catalog::plan(&req, memory_gb << 30).map(|p| serde_json::to_value(p).unwrap_or(Value::Null)) } "lint_qasm" => Ok(job::lint(qasm()?)), "critique_qasm" => Ok(critique::critique(qasm()?)), @@ -629,7 +635,14 @@ fn call(name: &str, args: &Value, memory_gb: u64, key: &SigningKey, client: &Cli return Ok(wai_quantum::engine::variational::verify(given)); } let (valid, key) = job::verify(given)?; - Ok(json!({ "valid": valid, "key": key })) + let mut said = json!({ "valid": valid, "key": key }); + if let Some(p) = wai_quantum::engine::planner::statement(&given["result"]) { + said["planner"] = p; + } + if args.get("recheck") == Some(&Value::Bool(true)) { + said["recheck"] = wai_quantum::engine::planner::recheck(wai_quantum::engine::registry::Registry::builtins(), given)?; + } + Ok(said) } "list_methods" => Ok(json!({ "methods": catalog::describe(memory_gb << 30) })), "list_fabric" => Ok(wai_quantum::engine::fabric::list(memory_gb << 30)), @@ -1059,7 +1072,7 @@ mod tests { #[allow(unused_mut)] let mut want = vec!["run_quantum_circuit", "plan_quantum_circuit", "lint_qasm", "repair_qasm", "critique_qasm", "check_equivalent", "convert_program", "improve_qasm", "classical_shortcuts", "compile_qasm", "estimate_resources", "draw_circuit", "debug_step", "debug_branches", "verify_quantum_result", "discover_evaluate", "discover_submit", "discover_archive", "novelty_qasm", "discover_novelty", "rewrite_qasm", "converge_cohort", "converge_history", "study_measure", "study_cohort", "taste_rank", "taste_next", "history_commit", "history_changes", "history_blame", "history_log", "list_methods", "list_fabric", "list_components", "qasm_diagnostics", "list_targets", "show_target", "run_on_target", "qec_code", "qec_decode", "qec_threshold", "pulse_schedule", "pulse_check", "gradient_qasm", "optimize_qasm", "vqe_ground_state", "qaoa_maxcut", "build_algorithm"]; #[cfg(feature = "providers")] - want.extend(["providers_list", "provider_estimate", "run_on_provider", "get_provider_job", "cancel_provider_job", "list_provider_jobs"]); + want.extend(["providers_list", "provider_estimate", "run_on_provider", "plan_routes", "run_routed", "get_provider_job", "cancel_provider_job", "list_provider_jobs"]); assert_eq!(names, want); let run = handle( &json!({ "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "run_quantum_circuit", "arguments": { "qasm": "OPENQASM 3.0; qubit[2] q; h q[0]; cx q[0], q[1];", "observables": ["Z0 Z1"] } } }), @@ -1665,6 +1678,19 @@ mod tests { let t = Target::new("lab", Kind::Process, Box::new(OpenProvider::new(Local(move |m: &Value| r.handle(m, None)))), None); let req = json!({ "qasm": bell, "shots": 50, "provider": "lab" }); hold("provider_estimate", &pjob::plan(&t, &req).unwrap().json, &mut called); + // Under a contract: the provider's plan with the reasoning, a route weighed, and each of them run. + let under = json!({ "qasm": bell, "shots": 50, "provider": "lab", "contract": { "exactness": "simulated" } }); + hold("provider_estimate", &pjob::plan(&t, &under).unwrap().json, &mut called); + hold("run_on_provider", &pjob::run(&t, &under, false, &key(), wait, |_| {}).unwrap(), &mut called); + let routed_to_it = json!({ "qasm": bell, "shots": 50, "contract": { "exactness": "simulated", "providers": "allowed" } }); + let routed = pjob::route(std::slice::from_ref(&t), &routed_to_it, 1 << 30).unwrap(); + hold("plan_routes", &routed.json(), &mut called); + let mut sent = pjob::start_routed(&t, &routed, &routed_to_it, false, &ledger).unwrap(); + hold("run_routed", pjob::check(&t, &mut sent, &key(), &ledger).unwrap().job(), &mut called); + let here = json!({ "qasm": bell, "shots": 50, "contract": { "exactness": "exact", "providers": "allowed" } }); + let routed = pjob::route(std::slice::from_ref(&t), &here, 1 << 30).unwrap(); + hold("plan_routes", &routed.json(), &mut called); + hold("run_routed", &pjob::run_routed_here(&routed, &here, &key(), json!({ "unmetered": "a test" })).unwrap(), &mut called); hold("run_on_provider", &pjob::run(&t, &req, false, &key(), wait, |_| {}).unwrap(), &mut called); // A job still at the provider, then finished, then one cancelled, each in the job's form. let waiting = std::sync::Arc::new(Reference::new(Config { polls: 1, ..Config::default() }).unwrap()); diff --git a/wai/wai-quantum-cli/src/providers.rs b/wai/wai-quantum-cli/src/providers.rs index ddd344f2d..045821e36 100644 --- a/wai/wai-quantum-cli/src/providers.rs +++ b/wai/wai-quantum-cli/src/providers.rs @@ -91,18 +91,19 @@ impl Books { /// `run`'s flags for a provider. #[derive(Args, Clone, Default)] +#[command(group = clap::ArgGroup::new("via_provider").args(["provider", "allow_providers"]).multiple(true))] pub struct RunArgs { /// Run on one of your own providers (`wai-quantum providers list`) instead of here: a device answers counts, sealed as measured on it, or as simulated when the provider's device is a simulator #[arg(long, value_name = "NAME")] pub provider: Option, - /// With --provider: the plan (the exact compile to the device's gates and its check by simulation) and the provider's estimate; nothing is submitted - #[arg(long, requires = "provider")] + /// With --provider or --allow-providers: the plan (the exact compile to the device's gates and its check by simulation) and the provider's estimate, or every route's price or reason; nothing is submitted + #[arg(long, requires = "via_provider")] pub dry_run: bool, - /// With --provider: confirm a run that is not free, or whose cost is unknown; without it such a run is refused (exit 3) - #[arg(long, requires = "provider")] + /// With --provider or --allow-providers: confirm a run that is not free, or whose cost is unknown; without it such a run is refused (exit 3). A cost ceiling is no confirmation + #[arg(long, requires = "via_provider")] pub yes: bool, - /// With --provider: send the job and answer with its handle, without waiting (`wai-quantum providers collect`) - #[arg(long, requires = "provider")] + /// With --provider or --allow-providers: send the job and answer with its handle, without waiting (`wai-quantum providers collect`) + #[arg(long, requires = "via_provider")] pub no_wait: bool, } @@ -290,25 +291,70 @@ fn sleeper() -> impl Fn(Duration) + 'static { } } -/// `run --provider`: the job on the person's provider, or its dry run. -pub fn run(job: &Job, out: &Output, key: &KeyArgs, args: &RunArgs) { - let name = args.provider.as_deref().unwrap_or_default(); - let mut req = job_request(job).unwrap_or_else(|e| die(&e)); - req["provider"] = json!(name); +/// Every provider the person has, each ready to be asked, with those that +/// cannot be opened as routes that say why. +fn targets(reg: &Registry, stores: &Stores, job_bytes: u64) -> (Vec, Vec) { + let (mut open, mut closed) = (Vec::new(), Vec::new()); + for e in reg.entries() { + match registry::open(e, stores) { + Ok(t) => open.push(t.with_job_bytes(job_bytes)), + Err(why) => closed.push(wai_quantum::engine::planner::Quote::cannot(e.name.clone(), why)), + } + } + (open, closed) +} + +/// `plan --allow-providers`: every route, the person's providers among them, +/// priced; each provider is asked for its estimate, and nothing is sent. +pub fn plan(job: &Job, as_json: bool) { + let req = job_request(job).unwrap_or_else(|e| die(&e)); let (reg, stores) = load(); - let t = registry::open(entry(®, name).unwrap_or_else(|e| die(&e)), &stores).unwrap_or_else(|e| die(&e)); + let (open, closed) = targets(®, &stores, job.memory_gb << 30); + let routed = pjob::route_with(&open, closed, &req, job.memory_gb << 30).unwrap_or_else(|e| die(&e.to_string())); + if as_json { + println!("{}", routed.json()); + } else { + crate::print_planner(&routed.reasoning); + } +} + +/// `run --allow-providers`: the route the planner chose, here or on a provider. +fn run_routed(job: &Job, out: &Output, key: &KeyArgs, args: &RunArgs) { + let req = job_request(job).unwrap_or_else(|e| die(&e)); + let (reg, stores) = load(); + let (open, closed) = targets(®, &stores, job.memory_gb << 30); + let routed = pjob::route_with(&open, closed, &req, job.memory_gb << 30).unwrap_or_else(|e| die(&e.to_string())); if args.dry_run { - let p = pjob::plan(&t, &req).unwrap_or_else(|e| die(&e.to_string())); if out.json { - println!("{}", p.json); + println!("{}", routed.json()); } else { - print_plan(&p.json); + crate::print_planner(&routed.reasoning); } return; } let k = load_key(key); + let Some(name) = routed.provider().map(str::to_string) else { + let body = pjob::run_routed_here(&routed, &req, &k.key, json!({ "unmetered": crate::UNMETERED })).unwrap_or_else(|e| die(&e.to_string())); + if out.json { + println!("{body}"); + } else { + print_job(&body, out.top); + } + if wai_quantum::engine::planner::missed(&body["result"]) { + std::process::exit(crate::CONTRACT_MISSED); + } + return; + }; + let t = open.iter().find(|t| t.name == name).unwrap_or_else(|| die("internal: the planner chose a provider it was not given")); let ledger = Ledger::load_default().unwrap_or_else(|e| die(&e)); - let mut ticket = match pjob::start(&t, &req, args.yes, &ledger) { + let ticket = pjob::start_routed(t, &routed, &req, args.yes, &ledger); + follow_started(t, ticket, &ledger, &k.key, out, args, &name); +} + +/// A job sent, followed as `run` follows one: refused, or left at the provider, +/// or sealed and shown. +fn follow_started(t: &Target, started: Result, ledger: &Ledger, key: &SigningKey, out: &Output, args: &RunArgs, name: &str) { + let mut ticket = match started { Ok(ticket) => ticket, Err(JobError::Unconfirmed { plan, message }) => { if out.json { @@ -326,8 +372,38 @@ pub fn run(job: &Job, out: &Output, key: &KeyArgs, args: &RunArgs) { return; } eprintln!("note: recorded as {h}: if this stops, the job goes on at {name}, and `wai-quantum providers collect {h}` comes back to it", h = ticket.handle()); - let progress = pjob::follow(&t, &mut ticket, &k.key, &ledger, WAIT, sleeper()).unwrap_or_else(|e| die(&e.to_string())); - std::process::exit(show(&progress, out)); + let progress = pjob::follow(t, &mut ticket, key, ledger, WAIT, sleeper()).unwrap_or_else(|e| die(&e.to_string())); + let status = show(&progress, out); + if status == 0 && wai_quantum::engine::planner::missed(&progress.job()["result"]) { + std::process::exit(crate::CONTRACT_MISSED); + } + std::process::exit(status); +} + +/// `run --provider`: the job on the person's provider, or its dry run; with +/// `--allow-providers` and none named, the route the planner chooses. +pub fn run(job: &Job, out: &Output, key: &KeyArgs, args: &RunArgs) { + if args.provider.is_none() { + return run_routed(job, out, key, args); + } + let name = args.provider.as_deref().unwrap_or_default(); + let mut req = job_request(job).unwrap_or_else(|e| die(&e)); + req["provider"] = json!(name); + let (reg, stores) = load(); + let t = registry::open(entry(®, name).unwrap_or_else(|e| die(&e)), &stores).unwrap_or_else(|e| die(&e)).with_job_bytes(job.memory_gb << 30); + if args.dry_run { + let p = pjob::plan(&t, &req).unwrap_or_else(|e| die(&e.to_string())); + if out.json { + println!("{}", p.json); + } else { + print_plan(&p.json); + } + return; + } + let k = load_key(key); + let ledger = Ledger::load_default().unwrap_or_else(|e| die(&e)); + let started = pjob::start(&t, &req, args.yes, &ledger); + follow_started(&t, started, &ledger, &k.key, out, args, name); } /// A job as the command line shows it, and the exit status that says where it @@ -613,6 +689,7 @@ fn provider_schema(extra: Value) -> Value { "inputs": { "type": "object", "additionalProperties": { "type": "integer" }, "description": "A generator's inputs' values, as {\"n\": 5}." }, "shots": { "type": "integer", "minimum": 1, "description": "Shots (default 1024)." }, "seed": { "type": "integer", "minimum": 0, "description": "A seed, for a provider that is a seeded simulator; a device ignores it." }, + "contract": wai_quantum::engine::planner::contract_schema(), } }); if let (Some(p), Some(e)) = (s["properties"].as_object_mut(), extra.as_object()) { @@ -643,6 +720,18 @@ pub fn mcp_tools() -> Vec { "inputSchema": provider_schema(json!({ "confirm_cost": { "type": "boolean", "description": "true only when the person has agreed to this run's cost. A run that is not free is refused without it." } })), "execution": { "taskSupport": "optional" }, }), + json!({ + "name": "plan_routes", + "title": "Weigh a contract against every route", + "description": "Every route a job could take under its contract: the methods on this machine and each of the person's own providers, each with its price or why it was rejected, what a provider's estimate leaves out, and the route the planner would choose: the cheapest that meets the contract, or the refusal (J071) with every route's reason. Each provider is asked to describe its device and estimate the job. Nothing is submitted and nothing is spent. A device is chosen only when exactness asks for measured or any.", + "inputSchema": route_schema(json!({})), + }), + json!({ + "name": "run_routed", + "title": "Run a job on the route its contract chooses (can spend the person's money)", + "description": "Runs a job on the route plan_routes chooses: a method on this machine, or one of the person's own providers. THIS CAN SPEND THE PERSON'S MONEY OR QUOTA, when the contract allows a provider and one is chosen. A cost ceiling confirms nothing: a run that is not free is refused unless confirm_cost is true, set only after the person has seen the estimate and agreed to that run. The answer is a job in the service's form, its result carrying the planner's reasoning under planner; a provider's result also carries a classical method's counts and their distance under shadow, or why no classical method could reach them. If the job has not finished within this call the answer has status running and an id, and get_provider_job collects it later. Do not run it again to find out: that is a second job, and it can be a second bill.", + "inputSchema": route_schema(json!({ "confirm_cost": { "type": "boolean", "description": "true only when the person has agreed to this run's cost. A run that is not free is refused without it, whatever the contract's ceiling." } })), + }), json!({ "name": "get_provider_job", "title": "Ask after a job on a provider", @@ -667,6 +756,27 @@ pub fn mcp_tools() -> Vec { ] } +/// What a routed job takes: a job's own members, under a contract that names no +/// provider. +fn route_schema(extra: Value) -> Value { + let mut s = json!({ + "type": "object", + "required": ["qasm", "contract"], + "properties": { + "qasm": { "type": "string", "description": "The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why." }, + "inputs": { "type": "object", "additionalProperties": { "type": "integer" }, "description": "A generator's inputs' values, as {\"n\": 5}." }, + "shots": { "type": "integer", "minimum": 1, "description": "Shots (default 1024)." }, + "seed": { "type": "integer", "minimum": 0, "description": "A seed." }, + "observables": { "type": "array", "items": { "type": "string" }, "description": "Pauli observables: a provider's job answers counts, so a method here answers these." }, + "contract": wai_quantum::engine::planner::contract_schema(), + } + }); + if let (Some(p), Some(e)) = (s["properties"].as_object_mut(), extra.as_object()) { + p.extend(e.clone()); + } + s +} + /// Appends these tools to a tools list. pub fn add_tools(tools: &mut Value) { if let Some(a) = tools.as_array_mut() { @@ -685,7 +795,7 @@ fn mcp_request(args: &Value) -> Result<(String, Value), String> { Some(_) => return Err("give \"inputs\" as an object of whole numbers".into()), }; let mut req = json!({ "qasm": crate::at_inputs(qasm.to_string(), &inputs)?, "provider": name }); - for k in ["shots", "seed"] { + for k in ["shots", "seed", "contract"] { if let Some(v) = args.get(k).filter(|v| !v.is_null()) { req[k] = v.clone(); } @@ -693,6 +803,27 @@ fn mcp_request(args: &Value) -> Result<(String, Value), String> { Ok((name, req)) } +/// The request a routed call makes: the program read at its inputs, under its +/// contract, naming no provider. +fn mcp_routed(args: &Value) -> Result { + let qasm = args.get("qasm").and_then(Value::as_str).ok_or("give \"qasm\": the program")?; + if args.get("contract").is_none_or(Value::is_null) { + return Err("give \"contract\": what the job wants; it is the contract that weighs the routes".into()); + } + let inputs: wai_quantum::qasm::Inputs = match args.get("inputs") { + None | Some(Value::Null) => Default::default(), + Some(Value::Object(m)) => m.iter().map(|(k, v)| v.as_i64().map(|n| (k.clone(), n)).ok_or(format!("inputs: {k} takes a whole number"))).collect::>()?, + Some(_) => return Err("give \"inputs\" as an object of whole numbers".into()), + }; + let mut req = json!({ "qasm": crate::at_inputs(qasm.to_string(), &inputs)? }); + for k in ["shots", "seed", "observables", "contract"] { + if let Some(v) = args.get(k).filter(|v| !v.is_null()) { + req[k] = v.clone(); + } + } + Ok(req) +} + /// One of the tools, with `reg`, `stores` and `ledger`; `None` for another tool. pub fn mcp_call_with(name: &str, args: &Value, key: &SigningKey, reg: &Registry, stores: &Stores, ledger: &Ledger, wait: Wait) -> Option> { Some(match name { @@ -716,6 +847,24 @@ pub fn mcp_call_with(name: &str, args: &Value, key: &SigningKey, reg: &Registry, Err(e) => Err(e.to_string()), } })(), + "plan_routes" | "run_routed" => (|| { + let req = mcp_routed(args)?; + let (open, closed) = targets(reg, stores, crate::DEFAULT_MEMORY_GB << 30); + let routed = pjob::route_with(&open, closed, &req, crate::DEFAULT_MEMORY_GB << 30).map_err(|e| e.to_string())?; + if name == "plan_routes" { + return Ok(routed.json()); + } + let Some(chosen) = routed.provider() else { + return pjob::run_routed_here(&routed, &req, key, json!({ "unmetered": crate::UNMETERED })).map_err(|e| e.to_string()); + }; + let t = open.iter().find(|t| t.name == chosen).ok_or("internal: the planner chose a provider it was not given")?; + let confirmed = args.get("confirm_cost") == Some(&Value::Bool(true)); + match pjob::start_routed(t, &routed, &req, confirmed, ledger).and_then(|mut ticket| pjob::follow(t, &mut ticket, key, ledger, wait, std::thread::sleep)) { + Ok(progress) => Ok(progress.job().clone()), + Err(JobError::Unconfirmed { plan, message }) => Err(format!("refused: {message}. Show the person this estimate; call again with confirm_cost: true only when they agree. The plan: {plan}")), + Err(e) => Err(e.to_string()), + } + })(), "get_provider_job" | "cancel_provider_job" => (|| { let handle = args.get("id").and_then(Value::as_str).ok_or("give \"id\": the job's id, from run_on_provider or list_provider_jobs")?; let _held = asking(); @@ -735,7 +884,7 @@ pub fn mcp_call_with(name: &str, args: &Value, key: &SigningKey, reg: &Registry, /// One of the tools, with the person's own registry and records; `None` for /// another tool. pub fn mcp_call(name: &str, args: &Value, key: &SigningKey) -> Option> { - if !matches!(name, "providers_list" | "provider_estimate" | "run_on_provider" | "get_provider_job" | "cancel_provider_job" | "list_provider_jobs") { + if !matches!(name, "providers_list" | "provider_estimate" | "plan_routes" | "run_routed" | "run_on_provider" | "get_provider_job" | "cancel_provider_job" | "list_provider_jobs") { return None; } match Books::load() { diff --git a/wai/wai-quantum-cli/tests/providers.rs b/wai/wai-quantum-cli/tests/providers.rs index 5417ae9b2..027ef960d 100644 --- a/wai/wai-quantum-cli/tests/providers.rs +++ b/wai/wai-quantum-cli/tests/providers.rs @@ -283,6 +283,109 @@ fn an_agent_lists_estimates_is_refused_and_runs_only_with_confirm_cost() { let _ = child.wait(); } +/// A person's contract, on the command line: run here with its reasoning in the +/// receipt, refused with every route's reason, weighed against their providers, +/// and sent to the one that meets it, with a classical method's counts beside its +/// own. +#[test] +fn a_contract_weighs_every_route_and_its_receipt_says_why() { + let h = Home::new("contract"); + add_process(&h, "free-lab", &[], false); + add_process(&h, "paid", &["--price", "0.25", "--currency", "EUR", "--per", "job"], false); + let p = h.program(); + let file = |name: &str, text: &str| { + let f = h.dir.join(name); + std::fs::write(&f, text).unwrap(); + f.display().to_string() + }; + // Here, with its reasoning sealed and checked. + let body: Value = serde_json::from_str(&h.ok(&["run", &p, "--shots", "100", "--exactness", "exact", "--deadline", "60", "--demo-key", "--json"], "")).unwrap(); + assert_eq!(body["result"]["planner"]["choice"], "method:stabilizer", "{}", body["result"]["planner"]); + let saved = file("here.json", &body.to_string()); + let checked: Value = serde_json::from_str(&h.ok(&["verify", &saved, "--json", "--recheck"], "")).unwrap(); + assert_eq!((checked["valid"].as_bool(), checked["recheck"]["holds"].as_bool(), checked["planner"]["choice"].as_str()), (Some(true), Some(true), Some("method:stabilizer")), "{checked}"); + let told = h.ok(&["verify", &saved, "--recheck"], ""); + assert!(told.contains("wanted exact") && told.contains("priced again the same"), "{told}"); + // The words a person reads name each route. + let plan = h.ok(&["plan", &p, "--shots", "100", "--exactness", "exact"], ""); + assert!(plan.contains("method:stabilizer") && plan.contains("method:mps") && plan.contains("rejected (class"), "{plan}"); + // Refused, with why; as data, with every route; nothing else runs. + let out = h.run(&["run", &p, "--exactness", "measured", "--demo-key"], ""); + assert_eq!(out.status.code(), Some(1)); + let said = String::from_utf8_lossy(&out.stderr); + assert!(said.contains("[J071]") && said.contains("method:stabilizer"), "{said}"); + let out = h.run(&["plan", &p, "--exactness", "measured", "--json"], ""); + assert_eq!(out.status.code(), Some(1)); + let v: Value = serde_json::from_slice(&out.stdout).unwrap(); + assert_eq!((v["refused"]["code"].as_str(), v["planner"]["choice"].as_str()), (Some("J071"), None), "{v}"); + // Weighed against the person's providers: exact is here. + let routed = h.ok(&["plan", &p, "--shots", "100", "--exactness", "exact", "--allow-providers"], ""); + assert!(routed.contains("provider:free-lab") && routed.contains("provider:paid"), "{routed}"); + assert!(jobs(&h).is_empty(), "a plan sends nothing"); + let body: Value = serde_json::from_str(&h.ok(&["run", &p, "--shots", "100", "--exactness", "exact", "--allow-providers", "--demo-key", "--json"], "")).unwrap(); + assert_eq!(body["result"]["method"], "stabilizer"); + assert!(jobs(&h).is_empty(), "a method here chosen, nothing is sent"); + // A provider's simulator asked for by its class: the free one, and its shadow. + let body: Value = serde_json::from_str(&h.ok(&["run", &p, "--shots", "100", "--seed", "3", "--exactness", "simulated", "--allow-providers", "--max-cost", "1:EUR", "--demo-key", "--json"], "")).unwrap(); + assert_eq!(body["result"]["provider"]["name"], "free-lab", "{}", body["result"]["planner"]); + assert_eq!(body["result"]["shadow"]["ran"], true); + assert_eq!(body["result"]["shadow"]["route"], "method:exact"); + let saved = file("routed.json", &body.to_string()); + let checked: Value = serde_json::from_str(&h.ok(&["verify", &saved, "--json", "--recheck"], "")).unwrap(); + assert_eq!((checked["valid"].as_bool(), checked["recheck"]["shadow"]["same"].as_bool()), (Some(true), Some(true)), "{checked}"); + assert_eq!(jobs(&h).len(), 1); + // Named, under a ceiling, a cost that is not free still takes the person's word. + let out = h.run(&["run", &p, "--provider", "paid", "--max-cost", "1:EUR", "--demo-key"], ""); + assert_eq!(out.status.code(), Some(3), "{}", String::from_utf8_lossy(&out.stderr)); + let out = h.run(&["run", &p, "--provider", "paid", "--max-cost", "0.1:EUR", "--yes", "--demo-key"], ""); + assert_eq!(out.status.code(), Some(1)); + assert!(String::from_utf8_lossy(&out.stderr).contains("above the ceiling")); + let told = h.ok(&["run", &p, "--provider", "paid", "--max-cost", "1:EUR", "--yes", "--demo-key"], ""); + assert!(told.contains("shadow") && told.contains("method:exact") && told.contains("kept cost: kept"), "{told}"); +} + +/// The same for an agent: a contract's routes, and a run on the one it chooses, +/// refused until the person confirms a cost. +#[test] +fn an_agent_weighs_a_contract_and_runs_on_the_route_it_chooses() { + let h = Home::new("agent-contract"); + add_process(&h, "paid", &["--price", "0.25", "--currency", "EUR", "--per", "job"], false); + let mut child = h.cmd().args(["mcp", "--demo-key"]).stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::null()).spawn().unwrap(); + let mut stdin = child.stdin.take().unwrap(); + let mut stdout = BufReader::new(child.stdout.take().unwrap()); + rpc(&mut stdin, &mut stdout, 1, "initialize", json!({ "protocolVersion": "2025-06-18" })); + let call = |stdin: &mut std::process::ChildStdin, stdout: &mut BufReader, id: u64, name: &str, args: Value| rpc(stdin, stdout, id, "tools/call", json!({ "name": name, "arguments": args }))["result"].clone(); + let simulated = json!({ "exactness": "simulated", "providers": "allowed", "max_cost": { "amount": "1", "currency": "EUR" } }); + let routes = call(&mut stdin, &mut stdout, 2, "plan_routes", json!({ "qasm": BELL, "shots": 100, "contract": simulated })); + assert_eq!(routes["isError"], false, "{routes}"); + assert_eq!(routes["structuredContent"]["planner"]["choice"], "provider:paid", "{routes}"); + assert_eq!(routes["structuredContent"]["provider_plan"]["estimate"]["amount"], "0.25", "{routes}"); + let refused = call(&mut stdin, &mut stdout, 3, "run_routed", json!({ "qasm": BELL, "shots": 100, "contract": simulated })); + assert_eq!(refused["isError"], true, "{refused}"); + assert!(refused["content"][0]["text"].as_str().unwrap().contains("confirm_cost: true"), "{refused}"); + let ran = call(&mut stdin, &mut stdout, 4, "run_routed", json!({ "qasm": BELL, "shots": 100, "contract": simulated, "confirm_cost": true })); + assert_eq!(ran["isError"], false, "{ran}"); + let job = ran["structuredContent"].clone(); + assert_eq!((job["result"]["provider"]["name"].as_str(), job["result"]["shadow"]["ran"].as_bool()), (Some("paid"), Some(true)), "{job}"); + let checked = call(&mut stdin, &mut stdout, 5, "verify_quantum_result", json!({ "job": job, "recheck": true })); + assert_eq!((checked["structuredContent"]["valid"].as_bool(), checked["structuredContent"]["recheck"]["holds"].as_bool()), (Some(true), Some(true)), "{checked}"); + // Under a contract its own tools meet: a method here, and no money. + let here = call(&mut stdin, &mut stdout, 6, "run_routed", json!({ "qasm": BELL, "shots": 100, "contract": { "exactness": "exact", "providers": "allowed" } })); + assert_eq!((here["isError"].as_bool(), here["structuredContent"]["result"]["method"].as_str()), (Some(false), Some("stabilizer")), "{here}"); + // No contract: nothing to weigh, and the tool says so. + let bare = call(&mut stdin, &mut stdout, 7, "plan_routes", json!({ "qasm": BELL })); + assert_eq!(bare["isError"], true, "{bare}"); + // The engine's own run tool runs a contract, on what is here, and reaches no provider. + let run = call(&mut stdin, &mut stdout, 8, "run_quantum_circuit", json!({ "qasm": BELL, "shots": 50, "contract": { "exactness": "exact", "providers": "allowed" } })); + assert_eq!((run["structuredContent"]["result"]["planner"]["host"]["providers"].as_array().map(Vec::len), run["isError"].as_bool()), (Some(0), Some(false)), "{run}"); + let no = call(&mut stdin, &mut stdout, 9, "run_quantum_circuit", json!({ "qasm": BELL, "contract": { "exactness": "simulated", "providers": "allowed" } })); + assert_eq!(no["isError"], true, "{no}"); + let plan = call(&mut stdin, &mut stdout, 10, "plan_quantum_circuit", json!({ "qasm": BELL, "contract": { "exactness": "exact" } })); + assert_eq!(plan["structuredContent"]["planner"]["choice"], "method:stabilizer", "{plan}"); + drop(stdin); + let _ = child.wait(); +} + fn jobs(h: &Home) -> Vec { let v: Value = serde_json::from_str(&h.ok(&["providers", "jobs", "--json"], "")).unwrap(); v["jobs"].as_array().unwrap().clone() diff --git a/wai/wai-quantum-qpu/src/job.rs b/wai/wai-quantum-qpu/src/job.rs index afbc8f5a4..72f7aef6f 100644 --- a/wai/wai-quantum-qpu/src/job.rs +++ b/wai/wai-quantum-qpu/src/job.rs @@ -29,6 +29,15 @@ //! still no; [`cancel`] is only ever someone asking. Any process can come back //! to a ticket, and its result is the one [`run`] would have sealed. //! +//! A job with a `contract` (wai/extensions/quantum-providers.md section 8.6) is +//! weighed by the engine's planner ([`planner`]): what the provider's estimate +//! says and leaves out is brought to it as a quote, and it runs only if the +//! provider meets the contract. [`route`] weighs every provider the person has +//! against the engine's own methods. Its reasoning goes in the receipt, with a +//! classical method's counts beside the provider's wherever one can reach them. +//! A ceiling is no confirmation: a run that is not free still runs only on the +//! person's word for that run (section 7). +//! //! A credential never appears in what these return: every message is passed //! through [`crate::Secret::redact`] first. @@ -40,7 +49,8 @@ use serde_json::{Value, json}; use std::time::Duration; use wai_quantum::ed25519_dalek::SigningKey; use wai_quantum::engine::targets::{import, layout}; -use wai_quantum::engine::{catalog, provider, receipt}; +use wai_quantum::engine::registry::Registry; +use wai_quantum::engine::{catalog, planner, provider, receipt}; use wai_quantum::quantum_fabric::sampling::Counts; use wai_quantum::quantum_toolchain::native::{NativeGate, NativeProgram}; @@ -56,13 +66,25 @@ pub struct Target { pub kind: Kind, pub provider: Box, secret: Option, + job_bytes: u64, } +/// The memory a classical method may take here beside a provider's job, unless a +/// host says otherwise ([`Target::with_job_bytes`]). +pub const SHADOW_BYTES: u64 = 8 << 30; + impl Target { /// `provider` under the person's name for it, with the credential it was /// given (kept only to take out of messages). pub fn new(name: impl Into, kind: Kind, provider: Box, secret: Option) -> Target { - Target { name: name.into(), kind, provider, secret } + Target { name: name.into(), kind, provider, secret, job_bytes: SHADOW_BYTES } + } + + /// The same, with the memory a contract job's local routes and its shadow + /// may take here. + pub fn with_job_bytes(mut self, job_bytes: u64) -> Target { + self.job_bytes = job_bytes; + self } /// `text` with the credential taken out. @@ -212,7 +234,10 @@ pub struct Plan { placement: Value, device: Device, details: Details, + execution: Option, estimate: Result, String>, + /// The planner's reasoning, for a job with a contract. + reasoning: Option, } impl Plan { @@ -220,10 +245,83 @@ impl Plan { pub fn confirmation(&self) -> String { self.json["confirm"].as_str().unwrap_or("").to_string() } + + /// What the provider's estimate says of this job, and what it leaves out, as + /// the planner weighs it. Nothing has been sent. + pub fn quote(&self, name: &str) -> planner::Quote { + let mut q = planner::Quote::new(name, self.device.name.clone(), self.device.provenance.label()); + q.approximate = self.details.describe.get("approximate") == Some(&Value::Bool(true)) && self.device.provenance.label() != "silicon"; + let (money, seconds) = match &self.estimate { + Ok(Some(e)) => { + let m = match (&e.cost, e.free) { + (_, true) => json!({ "free": true }), + (Some(c), false) => { + let mut m = json!({ "free": false, "amount": c.amount, "currency": c.currency }); + if let Some(u) = &e.unit { + m["unit"] = json!(u); + } + m + } + (None, false) => json!({ "free": false, "unknown": "the provider's estimate states no amount" }), + }; + (m, e.seconds) + } + Ok(None) => match &self.details.billing { + Billing::Free => (json!({ "free": true }), None), + Billing::Priced { unit, price, currency } => (json!({ "free": false, "unknown": format!("the provider gives no estimate; it bills {price} {currency} a {unit}") }), None), + Billing::Unknown(why) => (json!({ "free": false, "unknown": why }), None), + }, + Err(why) => (json!({ "free": false, "unknown": format!("the provider's estimate failed: {why}") }), None), + }; + // What a price of this kind cannot say, each in words a verifier knows. + let free = money["free"] == true; + let mut left = Vec::new(); + if seconds.is_none() { + left.push("time"); + } + if !free && money["amount"].is_null() { + left.push("amount"); + } + left.push("energy"); + // A client that sets mitigation off, or a device that has none, leaves nothing here. + let mitigation = self.execution.as_ref().and_then(|e| e["mitigation"].as_str().map(str::to_string)); + if !matches!(mitigation.as_deref(), Some("off" | "none")) { + left.push("mitigation"); + } + left.push("decoder"); + if !free { + left.push("charged"); + } + q.money = money; + q.seconds = seconds; + q.leaves_out = left.into_iter().map(str::to_string).collect(); + let c = &self.json["plan"]["compile"]; + q.program = json!({ "shots": self.read.shots, "native_gates": c["native_gates"], "two_qubit_gates": c["two_qubit_gates"], "swaps": c["swaps"] }); + if let Some(x) = self.placement.get("expected_success").filter(|x| x.is_number()) { + q.program["expected_success"] = x.clone(); + } + q + } } fn plan_with(t: &Target, sampler: &QpuSampler<&dyn Provider>, request: &Value) -> Result { - let read = provider::read(request).map_err(|e| t.fail(e))?; + let mut p = priced(t, sampler, request)?; + // Under a contract, the planner weighs this provider, and nothing is sent + // unless it meets it. + if planner::has_contract(request) { + let host = planner::Host::new(t.job_bytes).with_quotes(vec![p.quote(&t.name)]); + let d = planner::decide(Registry::builtins(), request, &host).map_err(|e| t.fail(e))?; + if !matches!(d.choice, planner::Choice::Provider(_)) { + let chosen = d.reasoning["choice"].as_str().unwrap_or_default(); + return Err(JobError::Failed(format!("this job's contract is met here by {chosen}, not by {}: the planner chose the cheaper route, and nothing was sent", t.name))); + } + p.reason_with(d.reasoning); + } + Ok(p) +} + +fn priced(t: &Target, sampler: &QpuSampler<&dyn Provider>, request: &Value) -> Result { + let read = provider::read_named(request, Some(&t.name)).map_err(|e| t.fail(e))?; if read.provider != t.name { return Err(JobError::Failed(format!("the job names the provider {:?}, and this is {:?}", read.provider, t.name))); } @@ -265,7 +363,103 @@ fn plan_with(t: &Target, sampler: &QpuSampler<&dyn Provider>, request: &Value) - "free": free, "confirm": confirm, }); - Ok(Plan { json, free, read, program, placement, device, details, estimate }) + let execution = t.provider.execution(&program); + Ok(Plan { json, free, read, program, placement, device, details, execution, estimate, reasoning: None }) +} + +impl Plan { + fn reason_with(&mut self, reasoning: Value) { + self.json["planner"] = reasoning.clone(); + self.reasoning = Some(reasoning); + } +} + +/// What the planner made of a contract job, with every provider brought. +pub struct Routed { + /// The reasoning: every route, each one's price or reason, and the choice. + pub reasoning: Value, + /// The route chosen, and its plan when it is one of the engine's methods. + pub choice: planner::Choice, + plans: Vec<(String, Plan)>, +} + +impl Routed { + /// What a dry run shows: the reasoning, the local plan when a method was + /// chosen, and the provider's own plan when one was. + pub fn json(&self) -> Value { + let mut v = json!({ "dry_run": true, "planner": self.reasoning }); + match &self.choice { + planner::Choice::Local(p) => v["plan"] = serde_json::to_value(p).unwrap_or(Value::Null), + planner::Choice::Provider(name) => { + if let Some((_, p)) = self.plans.iter().find(|(n, _)| n == name) { + v["provider_plan"] = p.json.clone(); + } + } + _ => {} + } + v + } + + /// The name of the provider chosen, when one was. + pub fn provider(&self) -> Option<&str> { + match &self.choice { + planner::Choice::Provider(n) => Some(n), + _ => None, + } + } +} + +/// `request`'s contract weighed against every provider in `targets` and the +/// engine's own methods, within `job_bytes` of memory: each provider is asked to +/// describe the device and estimate the job, and nothing is sent. A provider that +/// cannot run the job, or does not answer, is a route with why. The refusal, when +/// no route meets the contract, comes back with its reasons. +pub fn route(targets: &[Target], request: &Value, job_bytes: u64) -> Result { + route_with(targets, Vec::new(), request, job_bytes) +} + +/// [`route`], with `also` among the routes: the providers a host could not open, +/// each with why. +pub fn route_with(targets: &[Target], also: Vec, request: &Value, job_bytes: u64) -> Result { + let mut quotes = also; + let mut plans = Vec::new(); + for t in targets { + let planned = QpuSampler::new(&*t.provider).map_err(|e| t.fail(e)).and_then(|sampler| priced(t, &sampler, request)); + match planned { + Ok(p) => { + quotes.push(p.quote(&t.name)); + plans.push((t.name.clone(), p)); + } + Err(e) => quotes.push(planner::Quote::cannot(t.name.clone(), e.to_string())), + } + } + let host = planner::Host::new(job_bytes).with_quotes(quotes); + let d = planner::decide(Registry::builtins(), request, &host).map_err(JobError::Failed)?; + if let planner::Choice::Provider(name) = &d.choice + && let Some((_, p)) = plans.iter_mut().find(|(n, _)| n == name) + { + p.reason_with(d.reasoning.clone()); + } + Ok(Routed { reasoning: d.reasoning, choice: d.choice, plans }) +} + +/// A local route the planner chose ([`route`]) run here, its result carrying the +/// reasoning and sealed with `key`: `energy` is the host's word on it. +pub fn run_routed_here(routed: &Routed, request: &Value, key: &SigningKey, energy: Value) -> Result { + let planner::Choice::Local(plan) = &routed.choice else { return Err(JobError::Failed("the planner chose a provider, and this runs what it chose here".into())) }; + let mut result = Registry::builtins().run(request, plan).map_err(JobError::Failed)?; + planner::attach(&mut result, &routed.reasoning); + Ok(wai_quantum::engine::job::seal(request, plan, result, key, energy)) +} + +/// The provider [`route`] chose, as [`start`] sends it: refused, with the plan, +/// when it is not free and `confirmed` is false. +pub fn start_routed(t: &Target, routed: &Routed, request: &Value, confirmed: bool, ledger: &Ledger) -> Result { + let Some((_, p)) = routed.plans.iter().find(|(n, _)| *n == t.name) else { return Err(JobError::Failed(format!("the planner did not weigh {}", t.name))) }; + if routed.provider() != Some(t.name.as_str()) { + return Err(JobError::Failed(format!("the planner did not choose {}", t.name))); + } + start_planned(t, p, request, confirmed, ledger) } /// The dry run: the plan for `request` on `t`, with nothing submitted. @@ -299,20 +493,25 @@ fn sealing_of(t: &Target, p: &Plan, confirmed: bool) -> Value { let protocol = p.json["provider"]["protocol"].as_str().unwrap_or(PROTOCOL).to_string(); let mut compiled = compiled_json(&p.program); compiled["placement"] = p.placement.clone(); + let reasoning = p.reasoning.clone().unwrap_or(Value::Null); // A simulator the provider states is approximate (§5.1); a processor's // counts never are. let approximate = p.details.describe.get("approximate") == Some(&Value::Bool(true)) && p.device.provenance.label() != "silicon"; - json!({ + let mut sealing = json!({ "provider": provider_json(t, &p.device, &p.details), "calibration": p.details.calibration, "compiled": compiled, - "execution": t.provider.execution(&p.program), + "execution": p.execution, "approximate": approximate, "free": p.free, "estimate": estimate_json(&p.estimate), "confirmed": confirmed && !p.free, "why": format!("on {}, {} ({protocol}): compiled exactly to {} on its qubits and checked by simulation here before it was sent", t.name, p.device.name, basis_label(p.device.basis)), - }) + }); + if !reasoning.is_null() { + sealing["planner"] = reasoning; + } + sealing } /// The counts of job `id`, as a sealed job. Where its counts come from is the @@ -321,7 +520,7 @@ fn sealing_of(t: &Target, p: &Plan, confirmed: bool) -> Value { /// states it with the counts, else the client's, recorded when the job was /// sent, else no one's (a job recorded before clients said). #[allow(clippy::too_many_arguments)] -fn sealed(t: &Target, request: &Value, read: &provider::Request, sealing: &Value, id: &str, polls: u32, counts: Counts, info: &JobInfo, stated: &Stated, key: &SigningKey) -> Result { +fn sealed(t: &Target, request: &Value, read: &provider::Request, sealing: &Value, id: &str, polls: u32, counts: Counts, info: &JobInfo, stated: &Stated, elapsed_ms: Option, key: &SigningKey) -> Result { let charged = info.charged.as_ref().map(|c| json!({ "amount": c.amount, "currency": c.currency })); let measured = provider::Measured { counts, @@ -334,7 +533,11 @@ fn sealed(t: &Target, request: &Value, read: &provider::Request, sealing: &Value }; let execution = stated.execution.clone().or_else(|| sealing.get("execution").filter(|e| e.is_object()).cloned()).unwrap_or_else(provider::unstated_execution); let statement = provider::Statement::new(stated.counts_source.unwrap_or(CountsSource::VendorCounts), execution).approximate(sealing["approximate"] == true); - let result = provider::result_stated(read, measured, &statement).map_err(|e| t.fail(e))?; + let mut result = provider::result_stated(read, measured, &statement).map_err(|e| t.fail(e))?; + // A contract job's reasoning, its shadow and what it kept (section 8.6). + if let Some(reasoning) = sealing.get("planner") { + planner::seal_provider(Registry::builtins(), request, &mut result, reasoning, elapsed_ms); + } Ok(provider::seal(request, result, key, sealing["why"].as_str().unwrap_or_default())) } @@ -348,9 +551,11 @@ pub fn run(t: &Target, request: &Value, confirmed: bool, key: &SigningKey, wait: let p = plan_with(t, &sampler, request)?; refuse_unconfirmed(t, &p, confirmed)?; let sealing = sealing_of(t, &p, confirmed); + let began = std::time::Instant::now(); let (counts, record, stated): (_, JobRecord, _) = sampler.run_compiled_stated(&p.read.circuit, &p.program, p.read.shots, p.read.seed).map_err(|e| t.fail(e))?; let info = JobInfo { service_kwh: record.service_kwh, calibration: record.calibration, charged: record.charged }; - sealed(t, request, &p.read, &sealing, &record.id, record.polls, counts, &info, &stated, key) + let elapsed = u64::try_from(began.elapsed().as_millis()).ok(); + sealed(t, request, &p.read, &sealing, &record.id, record.polls, counts, &info, &stated, elapsed, key) } /// What came of asking after a recorded job. Each holds the job in the form @@ -395,8 +600,12 @@ pub fn progress_of(ticket: &Ticket) -> Progress { pub fn start(t: &Target, request: &Value, confirmed: bool, ledger: &Ledger) -> Result { let sampler = QpuSampler::new(&*t.provider).map_err(|e| t.fail(e))?; let p = plan_with(t, &sampler, request)?; - refuse_unconfirmed(t, &p, confirmed)?; - let mut ticket = Ticket::recording(&t.name, request, &p.program, p.read.shots, p.read.seed, sealing_of(t, &p, confirmed)); + start_planned(t, &p, request, confirmed, ledger) +} + +fn start_planned(t: &Target, p: &Plan, request: &Value, confirmed: bool, ledger: &Ledger) -> Result { + refuse_unconfirmed(t, p, confirmed)?; + let mut ticket = Ticket::recording(&t.name, request, &p.program, p.read.shots, p.read.seed, sealing_of(t, p, confirmed)); ledger.put(&ticket).map_err(|e| JobError::Failed(format!("nothing was sent: the job could not be recorded first ({e})")))?; match t.provider.submit_seeded(&p.program, p.read.shots, p.read.seed) { Ok(id) => { @@ -437,10 +646,11 @@ fn ask(t: &Target, ticket: &mut Ticket, key: &SigningKey, ledger: &Ledger) -> Re match t.provider.status(&id) { Ok(JobStatus::Pending) => return Ok(progress_of(ticket)), Ok(JobStatus::Done) => { - let read = provider::read(ticket.request()).map_err(|e| t.fail(e))?; + let read = provider::read_named(ticket.request(), Some(ticket.provider())).map_err(|e| t.fail(e))?; let program = ticket.program().map_err(|e| t.fail(e))?; let (counts, info, stated) = t.provider.counts_stated(&id, &program, ticket.shots()).map_err(|e| t.fail(e))?; - let body = sealed(t, ticket.request(), &read, ticket.sealing(), &id, ticket.polls(), counts, &info, &stated, key)?; + let elapsed = ticket.elapsed_ms(); + let body = sealed(t, ticket.request(), &read, ticket.sealing(), &id, ticket.polls(), counts, &info, &stated, Some(elapsed), key)?; ticket.done(body); } Ok(JobStatus::Ended { status, reason }) => { @@ -956,6 +1166,209 @@ mod tests { assert_eq!(plain.json["plan"]["compile"]["layout"], json!([0, 1])); } + /// The reference, reading as the processor a contract may ask for. + fn silicon(r: &Arc) -> Target { + let r = Arc::clone(r); + let ch = Local(move |m: &Value| { + let mut a = r.handle(m, None); + if m["op"] == "describe" { + a["provenance"] = json!("silicon"); + a.as_object_mut().unwrap().remove("simulator"); + } + a + }); + Target::new("device", Kind::Process, Box::new(OpenProvider::new(ch)), None) + } + + fn priced_at(price: &str) -> Arc { + Arc::new(Reference::new(Config { price: Some((price.into(), "USD".into(), Per::Shot)), ..Config::default() }).unwrap()) + } + + /// A job's contract is weighed before anything is sent: one its provider + /// cannot meet is refused with why, and the provider was asked only to + /// estimate it. + #[test] + fn a_contract_is_weighed_before_anything_is_sent() { + let key = SigningKey::from_bytes(&[4; 32]); + let r = Arc::new(Reference::new(Config::default()).unwrap()); + let (t, ops, _) = watched(&r); + // A simulator is not a device, however free. + let e = run(&t, &json!({ "qasm": BELL, "provider": "lab", "shots": 100, "contract": { "exactness": "measured" } }), false, &key, no_wait(), |_| {}).unwrap_err(); + assert!(e.to_string().ends_with("[J071]") && e.to_string().contains("simulated"), "{e}"); + assert_eq!(count(&ops, "submit"), 0); + // What it is, it meets. + let body = run(&t, &json!({ "qasm": BELL, "provider": "lab", "shots": 100, "seed": 3, "contract": { "exactness": "simulated" } }), false, &key, no_wait(), |_| {}).unwrap(); + let c = wai_quantum::engine::job::check(&body); + assert!(c.valid(), "{:?}\n{}", c.reasons, body["result"]); + assert_eq!(count(&ops, "submit"), 1); + let p = &body["result"]["planner"]; + assert_eq!((p["choice"].as_str(), p["wanted"].as_str()), (Some("provider:lab"), Some("simulated")), "{p}"); + // A dry run shows it, and sends nothing. + let dry = plan(&t, &json!({ "qasm": BELL, "provider": "lab", "contract": {} })).unwrap(); + assert_eq!(dry.json["planner"]["wanted_from"], "named"); + assert_eq!(dry.json["planner"]["shadow"]["route"], "method:exact", "{}", dry.json["planner"]); + assert_eq!(count(&ops, "submit"), 1); + // With no contract, none of it: its bytes are what they were. + let plain = run(&t, &json!({ "qasm": BELL, "provider": "lab", "shots": 100, "seed": 3 }), false, &key, no_wait(), |_| {}).unwrap(); + for k in ["planner", "shadow"] { + assert!(plain["result"].get(k).is_none(), "{k}"); + } + assert!(plan(&t, &json!({ "qasm": BELL, "provider": "lab" })).unwrap().json.get("planner").is_none()); + } + + /// The ceiling holds the estimate, and a ceiling is no confirmation: a run + /// that is not free still runs only on the person's word for it. + #[test] + fn a_cost_ceiling_holds_the_estimate_and_is_no_confirmation() { + let key = SigningKey::from_bytes(&[4; 32]); + let r = priced_at("0.0003"); + let (t, ops, _) = watched(&r); + let job = |most: &str| json!({ "qasm": BELL, "shots": 1000, "provider": "lab", "contract": { "max_cost": { "amount": most, "currency": "USD" } } }); + // 1000 shots at 0.0003 is 0.3. + let e = run(&t, &job("0.29"), true, &key, no_wait(), |_| {}).unwrap_err(); + assert!(e.to_string().contains("above the ceiling") && e.to_string().ends_with("[J071]"), "{e}"); + assert_eq!(count(&ops, "submit"), 0); + assert!(matches!(run(&t, &job("0.3"), false, &key, no_wait(), |_| {}), Err(JobError::Unconfirmed { .. })), "a ceiling is no confirmation"); + assert_eq!(count(&ops, "submit"), 0); + let body = run(&t, &job("0.3"), true, &key, no_wait(), |_| {}).unwrap(); + assert!(wai_quantum::engine::job::check(&body).valid(), "{:?}", wai_quantum::engine::job::check(&body).reasons); + let kept = &body["result"]["planner"]["kept"]["cost"]; + assert_eq!((kept["kept"].as_bool(), kept["charged"]["amount"].as_str()), (Some(true), Some("0.3")), "{kept}"); + // What the price leaves out is said on its route. + let route = &body["result"]["planner"]["routes"].as_array().unwrap().iter().find(|r| r["route"] == "provider:lab").unwrap().clone(); + assert_eq!(route["price"]["money"]["amount"], "0.3"); + assert_eq!(route["price"]["time"]["basis"], "provider"); + assert_eq!(route["price"]["leaves_out"], json!(["energy", "mitigation", "decoder", "charged"]), "{route}"); + assert_eq!(route["price"]["program"]["shots"], 1000); + // Another currency is not this one, and an estimate that fails is unknown. + let e = run(&t, &json!({ "qasm": BELL, "provider": "lab", "contract": { "max_cost": { "amount": "100", "currency": "EUR" } } }), true, &key, no_wait(), |_| {}).unwrap_err(); + assert!(e.to_string().contains("converts no currency"), "{e}"); + let quiet = Arc::new(Reference::new(Config::default()).unwrap()); + let ch = Local(move |m: &Value| if m["op"] == "estimate" { json!({ "ok": false, "error": { "code": "unsupported", "message": "no estimates" } }) } else if m["op"] == "describe" { let mut d = quiet.handle(m, None); d["billing"] = json!({}); d } else { quiet.handle(m, None) }); + let t = Target::new("lab", Kind::Process, Box::new(OpenProvider::new(ch)), None); + let e = plan(&t, &json!({ "qasm": BELL, "provider": "lab", "contract": { "max_cost": { "amount": "100", "currency": "USD" } } })).err().unwrap(); + assert!(e.to_string().contains("does not meet a ceiling"), "{e}"); + } + + fn bench(names: &[(&str, Option<&str>)]) -> Vec { + names.iter().map(|(name, price)| { + let r = price.map_or_else(|| Arc::new(Reference::new(Config::default()).unwrap()), priced_at); + let mut t = silicon(&r); + t.name = (*name).into(); + t + }).collect() + } + + /// With every provider brought, the cheapest route that meets the contract + /// runs, and a local method that meets it costs nothing to send. + #[test] + fn every_provider_is_weighed_against_the_engine_s_own_methods() { + let key = SigningKey::from_bytes(&[4; 32]); + let r = Arc::new(Reference::new(Config::default()).unwrap()); + let (watching, ops, _) = watched(&r); + // The local route wins, and nothing is sent. + let routed = route(&[watching], &json!({ "qasm": BELL, "shots": 100, "contract": { "providers": "allowed", "exactness": "exact" } }), 1 << 30).unwrap(); + assert_eq!(routed.reasoning["choice"], "method:stabilizer", "{}", routed.reasoning); + assert_eq!(count(&ops, "submit"), 0); + assert!(routed.provider().is_none()); + let req = json!({ "qasm": BELL, "shots": 100, "contract": { "providers": "allowed", "exactness": "exact" } }); + let body = run_routed_here(&routed, &req, &key, json!({ "unmetered": "a test" })).unwrap(); + assert!(wai_quantum::engine::job::check(&body).valid(), "{:?}", wai_quantum::engine::job::check(&body).reasons); + assert_eq!(body["result"]["planner"]["host"]["providers"], json!(["lab"])); + // A device wanted: of three, the cheapest under the ceiling. + let records = Records::new("routed"); + let want = json!({ "qasm": BELL, "shots": 1000, "seed": 2, "contract": { "providers": "allowed", "exactness": "measured", "max_cost": { "amount": "0.5", "currency": "USD" } } }); + let targets = bench(&[("dear", Some("0.001")), ("cheap", Some("0.0002")), ("mid", Some("0.0004"))]); + let routed = route(&targets, &want, 1 << 30).unwrap(); + assert_eq!(routed.provider(), Some("cheap"), "{}", routed.reasoning); + let dear = routed.reasoning["routes"].as_array().unwrap().iter().find(|r| r["route"] == "provider:dear").unwrap(); + assert_eq!(dear["rejected"]["code"], "cost"); + assert_eq!(routed.json()["provider_plan"]["plan"]["method"], "provider"); + // Sent, and collected as any job is, by the provider the planner chose. + let t = targets.iter().find(|t| t.name == "cheap").unwrap(); + assert!(matches!(start_routed(t, &routed, &want, false, &records.ledger()), Err(JobError::Unconfirmed { .. }))); + assert!(start_routed(targets.iter().find(|t| t.name == "mid").unwrap(), &routed, &want, true, &records.ledger()).is_err(), "the planner chose another"); + let mut ticket = start_routed(t, &routed, &want, true, &records.ledger()).unwrap(); + let Progress::Done(body) = check(t, &mut ticket, &key, &records.ledger()).unwrap() else { panic!("not done") }; + let c = wai_quantum::engine::job::check(&body); + assert!(c.valid(), "{:?}\n{}", c.reasons, body["result"]); + assert!(body["request"].get("provider").is_none(), "the request is sealed as it was asked"); + assert_eq!(body["result"]["provider"]["name"], "cheap"); + assert_eq!(body["result"]["accuracy"]["class"], "measured"); + assert_eq!(body["result"]["shadow"]["ran"], true); + assert!(body["result"]["planner"]["kept"]["cost"]["kept"] == true, "{}", body["result"]["planner"]["kept"]); + // No device can be had for this, and none falls back to a simulator or a method. + let e = route(&targets, &json!({ "qasm": BELL, "shots": 1000, "contract": { "providers": "allowed", "exactness": "measured", "max_cost": { "amount": "0.01", "currency": "USD" } } }), 1 << 30).err().unwrap(); + assert!(e.to_string().ends_with("[J071]") && e.to_string().contains("above the ceiling"), "{e}"); + // One that cannot run it is a route with why, and the rest are still weighed. + let wide = "OPENQASM 3.0; qubit[6] q; bit[6] c; h q[0]; c = measure q;"; + let routed = route(&targets, &json!({ "qasm": wide, "shots": 10, "contract": { "providers": "allowed" } }), 1 << 30).unwrap(); + assert_eq!(routed.reasoning["routes"].as_array().unwrap().iter().find(|r| r["route"] == "provider:cheap").unwrap()["rejected"]["code"], "cannot", "{}", routed.reasoning); + assert_eq!(routed.reasoning["choice"], "method:stabilizer"); + } + + /// A contract job's shadow is run where its counts are sealed, whichever + /// process comes back to it; and its reasoning was kept with its record. + #[test] + fn a_shadow_and_its_reasoning_outlive_what_sent_the_job() { + let records = Records::new("contract-record"); + let key = SigningKey::from_bytes(&[4; 32]); + let r = Arc::new(Reference::new(Config { polls: 2, ..Config::default() }).unwrap()); + let req = json!({ "qasm": BELL, "shots": 500, "seed": 7, "provider": "lab", "contract": { "deadline_seconds": 3600 } }); + let handle = start(&on(&r), &req, false, &records.ledger()).unwrap().handle().to_string(); + let t = on(&r); + let mut back = records.ledger().get(&handle).unwrap(); + let Progress::Done(body) = follow(&t, &mut back, &key, &records.ledger(), no_wait(), |_| {}).unwrap() else { panic!("not done") }; + let c = wai_quantum::engine::job::check(&body); + assert!(c.valid(), "{:?}\n{}", c.reasons, body["result"]); + let res = &body["result"]; + assert_eq!((res["shadow"]["ran"].as_bool(), res["shadow"]["route"].as_str()), (Some(true), Some("method:exact"))); + assert_eq!(res["planner"]["kept"]["deadline"]["kept"], true); + assert!(res["planner"]["kept"]["deadline"]["elapsed_ms"].is_u64()); + let rc = wai_quantum::engine::planner::recheck(Registry::builtins(), &body).unwrap(); + assert_eq!(rc["holds"], true, "{rc}"); + // Asked again, the same job, and asks no one. + let mut again = records.ledger().get(&handle).unwrap(); + let Progress::Done(same) = check(&t, &mut again, &key, &records.ledger()).unwrap() else { panic!("not done") }; + assert_eq!(same, body); + } + + /// The reference's own estimate says no time for a deadline only when it gives + /// none; a shadow it leaves no time for says so. + #[test] + fn a_deadline_it_cannot_be_held_to_is_refused_and_one_that_leaves_no_time_says_so() { + let r = Arc::new(Reference::new(Config::default()).unwrap()); + let quiet = { + let r = Arc::clone(&r); + Local(move |m: &Value| { + let mut a = r.handle(m, None); + if m["op"] == "estimate" { + a.as_object_mut().unwrap().remove("seconds"); + } + a + }) + }; + let t = Target::new("lab", Kind::Process, Box::new(OpenProvider::new(quiet)), None); + let e = plan(&t, &json!({ "qasm": BELL, "provider": "lab", "contract": { "deadline_seconds": 3600 } })).err().unwrap(); + assert!(e.to_string().contains("cannot be held to the deadline"), "{e}"); + let late = { + let r = Arc::clone(&r); + Local(move |m: &Value| { + let mut a = r.handle(m, None); + if m["op"] == "estimate" { + a["seconds"] = json!(100); + } + a + }) + }; + let t = Target::new("lab", Kind::Process, Box::new(OpenProvider::new(late)), None); + let key = SigningKey::from_bytes(&[4; 32]); + let body = run(&t, &json!({ "qasm": BELL, "provider": "lab", "shots": 100, "contract": { "deadline_seconds": 100 } }), false, &key, no_wait(), |_| {}).unwrap(); + let s = &body["result"]["shadow"]; + assert_eq!((s["ran"].as_bool(), s["code"].as_str()), (Some(false), Some("budget")), "{s}"); + assert!(wai_quantum::engine::job::check(&body).valid(), "{:?}", wai_quantum::engine::job::check(&body).reasons); + } + #[test] fn the_free_listing_names_the_engine_the_service_and_free_providers_only() { let d = |b: Billing, tier: Option| Details { protocol: PROTOCOL.into(), calibration: None, billing: b, free_tier: tier, describe: json!({}) }; diff --git a/wai/wai-quantum-qpu/src/ledger.rs b/wai/wai-quantum-qpu/src/ledger.rs index 8f64aa597..a8361e8fd 100644 --- a/wai/wai-quantum-qpu/src/ledger.rs +++ b/wai/wai-quantum-qpu/src/ledger.rs @@ -184,6 +184,12 @@ impl Ticket { &self.value["request"] } + /// How long since the job was written down, in milliseconds: a contract's + /// deadline is held to it. + pub(crate) fn elapsed_ms(&self) -> u64 { + now_ms().saturating_sub(self.submitted_ms()) + } + pub(crate) fn sealing(&self) -> &Value { &self.value["sealing"] } diff --git a/wai/wai-quantum-qpu/tests/clients.rs b/wai/wai-quantum-qpu/tests/clients.rs index 27847da5a..1bf4bf44e 100644 --- a/wai/wai-quantum-qpu/tests/clients.rs +++ b/wai/wai-quantum-qpu/tests/clients.rs @@ -647,6 +647,51 @@ fn posted(requests: Vec) -> Value { body_json(requests.iter().rev().find(|r| r.method == Method::Post && !r.url.contains("iam.test")).expect("a submission")) } +/// A built-in kind under a contract, through a service that follows its own: the +/// provider's estimate is unknown, so a ceiling refuses it and naming it runs it; +/// its result carries the planner's reasoning and a classical method's counts +/// beside the device's, and keeps every rule of section 8.6. +#[test] +fn a_built_in_kind_runs_under_a_contract_and_a_classical_method_shadows_it() { + use wai_quantum::ed25519_dalek::SigningKey; + use wai_quantum_qpu::job::{self, JobError, Target}; + use wai_quantum_qpu::registry::Kind; + let target = || { + let service = PrxService { jobs: Mutex::new(HashMap::new()) }; + let t = kept(move |r: &Request| service.answer(r)); + Target::new("lab", Kind::PrxCircuits, Box::new(PrxCircuits::new(t, Secret::new("prx-token"), "test-qc").with_base("https://prx.test/api/v1")), None) + }; + let key = SigningKey::from_bytes(&[42; 32]); + let bell = "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n"; + let wait = Wait { interval: std::time::Duration::ZERO, polls: 10 }; + // Its client states no price: an unknown cost does not meet a ceiling. + let capped = json!({ "qasm": bell, "provider": "lab", "shots": 400, "contract": { "max_cost": { "amount": "100", "currency": "USD" } } }); + let e = job::plan(&target(), &capped).err().unwrap().to_string(); + assert!(e.ends_with("[J071]") && e.contains("does not meet a ceiling"), "{e}"); + // Named, with the person's confirmation for an unknown cost, it runs. + let req = json!({ "qasm": bell, "provider": "lab", "shots": 400, "seed": 5, "contract": { "exactness": "measured" } }); + assert!(matches!(job::run(&target(), &req, false, &key, wait, |_| {}), Err(JobError::Unconfirmed { .. }))); + let body = job::run(&target(), &req, true, &key, wait, |_| {}).unwrap(); + let c = wai_quantum::engine::job::check(&body); + assert!(c.valid(), "{:?}\n{}", c.reasons, body["result"]); + let r = &body["result"]; + assert_eq!((r["accuracy"]["class"].as_str(), r["planner"]["choice"].as_str()), (Some("measured"), Some("provider:lab"))); + let route = r["planner"]["routes"].as_array().unwrap().iter().find(|x| x["route"] == "provider:lab").unwrap(); + assert_eq!(route["price"]["leaves_out"], json!(["time", "amount", "energy", "mitigation", "decoder", "charged"]), "{route}"); + assert!(route["price"]["money"]["unknown"].is_string(), "{route}"); + let s = &r["shadow"]; + assert_eq!((s["ran"].as_bool(), s["accuracy"]["class"].as_str()), (Some(true), Some("bit-exact")), "{s}"); + let total: u64 = s["counts"].as_object().unwrap().values().filter_map(Value::as_u64).sum(); + assert_eq!(total, 400); + // The service follows its contract and the circuit is a Bell pair: both answers + // are the same distribution, within what the shots leave. + let d = &s["distance"]; + assert!(d["total_variation"].as_f64().unwrap() < 0.15, "{d}"); + if let Some(dir) = std::env::var_os("WAI_QUANTUM_RECEIPT_CORPUS") { + std::fs::write(std::path::Path::new(&dir).join("scripted-contract-prx-circuits.json"), format!("{}\n", serde_json::to_string_pretty(&body).unwrap())).unwrap(); + } +} + /// Each built-in kind, through a service that follows its contract, states /// what its client sent (read from the very body it posts), where its counts /// come from, and its class by its device's provenance; and its receipt keeps diff --git a/wai/wai-quantum-service/schemas/service-tools.v1.json b/wai/wai-quantum-service/schemas/service-tools.v1.json index 20428c117..298feabca 100644 --- a/wai/wai-quantum-service/schemas/service-tools.v1.json +++ b/wai/wai-quantum-service/schemas/service-tools.v1.json @@ -427,6 +427,9 @@ } } } + }, + "planner": { + "$ref": "https://git.transaction.science/Transaction-Science/open-standards/raw/branch/main/wai/wai-quantum/schemas/job-result.v1.json#/$defs/planner" } } }, diff --git a/wai/wai-quantum-service/src/http.rs b/wai/wai-quantum-service/src/http.rs index b3c85fa54..2327672a0 100644 --- a/wai/wai-quantum-service/src/http.rs +++ b/wai/wai-quantum-service/src/http.rs @@ -99,7 +99,8 @@ use std::net::{IpAddr, SocketAddr}; use std::sync::Arc; use std::time::Duration; use wai_quantum::engine::refusal::{self, tag}; -use wai_quantum::engine::sets; +use wai_quantum::engine::registry::Registry; +use wai_quantum::engine::{planner, sets}; /// The largest request body, bytes. pub const MAX_BODY: usize = 1 << 20; @@ -284,9 +285,28 @@ pub(crate) fn plan_job(app: &App, request: &Value) -> Result<(catalog::Plan, Wor return Ok((sets::summary(&plans), Work::Set { items, plans })); } job_bounds(request)?; + // A contract is weighed against the methods here, and the service reaches no + // provider, so none is ever among its routes. + if planner::has_contract(request) { + let joules = |p: &catalog::Plan| joules_estimate(app, p); + let host = planner::Host::new(cap).with_joules(&joules); + let d = planner::decide(Registry::builtins(), request, &host).map_err(|e| (400, e))?; + let planner::Choice::Local(p) = d.choice else { return Err((500, "the planner chose a route this service does not have".to_string())) }; + return Ok((p, Work::Planned(d.reasoning))); + } Ok((catalog::plan(request, cap).map_err(|e| (400, e))?, Work::One)) } +/// What the service estimates a plan's energy at, from what it has metered, or +/// why it estimates none. +fn joules_estimate(app: &App, p: &catalog::Plan) -> Result<(f64, String), String> { + let (_, e) = app.service.estimate(p); + match e["joules_micro_estimate"].as_u64() { + Some(u) => Ok((u as f64 / 1e6, e["basis"].as_str().unwrap_or("an estimate from what this service has metered").to_string())), + None => Err(e["unestimated"].as_str().unwrap_or("this service estimates none").to_string()), + } +} + /// Plans and admits `request` for `who`: the job's id, or the refusal's /// status and reason. A request sent again with its key is the key's job, /// whatever planning it now would give. @@ -349,12 +369,23 @@ pub(crate) fn dry_run(app: &App, who: &str, request: &Value) -> Result { + Work::One | Work::Planned(_) => { let (t, e) = estimate(&plan); (t, e, None) } diff --git a/wai/wai-quantum-service/src/jobs.rs b/wai/wai-quantum-service/src/jobs.rs index 7b93f48ff..7fcd715d4 100644 --- a/wai/wai-quantum-service/src/jobs.rs +++ b/wai/wai-quantum-service/src/jobs.rs @@ -64,7 +64,7 @@ use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::sync::{Notify, Semaphore, broadcast}; use wai_quantum::engine::refusal::{self, tag}; -use wai_quantum::engine::{receipt as canon, sets}; +use wai_quantum::engine::{planner, receipt as canon, sets}; /// The service's limits, from the environment ([`Config::from_env`]). #[derive(Clone, Debug)] @@ -187,6 +187,9 @@ pub fn check_key(key: &str) -> Result<(), String> { #[derive(Clone, Debug)] pub enum Work { One, + /// One program under a contract, with the planner's reasoning, which its + /// result carries (`engine::planner`). + Planned(Value), Set { items: Vec, plans: Vec }, } @@ -489,7 +492,11 @@ impl Service { Status::Queued => { let cap = s.config.job_mib << 20; let replanned = match &job.work { - Work::One => crate::catalog::plan(&job.request, cap).map(|p| (p, Work::One)), + Work::One | Work::Planned(_) if planner::has_contract(&job.request) => planner::decide(wai_quantum::engine::registry::Registry::builtins(), &job.request, &planner::Host::new(cap)).and_then(|d| match d.choice { + planner::Choice::Local(p) => Ok((p, Work::Planned(d.reasoning))), + _ => Err("its contract's route is not on this service".to_string()), + }), + Work::One | Work::Planned(_) => crate::catalog::plan(&job.request, cap).map(|p| (p, Work::One)), Work::Set { items, .. } => sets::plan(items, cap).map(|plans| (sets::summary(&plans), Work::Set { items: items.clone(), plans })), }; match replanned.and_then(|(p, w)| if p.memory_bytes.div_ceil(1 << 20) > s.config.job_mib { Err(format!("it needs about {} MiB, more than one job may take here now", p.memory_bytes >> 20)) } else { Ok((p, w)) }) { @@ -735,7 +742,7 @@ impl Service { self.count(client)?; let unkept = |e: String| Refused(503, tag(refusal::BUSY, format!("the job store could not keep the job ({e}); try again later"))); let programs: Vec<&str> = match &work { - Work::One => request.get("qasm").and_then(Value::as_str).into_iter().collect(), + Work::One | Work::Planned(_) => request.get("qasm").and_then(Value::as_str).into_iter().collect(), Work::Set { items, .. } => items.iter().filter_map(|i| i.request.get("qasm").and_then(Value::as_str)).collect(), }; let mut digests = Digests { request: Some(self.store.put(&canonical).map_err(unkept)?), ..Digests::default() }; @@ -845,7 +852,7 @@ impl Service { } }; match &job.work { - Work::One => push(&job.plan.method, job.plan.work, r, &r["energy"]), + Work::One | Work::Planned(_) => push(&job.plan.method, job.plan.work, r, &r["energy"]), // A set's items are timed one by one; the set's energy covers them all. Work::Set { plans, .. } => { for (it, p) in r["items"].as_array().into_iter().flatten().zip(plans) { @@ -998,7 +1005,7 @@ impl Service { j.started_ms = Some(now_ms()); let _ = self.keep(j); let input = match &j.work { - Work::One => json!({ "request": j.request, "plan": j.plan }), + Work::One | Work::Planned(_) => json!({ "request": j.request, "plan": j.plan }), Work::Set { items, plans } => json!({ "set": items.iter().zip(plans).map(|(i, p)| json!({ "request": i.request, "plan": p })).collect::>() }), }; Some((input, matches!(j.plan.method.as_str(), "statevector_single" | "cutrank_single") || matches!(&j.work, Work::Set { plans, .. } if plans.iter().any(|p| matches!(p.method.as_str(), "statevector_single" | "cutrank_single"))), others)) @@ -1102,10 +1109,15 @@ impl Service { fn seal(&self, request: &Value, work: &Work, out: Value, figure: Value, elapsed_ms: u64) -> Result<(Value, Value), String> { let signer = self.sealer.get().ok_or("the service has no signing key")?; match work { - Work::One => { + Work::One | Work::Planned(_) => { let mut r = out; // Inside the result, so the receipt seals the figure and its class. r["energy"] = figure; + // A contract's reasoning, and what it kept against the figure. + if let Work::Planned(reasoning) = work { + planner::attach(&mut r, reasoning); + planner::finish(request, &mut r, None); + } let receipt = signer.seal(request, &r); Ok((r, receipt)) } @@ -1170,7 +1182,10 @@ impl Service { }); // The admitted memory, with room for the process itself. let limit = (mib + 256) << 20; - let deadline = Instant::now() + self.config.job_timeout; + // A contract's deadline, where it is sooner than the job's limit: this host + // can stop a run, so one past it is stopped. + let asked = planner::Contract::read(&input["request"]).ok().flatten().and_then(|c| c.deadline_seconds).and_then(|d| Duration::try_from_secs_f64(d).ok()).filter(|d| *d < self.config.job_timeout); + let deadline = Instant::now() + asked.unwrap_or(self.config.job_timeout); let mut peak = 0u64; let mut reading = None; let mut after = None; @@ -1206,7 +1221,10 @@ impl Service { if Instant::now() > deadline { kill(pid); let _ = child.wait().await; - break Err(format!("the job ran past {} s; it was stopped", self.config.job_timeout.as_secs())); + break Err(match asked { + Some(d) => tag(refusal::DEADLINE_PASSED, format!("the job ran past its contract's deadline of {} s, though it was planned to take less; it was stopped, and nothing was sealed", d.as_secs_f64())), + None => format!("the job ran past {} s; it was stopped", self.config.job_timeout.as_secs()), + }); } if exited.is_none() { match tokio::time::timeout(Duration::from_millis(200), child.wait()).await { diff --git a/wai/wai-quantum-service/src/mcp.rs b/wai/wai-quantum-service/src/mcp.rs index 3aa1cbf77..0ee1af45c 100644 --- a/wai/wai-quantum-service/src/mcp.rs +++ b/wai/wai-quantum-service/src/mcp.rs @@ -235,19 +235,21 @@ fn tool_list() -> Value { "mitigate": wai_quantum::engine::mitigate::schema(), "pulse": wai_quantum::engine::pulse::options_schema(), "source": wai_quantum::engine::formats::source_schema(), - "params": { "type": "object", "additionalProperties": { "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read; a parameter left without one is refused (J050). In a sweep, the parameters it fixes." } + "params": { "type": "object", "additionalProperties": { "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read; a parameter left without one is refused (J050). In a sweep, the parameters it fixes." }, + "contract": wai_quantum::engine::planner::contract_schema() }); let mut on_target = json!({ "type": "object", "required": ["target"], "anyOf": wai_quantum::engine::formats::program_required(), "properties": job_props.clone() }); on_target["properties"].as_object_mut().map(|o| o.remove("method")); // A set: the job's fields, shared by every item, and its programs or its sweep. let mut set_props = job_props.clone(); - set_props.as_object_mut().map(|o| o.remove("source")); + set_props.as_object_mut().map(|o| { o.remove("source"); o.remove("contract"); }); set_props["qasm"] = json!({ "type": "string", "description": "With sweep: the program, which declares the inputs the sweep gives values (`input uint n;`, `input float theta;`, `input angle phi;`)." }); set_props["programs"] = json!({ "type": "array", "minItems": 1, "maxItems": wai_quantum::engine::sets::MAX_ITEMS, "items": { "anyOf": [{ "type": "string" }, { "type": "object", "required": ["qasm"] }] }, "description": "The set's programs: each a program's text, or a job ({\"qasm\", …}) whose own fields win over the set's." }); set_props["sweep"] = json!({ "type": "object", "additionalProperties": { "type": "array", "minItems": 1, "items": { "type": "number" } }, "description": "Each input of qasm and its values: every combination runs, the names in sorted order, the first varying slowest; an integer input's values are whole numbers." }); let mut plan_props = set_props.clone(); plan_props["qasm"] = job_props["qasm"].clone(); plan_props["source"] = job_props["source"].clone(); + plan_props["contract"] = job_props["contract"].clone(); // A run's key, which a plan does not take. let key = json!({ "type": "string", "minLength": 1, "maxLength": crate::jobs::KEY_MAX, "pattern": "^[!#-\\[\\]-~]+$", "description": "A key of your making that names this run, so that a call sent again is not a second job: the same key with the same arguments answers with the job it names, for as long as the job is kept, rather than running another; the same key with other arguments is refused (J034). Make it unguessable (a UUID). A job the service interrupted is run again under its key. Without a key, every call is a new job." }); for props in [&mut job_props, &mut set_props, &mut on_target["properties"]] { diff --git a/wai/wai-quantum-service/tests/contract.rs b/wai/wai-quantum-service/tests/contract.rs new file mode 100644 index 000000000..94c4b7a6f --- /dev/null +++ b/wai/wai-quantum-service/tests/contract.rs @@ -0,0 +1,133 @@ +//! A contract on the free job service, over HTTP, with its worker: what meets it +//! runs, its reasoning sealed; what does not is refused with every route's +//! reason; the service never reaches a provider; and a deadline it can hold a run +//! to, it holds. + +use serde_json::{Value, json}; +use std::io::{Read, Write}; +use std::net::{TcpListener, TcpStream}; +use std::path::Path; +use std::process::{Child, Command, Stdio}; +use std::time::{Duration, Instant}; + +fn free_port() -> u16 { + TcpListener::bind("127.0.0.1:0").unwrap().local_addr().unwrap().port() +} + +fn http(port: u16, method: &str, path: &str, body: Option<&Value>) -> (u16, Value) { + let mut s = TcpStream::connect(("127.0.0.1", port)).unwrap(); + s.set_read_timeout(Some(Duration::from_secs(120))).unwrap(); + let text = body.map(Value::to_string).unwrap_or_default(); + write!(s, "{method} {path} HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{text}", text.len()).unwrap(); + let mut out = String::new(); + s.read_to_string(&mut out).unwrap(); + let status = out.split_whitespace().nth(1).and_then(|c| c.parse().ok()).unwrap_or(0); + let body = out.split_once("\r\n\r\n").map(|(_, b)| b.to_string()).unwrap_or_default(); + (status, serde_json::from_str(&body).unwrap_or(Value::Null)) +} + +fn start(dir: &Path, port: u16) -> Child { + let child = Command::new(env!("CARGO_BIN_EXE_wai-quantum-service")) + .arg("serve") + .env("WAI_QSVC_ADDR", format!("127.0.0.1:{port}")) + .env("WAI_QSVC_STORE", dir.join("store")) + .env("WAI_QSVC_KEY", dir.join("signing.key")) + .env("WAI_QSVC_JOB_GB", "2") + .env("WAI_QSVC_BUDGET_GB", "4") + .env("WAI_QSVC_WORKERS", "1") + .env("WAI_QSVC_ENERGY", "0") + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .expect("the service starts"); + let t = Instant::now(); + while TcpStream::connect(("127.0.0.1", port)).is_err() || http(port, "GET", "/v1/health", None).0 != 200 { + assert!(t.elapsed() < Duration::from_secs(60), "the service did not answer"); + std::thread::sleep(Duration::from_millis(50)); + } + child +} + +fn until_done(port: u16, id: &str) -> Value { + let t = Instant::now(); + loop { + let (_, j) = http(port, "GET", &format!("/v1/jobs/{id}"), None); + if ["done", "failed", "cancelled", "interrupted"].contains(&j["status"].as_str().unwrap_or("")) { + return j; + } + assert!(t.elapsed() < Duration::from_secs(120), "{id} did not finish: {j}"); + std::thread::sleep(Duration::from_millis(50)); + } +} + +struct Service(Child, std::path::PathBuf); + +impl Drop for Service { + fn drop(&mut self) { + let _ = self.0.kill(); + let _ = self.0.wait(); + let _ = std::fs::remove_dir_all(&self.1); + } +} + +const BELL: &str = "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n"; + +#[test] +fn a_contract_is_met_or_refused_and_the_service_never_reaches_a_provider() { + let dir = std::env::temp_dir().join(format!("wai-qsvc-contract-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(&dir).unwrap(); + let port = free_port(); + let _service = Service(start(&dir, port), dir.clone()); + + // Met: its reasoning sealed, and the receipt held to it. + let req = json!({ "qasm": BELL, "shots": 200, "contract": { "exactness": "exact", "deadline_seconds": 60, "providers": "allowed" } }); + let (code, made) = http(port, "POST", "/v1/jobs", Some(&req)); + assert_eq!(code, 202, "{made}"); + let job = until_done(port, made["id"].as_str().unwrap()); + assert_eq!(job["status"], "done", "{job}"); + let r = &job["result"]; + assert_eq!(r["planner"]["choice"], "method:stabilizer", "{}", r["planner"]); + let c = wai_quantum::engine::job::check(&job); + assert!(c.valid(), "{:?}", c.reasons); + assert_eq!(r["planner"]["host"]["providers"], json!([]), "the service brings none"); + assert!(r["planner"]["routes"].as_array().unwrap().iter().all(|x| x["kind"] == "local"), "{}", r["planner"]); + assert_eq!(r["planner"]["kept"]["deadline"]["kept"], true, "{}", r["planner"]["kept"]); + assert_eq!(r["planner"]["stable"]["choice"], false, "providers allowed makes a choice the host's"); + // The same again, what a host that reaches none owes: run for this job alone. + let plain = json!({ "qasm": BELL, "shots": 200 }); + let (_, made) = http(port, "POST", "/v1/jobs", Some(&plain)); + let plain_job = until_done(port, made["id"].as_str().unwrap()); + assert_eq!(plain_job["result"]["counts"], r["counts"], "the same seed, the same method, the same counts"); + assert!(plain_job["result"].get("planner").is_none()); + + // A dry run shows every route, and the refused one every reason. + let (_, dry) = http(port, "POST", "/v1/jobs", Some(&json!({ "qasm": BELL, "dry_run": true, "contract": { "exactness": "exact" } }))); + assert_eq!((dry["accepted"].as_bool(), dry["method"].as_str(), dry["planner"]["choice"].as_str()), (Some(true), Some("stabilizer"), Some("method:stabilizer")), "{dry}"); + let (_, dry) = http(port, "POST", "/v1/jobs", Some(&json!({ "qasm": BELL, "dry_run": true, "contract": { "exactness": "measured", "providers": "allowed" } }))); + assert_eq!((dry["accepted"].as_bool(), dry["refusal"]["code"].as_str()), (Some(false), Some("J071")), "{dry}"); + assert!(dry["planner"]["routes"].as_array().unwrap().iter().all(|x| x["rejected"]["code"] == "class" || x["rejected"]["code"] == "cannot"), "{dry}"); + + // Asked for a device, for a provider by name, or for energy it has not metered: refused. + for (req, code_want) in [ + (json!({ "qasm": BELL, "contract": { "exactness": "measured", "providers": "allowed" } }), "J071"), + (json!({ "qasm": BELL, "provider": "lab", "contract": { "providers": "allowed" } }), "J002"), + (json!({ "qasm": BELL, "contract": { "max_joules": 1000 } }), "J071"), + (json!({ "qasm": BELL, "contract": { "exact": true } }), "J070"), + (json!({ "programs": [BELL, BELL], "contract": {} }), "J073"), + ] { + let (code, body) = http(port, "POST", "/v1/jobs", Some(&req)); + assert_eq!(code, 400, "{req}: {body}"); + assert_eq!(body["code"], code_want, "{req}: {body}"); + } + + // A run past its deadline is stopped: this one's nominal time counts its state, + // and its million shots are what takes the time. + let slow = json!({ "qasm": "OPENQASM 3.0;\nqubit[24] q;\nbit[24] c;\nrx(0.3) q[0];\nc = measure q;\n", "method": "statevector", "shots": 1000000, "contract": { "deadline_seconds": 0.05 } }); + let (code, made) = http(port, "POST", "/v1/jobs", Some(&slow)); + assert_eq!(code, 202, "{made}"); + let job = until_done(port, made["id"].as_str().unwrap()); + assert_eq!(job["status"], "failed", "{job}"); + assert!(job["error"].as_str().unwrap().ends_with("[J074]"), "{job}"); + assert!(job.get("result").is_none(), "nothing was sealed: {job}"); +} diff --git a/wai/wai-quantum/docs/job-refusals.md b/wai/wai-quantum/docs/job-refusals.md index 87384a3d3..0514bf3cf 100644 --- a/wai/wai-quantum/docs/job-refusals.md +++ b/wai/wai-quantum/docs/job-refusals.md @@ -85,6 +85,11 @@ browser engine. A test holds this page to the code's table. | `J063` | refused | A component the registry does not take: a name its kind holds already (a built-in's among them), a name or version that is empty or not plain text, a descriptor that is not a JSON object, a channel on other than one or two qubits, or a pass whose check states no bound. | | `J064` | refused | A registered component's answer that breaks the engine's contract: a method's result without an accuracy class it declared, or one that writes a member the engine writes (method, qubits, gates, compiled, repaired, engine, schema, components, receipt, verdict); a pass's gates on qubits the program does not have, or that do not read back; a front end's program that does not read. Nothing it gave is returned. | | `J065` | refused | An intent on a job whose noise names a registered channel: the intent checks model the built-in channels alone, so the check is refused rather than made against another model. | +| `J070` | refused | A contract that does not read: not an object, a member a contract does not have, an exactness that is no class, a max_cost that is not an amount in decimals and a currency, a deadline or an energy ceiling that is not above zero, providers that is neither never nor allowed, or a job that names a provider while its contract says never. | +| `J071` | refused | No route this host can see meets the contract: each route's price or reason is listed, so the contract or the job can be changed. Nothing fell back to a route the contract does not allow. | +| `J072` | refused | A method's result whose accuracy class does not meet the contract, as can only happen to a plan that is not the planner's: nothing it gave is returned. | +| `J073` | refused | A contract where it cannot be honoured: on a set or an item of one (each program runs under its own contract, alone), or on a build with no planner. It is refused rather than read as absent. | +| `J074` | refused | A run stopped at its contract's deadline, by a host that can stop one: the estimate it was planned on was wrong here, and nothing was sealed. | | `J100` | dropped | A line of an answer that is not a statement (`name = View(...)`), a program (a fenced `qasm` block with its name), a comment or a marker: left out. | | `J101` | dropped | A view the answer layer does not have: left out (the views are listed in the layer's specification). | | `J102` | dropped | An `@` call the engine does not have: the statement is left out. | diff --git a/wai/wai-quantum/schemas/job-request.v1.json b/wai/wai-quantum/schemas/job-request.v1.json index 96c48c65a..4f2b9c60d 100644 --- a/wai/wai-quantum/schemas/job-request.v1.json +++ b/wai/wai-quantum/schemas/job-request.v1.json @@ -404,6 +404,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } }, "$defs": { diff --git a/wai/wai-quantum/schemas/job-result.v1.json b/wai/wai-quantum/schemas/job-result.v1.json index 18486d699..5d3fd5c18 100644 --- a/wai/wai-quantum/schemas/job-result.v1.json +++ b/wai/wai-quantum/schemas/job-result.v1.json @@ -717,6 +717,12 @@ } } } + }, + "planner": { + "$ref": "#/$defs/planner" + }, + "shadow": { + "$ref": "#/$defs/shadow" } }, "$defs": { @@ -1505,6 +1511,596 @@ "description": "Beside a registered component: the engine does not certify it." } } + }, + "route_money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "route_price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "$ref": "#/$defs/route_money" + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "route": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "$ref": "#/$defs/route_price" + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "$ref": "#/$defs/route" + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "$ref": "#/$defs/route_price" + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "$ref": "#/$defs/accuracy" + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } } diff --git a/wai/wai-quantum/schemas/plan.v1.json b/wai/wai-quantum/schemas/plan.v1.json index b5107e3ae..e69789a48 100644 --- a/wai/wai-quantum/schemas/plan.v1.json +++ b/wai/wai-quantum/schemas/plan.v1.json @@ -2,7 +2,7 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://git.transaction.science/Transaction-Science/open-standards/raw/branch/main/wai/wai-quantum/schemas/plan.v1.json", "title": "wai.quantum.plan/1", - "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it.", + "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it. A job with a contract carries the planner's reasoning.", "type": "object", "required": [ "method", @@ -32,6 +32,9 @@ }, "target": { "$ref": "job-result.v1.json#/$defs/target_placement" + }, + "planner": { + "$ref": "job-result.v1.json#/$defs/planner" } } } diff --git a/wai/wai-quantum/src/engine/catalog.rs b/wai/wai-quantum/src/engine/catalog.rs index cec85febf..b49c72d12 100644 --- a/wai/wai-quantum/src/engine/catalog.rs +++ b/wai/wai-quantum/src/engine/catalog.rs @@ -1134,8 +1134,22 @@ pub(crate) fn reads_own<'a>(reg: &'a Registry, v: &Value) -> Option<&'a dyn Meth v.get("method").and_then(Value::as_str).and_then(|n| reg.method(n)).filter(|m| m.reads_program()) } -/// [`plan`] through `reg`: its methods, channels and passes. +/// [`plan`] through `reg`: its methods, channels and passes. A job with a +/// `contract` is the planner's ([`super::planner`]); one with none plans as it +/// always has, byte for byte. pub(crate) fn plan_in(reg: &Registry, v: &Value, job_bytes: u64) -> Result { + if v.get("contract").is_some_and(|c| !c.is_null()) { + #[cfg(feature = "quantum_receipt")] + return super::planner::plan_in(reg, v, job_bytes); + #[cfg(not(feature = "quantum_receipt"))] + return Err(tag(refusal::CONTRACT_HERE, "this build has no planner under a contract (the engine's quantum_receipt feature)")); + } + plan_plain(reg, v, job_bytes) +} + +/// The plan of a job taken without its contract, as `auto` or the method it +/// names gives it. +pub(crate) fn plan_plain(reg: &Registry, v: &Value, job_bytes: u64) -> Result { if let Some(m) = reads_own(reg, v) { return m.plan(&Job::new(reg, v, job_bytes, None, &[])); } @@ -1163,7 +1177,7 @@ pub(crate) fn plan_in(reg: &Registry, v: &Value, job_bytes: u64) -> Result) -> Result { +pub(crate) fn choose_placed(job: &Job<'_>) -> Result { use super::fabric::Ask; let r = job.request()?; let ask = super::fabric::asked(job.json())?; @@ -1177,13 +1191,18 @@ fn choose_placed(job: &Job<'_>) -> Result { /// `p` for the job `v`, read as `r`, admitting the memory its intents' check /// takes beside the run, where it fits (super::verdict). fn with_intent(reg: &Registry, v: &Value, r: &Request, mut p: Plan, job_bytes: u64) -> Result { - if let Some(i) = v.get("intent").filter(|i| !i.is_null()) { - let need = super::verdict::intent_memory_in(reg, v, &super::verdict::intents(i)?, r.program.n_qubits, r.noise.is_some(), job_bytes); - p.memory_bytes = p.memory_bytes.max(need); - } + p.memory_bytes = p.memory_bytes.max(intent_need(reg, v, r, job_bytes)?); Ok(p) } +/// The memory the job's intents' check takes beside the run, where it fits. +pub(crate) fn intent_need(reg: &Registry, v: &Value, r: &Request, job_bytes: u64) -> Result { + match v.get("intent").filter(|i| !i.is_null()) { + Some(i) => Ok(super::verdict::intent_memory_in(reg, v, &super::verdict::intents(i)?, r.program.n_qubits, r.noise.is_some(), job_bytes)), + None => Ok(0), + } +} + /// The method `m`'s plan for `job`: refused for a method that models no /// noise when the job has a noise model, then the method's own plan, then /// every channel the job names held to what the method takes (each refusal diff --git a/wai/wai-quantum/src/engine/job.rs b/wai/wai-quantum/src/engine/job.rs index eede2b1b2..61f237405 100644 --- a/wai/wai-quantum/src/engine/job.rs +++ b/wai/wai-quantum/src/engine/job.rs @@ -23,6 +23,10 @@ pub fn plan_and_run(request: &Value, job_bytes: u64) -> Result<(catalog::Plan, V if let Some(at) = receipt::inexact_number(request) { return Err(super::refusal::tag(super::refusal::LIMIT, format!("`{at}`: a whole number here must be within ±9007199254740991 (2^53 − 1), so that every JSON reader reads it alike and the receipt binds it"))); } + // A contract's reasoning travels with its result (engine::planner). + if super::planner::has_contract(request) { + return super::planner::plan_and_run_in(super::registry::Registry::builtins(), request, &super::planner::Host::new(job_bytes)); + } let plan = catalog::plan(request, job_bytes)?; let result = super::run::run(request, &plan)?; Ok((plan, result)) @@ -32,6 +36,7 @@ pub fn plan_and_run(request: &Value, job_bytes: u64) -> Result<(catalog::Plan, V /// form: `energy` inside the result, and the result sealed with `key`. pub fn seal(request: &Value, plan: &catalog::Plan, mut result: Value, key: &SigningKey, energy: Value) -> Value { result["energy"] = energy; + super::planner::finish(request, &mut result, None); let seal = receipt::seal(key, request, &result); result["receipt"] = seal; json!({ @@ -88,6 +93,9 @@ pub struct Check { /// to state it: the class, whether its fields are stated, its counts' /// source and how the device was asked to run the program. pub provider: Option, + /// For a contract job, what its reasoning says (§8.6): the route chosen, + /// the class wanted and given, what was kept, and the shadow. + pub planner: Option, } impl Check { @@ -104,6 +112,9 @@ impl Check { if let Some(p) = &self.provider { v["provider"] = p.clone(); } + if let Some(p) = &self.planner { + v["planner"] = p.clone(); + } v } @@ -181,6 +192,7 @@ pub fn check(job: &Value) -> Check { // Nothing to check it against, but the result still says what it is. let mut c = Check::only(NO_RECEIPT); c.provider = super::provider::check(request, result).1; + c.planner = super::planner::statement(result); return c; }; let mut c = check_parts(request, result, seal); @@ -212,6 +224,10 @@ fn check_parts(request: &Value, result: &Value, seal: &Value) -> Check { c.push(r); } c.provider = said; + for r in super::planner::check(request, &bare) { + c.push(r); + } + c.planner = super::planner::statement(&bare); c } diff --git a/wai/wai-quantum/src/engine/mod.rs b/wai/wai-quantum/src/engine/mod.rs index 0338ed620..062dda2f0 100644 --- a/wai/wai-quantum/src/engine/mod.rs +++ b/wai/wai-quantum/src/engine/mod.rs @@ -17,6 +17,13 @@ //! form. //! - [`job`] (with `quantum_receipt`): a job end to end, planned, run and //! sealed, in the service's form; its check; and a program's lint. +//! - [`planner`] (with `quantum_receipt`): the planner under a contract. A job +//! says how exact its answer must be, what it may cost, by when, on how much +//! energy, and whether a provider may give it; every route the host can see +//! is priced with what is really known, those that cannot meet the contract +//! are rejected, the cheapest of the rest is chosen, and the reasoning is +//! sealed in the result. Nothing falls back in silence. A provider's answer +//! is shadowed by a classical method wherever one can reach it. //! - [`provider`] (with `quantum_receipt`): a job on the person's own //! provider (a processor, an on-premises device or a simulator, reached by //! a host that holds their credentials): what it may ask, its measured @@ -228,6 +235,8 @@ pub mod novelty; pub mod provider; #[cfg(feature = "quantum_receipt")] pub mod receipt; +#[cfg(feature = "quantum_receipt")] +pub mod planner; pub mod pulse; pub mod refusal; pub mod registry; diff --git a/wai/wai-quantum/src/engine/planner.rs b/wai/wai-quantum/src/engine/planner.rs new file mode 100644 index 000000000..8e1f72e12 --- /dev/null +++ b/wai/wai-quantum/src/engine/planner.rs @@ -0,0 +1,1373 @@ +//! The planner under a contract: a job says what it wants of an answer (how +//! exact, what it may cost, by when, on how much energy, and whether a +//! provider may give it), and the planner lists every route it can see, prices +//! each with what is really known, rejects those that cannot meet the +//! contract, and chooses the cheapest that can. Its reasoning goes in the +//! result, where the receipt seals it. +//! +//! A job with no `contract` never comes here, and gives the bytes it gave. +//! +//! ```json fragment +//! "contract": { +//! "exactness": "exact", +//! "max_cost": { "amount": "0.50", "currency": "USD" }, +//! "deadline_seconds": 30, +//! "max_joules": 500, +//! "providers": "allowed" +//! } +//! ``` +//! +//! # No silent fallback +//! +//! A route is rejected unless it meets every member of the contract, and an +//! unknown is never read as a value that passes: a time nobody can state does +//! not meet a deadline, a price nobody states does not meet a ceiling, and an +//! energy no one estimates does not meet an energy ceiling. So nothing falls +//! back from exact to approximate, from a simulator to a device, or the +//! reverse. If no route is left, the job is refused ([`refusal::NOTHING_MEETS`]) +//! with each route's reason. +//! +//! A contract that names no class keeps the class `auto` would give: `auto`'s +//! pick stands while it meets the rest of the contract, and when it does not, +//! only a route at least as exact may take its place. A device's counts are in +//! no classical class, so a device is reached only by asking for `measured` +//! (or `any`), or by naming the provider. +//! +//! # What is priced +//! +//! - A local method: free of money, its memory and work as the planner counts +//! them, its time at the planner's nominal rate ([`catalog::nominal_rate`]), +//! where its work predicts its time, and its energy only where the host has +//! an estimate ([`Host::with_joules`]). +//! - A provider: the provider's own estimate, and what that leaves out, named +//! in `leaves_out`. A host gathers it ([`Quote`]): the engine never reaches +//! a provider itself. +//! +//! # What is stable across hosts +//! +//! `stable.digest` covers what the local routes that depend on nothing of the +//! host cost: the same for the same request and job memory, on every host of +//! one engine. `stable.choice` says whether the choice itself is. A provider +//! route, a method on a GPU and a registered method are the host's, and marked +//! `host_dependent`. +//! +//! # The shadow +//! +//! When a provider answers a contract job, a classical method that can reach +//! the same counts within the contract runs too, and the result carries both +//! with their distance ([`shadow`]). When none can, the result says so and why. +//! +//! The rules a verifier holds all this to are in +//! `wai/extensions/quantum-providers.md` section 8.6; [`check`] is the +//! reference's, and [`recheck`] runs what can be run again. + +use super::catalog::{self, Plan, Request}; +use super::fabric; +use super::receipt; +use super::refusal::{self, tag}; +use super::registry::{Identity, Job, Kind, Method, Registry}; +use serde_json::{Map, Value, json}; +use std::cmp::Ordering; + +/// The reasoning's format. +pub const FORMAT: &str = "wai.quantum.planner/1"; + +/// Every class a contract may want. `any` takes every route, and says so. +pub const CLASSES: [&str; 9] = ["bit-exact", "exact", "single", "bounded", "estimate", "heuristic", "measured", "simulated", "any"]; + +/// How long a shadow may be expected to take when the contract states no +/// deadline: a shadow is a check nobody asked to wait for, so it stays small. +pub const SHADOW_MAX_SECONDS: f64 = 300.0; + +/// A shadow's seed is the job's plus this, modulo 2^53: its own stream, so that +/// a seeded simulator's counts are not its counts by construction. +pub const SHADOW_SEED_OFFSET: u64 = 1 << 32; + +/// The reasons a verifier gives (section 8.6). +/// +/// The request's `contract` is not of its form. +pub const CONTRACT_FORM: &str = "contract_form"; +/// A contract job's `planner` is missing or not of its form, or a job with no +/// contract carries one. +pub const PLANNER_FORM: &str = "planner_form"; +/// A route's outcome is not what the contract and its price give. +pub const PLANNER_ROUTE: &str = "planner_route"; +/// The choice is not the route the rule picks, or not the route that ran. +pub const PLANNER_CHOICE: &str = "planner_choice"; +/// `stable` is not what the routes give. +pub const PLANNER_STABLE: &str = "planner_stable"; +/// `kept` is not what the contract and the result give. +pub const PLANNER_KEPT: &str = "planner_kept"; +/// The result's class does not meet the class wanted. +pub const CONTRACT_CLASS: &str = "contract_class"; +/// A provider's contract job's shadow is missing or not what its counts give. +pub const SHADOW: &str = "shadow"; + +/// Whether a result of class `got` meets a contract that wants `wanted`: the +/// table in section 8.6, not a ladder. A class with a stated error does not +/// meet one that asks for a rigorous bound, and a device's counts are in no +/// classical class. +pub fn meets(wanted: &str, got: &str) -> bool { + match wanted { + "any" => true, + "bit-exact" => got == "bit-exact", + "exact" => matches!(got, "bit-exact" | "exact"), + "single" => matches!(got, "bit-exact" | "exact" | "single"), + "bounded" => matches!(got, "bit-exact" | "exact" | "bounded"), + "estimate" => matches!(got, "bit-exact" | "exact" | "bounded" | "estimate"), + "heuristic" => matches!(got, "bit-exact" | "exact" | "single" | "bounded" | "estimate" | "heuristic"), + "measured" => got == "measured", + "simulated" => got == "simulated", + _ => false, + } +} + +/// How exact a class is, for a shadow's choice among classical methods: the +/// strongest first. +fn strength(class: &str) -> u32 { + match class { + "bit-exact" => 0, + "exact" => 1, + "single" => 2, + "bounded" => 3, + "estimate" => 4, + "heuristic" => 5, + _ => 6, + } +} + +/// A request's contract, read and checked. +#[derive(Clone, Debug, Default, PartialEq)] +#[non_exhaustive] +pub struct Contract { + /// The class wanted; one of [`CLASSES`]. + pub exactness: Option, + /// The most it may cost, its amount in decimals and its currency. + pub max_cost: Option<(String, String)>, + /// When it must be done by, in seconds from when it starts. + pub deadline_seconds: Option, + /// The most energy it may take, in joules. + pub max_joules: Option, + /// Whether a provider may be used: `Some(true)` for `allowed`, + /// `Some(false)` for `never`, and `None` when the contract does not say, + /// which is `never`. + pub providers: Option, +} + +/// Whether a request holds a contract: a `contract` member other than `null`. +pub fn has_contract(v: &Value) -> bool { + v.get("contract").is_some_and(|c| !c.is_null()) +} + +/// Whether `s` is an amount in decimals: digits, and optionally `.` and digits. +pub fn is_decimal(s: &str) -> bool { + let (whole, frac) = s.split_once('.').map_or((s, None), |(a, b)| (a, Some(b))); + !whole.is_empty() && whole.bytes().all(|b| b.is_ascii_digit()) && frac.is_none_or(|f| !f.is_empty() && f.bytes().all(|b| b.is_ascii_digit())) +} + +/// Two amounts in decimals compared exactly, with no double between them. +pub fn decimal_cmp(a: &str, b: &str) -> Ordering { + let parts = |s: &'_ str| -> (String, String) { + let (whole, frac) = s.split_once('.').unwrap_or((s, "")); + let w = whole.trim_start_matches('0').to_string(); + (w, frac.trim_end_matches('0').to_string()) + }; + let ((wa, fa), (wb, fb)) = (parts(a), parts(b)); + wa.len().cmp(&wb.len()).then_with(|| wa.cmp(&wb)).then_with(|| fa.cmp(&fb)) +} + +impl Contract { + /// The contract of the job `v`, or `None` when it has none. Anything else + /// that does not read is refused ([`refusal::CONTRACT_FORM`]): a member read + /// as absent would be a requirement dropped in silence. + pub fn read(v: &Value) -> Result, String> { + let Some(c) = v.get("contract").filter(|c| !c.is_null()) else { return Ok(None) }; + let bad = |m: String| tag(refusal::CONTRACT_FORM, m); + let Some(o) = c.as_object() else { return Err(bad("\"contract\" is an object: exactness, max_cost, deadline_seconds, max_joules and providers, each optional".into())) }; + if let Some(k) = o.keys().find(|k| !["exactness", "max_cost", "deadline_seconds", "max_joules", "providers"].contains(&k.as_str())) { + return Err(bad(format!("contract: {k:?} is no member of a contract: it takes exactness, max_cost, deadline_seconds, max_joules and providers"))); + } + let member = |k: &str| o.get(k).filter(|x| !x.is_null()); + let exactness = match member("exactness") { + None => None, + Some(e) => match e.as_str().filter(|s| CLASSES.contains(s)) { + Some(s) => Some(s.to_string()), + None => return Err(bad(format!("contract: exactness is one of {}, not {e}", CLASSES.join(", ")))), + }, + }; + let max_cost = match member("max_cost") { + None => None, + Some(m) => { + let (a, cur) = (m.get("amount").and_then(Value::as_str), m.get("currency").and_then(Value::as_str)); + match (a.filter(|a| is_decimal(a)), cur.filter(|c| !c.is_empty()), m.as_object().map(Map::len)) { + (Some(a), Some(cur), Some(2)) => Some((a.to_string(), cur.to_string())), + _ => return Err(bad(format!("contract: max_cost is {{\"amount\": \"0.50\", \"currency\": \"USD\"}}, the amount in decimals as a string, not {m}"))), + } + } + }; + let positive = |k: &str| -> Result, String> { + match member(k) { + None => Ok(None), + Some(x) => match x.as_f64().filter(|x| x.is_finite() && *x > 0.0) { + Some(x) => Ok(Some(x)), + None => Err(bad(format!("contract: {k} is a number above zero, not {x}"))), + }, + } + }; + let deadline_seconds = positive("deadline_seconds")?; + let max_joules = positive("max_joules")?; + let providers = match member("providers") { + None => None, + Some(x) => match x.as_str() { + Some("never") => Some(false), + Some("allowed") => Some(true), + _ => return Err(bad(format!("contract: providers is never or allowed, not {x}"))), + }, + }; + Ok(Some(Contract { exactness, max_cost, deadline_seconds, max_joules, providers })) + } +} + +/// What a host brings of one of the person's providers: what it would run, what +/// its provider's estimate says, and what the estimate leaves out. Asking for +/// it spends nothing. The engine never reaches a provider itself. +#[derive(Clone, Debug, PartialEq)] +#[non_exhaustive] +pub struct Quote { + /// The person's name for the provider. + pub name: String, + /// The device, as the result would name it. + pub device: String, + /// `silicon`, or `simulator` or `emulator`, alone or with what it is. + pub provenance: String, + /// The provider states this simulator's results are approximate. + pub approximate: bool, + /// Why this provider cannot run this job, when it cannot: the rest is then + /// not known. + pub cannot: Option, + /// What it costs: `{"free": true}`, `{"free": false, "amount", "currency"}` + /// with an optional `unit`, or `{"free": false, "unknown": "why"}`. + pub money: Value, + /// How long the provider says it takes, queue included. + pub seconds: Option, + /// What the estimate leaves out: words of [`LEFT_OUT`]. + pub leaves_out: Vec, + /// What the job would ask of the device: its shots and the program's + /// gates, and its expected success when a calibration states one. + pub program: Value, +} + +/// What an estimate can leave out (section 8.6). +pub const LEFT_OUT: [&str; 6] = ["time", "amount", "energy", "mitigation", "decoder", "charged"]; + +impl Quote { + /// A provider that can run the job, with nothing known of it yet: its + /// cost unknown and its time not stated, each left out until a host says. + pub fn new(name: impl Into, device: impl Into, provenance: impl Into) -> Quote { + Quote { + name: name.into(), + device: device.into(), + provenance: provenance.into(), + approximate: false, + cannot: None, + money: json!({ "free": false, "unknown": "the provider states no cost" }), + seconds: None, + leaves_out: Vec::new(), + program: json!({}), + } + } + + /// A provider that cannot run the job, and why. + pub fn cannot(name: impl Into, why: impl Into) -> Quote { + let mut q = Quote::new(name, "", ""); + q.cannot = Some(why.into()); + q + } + + fn class(&self) -> &'static str { + match super::provider::class_of_provenance(&self.provenance) { + Some("measured") => "measured", + Some(_) => "simulated", + None => "unknown", + } + } +} + +/// An estimate of a job's energy before it runs, from a host's own readings: +/// its joules and what they rest on, or why there is none. +pub type Joules<'a> = dyn Fn(&Plan) -> Result<(f64, String), String> + 'a; + +/// What a host brings to the planner. +#[non_exhaustive] +pub struct Host<'a> { + /// The memory one job may take here, bytes. + pub job_bytes: u64, + /// What each of the person's providers says of this job. + pub quotes: Vec, + /// The host's energy estimate, where it has one. + pub joules: Option<&'a Joules<'a>>, +} + +impl<'a> Host<'a> { + /// A host that reaches no provider and estimates no energy. + pub fn new(job_bytes: u64) -> Host<'a> { + Host { job_bytes, quotes: Vec::new(), joules: None } + } + + pub fn with_quotes(mut self, quotes: Vec) -> Host<'a> { + self.quotes = quotes; + self + } + + pub fn with_joules(mut self, joules: &'a Joules<'a>) -> Host<'a> { + self.joules = Some(joules); + self + } +} + +/// What the planner chose. +#[derive(Clone, Debug, PartialEq)] +#[non_exhaustive] +pub enum Choice { + /// One of the engine's methods, with its plan. + Local(Plan), + /// One of the person's providers, by name. + Provider(String), +} + +/// A contract met: the route chosen and the reasoning a result carries. +#[derive(Clone, Debug, PartialEq)] +#[non_exhaustive] +pub struct Decision { + pub choice: Choice, + pub reasoning: Value, +} + +/// A contract considered: the reasoning, with `choice` `null` and `refusal` +/// set when no route meets it. Nothing is refused here that a plan's surface +/// would want to show: each route's price or reason is in it. +#[derive(Clone, Debug, PartialEq)] +#[non_exhaustive] +pub struct Considered { + pub reasoning: Value, + pub plan: Option, + /// The refusal, ending with its code, when no route meets the contract. + pub refusal: Option, +} + +/// A whole number as JSON, or the double nearest it past what every reader reads +/// alike: a price is sealed, and an inexact whole number invalidates a receipt. +fn whole(x: u64) -> Value { + if x <= (1 << 53) - 1 { json!(x) } else { json!(x as f64) } +} + +fn is_gpu(method: &str) -> bool { + matches!(method, "statevector_single" | "cutrank_single") +} + +/// The class a method's result has at worst, as far as the plan can say: the +/// weakest it declares, or for the methods whose class the job fixes, that one. +fn class_of(m: &dyn Method, r: Option<&Request>, plan: Option<&Plan>, target: bool) -> String { + let worst = || m.classes().into_iter().max_by_key(|c| strength(c)).unwrap_or_else(|| "unknown".into()); + match (m.name(), r) { + ("stabilizer", Some(r)) => if r.noise.is_some() || target { "estimate".into() } else { "exact".into() }, + ("stabilizer_rank", Some(r)) => if ["terms", "epsilon"].iter().any(|k| r.options.get(*k).is_some_and(|x| !x.is_null())) { "estimate".into() } else { "exact".into() }, + // The table's precision is chosen by the memory the job has, and the plan says which. + ("cutrank", _) => match plan { + Some(p) if p.why.contains("single precision") => "single".into(), + _ => "exact".into(), + }, + _ => worst(), + } +} + +/// A local route's time: at the planner's nominal rate, where its work predicts +/// its time. +fn time_of(p: &Plan) -> Value { + match catalog::nominal_rate(&p.method) { + Some(rate) => json!({ "seconds": p.work as f64 / rate, "basis": "nominal" }), + None => json!({ "seconds": null, "why": format!("the work the planner counts for {} does not predict its time", p.method) }), + } +} + +/// A local route's energy: the host's estimate, or why there is none. +fn energy_of(p: &Plan, host: &Host<'_>) -> Value { + match host.joules { + None => json!({ "joules": null, "why": "this host estimates no job's energy before it runs" }), + Some(f) => match f(p) { + Ok((joules, basis)) => json!({ "joules": joules, "basis": basis }), + Err(why) => json!({ "joules": null, "why": why }), + }, + } +} + +fn local_route(m: &dyn Method, identity: Option<&Identity>, r: Option<&Request>, plan: Option<&Plan>, host: &Host<'_>, target: bool) -> Value { + let mut route = json!({ + "route": format!("method:{}", m.name()), + "kind": "local", + "method": m.name(), + "class": class_of(m, r, plan, target), + "host_dependent": is_gpu(m.name()) || identity.is_some_and(|i| !i.is_builtin()), + "price": null, + }); + if let Some(p) = plan { + route["price"] = json!({ + "money": { "free": true }, + "time": time_of(p), + "memory_bytes": whole(p.memory_bytes), + "work": whole(p.work), + "energy": energy_of(p, host), + "leaves_out": [], + }); + } + route +} + +fn provider_route(q: &Quote) -> Value { + let mut route = json!({ + "route": format!("provider:{}", q.name), + "kind": "provider", + "provider": q.name, + "class": q.class(), + "host_dependent": true, + "price": null, + }); + if q.cannot.is_some() { + route["class"] = json!("unknown"); + return route; + } + route["device"] = json!(q.device); + route["provenance"] = json!(q.provenance); + if q.approximate { + route["approximate"] = json!(true); + } + let time = match q.seconds { + Some(s) => json!({ "seconds": s, "basis": "provider" }), + None => json!({ "seconds": null, "why": "the provider's estimate states no time" }), + }; + route["price"] = json!({ + "money": q.money, + "time": time, + "memory_bytes": null, + "work": null, + "energy": { "joules": null, "why": "no provider states a job's energy before it runs" }, + "leaves_out": q.leaves_out, + "program": q.program, + }); + route +} + +/// What a route is held to. +struct Held<'a> { + contract: &'a Contract, + provider: Option<&'a str>, + method: Option<&'a str>, + fabric: Fab, + wanted: Option<&'a str>, + job_bytes: f64, +} + +#[derive(Clone, Copy, PartialEq)] +enum Fab { + Free, + Cpu, + Placed, +} + +fn fab_of(v: &Value) -> Fab { + match v.get("fabric") { + None | Some(Value::Null) => Fab::Free, + Some(Value::String(s)) if s == "auto" => Fab::Free, + Some(Value::String(s)) if s == "cpu" => Fab::Cpu, + _ => Fab::Placed, + } +} + +/// What a request names: a provider, or a method other than `auto`. +fn named(v: &Value) -> (Option<&str>, Option<&str>) { + let provider = v.get("provider").and_then(Value::as_str); + let method = if provider.is_some() { None } else { v.get("method").and_then(Value::as_str).filter(|m| *m != "auto") }; + (provider, method) +} + +/// The first rule of section 8.6 a route breaks, in its order, or `None` when +/// it meets the contract. Its class is judged before anything about its price, +/// so that the code says the same whatever a host can run. An unknown never +/// passes where something is asked of it. +fn gate(route: &Value, h: &Held<'_>) -> Option<&'static str> { + let name = route["route"].as_str().unwrap_or(""); + let (method, provider) = (name.strip_prefix("method:"), name.strip_prefix("provider:")); + match (h.provider, h.method) { + (Some(p), _) if provider != Some(p) => return Some("not_named"), + (None, Some(m)) if method != Some(m) => return Some("not_named"), + _ => {} + } + if h.provider.is_none() && h.method.is_none() { + match h.fabric { + Fab::Placed if method != Some("statevector") => return Some("fabric"), + Fab::Cpu if method.is_some_and(is_gpu) => return Some("fabric"), + _ => {} + } + } + let class = route["class"].as_str().unwrap_or(""); + // A provider that cannot run the job has no class to judge. + if class == "unknown" && route["price"].is_null() { + return Some("cannot"); + } + match h.wanted { + Some(w) if !meets(w, class) || (w == "simulated" && route["approximate"] == true) => return Some("class"), + None if provider.is_some() => return Some("class"), + _ => {} + } + let price = &route["price"]; + if !price.is_object() { + return Some("cannot"); + } + if price["memory_bytes"].as_f64().is_some_and(|m| m > h.job_bytes) { + return Some("memory"); + } + if provider.is_some() && h.provider.is_none() && h.contract.providers != Some(true) { + return Some("providers"); + } + if let Some(d) = h.contract.deadline_seconds { + match price["time"]["seconds"].as_f64() { + None => return Some("deadline_unknown"), + Some(s) if s > d => return Some("deadline"), + _ => {} + } + } + if provider.is_some() && price["money"]["free"] != true { + let (amount, currency) = (price["money"]["amount"].as_str().filter(|a| is_decimal(a)), price["money"]["currency"].as_str()); + match &h.contract.max_cost { + // A provider named by the job is the person's choice, as it is with + // no contract: its cost is shown, and it runs on their confirmation. + None if h.provider.is_some() => {} + None => return Some("cost_no_ceiling"), + Some((most, cur)) => match (amount, currency) { + (Some(a), Some(c)) if c == cur => { + if decimal_cmp(a, most) == Ordering::Greater { + return Some("cost"); + } + } + (Some(_), Some(_)) => return Some("cost_currency"), + _ => return Some("cost_unknown"), + }, + } + } + if let Some(j) = h.contract.max_joules { + match price["energy"]["joules"].as_f64() { + None => return Some("energy_unknown"), + Some(x) if x > j => return Some("energy"), + _ => {} + } + } + None +} + +/// Why a route was rejected, in a sentence, for a code [`gate`] gave. +fn gate_why(code: &str, route: &Value, h: &Held<'_>) -> String { + let price = &route["price"]; + let class = route["class"].as_str().unwrap_or("unknown"); + match code { + "not_named" => "the job names another route".to_string(), + "fabric" => "the job's placement on the fabric is not this route's".to_string(), + "class" => match h.wanted { + Some(w) if class == "heuristic" && matches!(w, "bit-exact" | "exact" | "single" | "bounded" | "estimate") => format!("its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants {w}"), + Some(w) if w == "simulated" && route["approximate"] == true => "its provider states this simulator is approximate, and the job wants a simulator's counts that are not".to_string(), + Some(w) => format!("its class is {class}, and the job wants {w}"), + None => format!("its class is {class}; the job names no class, and nothing the planner would do today gives this one: ask for measured or any, or name the provider"), + }, + "memory" => format!("it takes {} bytes, and a job here takes at most {}", price["memory_bytes"], h.job_bytes), + "providers" => "the contract does not allow a provider".to_string(), + "deadline_unknown" => format!("its time is not known, so it cannot be held to the deadline of {} s: {}", h.contract.deadline_seconds.unwrap_or(0.0), price["time"]["why"].as_str().unwrap_or("")), + "deadline" => format!("about {} s, past the deadline of {} s", price["time"]["seconds"], h.contract.deadline_seconds.unwrap_or(0.0)), + "cost_no_ceiling" => format!("{}: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider", money_said(&price["money"])), + "cost_unknown" => format!("{}: an unknown cost does not meet a ceiling", money_said(&price["money"])), + "cost_currency" => format!("{}, and the ceiling is in {}: the planner converts no currency", money_said(&price["money"]), h.contract.max_cost.as_ref().map_or("", |c| c.1.as_str())), + "cost" => format!("{}, above the ceiling of {} {}", money_said(&price["money"]), h.contract.max_cost.as_ref().map_or("", |c| c.0.as_str()), h.contract.max_cost.as_ref().map_or("", |c| c.1.as_str())), + "energy_unknown" => format!("its energy is not known, so it cannot be held to the ceiling of {} J: {}", h.contract.max_joules.unwrap_or(0.0), price["energy"]["why"].as_str().unwrap_or("")), + "energy" => format!("about {} J, above the ceiling of {} J", price["energy"]["joules"], h.contract.max_joules.unwrap_or(0.0)), + other => other.to_string(), + } +} + +fn money_said(m: &Value) -> String { + match (m["free"].as_bool(), m["amount"].as_str(), m["currency"].as_str(), m["unknown"].as_str()) { + (Some(true), ..) => "free".to_string(), + (_, Some(a), Some(c), _) => format!("{a} {c}"), + (_, _, _, Some(u)) => u.to_string(), + _ => "its cost is unknown".to_string(), + } +} + +/// Which of two routes that meet the contract is cheaper: less money (free +/// first), then less time to the millisecond (a stated time before an unknown +/// one), a local route before a provider's, less memory, and then by name, so +/// that the order is total and every verifier finds the same route. +fn cheaper(a: &Value, b: &Value) -> Ordering { + let money = |r: &Value| -> Option { if r["price"]["money"]["free"] == true { None } else { Some(r["price"]["money"]["amount"].as_str().unwrap_or("").to_string()) } }; + let money_order = match (money(a), money(b)) { + (None, None) => Ordering::Equal, + (None, Some(_)) => Ordering::Less, + (Some(_), None) => Ordering::Greater, + (Some(x), Some(y)) if is_decimal(&x) && is_decimal(&y) => decimal_cmp(&x, &y), + _ => Ordering::Equal, + }; + let ms = |r: &Value| r["price"]["time"]["seconds"].as_f64().map(|s| (s * 1000.0).ceil()); + let time_order = match (ms(a), ms(b)) { + (Some(x), Some(y)) => x.total_cmp(&y), + (Some(_), None) => Ordering::Less, + (None, Some(_)) => Ordering::Greater, + (None, None) => Ordering::Equal, + }; + let local = |r: &Value| r["kind"] != "local"; + let memory = |r: &Value| r["price"]["memory_bytes"].as_f64().unwrap_or(0.0); + money_order + .then(time_order) + .then_with(|| local(a).cmp(&local(b))) + .then_with(|| memory(a).total_cmp(&memory(b))) + .then_with(|| a["route"].as_str().unwrap_or("").as_bytes().cmp(b["route"].as_str().unwrap_or("").as_bytes())) +} + +/// The route the rule picks from `routes`, of those `h` lets through: `auto`'s +/// pick when the contract names no class and it meets the rest, else the +/// cheapest. Judged here, whatever a route's outcome says of itself. +fn pick<'a>(routes: &'a [Value], auto: Option<&str>, h: &Held<'_>) -> Option<&'a Value> { + let met = |r: &&Value| gate(r, h).is_none(); + if h.contract.exactness.is_none() + && let Some(a) = auto + && let Some(r) = routes.iter().filter(met).find(|r| r["route"] == a) + { + return Some(r); + } + routes.iter().filter(met).min_by(|a, b| cheaper(a, b)) +} + +/// `stable`: what the routes that depend on nothing of the host cost, in a +/// digest any verifier recomputes, and whether the choice depends on the host. +fn stable_of(routes: &[Value], job_bytes: &Value, choice: Option<&str>, contract: &Contract) -> Value { + let covered: Vec<&Value> = routes.iter().filter(|r| r["kind"] == "local" && r["host_dependent"] == false).collect(); + let facts: Vec = covered.iter().map(|r| json!({ "route": r["route"], "class": r["class"], "seconds": r["price"]["time"]["seconds"], "memory_bytes": r["price"]["memory_bytes"], "work": r["price"]["work"] })).collect(); + let digest = blake3::hash(&receipt::canonical(&json!({ "job_bytes": job_bytes, "routes": facts }))).to_hex().to_string(); + let chosen_stable = choice.is_some_and(|c| covered.iter().any(|r| r["route"] == c)); + let others = routes.iter().filter(|r| r["host_dependent"] != false).all(|r| matches!(r["rejected"]["code"].as_str(), Some("not_named" | "fabric" | "class"))); + json!({ + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": covered.iter().map(|r| r["route"].clone()).collect::>(), + "digest": digest, + "choice": chosen_stable && others && contract.providers != Some(true) && contract.max_joules.is_none(), + }) +} + +/// The local routes of a job, each priced or with why it cannot. +struct Local { + routes: Vec, + /// Each route that can run, with its plan. + plans: Vec<(String, Plan)>, + /// Why each route that cannot run cannot. + cannot: Vec<(String, String)>, + auto: Option, + /// What the job names, when the method it runs on is fixed. + method: Option, + read: Option, +} + +fn local_routes(reg: &Registry, v: &Value, host: &Host<'_>) -> Result { + let identity = |m: &dyn Method| reg.identity(Kind::Method, m.name()); + let job_bytes = host.job_bytes; + // A program its method reads itself, and a job on a device target, have one + // route: the method that reads it, and the method the device's noise takes. + let target = crate::engine::targets::job::names_target(v); + if catalog::reads_own(reg, v).is_some() || target { + let p = catalog::plan_plain(reg, v, job_bytes)?; + let m = reg.method(&p.method).ok_or_else(|| format!("internal: no method {}", p.method))?; + let route = local_route(m, identity(m), None, Some(&p), host, target); + let name = route["route"].as_str().unwrap_or("").to_string(); + return Ok(Local { routes: vec![route], plans: vec![(name, p.clone())], cannot: Vec::new(), auto: None, method: Some(p.method), read: None }); + } + let (r, uses) = catalog::read_in(reg, v)?; + let named_method = (r.method != "auto").then(|| r.method.clone()); + if let Some(n) = &named_method + && reg.method(n).is_none() + { + return Err(tag(refusal::UNKNOWN_METHOD, format!("unknown method {n}; GET /v1/methods lists them"))); + } + let need = catalog::intent_need(reg, v, &r, job_bytes)?; + let mut out = Local { routes: Vec::new(), plans: Vec::new(), cannot: Vec::new(), auto: None, method: named_method.clone(), read: None }; + { + let job = Job::new(reg, v, job_bytes, Some(&r), &uses); + if named_method.is_none() { + out.auto = catalog::choose_placed(&job).ok().map(|p| format!("method:{}", p.method)); + } + for m in reg.methods() { + let name = format!("method:{}", m.name()); + let unasked = named_method.as_ref().is_some_and(|n| n != m.name()); + let planned = if unasked { + None + } else if m.reads_program() { + out.cannot.push((name.clone(), format!("{} reads its own program, and runs only when a job names it", m.name()))); + None + } else { + match catalog::plan_one(m, &job) { + Ok(mut p) => { + p.memory_bytes = p.memory_bytes.max(need); + Some(p) + } + Err(e) => { + out.cannot.push((name.clone(), e)); + None + } + } + }; + out.routes.push(local_route(m, identity(m), Some(&r), planned.as_ref(), host, false)); + if let Some(p) = planned { + out.plans.push((name, p)); + } + } + } + out.read = Some(r); + Ok(out) +} + +/// `contract` weighed against every route `host` can see. An error is a job that +/// does not read, or a contract that does not; a contract no route meets gives +/// the reasoning with the refusal in it. +pub fn consider(reg: &Registry, v: &Value, host: &Host<'_>) -> Result { + let contract = Contract::read(v)?.ok_or_else(|| "internal: a job with no contract was brought to the planner".to_string())?; + let (provider, _) = named(v); + if provider.is_some() && contract.providers == Some(false) { + return Err(tag(refusal::CONTRACT_FORM, "the job names a provider, and its contract says providers: never")); + } + if v.get("provider").is_some_and(|p| !p.is_null()) && !provider.is_some_and(|p| host.quotes.iter().any(|q| q.name == p)) { + // Refused as a job that names a provider is refused where none is reached. + catalog::read_in(reg, v)?; + return Err(tag(refusal::PROVIDER_HERE, "this job names a provider this host has not brought")); + } + // A job that names a provider runs on it: the methods are listed unpriced. + let mut local = if provider.is_some() { + let mut l = Local { routes: Vec::new(), plans: Vec::new(), cannot: Vec::new(), auto: None, method: None, read: None }; + for m in reg.methods() { + l.routes.push(local_route(m, reg.identity(Kind::Method, m.name()), None, None, host, false)); + } + l + } else { + local_routes(reg, v, host)? + }; + let auto = local.auto.take(); + let mut routes = std::mem::take(&mut local.routes); + routes.extend(host.quotes.iter().map(provider_route)); + let quote_cannot = |name: &str| host.quotes.iter().find(|q| format!("provider:{}", q.name) == name).and_then(|q| q.cannot.clone()); + let method = provider.is_none().then(|| local.method.clone()).flatten(); + // What the job wants: what the contract says, else what it would have had. + let named_route = provider.map(|p| format!("provider:{p}")).or_else(|| method.as_ref().map(|m| format!("method:{m}"))); + let class_of_route = |name: &str| routes.iter().find(|r| r["route"] == name).and_then(|r| r["class"].as_str()).map(str::to_string); + let (wanted, wanted_from) = match (&contract.exactness, &named_route, &auto) { + (Some(w), _, _) => (Some(w.clone()), Some("contract")), + (None, Some(n), _) => (class_of_route(n), Some("named")), + (None, None, Some(a)) => (class_of_route(a), Some("auto")), + (None, None, None) => (None, None), + }; + let job_bytes = whole(host.job_bytes); + let fabric = if provider.is_some() { Fab::Free } else { fab_of(v) }; + let held = Held { contract: &contract, provider, method: method.as_deref(), fabric, wanted: wanted.as_deref(), job_bytes: host.job_bytes as f64 }; + for route in &mut routes { + let name = route["route"].as_str().unwrap_or("").to_string(); + match gate(route, &held) { + None => route["outcome"] = json!("met"), + Some(code) => { + let why = match code { + "cannot" => local.cannot.iter().find(|(n, _)| *n == name).map(|(_, w)| w.clone()).or_else(|| quote_cannot(&name)).unwrap_or_else(|| "it cannot take this job".to_string()), + _ => gate_why(code, route, &held), + }; + route["outcome"] = json!("rejected"); + route["rejected"] = json!({ "code": code, "why": why }); + } + } + } + let total = routes.len(); + let met = routes.iter().filter(|r| r["outcome"] != "rejected").count(); + let chosen = pick(&routes, auto.as_deref(), &held).map(|r| r["route"].as_str().unwrap_or("").to_string()); + if let Some(c) = &chosen + && let Some(r) = routes.iter_mut().find(|r| r["route"] == c.as_str()) + { + r["outcome"] = json!("chosen"); + } + let mut reasoning = json!({ + "format": FORMAT, + "wanted": wanted, + "wanted_from": wanted_from, + "auto": auto, + "host": { + "job_bytes": job_bytes, + "providers": host.quotes.iter().map(|q| q.name.clone()).collect::>(), + }, + "routes": routes, + "choice": chosen, + }); + let Some(chosen) = chosen else { + let reasons: Vec = reasoning["routes"].as_array().into_iter().flatten().filter(|r| !matches!(r["rejected"]["code"].as_str(), Some("not_named"))).map(|r| format!("{}: {}", r["route"].as_str().unwrap_or(""), r["rejected"]["why"].as_str().unwrap_or(""))).collect(); + let refusal = tag(refusal::NOTHING_MEETS, format!("no route meets this contract — {}", reasons.join("; "))); + reasoning["why"] = json!(refusal); + reasoning["refusal"] = refusal::refusal_json(&refusal); + reasoning["stable"] = stable_of(reasoning["routes"].as_array().map_or(&[], Vec::as_slice), &reasoning["host"]["job_bytes"], None, &contract); + return Ok(Considered { reasoning, plan: None, refusal: Some(refusal) }); + }; + let said = match wanted_from { + Some("named") => format!("the route the job names, which meets its contract ({met} of {total} routes)"), + Some("auto") if auto.as_deref() == Some(chosen.as_str()) => format!("what auto picks, which meets the contract: the contract names no class, so it keeps auto's ({met} of {total} routes meet it)"), + Some("auto") => format!("auto's pick does not meet the contract, so the cheapest route at least as exact ({met} of {total} routes meet it)"), + _ => format!("the cheapest of the {met} of {total} routes that meet the contract"), + }; + reasoning["why"] = json!(said); + reasoning["stable"] = stable_of(reasoning["routes"].as_array().map_or(&[], Vec::as_slice), &reasoning["host"]["job_bytes"], Some(&chosen), &contract); + let mut plan = local.plans.iter().find(|(n, _)| *n == chosen).map(|(_, p)| p.clone()); + if let Some(p) = &mut plan { + p.why = format!("{}; {said}", p.why); + if let Some(r) = &local.read { + fabric::admit(v, r, p)?; + } + } + if chosen.starts_with("provider:") { + reasoning["shadow"] = shadow_plan(reg, v, host, &contract, provider_seconds(&reasoning["routes"], &chosen)); + } + Ok(Considered { reasoning, plan, refusal: None }) +} + +fn provider_seconds(routes: &Value, chosen: &str) -> Option { + routes.as_array()?.iter().find(|r| r["route"] == chosen)?["price"]["time"]["seconds"].as_f64() +} + +/// `contract` met: the route chosen and the reasoning, or the refusal. +pub fn decide(reg: &Registry, v: &Value, host: &Host<'_>) -> Result { + let c = consider(reg, v, host)?; + if let Some(e) = c.refusal { + return Err(e); + } + let name = c.reasoning["choice"].as_str().unwrap_or("").to_string(); + let choice = match (c.plan, name.strip_prefix("provider:")) { + (Some(p), _) => Choice::Local(p), + (None, Some(n)) => Choice::Provider(n.to_string()), + (None, None) => return Err(format!("internal: the planner chose {name} and has no plan for it")), + }; + Ok(Decision { choice, reasoning: c.reasoning }) +} + +/// The plan of a contract job on a host that reaches no provider. +pub(crate) fn plan_in(reg: &Registry, v: &Value, job_bytes: u64) -> Result { + match decide(reg, v, &Host::new(job_bytes))?.choice { + Choice::Local(p) => Ok(p), + Choice::Provider(name) => Err(format!("internal: the planner chose the provider {name} with none brought")), + } +} + +/// A contract job's plan as the plan surfaces give it: the plan, with the +/// reasoning under `planner`, or the refusal. +pub fn plan_value(reg: &Registry, v: &Value, job_bytes: u64) -> Result { + let d = decide(reg, v, &Host::new(job_bytes))?; + let Choice::Local(p) = d.choice else { return Err("internal: a provider chosen with none brought".to_string()) }; + let mut o = serde_json::to_value(&p).map_err(|e| e.to_string())?; + o["planner"] = d.reasoning; + Ok(o) +} + +/// A contract job's plan and its result, carrying the reasoning: what a host +/// that runs a job in its own process does. +pub fn plan_and_run_in(reg: &Registry, v: &Value, host: &Host<'_>) -> Result<(Plan, Value), String> { + let d = decide(reg, v, host)?; + match d.choice { + Choice::Local(p) => { + let mut result = reg.run(v, &p)?; + attach(&mut result, &d.reasoning); + Ok((p, result)) + } + Choice::Provider(name) => Err(format!("this job's contract is met by the provider {name}; a host that reaches it runs it there")), + } +} + +/// What a job's `contract` takes, as its committed schema has it: for the tool +/// lists. +pub fn contract_schema() -> Value { + let text = super::schema::FILES.iter().find(|(n, _)| *n == "job-request.v1.json").map_or("{}", |(_, t)| *t); + serde_json::from_str::(text).ok().and_then(|v| v.pointer("/properties/contract").cloned()).unwrap_or_else(|| json!({ "type": "object" })) +} + +/// `reasoning` in `result`. +pub fn attach(result: &mut Value, reasoning: &Value) { + result["planner"] = reasoning.clone(); +} + +/// A result's class held to the contract once it has run: a method that gave +/// less than the job wants gives no answer ([`refusal::CLASS_BROKEN`]). What the +/// run is held to here is the class the contract names; `check` also holds a +/// sealed result to the class it kept. +pub(crate) fn hold_class(v: &Value, result: &Value) -> Result<(), String> { + let Some(contract) = Contract::read(v)? else { return Ok(()) }; + let Some(wanted) = contract.exactness else { return Ok(()) }; + let got = result.pointer("/accuracy/class").and_then(Value::as_str).unwrap_or(""); + if !meets(&wanted, got) { + return Err(tag(refusal::CLASS_BROKEN, format!("the method {} gave a result of class {got:?}, and the contract wants {wanted}: nothing it gave is returned", result["method"].as_str().unwrap_or("?")))); + } + Ok(()) +} + +/// What the contract asked, against what happened: the deadline against the +/// time it took (`elapsed_ms`, else the result's own), the energy ceiling against +/// the result's figure, and the cost ceiling against what was charged. A result +/// that missed one is sealed and says so; one that cannot say says `null`. Done +/// when the result is complete, before it is sealed. +pub fn finish(v: &Value, result: &mut Value, elapsed_ms: Option) { + let Ok(Some(c)) = Contract::read(v) else { return }; + if result.get("planner").is_none() { + return; + } + let mut kept = Map::new(); + if let Some(d) = c.deadline_seconds { + let e = elapsed_ms.or_else(|| result.get("elapsed_ms").and_then(Value::as_u64)); + kept.insert("deadline".into(), json!({ "seconds": d, "elapsed_ms": e, "kept": e.map(|e| e as f64 <= d * 1000.0) })); + } + if let Some(j) = c.max_joules { + let x = result.pointer("/energy/joules_micro").and_then(Value::as_f64).map(|u| u / 1e6); + kept.insert("energy".into(), json!({ "max_joules": j, "joules": x, "kept": x.map(|x| x <= j) })); + } + if let Some((amount, currency)) = &c.max_cost { + let charged = result.pointer("/cost/charged").filter(|x| !x.is_null()).cloned(); + let free = result.pointer("/cost/free").is_none_or(|f| f == true); + let held = match (&charged, free) { + (Some(x), _) => x["amount"].as_str().filter(|a| is_decimal(a) && x["currency"] == currency.as_str()).map(|a| decimal_cmp(a, amount) != Ordering::Greater), + (None, true) => Some(true), + (None, false) => None, + }; + kept.insert("cost".into(), json!({ "max_cost": { "amount": amount, "currency": currency }, "charged": charged, "kept": held })); + } + result["planner"]["kept"] = Value::Object(kept); +} + +/// Whether anything the contract asked was missed, as the result says. +pub fn missed(result: &Value) -> bool { + result.pointer("/planner/kept").and_then(Value::as_object).is_some_and(|k| k.values().any(|x| x["kept"] == false)) +} + +// --------------------------------------------------------------------------- +// The shadow +// --------------------------------------------------------------------------- + +/// The seed a job's shadow samples with. +pub fn shadow_seed(v: &Value) -> u64 { + let seed = v.get("seed").and_then(Value::as_u64).unwrap_or(1); + (seed + SHADOW_SEED_OFFSET) % (1 << 53) +} + +/// The classical method that can reach the provider's counts within the +/// contract, the most exact first and then the cheapest, or why none can: what +/// the contract leaves after the provider's own time, or [`SHADOW_MAX_SECONDS`]. +fn shadow_plan(reg: &Registry, v: &Value, host: &Host<'_>, contract: &Contract, provider_seconds: Option) -> Value { + let budget = match (contract.deadline_seconds, provider_seconds) { + (Some(d), Some(s)) => (d - s).max(0.0), + (Some(d), None) => d, + (None, _) => SHADOW_MAX_SECONDS, + }; + let Ok(read) = super::provider::read_named(v, Some("shadow")) else { + return json!({ "route": null, "code": "none", "why": "the job does not read as a provider job" }); + }; + let mut req = json!({ "qasm": v.get("qasm").cloned().unwrap_or(Value::Null), "shots": read.shots, "seed": shadow_seed(v) }); + let auto = match catalog::read_in(reg, &req) { + Ok(a) => a, + Err(e) => return json!({ "route": null, "code": "none", "why": e }), + }; + let mut candidates: Vec = Vec::new(); + let mut tried: Vec = Vec::new(); + { + let (r, uses) = (&auto.0, &auto.1); + let job = Job::new(reg, &req, host.job_bytes, Some(r), uses); + for m in reg.methods().filter(|m| !m.reads_program()) { + let route = format!("method:{}", m.name()); + match catalog::plan_one(m, &job) { + Err(e) => tried.push(json!({ "route": route, "code": "none", "why": e })), + Ok(p) if p.memory_bytes > host.job_bytes => tried.push(json!({ "route": route, "code": "memory", "why": format!("it takes {} bytes, and a job here takes at most {}", p.memory_bytes, host.job_bytes) })), + Ok(p) => { + let priced = local_route(m, reg.identity(Kind::Method, m.name()), Some(r), Some(&p), host, false); + match priced["price"]["time"]["seconds"].as_f64() { + Some(s) if s <= budget => candidates.push(priced), + Some(s) => tried.push(json!({ "route": route, "code": "budget", "why": format!("about {s} s, and the contract leaves a shadow {budget} s") })), + None => tried.push(json!({ "route": route, "code": "budget", "why": "its time is not known" })), + } + } + } + } + } + candidates.sort_by(|a, b| strength(a["class"].as_str().unwrap_or("")).cmp(&strength(b["class"].as_str().unwrap_or(""))).then_with(|| cheaper(a, b))); + let Some(best) = candidates.into_iter().next() else { + let has = |c: &str| tried.iter().any(|t| t["code"] == c); + let code = if has("budget") { "budget" } else if has("memory") { "memory" } else { "none" }; + let why = match code { + "budget" => format!("a classical method could reach these counts, but not in the {budget} s the contract leaves a shadow"), + "memory" => "a classical method could reach these counts, but not in a job's memory here".to_string(), + _ => "no classical method here takes this program".to_string(), + }; + return json!({ "route": null, "code": code, "why": why, "tried": tried }); + }; + req["method"] = best["method"].clone(); + json!({ "route": best["route"], "class": best["class"], "request": req, "budget_seconds": budget, "price": best["price"] }) +} + +/// The distance between two lists of counts of the same shots, recomputable +/// from them: the total variation exactly, as whole numbers, and the Hellinger +/// fidelity and what the shots alone would leave, each in a fixed order of +/// outcomes (section 8.6). `None` when either leaves out shots. +pub fn distance(a: &Value, b: &Value, shots: u64) -> Option { + let (a, b) = (a.as_object()?, b.as_object()?); + let mut keys: Vec<&String> = a.keys().chain(b.keys()).collect(); + keys.sort_by(|x, y| x.as_bytes().cmp(y.as_bytes())); + keys.dedup(); + let s = shots as f64; + let (mut numerator, mut root, mut floor) = (0u64, 0.0f64, 0.0f64); + for k in keys { + let x = a.get(k).and_then(Value::as_u64).unwrap_or(0); + let y = b.get(k).and_then(Value::as_u64).unwrap_or(0); + numerator += x.abs_diff(y); + root += ((x * y) as f64).sqrt(); + let p = (x + y) as f64 / (2.0 * s); + floor += (4.0 * p * (1.0 - p) / (std::f64::consts::PI * s)).sqrt(); + } + let denominator = 2 * shots; + Some(json!({ + "computed": true, + "numerator": numerator, + "denominator": denominator, + "total_variation": numerator as f64 / denominator as f64, + "hellinger_fidelity": root * root / (s * s), + "sampling_tvd_expected": 0.5 * floor, + })) +} + +/// A provider's result, with the shadow the reasoning planned run beside it: a +/// result's `shadow`, carrying both counts' distance, or why there is none. +pub fn shadow(reg: &Registry, reasoning: &Value, result: &Value) -> Value { + let plan = &reasoning["shadow"]; + if plan["route"].is_null() { + return json!({ "ran": false, "code": plan["code"], "why": plan["why"] }); + } + let req = &plan["request"]; + let job_bytes = reasoning["host"]["job_bytes"].as_u64().unwrap_or(u64::MAX); + let run = catalog::plan_plain(reg, req, job_bytes).and_then(|p| reg.run(req, &p)); + let out = match run { + Ok(o) => o, + Err(e) => return json!({ "ran": false, "code": "failed", "why": e }), + }; + let shots = result.get("shots").and_then(Value::as_u64).unwrap_or(0); + let whole_lists = result["omitted_shots"].as_u64() == Some(0) && out["omitted_shots"].as_u64() == Some(0); + let distance = if whole_lists { + distance(&result["counts"], &out["counts"], shots).unwrap_or_else(|| json!({ "computed": false, "why": "the counts are not of their form" })) + } else { + json!({ "computed": false, "why": "a list of counts leaves out shots, so the distance is not known from them" }) + }; + let mut s = json!({ + "ran": true, + "route": plan["route"], + "accuracy": out["accuracy"], + "request": req, + "shots": shots, + "counts": out["counts"], + "distinct_outcomes": out["distinct_outcomes"], + "omitted_shots": out["omitted_shots"], + "distance": distance, + }); + if let Some(e) = out.get("elapsed_ms") { + s["elapsed_ms"] = e.clone(); + } + s +} + +/// A provider's contract job's result made complete: the reasoning, the shadow +/// and what the contract kept. What the job took, from its submission, is the +/// host's to say. +pub fn seal_provider(reg: &Registry, v: &Value, result: &mut Value, reasoning: &Value, elapsed_ms: Option) { + attach(result, reasoning); + result["shadow"] = shadow(reg, reasoning, result); + finish(v, result, elapsed_ms); +} + +// --------------------------------------------------------------------------- +// What a verifier holds a sealed result to (section 8.6) +// --------------------------------------------------------------------------- + +fn is_whole(v: &Value) -> bool { + v.as_f64().is_some_and(|x| x.fract() == 0.0 && x >= 0.0) +} + +fn route_form(r: &Value) -> bool { + let Some(name) = r["route"].as_str() else { return false }; + let kind = r["kind"].as_str(); + let kind_ok = (name.strip_prefix("method:").is_some_and(|m| !m.is_empty()) && kind == Some("local")) || (name.strip_prefix("provider:").is_some_and(|m| !m.is_empty()) && kind == Some("provider")); + let outcome = r["outcome"].as_str(); + let outcome_ok = match outcome { + Some("chosen" | "met") => r.get("rejected").is_none(), + Some("rejected") => r["rejected"]["code"].is_string() && r["rejected"]["why"].is_string(), + _ => false, + }; + let price_ok = match r.get("price") { + Some(Value::Null) => true, + Some(p) if p.is_object() => { + let m = &p["money"]; + let money_ok = match m["free"].as_bool() { + Some(true) => true, + Some(false) => m["unknown"].is_string() || (m["amount"].is_string() && m["currency"].is_string()), + None => false, + }; + let time_ok = p["time"].is_object() && (p["time"]["seconds"].is_null() || p["time"]["seconds"].as_f64().is_some_and(|s| s >= 0.0)); + let energy_ok = p["energy"].is_object() && (p["energy"]["joules"].is_null() || p["energy"]["joules"].is_number()); + let left_ok = p["leaves_out"].as_array().is_some_and(|a| a.iter().all(|w| w.as_str().is_some_and(|w| LEFT_OUT.contains(&w)))); + let counted = ["memory_bytes", "work"].iter().all(|k| p.get(*k).is_some_and(|x| x.is_null() || is_whole(x))); + money_ok && time_ok && energy_ok && left_ok && counted + } + _ => false, + }; + kind_ok && outcome_ok && price_ok && r["class"].is_string() && r["host_dependent"].is_boolean() +} + +fn planner_form(p: &Value) -> bool { + let wanted_ok = p["wanted"].is_null() || p["wanted"].is_string(); + let from_ok = match p.get("wanted_from") { + Some(Value::String(s)) => ["contract", "named", "auto"].contains(&s.as_str()), + Some(Value::Null) => p["wanted"].is_null(), + _ => false, + }; + let Some(routes) = p["routes"].as_array().filter(|a| !a.is_empty()) else { return false }; + let mut names: Vec<&str> = routes.iter().filter_map(|r| r["route"].as_str()).collect(); + let n = names.len(); + names.sort_unstable(); + names.dedup(); + let listed = |x: &Value| x.as_str().is_some_and(|s| routes.iter().any(|r| r["route"] == s)); + p["format"] == FORMAT + && wanted_ok + && from_ok + && (p["auto"].is_null() || listed(&p["auto"])) + && is_whole(&p["host"]["job_bytes"]) + && p["host"]["providers"].as_array().is_some_and(|a| a.iter().all(Value::is_string)) + && names.len() == n + && n == routes.len() + && routes.iter().all(route_form) + && listed(&p["choice"]) + && p["why"].is_string() + && p["stable"].is_object() + && p["kept"].is_object() +} + +/// What is wrong with a sealed result's reasoning (section 8.6): nothing, for a +/// job with no contract and no reasoning. `method` here is the result's, so a +/// route is held to what ran. +pub fn check(request: &Value, result: &Value) -> Vec<&'static str> { + let planner = result.get("planner"); + let contract = match Contract::read(request) { + Ok(Some(c)) => c, + Ok(None) => { + let mut out = Vec::new(); + if planner.is_some() { + out.push(PLANNER_FORM); + } + if result.get("shadow").is_some() { + out.push(SHADOW); + } + return out; + } + Err(_) => return vec![CONTRACT_FORM], + }; + let Some(p) = planner.filter(|p| planner_form(p)) else { return vec![PLANNER_FORM] }; + let mut out = Vec::new(); + let routes = p["routes"].as_array().map_or(&[][..], Vec::as_slice); + let (provider, mut method) = named(request); + let class_named = |name: String| routes.iter().find(|r| r["route"] == name.as_str()).and_then(|r| r["class"].as_str()).map(str::to_string); + // A program a method reads itself, or a job on a device target, has one route. + let single = routes.len() == 1; + if single && provider.is_none() { + method = routes[0]["route"].as_str().and_then(|n| n.strip_prefix("method:")); + } + let wanted = match (&contract.exactness, provider, method, p["auto"].as_str()) { + (Some(w), ..) => Some(w.clone()), + (None, Some(n), ..) => class_named(format!("provider:{n}")), + (None, None, Some(m), _) => class_named(format!("method:{m}")), + (None, None, None, Some(a)) => class_named(a.to_string()), + (None, None, None, None) => None, + }; + let from = match (&contract.exactness, provider.is_some() || method.is_some(), p["auto"].is_string()) { + (Some(_), ..) => Some("contract"), + (None, true, _) => Some("named"), + (None, false, true) => Some("auto"), + (None, false, false) => None, + }; + if p["wanted"].as_str() != wanted.as_deref() || p["wanted_from"].as_str() != from { + out.push(PLANNER_FORM); + return out; + } + let held = Held { contract: &contract, provider, method, fabric: if provider.is_some() { Fab::Free } else { fab_of(request) }, wanted: wanted.as_deref(), job_bytes: p["host"]["job_bytes"].as_f64().unwrap_or(0.0) }; + let mut route_broken = false; + let mut choice = None; + for r in routes { + let stated = r["rejected"]["code"].as_str(); + let chosen = r["outcome"] == "chosen"; + if chosen { + if choice.is_some() { + route_broken = true; + } + choice = r["route"].as_str(); + } + if stated != gate(r, &held) { + route_broken = true; + } + } + if route_broken || choice != p["choice"].as_str() { + out.push(PLANNER_ROUTE); + } + let picked = pick(routes, p["auto"].as_str(), &held); + let ran = if result["method"] == "provider" { result.pointer("/provider/name").and_then(Value::as_str).map(|n| format!("provider:{n}")) } else { result["method"].as_str().map(|m| format!("method:{m}")) }; + if picked.and_then(|r| r["route"].as_str()) != p["choice"].as_str() || ran.as_deref() != p["choice"].as_str() { + out.push(PLANNER_CHOICE); + } + let want_stable = stable_of(routes, &p["host"]["job_bytes"], p["choice"].as_str(), &contract); + if ["routes", "digest", "choice"].iter().any(|k| p["stable"].get(*k) != want_stable.get(*k)) { + out.push(PLANNER_STABLE); + } + if !kept_holds(&contract, p, result) { + out.push(PLANNER_KEPT); + } + let class = result.pointer("/accuracy/class").and_then(Value::as_str).unwrap_or(""); + let approximate = result.pointer("/accuracy/approximate") == Some(&Value::Bool(true)); + if let Some(w) = wanted.as_deref() + && (!meets(w, class) || (w == "simulated" && approximate)) + { + out.push(CONTRACT_CLASS); + } + let is_provider = p["choice"].as_str().is_some_and(|c| c.starts_with("provider:")); + if is_provider != result.get("shadow").is_some() || is_provider != p.get("shadow").is_some() || (is_provider && !shadow_holds(request, p, result)) { + out.push(SHADOW); + } + out +} + +/// Whether a sealed `kept` is what the contract and the result give. +fn kept_holds(c: &Contract, p: &Value, result: &Value) -> bool { + let kept = &p["kept"]; + let Some(k) = kept.as_object() else { return false }; + let asked = [("deadline", c.deadline_seconds.is_some()), ("energy", c.max_joules.is_some()), ("cost", c.max_cost.is_some())]; + if k.len() != asked.iter().filter(|(_, a)| *a).count() || !asked.iter().all(|(n, a)| kept.get(*n).is_some() == *a) { + return false; + } + if let Some(d) = c.deadline_seconds { + let e = &kept["deadline"]["elapsed_ms"]; + let want = e.as_f64().map(|e| e <= d * 1000.0); + let local_e = result["method"] != "provider" && result.get("elapsed_ms").is_some_and(|x| x != e); + if kept["deadline"]["seconds"].as_f64() != Some(d) || !(e.is_null() || is_whole(e)) || kept["deadline"]["kept"].as_bool() != want || local_e { + return false; + } + } + if let Some(j) = c.max_joules { + let x = result.pointer("/energy/joules_micro").and_then(Value::as_f64).map(|u| u / 1e6); + if kept["energy"]["max_joules"].as_f64() != Some(j) || kept["energy"]["joules"].as_f64() != x || kept["energy"]["kept"].as_bool() != x.map(|x| x <= j) { + return false; + } + } + if let Some((amount, currency)) = &c.max_cost { + let charged = result.pointer("/cost/charged").filter(|x| !x.is_null()); + let free = result.pointer("/cost/free").is_none_or(|f| f == true); + let held = match (charged, free) { + (Some(x), _) => x["amount"].as_str().filter(|a| is_decimal(a) && x["currency"] == currency.as_str()).map(|a| decimal_cmp(a, amount) != Ordering::Greater), + (None, true) => Some(true), + (None, false) => None, + }; + let sealed = &kept["cost"]; + if sealed["max_cost"]["amount"].as_str() != Some(amount.as_str()) || sealed["max_cost"]["currency"].as_str() != Some(currency.as_str()) || sealed["kept"].as_bool() != held || (sealed["charged"].is_null() != charged.is_none()) { + return false; + } + } + true +} + +/// Whether a sealed shadow is of its form, what its plan says, and its distance +/// what its counts give. +fn shadow_holds(request: &Value, p: &Value, result: &Value) -> bool { + let (s, plan) = (&result["shadow"], &p["shadow"]); + match s["ran"].as_bool() { + Some(false) => s["code"].is_string() && s["why"].is_string() && (plan["route"].is_null().then(|| plan["code"] == s["code"]).unwrap_or(s["code"] == "failed")), + Some(true) => { + let shots = result["shots"].as_f64(); + let req = &s["request"]; + let seed = request.get("seed").and_then(Value::as_u64).unwrap_or(1); + let req_ok = plan["request"] == *req + && req["qasm"] == request["qasm"] + && req["shots"].as_f64() == shots + && req["seed"].as_u64() == Some((seed + SHADOW_SEED_OFFSET) % (1 << 53)) + && plan["route"].as_str().and_then(|r| r.strip_prefix("method:")) == req["method"].as_str(); + let m = s["counts"].as_object(); + let listed: Option = m.map(|o| o.values().filter_map(Value::as_f64).sum()); + let counts_ok = m.is_some() && s["omitted_shots"].as_f64().zip(listed).map(|(o, l)| o + l) == shots && is_whole(&s["distinct_outcomes"]); + let distance_ok = match s["distance"]["computed"].as_bool() { + Some(false) => s["distance"]["why"].is_string(), + Some(true) => shots.and_then(|x| distance(&result["counts"], &s["counts"], x as u64)).is_some_and(|d| { + ["numerator", "denominator", "total_variation", "hellinger_fidelity", "sampling_tvd_expected"].iter().all(|k| d[*k].as_f64() == s["distance"][*k].as_f64()) + }) && result["omitted_shots"].as_u64() == Some(0) && s["omitted_shots"].as_u64() == Some(0), + None => false, + }; + req_ok && counts_ok && distance_ok && s["route"] == plan["route"] && s["accuracy"]["class"].is_string() && s["shots"].as_f64() == shots + } + None => false, + } +} + +/// What a verifier states of a contract job: the choice, the class wanted and +/// the class given, what was kept, and the shadow. +pub fn statement(result: &Value) -> Option { + let p = result.get("planner")?; + let s = &result["shadow"]; + Some(json!({ + "choice": p["choice"], + "wanted": p["wanted"], + "class": result.pointer("/accuracy/class"), + "stable_choice": p["stable"]["choice"], + "kept": p["kept"], + "shadow_ran": s["ran"], + "shadow_total_variation": s["distance"]["total_variation"], + })) +} + +/// What can be run again of a sealed contract job, by this engine: the local +/// routes priced again at the job's memory, held to the sealed digest, and the +/// shadow run again, held to its counts bit for bit. Nothing else is recomputed +/// here: a provider's counts cannot be, and a price the host stated is its word. +pub fn recheck(reg: &Registry, job: &Value) -> Result { + let (Some(request), Some(result)) = (job.get("request"), job.get("result")) else { + return Err("expected a job: {\"request\": ..., \"result\": ...}".into()); + }; + let Some(p) = result.get("planner") else { return Err("this result carries no planner's reasoning".into()) }; + let engine = result.pointer("/engine/version").and_then(Value::as_str); + let same_engine = engine == Some(super::schema::ENGINE_VERSION); + let job_bytes = p["host"]["job_bytes"].as_u64().ok_or("the reasoning names no job memory")?; + let (provider, _) = named(request); + let priced = if provider.is_some() { + json!({ "checked": false, "why": "the job names its provider, so no local route was priced" }) + } else { + let host = Host::new(job_bytes); + let mut plain = request.clone(); + // Priced as the job asks, whatever the host had beside. + if let Some(o) = plain.as_object_mut() { + o.shift_remove("provider"); + } + let local = local_routes(reg, &plain, &host)?; + let digest = stable_of(&local.routes, &p["host"]["job_bytes"], None, &Contract::default())["digest"].clone(); + json!({ "checked": true, "digest": digest, "same": digest == p["stable"]["digest"] }) + }; + let s = &result["shadow"]; + let shadow = if s.get("ran").is_none() { + json!({ "checked": false, "why": "no provider answered this job, so it has no shadow" }) + } else if s["ran"] != true { + json!({ "checked": false, "why": "no shadow ran" }) + } else { + let req = &s["request"]; + let run = catalog::plan_plain(reg, req, job_bytes).and_then(|pl| reg.run(req, &pl))?; + json!({ "checked": true, "same": run["counts"] == s["counts"] }) + }; + let holds = priced["same"] != false && shadow["same"] != false; + Ok(json!({ "holds": holds, "engine": { "sealed_by": engine, "this": super::schema::ENGINE_VERSION, "same": same_engine }, "priced": priced, "shadow": shadow })) +} + +#[cfg(test)] +mod tests; diff --git a/wai/wai-quantum/src/engine/planner/tests.rs b/wai/wai-quantum/src/engine/planner/tests.rs new file mode 100644 index 000000000..598454f9a --- /dev/null +++ b/wai/wai-quantum/src/engine/planner/tests.rs @@ -0,0 +1,900 @@ +use super::*; +use crate::engine::{job, provider}; +use ed25519_dalek::SigningKey; + +const BELL: &str = "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n"; +const ROT: &str = "OPENQASM 3.0;\nqubit[2] q;\nrx(0.3) q[0];\ncx q[0], q[1];\n"; +const GIB: u64 = 1 << 30; + +fn reg() -> &'static Registry { + Registry::builtins() +} + +fn wide(n: u32) -> String { + format!("OPENQASM 3.0;\nqubit[{n}] q;\nrx(0.3) q;\ncx q[0], q[1];\n") +} + +fn seal_local(req: &Value) -> Value { + job::run(req, GIB, &SigningKey::from_bytes(&[3; 32]), json!({ "unmetered": "a test" })).unwrap() +} + +fn route<'a>(reasoning: &'a Value, name: &str) -> &'a Value { + reasoning["routes"].as_array().unwrap().iter().find(|r| r["route"] == name).unwrap_or_else(|| panic!("no route {name}: {reasoning}")) +} + +fn code<'a>(reasoning: &'a Value, name: &str) -> Option<&'a str> { + route(reasoning, name)["rejected"]["code"].as_str() +} + +fn considered(req: &Value, cap: u64) -> Considered { + consider(reg(), req, &Host::new(cap)).unwrap() +} + +/// The class table of section 8.6, every pair, written out here by hand. +#[test] +fn a_class_meets_what_the_table_says_and_nothing_else() { + let table: [(&str, &[&str]); 9] = [ + ("bit-exact", &["bit-exact"]), + ("exact", &["bit-exact", "exact"]), + ("single", &["bit-exact", "exact", "single"]), + ("bounded", &["bit-exact", "exact", "bounded"]), + ("estimate", &["bit-exact", "exact", "bounded", "estimate"]), + ("heuristic", &["bit-exact", "exact", "single", "bounded", "estimate", "heuristic"]), + ("measured", &["measured"]), + ("simulated", &["simulated"]), + ("any", &["bit-exact", "exact", "single", "bounded", "estimate", "heuristic", "measured", "simulated"]), + ]; + assert_eq!(table.iter().map(|t| t.0).collect::>(), CLASSES); + for (wanted, met) in table { + for got in ["bit-exact", "exact", "single", "bounded", "estimate", "heuristic", "measured", "simulated"] { + assert_eq!(meets(wanted, got), met.contains(&got), "{wanted} of {got}"); + } + } + // A device is in no classical class, and a class nobody knows meets only `any`. + assert!(!meets("heuristic", "measured") && !meets("exact", "later") && meets("any", "later")); +} + +/// An amount is compared as digits, with no double between them. +#[test] +fn amounts_are_compared_exactly() { + use std::cmp::Ordering::*; + for (a, b, want) in [("0.1", "0.10", Equal), ("0010", "10.0", Equal), ("0.3", "0.30000000000000000000000000000001", Less), ("10", "9.99", Greater), ("1", "1.0000000000000000000000000000000000001", Less), ("0", "0.0", Equal), ("100", "99", Greater)] { + assert_eq!(decimal_cmp(a, b), want, "{a} {b}"); + assert_eq!(decimal_cmp(b, a), want.reverse(), "{b} {a}"); + } + for ok in ["0", "0.50", "12", "007.5"] { + assert!(is_decimal(ok), "{ok}"); + } + for bad in ["", ".5", "5.", "1e3", "-1", "1,5", "0x10", " 1"] { + assert!(!is_decimal(bad), "{bad}"); + } +} + +/// A contract that does not read is refused, member by member: read as absent, +/// a misspelt requirement would drop in silence. +#[test] +fn a_contract_that_does_not_read_is_refused_with_its_code() { + for c in [ + json!(5), + json!([]), + json!({ "deadline": 30 }), + json!({ "exactness": "nearly" }), + json!({ "exactness": 3 }), + json!({ "max_cost": "0.50" }), + json!({ "max_cost": { "amount": "0.50" } }), + json!({ "max_cost": { "amount": 0.5, "currency": "USD" } }), + json!({ "max_cost": { "amount": "1e3", "currency": "USD" } }), + json!({ "max_cost": { "amount": "1", "currency": "" } }), + json!({ "max_cost": { "amount": "1", "currency": "USD", "more": 1 } }), + json!({ "deadline_seconds": 0 }), + json!({ "deadline_seconds": -1 }), + json!({ "deadline_seconds": "soon" }), + json!({ "max_joules": 0 }), + json!({ "providers": "sometimes" }), + json!({ "providers": true }), + ] { + let e = catalog::plan(&json!({ "qasm": BELL, "contract": c }), GIB).unwrap_err(); + assert_eq!(refusal::codes_in(&e).last().copied(), Some("J070"), "{c}: {e}"); + } + let host = Host::new(GIB).with_quotes(vec![Quote::new("lab", "lab:device", "silicon")]); + let e = consider(reg(), &json!({ "qasm": BELL, "provider": "lab", "contract": { "providers": "never" } }), &host).unwrap_err(); + assert_eq!(refusal::codes_in(&e), ["J070"], "{e}"); + // Null is what absent is, everywhere in a job. + assert!(!has_contract(&json!({ "qasm": BELL, "contract": null }))); + assert!(catalog::plan(&json!({ "qasm": BELL, "contract": { "exactness": null, "max_cost": null, "deadline_seconds": null, "max_joules": null, "providers": null } }), GIB).is_ok()); +} + +/// A result less what a contract adds to it. +fn answer_of(body: &Value) -> Value { + let mut r = body["result"].clone(); + let o = r.as_object_mut().unwrap(); + for k in ["planner", "receipt", "elapsed_ms"] { + o.shift_remove(k); + } + r +} + +/// Absent members keep today's behaviour: a contract that asks nothing, or only +/// what `auto`'s pick already meets, runs what `auto` picks, to the same bytes. +#[test] +fn a_contract_that_asks_nothing_changes_nothing_but_the_reasoning() { + for (qasm, extra) in [ + (BELL, json!({ "shots": 1000, "seed": 4 })), + (ROT, json!({ "shots": 300, "observables": ["Z0 Z1"], "amplitudes": ["00"] })), + ("OPENQASM 3.0;\nqubit[2] q;\nh q[0];\nt q[0];\ncx q[0], q[1];\n", json!({ "shots": 50 })), + (BELL, json!({ "shots": 100, "noise": { "depolarizing_2q": 0.02 } })), + (&wide(40), json!({ "shots": 10 })), + ] { + let mut plain = json!({ "qasm": qasm }); + plain.as_object_mut().unwrap().extend(extra.as_object().unwrap().clone()); + let (auto, _) = job::plan_and_run(&plain, GIB).unwrap(); + for contract in [json!({}), json!({ "providers": "never" }), json!({ "deadline_seconds": 1e9 }), json!({ "providers": "allowed" })] { + let mut under = plain.clone(); + under["contract"] = contract.clone(); + let (p, _) = job::plan_and_run(&under, GIB).unwrap(); + assert_eq!(p.method, auto.method, "{under}"); + assert_eq!(p.memory_bytes, auto.memory_bytes, "{under}"); + let (a, b) = (seal_local(&plain), seal_local(&under)); + assert_eq!(answer_of(&a), answer_of(&b), "{under}"); + assert_eq!(b["result"]["planner"]["auto"], format!("method:{}", auto.method), "{under}"); + assert_eq!(b["result"]["planner"]["choice"], format!("method:{}", auto.method), "{under}"); + assert!(job::check(&b).valid(), "{:?}\n{under}", job::check(&b).reasons); + } + // And with no contract at all, nothing of a planner. + assert!(seal_local(&plain)["result"].get("planner").is_none()); + } + // A method whose time is not known keeps its place, until a deadline asks. + let pauli = json!({ "qasm": wide(100), "observables": ["Z0 Z1"], "contract": {} }); + assert_eq!(catalog::plan(&pauli, GIB).unwrap().method, "pauli"); +} + +/// With a class named, the cheapest route of that class runs: less money, then +/// less time to the millisecond, then less memory. +#[test] +fn the_cheapest_route_that_meets_the_contract_runs() { + let t = "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\nh q[0];\nt q[0];\ncx q[0], q[1];\nc = measure q;\n"; + for (qasm, wanted, method) in [ + (BELL, "exact", "stabilizer"), + (BELL, "bit-exact", "exact"), + (t, "exact", "exact"), + (ROT, "exact", "statevector"), + (ROT, "heuristic", "statevector"), + ] { + let req = json!({ "qasm": qasm, "shots": 100, "contract": { "exactness": wanted } }); + let body = seal_local(&req); + assert_eq!(body["result"]["method"], method, "{qasm} {wanted}: {}", body["result"]["planner"]); + assert_eq!(body["result"]["planner"]["choice"], format!("method:{method}")); + assert_eq!(route(&body["result"]["planner"], &format!("method:{method}"))["outcome"], "chosen"); + let c = job::check(&body); + assert!(c.valid(), "{:?}", c.reasons); + assert_eq!(c.planner.as_ref().unwrap()["choice"], format!("method:{method}")); + } + // A time that matters decides: 26 qubits' double-precision state is quicker + // at the planner's rates than the fixed-point one. + let many = "OPENQASM 3.0;\nqubit[26] q;\nbit[26] c;\nh q;\nt q;\ncx q[0], q[1];\nt q[0];\nc = measure q;\n"; + let p = catalog::plan(&json!({ "qasm": many, "shots": 1, "contract": { "exactness": "exact" } }), 8 * GIB).unwrap(); + assert_eq!(p.method, "statevector", "{}", p.why); + assert!(p.why.contains("the cheapest of"), "{}", p.why); +} + +/// The other half of a choice: what each route was rejected for, and its price +/// wherever it has one. +#[test] +fn every_route_it_sees_is_listed_with_its_price_or_why_not() { + let req = json!({ "qasm": ROT, "shots": 100, "contract": { "exactness": "exact" } }); + let c = considered(&req, GIB); + let p = &c.reasoning; + let names: Vec<&str> = p["routes"].as_array().unwrap().iter().map(|r| r["route"].as_str().unwrap()).collect(); + for m in reg().methods() { + assert!(names.contains(&format!("method:{}", m.name()).as_str()), "{}", m.name()); + } + assert_eq!(p["wanted"], "exact"); + assert_eq!(p["wanted_from"], "contract"); + assert_eq!(p["host"]["job_bytes"], GIB); + let sv = route(p, "method:statevector"); + assert_eq!((sv["outcome"].as_str(), sv["class"].as_str(), sv["host_dependent"].as_bool()), (Some("chosen"), Some("exact"), Some(false))); + assert_eq!(sv["price"]["money"], json!({ "free": true })); + assert_eq!(sv["price"]["time"]["basis"], "nominal"); + assert_eq!(sv["price"]["time"]["seconds"].as_f64(), Some((2u64 << 2) as f64 / 1e9)); + assert_eq!(sv["price"]["memory_bytes"].as_u64(), Some(catalog::statevector_bytes(2) + 100 * 24)); + // Not dyadic: the bit-exact method cannot, and says why; a heuristic's price + // is shown beside its rejection. + assert_eq!(code(p, "method:exact"), Some("cannot")); + assert!(route(p, "method:exact")["rejected"]["why"].as_str().unwrap().contains("dyadic"), "{p}"); + let mps = route(p, "method:mps"); + assert_eq!((mps["rejected"]["code"].as_str(), mps["class"].as_str()), (Some("class"), Some("heuristic"))); + assert!(mps["price"]["memory_bytes"].is_number()); + assert!(mps["rejected"]["why"].as_str().unwrap().contains("before it runs"), "{mps}"); + assert_eq!(code(p, "method:statevector_single"), Some("class"), "{p}"); + assert_eq!(route(p, "method:statevector_single")["host_dependent"], true); + // A method that cannot take it, whatever its class: no price, and why. + assert_eq!(code(p, "method:tensor_network"), Some("cannot")); + assert!(route(p, "method:tensor_network")["price"].is_null()); + // A class that is not wanted is said first, the same on every host. + assert_eq!(code(p, "method:pauli"), Some("class")); +} + +/// From exact to approximate, nothing falls back: the job names exact, or names +/// no class and so keeps auto's; only asking for less lets less run. +#[test] +fn nothing_falls_back_from_exact_to_approximate() { + let w = wide(40); + // Past every exact route: the matrix product state can, and is not asked. + let req = json!({ "qasm": w, "shots": 10, "contract": { "exactness": "exact" } }); + let e = catalog::plan(&req, GIB).unwrap_err(); + assert_eq!(refusal::codes_in(&e).last().copied(), Some("J071"), "{e}"); + assert!(e.contains("method:mps") && e.contains("method:statevector") && e.contains("heuristic"), "{e}"); + let c = considered(&req, GIB); + assert_eq!((c.reasoning["choice"].as_str(), c.plan.is_none()), (None, true)); + assert_eq!(c.reasoning["refusal"]["code"], "J071"); + // Asked for, and labelled: it says heuristic, and its result what it was. + let asked = json!({ "qasm": w, "shots": 10, "contract": { "exactness": "heuristic" } }); + let p = catalog::plan(&asked, GIB).unwrap(); + assert_eq!(p.method, "mps"); + // No class named, and a deadline auto's pick misses: only as exact may take over. + let dense = wide(30); + let plain = catalog::plan(&json!({ "qasm": dense, "shots": 10 }), 72 * GIB).unwrap(); + assert_eq!(plain.method, "statevector"); + let tight = json!({ "qasm": dense, "shots": 10, "contract": { "deadline_seconds": 1 } }); + let e = catalog::plan(&tight, 72 * GIB).unwrap_err(); + assert!(refusal::codes_in(&e).contains(&"J071"), "{e}"); + let c = considered(&tight, 72 * GIB); + assert_eq!((c.reasoning["wanted"].as_str(), c.reasoning["wanted_from"].as_str(), c.reasoning["auto"].as_str()), (Some("exact"), Some("auto"), Some("method:statevector"))); + assert_eq!(code(&c.reasoning, "method:statevector"), Some("deadline")); + assert_eq!(code(&c.reasoning, "method:mps"), Some("class"), "the quicker route is the less exact one, and it is not taken"); + // With that class given up by name, the same deadline is met. + let given_up = json!({ "qasm": dense, "shots": 10, "contract": { "deadline_seconds": 1, "exactness": "heuristic" } }); + assert_eq!(catalog::plan(&given_up, 72 * GIB).unwrap().method, "mps"); +} + +/// A class named by the job's own method holds too: naming a method names the +/// route, and it is held to the rest of the contract. +#[test] +fn a_named_method_is_held_to_the_contract_and_nothing_stands_in_for_it() { + let named = json!({ "qasm": ROT, "shots": 10, "method": "statevector", "contract": { "exactness": "exact" } }); + let body = seal_local(&named); + assert_eq!(body["result"]["method"], "statevector"); + let p = &body["result"]["planner"]; + assert_eq!(code(p, "method:mps"), Some("not_named")); + assert!(route(p, "method:mps")["price"].is_null(), "only what the job names is priced: {p}"); + assert_eq!(p["auto"], Value::Null); + assert!(job::check(&body).valid(), "{:?}", job::check(&body).reasons); + // Its class is what it is, and a higher one wanted refuses it. + let e = catalog::plan(&json!({ "qasm": ROT, "shots": 10, "method": "mps", "contract": { "exactness": "exact" } }), GIB).unwrap_err(); + assert!(e.ends_with("[J071]"), "{e}"); + // A method that cannot take the job, or that does not exist. + let e = catalog::plan(&json!({ "qasm": ROT, "shots": 10, "method": "stabilizer", "contract": {} }), GIB).unwrap_err(); + assert!(e.contains("Clifford") && e.ends_with("[J071]"), "{e}"); + let e = catalog::plan(&json!({ "qasm": ROT, "shots": 10, "method": "nonsense", "contract": {} }), GIB).unwrap_err(); + assert!(e.ends_with("[J010]"), "{e}"); + // Named with no class, its own stands: a heuristic may run as itself. + let body = seal_local(&json!({ "qasm": ROT, "shots": 10, "method": "mps", "contract": {} })); + assert_eq!(body["result"]["planner"]["wanted_from"], "named"); + assert!(job::check(&body).valid(), "{:?}", job::check(&body).reasons); +} + +/// A time nobody can state does not meet a deadline; a time that can does. +#[test] +fn an_unknown_time_does_not_meet_a_deadline() { + let w = wide(100); + let req = json!({ "qasm": w, "observables": ["Z0 Z1"], "contract": { "exactness": "bounded" } }); + let p = catalog::plan(&req, 8 * GIB).unwrap(); + assert_eq!(p.method, "pauli", "{}", p.why); + let c = considered(&json!({ "qasm": w, "observables": ["Z0 Z1"], "contract": { "exactness": "bounded", "deadline_seconds": 3600 } }), 8 * GIB); + let r = route(&c.reasoning, "method:pauli"); + assert_eq!(r["rejected"]["code"], "deadline_unknown", "{r}"); + assert!(r["price"]["time"]["seconds"].is_null()); + assert!(r["rejected"]["why"].as_str().unwrap().contains("does not predict"), "{r}"); + assert!(c.refusal.unwrap().ends_with("[J071]")); +} + +/// An energy no one estimates does not meet an energy ceiling; a host that +/// estimates one holds each route to it, and says what it rests on. +#[test] +fn an_energy_ceiling_holds_where_a_host_estimates_one() { + let req = json!({ "qasm": BELL, "shots": 100, "contract": { "max_joules": 2.0 } }); + let c = considered(&req, GIB); + assert_eq!(code(&c.reasoning, "method:stabilizer"), Some("energy_unknown")); + assert!(c.refusal.unwrap().contains("estimates no job's energy")); + let by_method = |p: &Plan| -> Result<(f64, String), String> { + match p.method.as_str() { + "stabilizer" => Ok((5.0, "a test's figure".to_string())), + "exact" => Ok((1.5, "a test's figure".to_string())), + _ => Err("not metered".to_string()), + } + }; + let host = Host::new(GIB).with_joules(&by_method); + let c = consider(reg(), &json!({ "qasm": BELL, "shots": 100, "contract": { "exactness": "exact", "max_joules": 2.0 } }), &host).unwrap(); + assert_eq!(c.reasoning["choice"], "method:exact", "{}", c.reasoning); + assert_eq!(code(&c.reasoning, "method:stabilizer"), Some("energy")); + assert_eq!(route(&c.reasoning, "method:exact")["price"]["energy"], json!({ "joules": 1.5, "basis": "a test's figure" })); + assert_eq!(code(&c.reasoning, "method:statevector"), Some("energy_unknown")); + assert_eq!(c.reasoning["stable"]["choice"], false, "the host's estimate decided"); +} + +/// A quote as a host brings it. +fn quote(name: &str, provenance: &str, money: Value, seconds: Option) -> Quote { + let mut q = Quote::new(name, format!("{name}:device"), provenance); + q.money = money; + q.seconds = seconds; + q.leaves_out = vec!["energy".into(), "mitigation".into(), "decoder".into(), "charged".into()]; + q.program = json!({ "shots": 1000, "native_gates": 9, "two_qubit_gates": 1, "swaps": 0 }); + q +} + +fn usd(a: &str) -> Value { + json!({ "free": false, "amount": a, "currency": "USD", "unit": "shot" }) +} + +fn decided(req: &Value, quotes: Vec) -> Considered { + consider(reg(), req, &Host::new(GIB).with_quotes(quotes)).unwrap() +} + +/// From a simulator to a device and the reverse, nothing falls back: a device +/// is reached by asking for its class, or by naming the provider. +#[test] +fn nothing_falls_back_between_a_simulator_and_a_device() { + let quotes = || vec![quote("sim", "simulator:a state vector", json!({ "free": true }), Some(0.0)), quote("qpu", "silicon", usd("0.30"), Some(12.0))]; + let ask = |c: Value| json!({ "qasm": BELL, "shots": 1000, "contract": c }); + // Allowed, and no class: what auto picks here, and no device. + let c = decided(&ask(json!({ "providers": "allowed" })), quotes()); + assert_eq!(c.reasoning["choice"], "method:stabilizer", "{}", c.reasoning); + assert_eq!(code(&c.reasoning, "provider:qpu"), Some("class")); + assert_eq!(code(&c.reasoning, "provider:sim"), Some("class")); + // Wanting exact, no provider's counts are it, free or not. + let c = decided(&ask(json!({ "exactness": "exact", "providers": "allowed" })), quotes()); + assert_eq!(c.reasoning["choice"], "method:stabilizer"); + assert!(route(&c.reasoning, "provider:sim")["rejected"]["why"].as_str().unwrap().contains("simulated"), "{}", c.reasoning); + // Wanting a device: no local method, and no simulator however free. + let c = decided(&ask(json!({ "exactness": "measured", "providers": "allowed", "max_cost": { "amount": "1", "currency": "USD" } })), quotes()); + assert_eq!(c.reasoning["choice"], "provider:qpu", "{}", c.reasoning); + assert_eq!(code(&c.reasoning, "provider:sim"), Some("class")); + assert_eq!(code(&c.reasoning, "method:stabilizer"), Some("class")); + // Wanting a simulator's counts: no device. + let c = decided(&ask(json!({ "exactness": "simulated", "providers": "allowed" })), quotes()); + assert_eq!(c.reasoning["choice"], "provider:sim"); + assert_eq!(code(&c.reasoning, "provider:qpu"), Some("class")); + // The device is down: it does not become the simulator, or the reverse. + let e = decided(&ask(json!({ "exactness": "measured", "providers": "allowed", "max_cost": { "amount": "1", "currency": "USD" } })), vec![quote("sim", "simulator", json!({ "free": true }), Some(0.0))]); + assert!(e.refusal.unwrap().ends_with("[J071]")); + let e = decided(&ask(json!({ "exactness": "simulated", "providers": "allowed" })), vec![quote("qpu", "silicon", json!({ "free": true }), Some(0.0))]); + assert!(e.refusal.unwrap().ends_with("[J071]")); + // Asking for a device with providers not allowed is refused, and says so. + let e = decided(&ask(json!({ "exactness": "measured" })), quotes()); + assert_eq!(code(&e.reasoning, "provider:qpu"), Some("providers")); + assert!(e.refusal.unwrap().contains("does not allow a provider")); + // An approximate simulator is not what simulated asks. + let mut approx = quote("sim", "simulator:a truncated network", json!({ "free": true }), Some(0.0)); + approx.approximate = true; + let e = decided(&ask(json!({ "exactness": "simulated", "providers": "allowed" })), vec![approx.clone()]); + assert!(e.reasoning["routes"].as_array().unwrap().iter().any(|r| r["route"] == "provider:sim" && r["rejected"]["why"].as_str().unwrap().contains("approximate")), "{}", e.reasoning); + let c = decided(&ask(json!({ "exactness": "any", "providers": "allowed" })), vec![approx.clone()]); + assert_eq!(c.reasoning["choice"], "provider:sim", "any takes every route, and this one states it takes no time"); + // A tie to the millisecond goes to the local route. + approx.seconds = Some(0.0005); + let c = decided(&ask(json!({ "exactness": "any", "providers": "allowed" })), vec![approx]); + assert_eq!(c.reasoning["choice"], "method:stabilizer", "{}", c.reasoning); +} + +/// What a provider costs, against the ceiling: money only under a stated ceiling +/// in its own currency, and an unknown is never read as free. +#[test] +fn a_provider_is_held_to_the_cost_ceiling_and_an_unknown_is_not_free() { + let ask = |ceiling: Option<(&str, &str)>| { + let mut c = json!({ "exactness": "measured", "providers": "allowed" }); + if let Some((a, cur)) = ceiling { + c["max_cost"] = json!({ "amount": a, "currency": cur }); + } + json!({ "qasm": BELL, "shots": 1000, "contract": c }) + }; + let priced = |a: &str| vec![quote("qpu", "silicon", usd(a), Some(12.0))]; + let of = |c: &Considered| code(&c.reasoning, "provider:qpu").map(str::to_string); + assert_eq!(of(&decided(&ask(None), priced("0.3"))).as_deref(), Some("cost_no_ceiling"), "nothing bounds what would be spent"); + assert_eq!(of(&decided(&ask(Some(("0.29", "USD"))), priced("0.3"))).as_deref(), Some("cost")); + assert_eq!(of(&decided(&ask(Some(("0.3", "USD"))), priced("0.30"))), None, "at the ceiling meets it"); + assert_eq!(of(&decided(&ask(Some(("100", "EUR"))), priced("0.3"))).as_deref(), Some("cost_currency"), "nothing is converted"); + let unknown = vec![quote("qpu", "silicon", json!({ "free": false, "unknown": "the provider gives no estimate" }), Some(12.0))]; + assert_eq!(of(&decided(&ask(Some(("100", "USD"))), unknown.clone())).as_deref(), Some("cost_unknown")); + assert_eq!(of(&decided(&ask(None), unknown)).as_deref(), Some("cost_no_ceiling")); + assert_eq!(of(&decided(&ask(Some(("100", "USD"))), vec![quote("qpu", "silicon", usd("lots"), Some(1.0))])).as_deref(), Some("cost_unknown"), "an amount that is no decimal is unknown"); + // Free needs no ceiling. + assert_eq!(of(&decided(&ask(None), vec![quote("qpu", "silicon", json!({ "free": true }), Some(1.0))])), None); + // Named by the job, its cost is the person's to confirm, as it is with no contract. + let named = json!({ "qasm": BELL, "shots": 1000, "provider": "qpu", "contract": {} }); + let c = decided(&named, priced("0.3")); + assert_eq!(c.reasoning["choice"], "provider:qpu"); + assert_eq!(c.reasoning["wanted_from"], "named"); + assert_eq!(c.reasoning["wanted"], "measured"); + assert_eq!(code(&c.reasoning, "method:stabilizer"), Some("not_named")); + // Named, a ceiling still holds, and a named device is still held to its class. + let e = decided(&json!({ "qasm": BELL, "provider": "qpu", "contract": { "max_cost": { "amount": "0.1", "currency": "USD" } } }), priced("0.3")); + assert_eq!(code(&e.reasoning, "provider:qpu"), Some("cost")); + let e = decided(&json!({ "qasm": BELL, "provider": "qpu", "contract": { "exactness": "simulated" } }), priced("0.3")); + assert_eq!(code(&e.reasoning, "provider:qpu"), Some("class")); + // A provider this host has not brought is refused as today. + let e = consider(reg(), &json!({ "qasm": BELL, "provider": "other", "contract": {} }), &Host::new(GIB)).unwrap_err(); + assert!(e.ends_with("[J002]"), "{e}"); +} + +/// What it costs decides among providers: money, then time, then its name; and +/// a time it does not state does not meet a deadline. +#[test] +fn the_cheapest_provider_is_chosen_and_what_its_estimate_leaves_out_is_said() { + let req = |c: Value| json!({ "qasm": BELL, "shots": 1000, "contract": c }); + let base = json!({ "exactness": "measured", "providers": "allowed", "max_cost": { "amount": "1", "currency": "USD" } }); + let c = decided(&req(base.clone()), vec![quote("dear", "silicon", usd("0.9"), Some(1.0)), quote("cheap", "silicon", usd("0.2"), Some(100.0)), quote("free", "silicon", json!({ "free": true }), None)]); + assert_eq!(c.reasoning["choice"], "provider:free", "{}", c.reasoning); + let c = decided(&req(base.clone()), vec![quote("slow", "silicon", usd("0.2"), Some(100.0)), quote("quick", "silicon", usd("0.20"), Some(10.0))]); + assert_eq!(c.reasoning["choice"], "provider:quick"); + let mut with_deadline = base.clone(); + with_deadline["deadline_seconds"] = json!(30); + let c = decided(&req(with_deadline), vec![quote("quiet", "silicon", usd("0.1"), None), quote("slow", "silicon", usd("0.1"), Some(100.0)), quote("quick", "silicon", usd("0.5"), Some(10.0))]); + assert_eq!(c.reasoning["choice"], "provider:quick"); + assert_eq!(code(&c.reasoning, "provider:quiet"), Some("deadline_unknown")); + assert_eq!(code(&c.reasoning, "provider:slow"), Some("deadline")); + // What the price is and what it leaves out, on the route. + let r = route(&c.reasoning, "provider:quick"); + assert_eq!(r["price"]["money"]["amount"], "0.5"); + assert_eq!(r["price"]["leaves_out"], json!(["energy", "mitigation", "decoder", "charged"])); + assert_eq!(r["price"]["program"]["two_qubit_gates"], 1); + assert_eq!(r["provenance"], "silicon"); + assert_eq!(r["host_dependent"], true); + // No provider's energy is known before it runs. + let mut joules = base; + joules["max_joules"] = json!(1e9); + let c = decided(&req(joules), vec![quote("qpu", "silicon", usd("0.1"), Some(1.0))]); + assert_eq!(code(&c.reasoning, "provider:qpu"), Some("energy_unknown")); + // One that cannot run the job says why, and nothing else of it is known. + let c = decided(&req(json!({ "exactness": "any", "providers": "allowed" })), vec![Quote::cannot("small", "this device holds 1 qubit")]); + let r = route(&c.reasoning, "provider:small"); + assert_eq!((r["rejected"]["code"].as_str(), r["rejected"]["why"].as_str(), r["price"].is_null()), (Some("cannot"), Some("this device holds 1 qubit"), true)); +} + +/// On a host that reaches no provider, a contract that allows one is met by what +/// is here or refused: the job service's case. +#[test] +fn a_host_that_reaches_no_provider_lists_none_and_never_stands_in() { + let c = considered(&json!({ "qasm": BELL, "shots": 10, "contract": { "providers": "allowed" } }), GIB); + assert_eq!(c.reasoning["host"]["providers"], json!([])); + assert!(c.reasoning["routes"].as_array().unwrap().iter().all(|r| r["kind"] == "local")); + assert_eq!(c.reasoning["choice"], "method:stabilizer"); + let e = considered(&json!({ "qasm": BELL, "shots": 10, "contract": { "providers": "allowed", "exactness": "measured" } }), GIB); + assert!(e.refusal.unwrap().ends_with("[J071]")); + let e = catalog::plan(&json!({ "qasm": BELL, "provider": "lab", "contract": { "providers": "allowed" } }), GIB).unwrap_err(); + assert!(e.ends_with("[J002]"), "{e}"); +} + +/// Beyond what the reader and the method refuse, the program's own limits: a +/// memory ceiling in the job's bytes is the host's, and a route past it is out. +#[test] +fn a_route_past_a_job_s_memory_is_rejected_for_it() { + // The fixed-point state of 26 qubits takes more than 1 GiB; today's plan says + // so and the host refuses at admission. Under a contract, the planner does. + let t26 = "OPENQASM 3.0;\nqubit[26] q;\nh q;\nt q;\n"; + let c = considered(&json!({ "qasm": t26, "shots": 1, "contract": { "exactness": "bit-exact" } }), GIB); + assert_eq!(code(&c.reasoning, "method:exact"), Some("memory")); + assert!(c.refusal.is_some()); +} + +/// What a plan is: a plan's form, or a refusal with the reasoning. +#[test] +fn a_contract_s_plan_states_its_reasoning_in_its_schema() { + let r = crate::engine::schema::Registry::engine(); + let bad = |errs: Vec, what: &str| assert!(errs.is_empty(), "{what}: {errs:#?}"); + let req = json!({ "qasm": BELL, "shots": 100, "contract": { "exactness": "exact", "deadline_seconds": 30, "max_cost": { "amount": "0.50", "currency": "USD" }, "providers": "allowed" } }); + bad(r.check("job-request.v1.json", &req), "the request"); + let v = plan_value(reg(), &req, GIB).unwrap(); + bad(r.check("plan.v1.json", &v), "the plan"); + assert_eq!(v["method"], "stabilizer"); + assert_eq!(v["planner"]["choice"], "method:stabilizer"); + let body = seal_local(&req); + bad(r.check("job.v1.json", &body), "the job"); + bad(r.check("job-result.v1.json", &body["result"]), "the result"); + assert_eq!(body["result"]["planner"]["kept"]["cost"]["kept"], true, "{}", body["result"]["planner"]["kept"]); + assert_eq!(body["result"]["planner"]["kept"]["deadline"]["kept"], true); + assert_eq!(body["result"]["planner"]["kept"]["deadline"]["seconds"].as_f64(), Some(30.0)); + // A refusal, with every route's reason. + let refused = considered(&json!({ "qasm": ROT, "shots": 10, "contract": { "exactness": "bit-exact" } }), GIB); + bad(r.check_value(&json!({ "$ref": "job-result.v1.json#/$defs/planner" }), &refused.reasoning), "the refused reasoning"); + assert!(plan_value(reg(), &json!({ "qasm": ROT, "shots": 10, "contract": { "exactness": "bit-exact" } }), GIB).unwrap_err().ends_with("[J071]")); +} + +/// A contract is one job's: a set's items would lose its reasoning, so a set +/// refuses it, whether it is the set's or an item's. +#[test] +fn a_set_refuses_a_contract_rather_than_dropping_it() { + for req in [ + json!({ "programs": [BELL, BELL], "shots": 10, "contract": {} }), + json!({ "programs": [{ "qasm": BELL, "contract": { "exactness": "exact" } }, BELL], "shots": 10 }), + json!({ "qasm": "OPENQASM 3.0;\ninput float t;\nqubit q;\nrx(t) q;\n", "sweep": { "t": [0.1, 0.2] }, "shots": 10, "contract": {} }), + ] { + let e = crate::engine::sets::expand(&req).unwrap_err(); + assert!(e.ends_with("[J073]"), "{e}"); + } + assert!(crate::engine::sets::expand(&json!({ "programs": [BELL, BELL], "shots": 10 })).is_ok()); +} + +/// A result below the contract's class gives no answer, whatever plan it came +/// from: the mps method's truncation shows only once it has run. +#[test] +fn a_result_below_the_class_wanted_gives_no_answer() { + let dense = "OPENQASM 3.0;\nqubit[6] q;\nrx(0.3) q;\ncx q[0], q[1];\ncx q[1], q[2];\ncx q[2], q[3];\nrx(0.2) q;\ncx q[0], q[1];\ncx q[1], q[2];\ncx q[2], q[3];\n"; + let plain = json!({ "qasm": dense, "shots": 10, "method": "mps", "options": { "max_bond": 1 } }); + let p = catalog::plan(&plain, GIB).unwrap(); + let mut asked = plain.clone(); + asked["contract"] = json!({ "exactness": "exact" }); + // A plan that is not the planner's: its own plan refuses this job. + assert!(catalog::plan(&asked, GIB).is_err()); + let e = crate::engine::run::run(&asked, &p).unwrap_err(); + assert!(e.ends_with("[J072]"), "{e}"); + assert!(e.contains("heuristic") && e.contains("exact"), "{e}"); + // The same plan with less wanted runs. + asked["contract"] = json!({ "exactness": "heuristic" }); + assert!(crate::engine::run::run(&asked, &p).is_ok()); +} + +/// A host that ran a contract job and dropped the reasoning seals a result no +/// verifier passes. +#[test] +fn a_contract_job_sealed_without_its_reasoning_does_not_verify() { + let req = json!({ "qasm": BELL, "shots": 10, "contract": { "exactness": "exact" } }); + let p = catalog::plan(&req, GIB).unwrap(); + let result = crate::engine::run::run(&req, &p).unwrap(); + assert!(result.get("planner").is_none()); + let body = job::seal(&req, &p, result, &SigningKey::from_bytes(&[3; 32]), json!({ "unmetered": "a test" })); + assert_eq!(job::check(&body).reasons, vec![PLANNER_FORM]); +} + +fn resealed(body: &Value, edit: impl Fn(&mut Value)) -> Value { + let mut both = json!({ "request": body["request"], "result": body["result"] }); + both["result"].as_object_mut().unwrap().shift_remove("receipt"); + edit(&mut both); + let mut res = both["result"].take(); + let req = both["request"].take(); + res["receipt"] = receipt::seal(&SigningKey::from_bytes(&[9; 32]), &req, &res); + json!({ "status": "done", "request": req, "result": res }) +} + +fn reasons(body: &Value) -> Vec<&'static str> { + let mut r = job::check(body).reasons; + r.sort_unstable(); + r +} + +fn routes_of(b: &mut Value) -> &mut Vec { + b["result"]["planner"]["routes"].as_array_mut().unwrap() +} + +fn at<'a>(b: &'a mut Value, name: &str) -> &'a mut Value { + routes_of(b).iter_mut().find(|r| r["route"] == name).unwrap() +} + +/// Each rule of section 8.6 on a local job, broken once and found alone, the +/// receipt sealed again so that nothing else is wrong with it. +#[test] +fn every_rule_a_verifier_holds_a_local_contract_job_to_is_broken_once_and_found_alone() { + let good = seal_local(&json!({ "qasm": ROT, "shots": 100, "contract": { "exactness": "exact", "deadline_seconds": 30, "max_cost": { "amount": "1", "currency": "USD" } } })); + assert_eq!(reasons(&good), Vec::<&str>::new(), "{}", good["result"]["planner"]); + type Edit = Box; + let cases: Vec<(&[&str], Edit)> = vec![ + (&[CONTRACT_FORM], Box::new(|b| b["request"]["contract"]["exactness"] = json!("nearly"))), + (&[CONTRACT_FORM], Box::new(|b| b["request"]["contract"]["deadline"] = json!(1))), + (&[PLANNER_FORM], Box::new(|b| { b["result"].as_object_mut().unwrap().shift_remove("planner"); })), + (&[PLANNER_FORM], Box::new(|b| b["result"]["planner"]["format"] = json!("wai.quantum.planner/2"))), + (&[PLANNER_FORM], Box::new(|b| { b["result"]["planner"].as_object_mut().unwrap().shift_remove("kept"); })), + (&[PLANNER_FORM], Box::new(|b| b["result"]["planner"]["choice"] = json!("method:another"))), + (&[PLANNER_FORM], Box::new(|b| b["result"]["planner"]["auto"] = json!("method:another"))), + (&[PLANNER_FORM], Box::new(|b| b["result"]["planner"]["wanted"] = json!("heuristic"))), + (&[PLANNER_FORM], Box::new(|b| b["result"]["planner"]["wanted_from"] = json!("auto"))), + (&[PLANNER_FORM], Box::new(|b| { let r = routes_of(b)[0].clone(); routes_of(b).push(r); })), + (&[PLANNER_FORM], Box::new(|b| at(b, "method:mps")["price"]["leaves_out"] = json!(["whatever"]))), + (&[PLANNER_FORM], Box::new(|b| at(b, "method:statevector")["price"]["money"] = json!({ "free": false }))), + (&[PLANNER_FORM], Box::new(|b| at(b, "method:statevector")["outcome"] = json!("best"))), + // A heuristic claimed to meet exact, a rejection for another reason, a + // route claimed to meet what it does not. + (&[PLANNER_ROUTE], Box::new(|b| { let r = at(b, "method:mps"); r["outcome"] = json!("met"); r.as_object_mut().unwrap().shift_remove("rejected"); })), + (&[PLANNER_ROUTE], Box::new(|b| at(b, "method:mps")["rejected"]["code"] = json!("deadline"))), + (&[PLANNER_ROUTE, PLANNER_CHOICE], Box::new(|b| { let r = at(b, "method:statevector"); r["outcome"] = json!("rejected"); r["rejected"] = json!({ "code": "deadline", "why": "too slow" }); b["result"]["planner"]["choice"] = json!("method:cutrank"); let c = at(b, "method:cutrank"); c["outcome"] = json!("chosen"); c.as_object_mut().unwrap().shift_remove("rejected"); })), + // A price changed, which the digest covers, and the rule still picks it. + (&[PLANNER_STABLE], Box::new(|b| at(b, "method:statevector")["price"]["memory_bytes"] = json!(1u64 << 29))), + // Past the contract by what it states of itself: with no other route, no choice. + (&[PLANNER_ROUTE, PLANNER_CHOICE, PLANNER_STABLE], Box::new(|b| at(b, "method:statevector")["price"]["time"]["seconds"] = json!(31.0))), + (&[PLANNER_ROUTE, PLANNER_CHOICE, PLANNER_STABLE], Box::new(|b| at(b, "method:statevector")["price"]["time"] = json!({ "seconds": null, "why": "not known" }))), + (&[PLANNER_ROUTE, PLANNER_CHOICE, PLANNER_STABLE], Box::new(|b| at(b, "method:statevector")["price"]["memory_bytes"] = json!(1u64 << 40))), + (&[PLANNER_CHOICE], Box::new(|b| b["result"]["method"] = json!("mps"))), + (&[PLANNER_STABLE], Box::new(|b| b["result"]["planner"]["stable"]["digest"] = json!("00".repeat(32)))), + (&[PLANNER_STABLE], Box::new(|b| b["result"]["planner"]["stable"]["choice"] = json!(false))), + (&[PLANNER_STABLE], Box::new(|b| b["result"]["planner"]["stable"]["routes"] = json!([]))), + (&[PLANNER_KEPT], Box::new(|b| b["result"]["planner"]["kept"]["deadline"]["kept"] = json!(false))), + (&[PLANNER_KEPT], Box::new(|b| b["result"]["planner"]["kept"]["deadline"]["elapsed_ms"] = json!(999_999))), + (&[PLANNER_KEPT], Box::new(|b| b["result"]["planner"]["kept"]["deadline"]["seconds"] = json!(60))), + (&[PLANNER_KEPT], Box::new(|b| { b["result"]["planner"]["kept"].as_object_mut().unwrap().shift_remove("cost"); })), + (&[PLANNER_KEPT], Box::new(|b| b["result"]["planner"]["kept"]["energy"] = json!({ "max_joules": 1, "joules": null, "kept": null }))), + (&[PLANNER_KEPT], Box::new(|b| b["result"]["planner"]["kept"]["cost"]["kept"] = json!(false))), + (&[PLANNER_KEPT], Box::new(|b| b["result"]["elapsed_ms"] = json!(999_999))), + (&[CONTRACT_CLASS], Box::new(|b| b["result"]["accuracy"]["class"] = json!("heuristic"))), + (&[SHADOW], Box::new(|b| b["result"]["shadow"] = json!({ "ran": false, "code": "none", "why": "no provider answered" }))), + ]; + for (want, edit) in cases { + let body = resealed(&good, edit); + let mut want = want.to_vec(); + want.sort_unstable(); + assert_eq!(reasons(&body), want, "{}", body["result"]["planner"]); + } + // Another route that meets the contract chosen and run, when the rule picks + // the cheaper: the choice alone is wrong. + let two = seal_local(&json!({ "qasm": BELL, "shots": 100, "contract": { "exactness": "exact" } })); + assert_eq!(two["result"]["planner"]["choice"], "method:stabilizer"); + let dearer = resealed(&two, |b| { + at(b, "method:stabilizer")["outcome"] = json!("met"); + at(b, "method:statevector")["outcome"] = json!("chosen"); + b["result"]["planner"]["choice"] = json!("method:statevector"); + b["result"]["method"] = json!("statevector"); + }); + assert_eq!(reasons(&dearer), vec![PLANNER_CHOICE]); + // A missed deadline is the truth stated, and valid. + let missed_it = resealed(&good, |b| { + b["result"]["elapsed_ms"] = json!(31_000); + b["result"]["planner"]["kept"]["deadline"]["elapsed_ms"] = json!(31_000); + b["result"]["planner"]["kept"]["deadline"]["kept"] = json!(false); + }); + assert_eq!(reasons(&missed_it), Vec::<&str>::new()); + assert!(missed(&missed_it["result"])); + assert!(!missed(&good["result"])); + // No contract, and yet a reasoning. + let plain = seal_local(&json!({ "qasm": ROT, "shots": 100 })); + assert_eq!(reasons(&resealed(&plain, |b| b["result"]["planner"] = good["result"]["planner"].clone())), vec![PLANNER_FORM]); + assert_eq!(reasons(&resealed(&plain, |b| b["result"]["shadow"] = json!({ "ran": false }))), vec![SHADOW]); + assert_eq!(reasons(&plain), Vec::<&str>::new()); +} + +/// A provider's result under a contract, as a host seals it. +fn provider_body(req: &Value, quotes: Vec, counts: Vec) -> Value { + let d = decide(reg(), req, &Host::new(GIB).with_quotes(quotes)).unwrap(); + let Choice::Provider(name) = d.choice else { panic!("a local route was chosen: {}", d.reasoning) }; + let read = provider::read_named(req, Some(&name)).unwrap(); + let text = "OPENQASM 3.0;\nbit[2] c;\ncz $0, $1;\n"; + let m = provider::Measured { + counts, + provider: json!({ "name": name, "kind": "process", "protocol": "wai.quantum.provider/1", "device": "lab:dev", "provenance": "silicon", "qubits": 5, "basis": "rzsxxcz", "describe": "ab".repeat(32) }), + calibration: Some("snap-1".into()), + compiled: json!({ "basis": "rzsxxcz", "program": blake3::hash(text.as_bytes()).to_hex().to_string(), "qasm3": text, "native_gates": 9, "two_qubit_gates": 1, "swaps": 0, "layout": [0, 1], "final_layout": [0, 1], "checked": "checked here" }), + job: json!({ "id": "j-1", "polls": 0 }), + cost: json!({ "free": false, "estimate": { "free": false, "amount": "0.3", "currency": "USD" }, "charged": { "amount": "0.3", "currency": "USD" }, "confirmed": true }), + energy: json!({ "unmetered": "the work ran at the provider" }), + }; + let e = provider::provider_execution(&json!({ "mitigation": "none", "twirling": "none", "decoder": "none", "decoupling": "none", "remapping": "none", "optimisation": "none", "verbatim": true })); + let e = e.unwrap_or_else(|_| provider::provider_execution(&json!({ "mitigation": "none", "twirling": "none", "decoupling": "none", "remapping": "none", "optimisation": "none", "verbatim": true })).unwrap()); + let mut result = provider::result_stated(&read, m, &provider::Statement::new(provider::CountsSource::Shots, e)).unwrap(); + seal_provider(reg(), req, &mut result, &d.reasoning, Some(12_000)); + provider::seal(req, result, &SigningKey::from_bytes(&[9; 32]), "on lab") +} + +fn device_contract() -> Value { + json!({ "qasm": BELL, "shots": 1000, "seed": 7, "contract": { "exactness": "measured", "providers": "allowed", "max_cost": { "amount": "1", "currency": "USD" }, "deadline_seconds": 300 } }) +} + +/// A provider's answer has a classical method's beside it, by the strongest class +/// that can reach it, and their distance, which anyone recomputes from the two. +#[test] +fn a_provider_s_answer_is_shadowed_and_both_are_sealed_with_their_distance() { + let req = device_contract(); + let body = provider_body(&req, vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))], vec![450, 100, 0, 450]); + let c = job::check(&body); + assert!(c.valid(), "{:?}\n{}", c.reasons, body["result"]); + let r = &body["result"]; + let s = &r["shadow"]; + assert_eq!((s["ran"].as_bool(), s["route"].as_str()), (Some(true), Some("method:exact")), "{s}"); + assert_eq!(s["accuracy"]["class"], "bit-exact"); + // Sampled on a stream of its own, and of the same shots. + assert_eq!((s["request"]["seed"].as_u64(), s["request"]["shots"].as_u64()), (Some(7 + (1 << 32)), Some(1000)), "{s}"); + assert_eq!(s["request"]["qasm"], BELL); + assert_eq!(r["planner"]["shadow"]["route"], "method:exact"); + assert_eq!(r["planner"]["shadow"]["budget_seconds"].as_f64(), Some(288.0), "what the deadline leaves after the provider's own time"); + // The distance from the counts, by hand: the shadow's split is its own. + let (a, b) = (r["counts"].as_object().unwrap(), s["counts"].as_object().unwrap()); + let shadow_00 = b["00"].as_u64().unwrap(); + let shadow_11 = b["11"].as_u64().unwrap(); + assert_eq!(shadow_00 + shadow_11, 1000, "the circuit gives no other outcome: {b:?}"); + let want = shadow_00.abs_diff(450) + shadow_11.abs_diff(450) + 100; + assert_eq!(s["distance"]["numerator"].as_u64(), Some(want)); + assert_eq!(s["distance"]["denominator"], 2000); + assert_eq!(s["distance"]["total_variation"].as_f64(), Some(want as f64 / 2000.0)); + assert_eq!(a["01"], 100); + let root = ((450 * shadow_00) as f64).sqrt() + ((450 * shadow_11) as f64).sqrt(); + assert_eq!(s["distance"]["hellinger_fidelity"].as_f64(), Some(root * root / 1e6)); + // The same again: the shadow is the only part of a provider's result that is. + let again = provider_body(&req, vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))], vec![450, 100, 0, 450]); + assert_eq!(again["result"]["shadow"]["counts"], s["counts"]); + let rc = recheck(reg(), &body).unwrap(); + assert_eq!((rc["holds"].as_bool(), rc["shadow"]["same"].as_bool()), (Some(true), Some(true)), "{rc}"); + let mut forged = body.clone(); + forged["result"]["shadow"]["counts"]["00"] = json!(shadow_00 + 1); + forged["result"]["shadow"]["counts"]["11"] = json!(shadow_11 - 1); + assert_eq!(recheck(reg(), &forged).unwrap()["holds"], false); + // What it kept, stated. + let kept = &r["planner"]["kept"]; + assert_eq!((kept["deadline"]["elapsed_ms"].as_u64(), kept["deadline"]["kept"].as_bool(), kept["cost"]["kept"].as_bool()), (Some(12_000), Some(true), Some(true)), "{kept}"); + // A request that names no provider verifies by the planner's choice, and one + // that does by its own. + assert_eq!(r["provider"]["name"], "qpu"); + let mut named = req.clone(); + named["provider"] = json!("qpu"); + assert!(job::check(&provider_body(&named, vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))], vec![500, 0, 0, 500])).valid()); + // A Clifford circuit wider than any state: the tableau shadows it. + let ghz = format!("OPENQASM 3.0;\nqubit[60] q;\nbit[60] c;\nh q[0];\n{}c = measure q;\n", (1..60).map(|i| format!("cx q[0], q[{i}];\n")).collect::()); + let wide_req = json!({ "qasm": ghz, "shots": 100, "contract": { "exactness": "measured", "providers": "allowed", "max_cost": { "amount": "1", "currency": "USD" } } }); + let c = decided(&wide_req, vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))]); + assert_eq!(c.reasoning["shadow"]["route"], "method:stabilizer", "{}", c.reasoning["shadow"]); + assert_eq!(c.reasoning["shadow"]["budget_seconds"].as_f64(), Some(SHADOW_MAX_SECONDS)); +} + +/// When no classical method can reach the same answer within the contract, the +/// result says so and why: the provider's answer stands, and stands alone. +#[test] +fn when_no_shadow_was_possible_the_result_says_so_and_why() { + // The deadline leaves it no time. + let mut req = device_contract(); + req["contract"]["deadline_seconds"] = json!(12); + let body = provider_body(&req, vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))], vec![500, 0, 0, 500]); + let s = &body["result"]["shadow"]; + assert_eq!((s["ran"].as_bool(), s["code"].as_str()), (Some(false), Some("budget")), "{s}"); + assert!(s["why"].as_str().unwrap().contains("0 s"), "{s}"); + assert!(body["result"]["planner"]["shadow"]["route"].is_null()); + assert!(body["result"]["planner"]["shadow"]["tried"].as_array().unwrap().iter().any(|t| t["route"] == "method:stabilizer" && t["code"] == "budget"), "{s}"); + assert!(s.get("counts").is_none()); + assert!(job::check(&body).valid(), "{:?}", job::check(&body).reasons); + let rc = recheck(reg(), &body).unwrap(); + assert_eq!((rc["holds"].as_bool(), rc["shadow"]["checked"].as_bool()), (Some(true), Some(false)), "{rc}"); + // No memory: on a host with less than any method's margin. + let host = Host::new(1 << 20).with_quotes(vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))]); + let c = consider(reg(), &device_contract(), &host).unwrap(); + assert_eq!(c.reasoning["shadow"]["code"], "memory", "{}", c.reasoning["shadow"]); + // Nothing takes it: the seed too wide for a tableau's reach is not the case + // for a provider's dyadic program, so a method's run failing says that. + let reasoning = json!({ "shadow": { "route": "method:exact", "request": { "qasm": "not a program", "shots": 1, "seed": 1, "method": "exact" } }, "host": { "job_bytes": GIB } }); + let s = shadow(reg(), &reasoning, &json!({ "shots": 1, "counts": { "0": 1 }, "omitted_shots": 0 })); + assert_eq!((s["ran"].as_bool(), s["code"].as_str()), (Some(false), Some("failed")), "{s}"); +} + +/// Each rule of a provider's contract job, broken once and found alone. +#[test] +fn every_rule_a_verifier_holds_a_provider_s_contract_job_to_is_broken_once_and_found_alone() { + let req = device_contract(); + let good = provider_body(&req, vec![quote("qpu", "silicon", usd("0.3"), Some(12.0)), quote("sim", "simulator:a state vector", json!({ "free": true }), Some(0.0))], vec![450, 100, 0, 450]); + assert_eq!(reasons(&good), Vec::<&str>::new(), "{}", good["result"]["planner"]); + type Edit = Box; + let cases: Vec<(&[&str], Edit)> = vec![ + (&[SHADOW], Box::new(|b| { b["result"].as_object_mut().unwrap().shift_remove("shadow"); })), + (&[SHADOW], Box::new(|b| { b["result"]["planner"].as_object_mut().unwrap().shift_remove("shadow"); })), + (&[SHADOW], Box::new(|b| { let n = b["result"]["shadow"]["distance"]["numerator"].as_u64().unwrap(); b["result"]["shadow"]["distance"]["numerator"] = json!(n + 1); })), + (&[SHADOW], Box::new(|b| b["result"]["shadow"]["distance"]["total_variation"] = json!(0.0))), + (&[SHADOW], Box::new(|b| b["result"]["shadow"]["distance"]["hellinger_fidelity"] = json!(1.0))), + (&[SHADOW], Box::new(|b| b["result"]["shadow"]["distance"]["sampling_tvd_expected"] = json!(0.0))), + (&[SHADOW], Box::new(|b| b["result"]["shadow"]["distance"] = json!({ "computed": false }))), + (&[SHADOW], Box::new(|b| b["result"]["shadow"]["omitted_shots"] = json!(1))), + (&[SHADOW], Box::new(|b| b["result"]["shadow"]["route"] = json!("method:statevector"))), + (&[SHADOW], Box::new(|b| b["result"]["shadow"]["request"]["seed"] = json!(7))), + (&[SHADOW], Box::new(|b| { b["result"]["shadow"]["request"]["seed"] = json!(7); b["result"]["planner"]["shadow"]["request"]["seed"] = json!(7); })), + (&[SHADOW], Box::new(|b| b["result"]["shadow"]["request"]["qasm"] = json!("OPENQASM 3.0;"))), + (&[SHADOW], Box::new(|b| b["result"]["shadow"] = json!({ "ran": false }))), + (&[SHADOW], Box::new(|b| b["result"]["shadow"] = json!({ "ran": false, "code": "none", "why": "says none, and its plan had one" }))), + (&[SHADOW], Box::new(|b| b["result"]["shadow"] = json!("no"))), + // A provider the planner did not choose answered. + (&[PLANNER_CHOICE, "request_provider"], Box::new(|b| b["result"]["provider"]["name"] = json!("sim"))), + // The simulator is claimed to meet what wants a device. + (&[PLANNER_ROUTE], Box::new(|b| { let r = at(b, "provider:sim"); r["outcome"] = json!("met"); r.as_object_mut().unwrap().shift_remove("rejected"); })), + // A cost past the ceiling, or a provider's time past the deadline, claimed to meet it. + (&[PLANNER_ROUTE, PLANNER_CHOICE], Box::new(|b| at(b, "provider:qpu")["price"]["money"]["amount"] = json!("1.01"))), + (&[PLANNER_ROUTE, PLANNER_CHOICE], Box::new(|b| at(b, "provider:qpu")["price"]["money"]["currency"] = json!("EUR"))), + (&[PLANNER_ROUTE, PLANNER_CHOICE], Box::new(|b| at(b, "provider:qpu")["price"]["money"] = json!({ "free": false, "unknown": "not said" }))), + (&[PLANNER_ROUTE, PLANNER_CHOICE], Box::new(|b| at(b, "provider:qpu")["price"]["time"]["seconds"] = json!(301.0))), + (&[PLANNER_ROUTE, PLANNER_CHOICE], Box::new(|b| at(b, "provider:qpu")["price"]["time"] = json!({ "seconds": null, "why": "not said" }))), + // A device's class that is not its provenance's. + (&[CONTRACT_CLASS, "provider_class"], Box::new(|b| b["result"]["accuracy"]["class"] = json!("simulated"))), + // Charged past the ceiling, and kept said to hold. + (&[PLANNER_KEPT], Box::new(|b| b["result"]["cost"]["charged"]["amount"] = json!("1.5"))), + (&[PLANNER_KEPT], Box::new(|b| b["result"]["planner"]["kept"]["cost"]["max_cost"]["amount"] = json!("100"))), + ]; + for (want, edit) in cases { + let body = resealed(&good, edit); + let mut want = want.to_vec(); + want.sort_unstable(); + assert_eq!(reasons(&body), want, "{}", body["result"]["shadow"]); + } + // Charged past the ceiling, stated: valid, and it says it missed. + let over = resealed(&good, |b| { + b["result"]["cost"]["charged"]["amount"] = json!("1.5"); + b["result"]["planner"]["kept"]["cost"]["charged"]["amount"] = json!("1.5"); + b["result"]["planner"]["kept"]["cost"]["kept"] = json!(false); + }); + assert_eq!(reasons(&over), Vec::<&str>::new()); + assert!(missed(&over["result"])); + // No contract's planner to name it, and the request names none. + let unnamed = resealed(&good, |b| { b["request"].as_object_mut().unwrap().shift_remove("contract"); }); + assert!(reasons(&unnamed).contains(&"request_provider"), "{:?}", reasons(&unnamed)); + // Without providers allowed, the planner's choice does not name it either. + let not_allowed = resealed(&good, |b| { b["request"]["contract"].as_object_mut().unwrap().shift_remove("providers"); }); + assert!(reasons(¬_allowed).contains(&"request_provider"), "{:?}", reasons(¬_allowed)); +} + +/// What a local route costs is one set of bytes on every host, and the digest +/// pins it: this test runs on each host and each architecture CI has. +#[test] +fn what_the_routes_cost_is_the_same_bytes_on_every_host() { + let jobs: [(Value, u64); 5] = [ + (json!({ "qasm": BELL, "shots": 1000, "contract": { "exactness": "exact" } }), GIB), + (json!({ "qasm": ROT, "shots": 100, "observables": ["Z0 Z1"], "contract": { "exactness": "exact" } }), GIB), + (json!({ "qasm": wide(40), "shots": 10, "contract": { "exactness": "heuristic" } }), 8 * GIB), + (json!({ "qasm": "OPENQASM 3.0;\nqubit[8] q;\nh q;\ncx q[0], q[1];\ncx q[1], q[2];\nrz(0.3) q[0];\nrx(0.2) q[2];\n", "shots": 50, "contract": { "exactness": "exact" } }), GIB), + (json!({ "qasm": BELL, "shots": 100, "noise": { "depolarizing_2q": 0.02 }, "contract": { "exactness": "exact" } }), GIB), + ]; + let got: Vec = jobs.iter().map(|(req, cap)| considered(req, *cap).reasoning["stable"]["digest"].as_str().unwrap().to_string()).collect(); + for (i, (req, cap)) in jobs.iter().enumerate() { + assert_eq!(got[i], PINNED_DIGESTS[i], "{req}: every digest now: {got:?}"); + // Heuristic takes what a GPU's single precision gives, so that choice is the host's. + assert_eq!(considered(req, *cap).reasoning["stable"]["choice"], i != 2, "{req}"); + } + // A GPU's route is the host's, and not among what the digest covers. + let c = considered(&jobs[0].0, GIB); + let covered = c.reasoning["stable"]["routes"].as_array().unwrap(); + assert!(!covered.contains(&json!("method:statevector_single")) && !covered.contains(&json!("method:cutrank_single")) && covered.contains(&json!("method:stabilizer")), "{covered:?}"); + // Asking for what a GPU could give makes the choice the host's. + let single = considered(&json!({ "qasm": ROT, "shots": 10, "contract": { "exactness": "single" } }), GIB); + assert_eq!(single.reasoning["stable"]["choice"], false); + // Allowing a provider does too, though this host has none. + assert_eq!(considered(&json!({ "qasm": BELL, "shots": 10, "contract": { "providers": "allowed" } }), GIB).reasoning["stable"]["choice"], false); + // And a local job can be priced again, here, to the sealed digest. + let body = seal_local(&jobs[0].0); + let rc = recheck(reg(), &body).unwrap(); + assert_eq!((rc["holds"].as_bool(), rc["priced"]["same"].as_bool()), (Some(true), Some(true)), "{rc}"); + let forged = resealed(&body, |b| b["result"]["planner"]["stable"]["digest"] = json!("00".repeat(32))); + assert_eq!(recheck(reg(), &forged).unwrap()["holds"], false); +} + +const PINNED_DIGESTS: [&str; 5] = [ + "2ff3b387677fc4860b0aeba26585eea08f41b2693b8d8cd26dbf927006e8a9b6", + "74e00ef788c2493e610521d4fbd79af43e2e0558aa1535a5f6955186e10cf2ad", + "28339eda6fb7659e124649aff6db9f8717da721f7a98d3a33c17879cb9ba43c8", + "23ab02c8b0e119f25db1adc71857da76e67be851ea8c53b71a6f1f86fb838fa4", + "8189fad98f54c33e6956f82c5d4f7d9bd2c46a7ad49ebb08f0bdbf003cb1d323", +]; + +/// Compile, repair, intent and noise pass through: a contract is what is asked of +/// the method, and the job's other members stay what they are. +#[test] +fn the_job_s_other_members_run_as_they_do_under_a_contract() { + // A compiled job's class is of the compiled program, and the result says how far. + let compiled = seal_local(&json!({ "qasm": "OPENQASM 3.0;\nqubit q;\nrx(0.4) q;\n", "shots": 20, "compile": { "epsilon": 0.001 }, "contract": { "exactness": "exact" } })); + assert!(compiled["result"].get("compiled").is_some()); + assert!(job::check(&compiled).valid(), "{:?}", job::check(&compiled).reasons); + // An intent is checked, with its memory in the price. + let intent = json!({ "distribution": { "00": 0.5, "11": 0.5 } }); + let body = seal_local(&json!({ "qasm": BELL, "shots": 50, "intent": intent, "contract": { "exactness": "exact" } })); + assert_eq!(body["result"]["verdict"]["holds"], true); + assert!(job::check(&body).valid()); + // Under noise, the classes are what the noise leaves. + let noisy = considered(&json!({ "qasm": BELL, "shots": 10, "noise": { "depolarizing_2q": 0.01 }, "contract": { "exactness": "exact" } }), GIB); + assert_eq!(noisy.reasoning["choice"], "method:density_matrix"); + assert_eq!(route(&noisy.reasoning, "method:stabilizer")["class"], "estimate"); + assert_eq!(code(&noisy.reasoning, "method:stabilizer"), Some("class")); + // A device target's job has its one route, held to the contract. + let on_target = json!({ "qasm": BELL, "shots": 50, "target": "synthetic-line-5", "contract": {} }); + let body = seal_local(&on_target); + assert_eq!(body["result"]["planner"]["routes"].as_array().unwrap().len(), 1); + assert_eq!(body["result"]["planner"]["wanted_from"], "named"); + assert!(job::check(&body).valid(), "{:?}", job::check(&body).reasons); + let e = catalog::plan(&json!({ "qasm": BELL, "shots": 50, "target": "synthetic-line-5", "contract": { "exactness": "measured" } }), GIB).unwrap_err(); + assert!(e.ends_with("[J071]"), "{e}"); + // A pulse job's bound is held the same way: its class is bounded, not exact. + let pulse = "OPENQASM 3.0;\ndefcalgrammar \"openpulse\";\ncal {\n port d0;\n frame f0 = newframe(d0, 5e9, 0);\n waveform w = gaussian(0.1, 16dt, 4dt);\n}\ndefcal x $0 {\n play(f0, w);\n}\nx $0;\n"; + let asked = json!({ "qasm": pulse, "method": "pulse", "contract": { "exactness": "exact" } }); + match catalog::plan(&asked, GIB) { + Ok(p) => panic!("{p:?}"), + Err(e) => assert!(e.ends_with("[J071]") || refusal::codes_in(&e).iter().any(|c| c.starts_with('J') || c.starts_with('Q')), "{e}"), + } + // On the fabric: a member asked for leaves only the state vector's route. + let c = considered(&json!({ "qasm": BELL, "shots": 10, "fabric": "cpu", "contract": {} }), GIB); + assert_eq!(c.reasoning["choice"], "method:stabilizer"); + assert_eq!(code(&c.reasoning, "method:statevector_single"), Some("fabric")); +} diff --git a/wai/wai-quantum/src/engine/provider.rs b/wai/wai-quantum/src/engine/provider.rs index bc46cdb5f..2edc72420 100644 --- a/wai/wai-quantum/src/engine/provider.rs +++ b/wai/wai-quantum/src/engine/provider.rs @@ -302,7 +302,7 @@ fn hex64(v: &Value) -> bool { /// A provider's provenance as §5.1 has it: `silicon`, or `simulator` or /// `emulator`, alone or followed by `:` and what it is. The class its results /// take: `measured` for silicon, `simulated` for the others. -fn class_of_provenance(p: &str) -> Option<&'static str> { +pub(crate) fn class_of_provenance(p: &str) -> Option<&'static str> { let kind = p.split_once(':').map_or(p, |(k, _)| k); match (kind, p) { (_, "silicon") => Some("measured"), @@ -363,8 +363,15 @@ pub fn check(request: &Value, result: &Value) -> (Vec<&'static str>, Option chosen, + p => p.and_then(Value::as_str), + }; + if result.pointer("/provider/name").and_then(Value::as_str).is_none_or(|n| asked_of != Some(n)) { out.push(REQUEST_PROVIDER); } let asked = match request.get("shots") { @@ -497,7 +504,13 @@ pub struct Request { /// is a program that measures in the middle or turns by an angle that is not /// a dyadic multiple of 2π. pub fn read(v: &Value) -> Result { - let provider = v.get("provider").and_then(Value::as_str).filter(|s| !s.is_empty()).ok_or("a provider job names its provider: \"provider\": \"\"")?.to_string(); + read_named(v, None) +} + +/// [`read`], for a job its contract's planner routed to the provider `name`: the +/// job names none itself, and a job that does is read as naming its own. +pub fn read_named(v: &Value, name: Option<&str>) -> Result { + let provider = v.get("provider").and_then(Value::as_str).or(name).filter(|s| !s.is_empty()).ok_or("a provider job names its provider: \"provider\": \"\"")?.to_string(); let src = v.get("qasm").and_then(Value::as_str).ok_or("a job needs \"qasm\": an OpenQASM 3 program")?; if let Some(at) = super::receipt::inexact_number(v) { return Err(format!("`{at}`: a whole number here must be within ±9007199254740991 (2^53 − 1), so that every JSON reader reads it alike and the receipt binds it")); diff --git a/wai/wai-quantum/src/engine/refusal.rs b/wai/wai-quantum/src/engine/refusal.rs index 08b760a5a..c811b3837 100644 --- a/wai/wai-quantum/src/engine/refusal.rs +++ b/wai/wai-quantum/src/engine/refusal.rs @@ -118,6 +118,13 @@ table! { CONTRACT = "J064", Refused, "A registered component's answer that breaks the engine's contract: a method's result without an accuracy class it declared, or one that writes a member the engine writes (method, qubits, gates, compiled, repaired, engine, schema, components, receipt, verdict); a pass's gates on qubits the program does not have, or that do not read back; a front end's program that does not read. Nothing it gave is returned."; REGISTERED_INTENT = "J065", Refused, "An intent on a job whose noise names a registered channel: the intent checks model the built-in channels alone, so the check is refused rather than made against another model."; + // A contract (engine::planner). + CONTRACT_FORM = "J070", Refused, "A contract that does not read: not an object, a member a contract does not have, an exactness that is no class, a max_cost that is not an amount in decimals and a currency, a deadline or an energy ceiling that is not above zero, providers that is neither never nor allowed, or a job that names a provider while its contract says never."; + NOTHING_MEETS = "J071", Refused, "No route this host can see meets the contract: each route's price or reason is listed, so the contract or the job can be changed. Nothing fell back to a route the contract does not allow."; + CLASS_BROKEN = "J072", Refused, "A method's result whose accuracy class does not meet the contract, as can only happen to a plan that is not the planner's: nothing it gave is returned."; + CONTRACT_HERE = "J073", Refused, "A contract where it cannot be honoured: on a set or an item of one (each program runs under its own contract, alone), or on a build with no planner. It is refused rather than read as absent."; + DEADLINE_PASSED = "J074", Refused, "A run stopped at its contract's deadline, by a host that can stop one: the estimate it was planned on was wrong here, and nothing was sealed."; + // An answer's view statements (the answer view layer). ANSWER_PARSE = "J100", Dropped, "A line of an answer that is not a statement (`name = View(...)`), a program (a fenced `qasm` block with its name), a comment or a marker: left out."; ANSWER_VIEW = "J101", Dropped, "A view the answer layer does not have: left out (the views are listed in the layer's specification)."; diff --git a/wai/wai-quantum/src/engine/registry/mod.rs b/wai/wai-quantum/src/engine/registry/mod.rs index 6ff1ceb05..4e64f72ea 100644 --- a/wai/wai-quantum/src/engine/registry/mod.rs +++ b/wai/wai-quantum/src/engine/registry/mod.rs @@ -870,6 +870,11 @@ impl Registry { if let Some(at) = inexact_integer(request) { return Err(tag(refusal::LIMIT, format!("`{at}`: a whole number here must be within ±9007199254740991 (2^53 − 1), so that every JSON reader reads it alike and the receipt binds it"))); } + // A contract's reasoning travels with its result (engine::planner). + #[cfg(feature = "quantum_receipt")] + if super::planner::has_contract(request) { + return super::planner::plan_and_run_in(self, request, &super::planner::Host::new(job_bytes)); + } let plan = self.plan(request, job_bytes)?; let result = self.run(request, &plan)?; Ok((plan, result)) diff --git a/wai/wai-quantum/src/engine/run.rs b/wai/wai-quantum/src/engine/run.rs index e450638eb..989cbb151 100644 --- a/wai/wai-quantum/src/engine/run.rs +++ b/wai/wai-quantum/src/engine/run.rs @@ -129,6 +129,9 @@ pub(crate) fn run_in(reg: &Registry, request: &Value, plan: &Plan) -> Result) -> Result { let mut out = run_job(reg, request, plan, passes)?; + // A contract's class holds, or nothing comes back (engine::planner). + #[cfg(feature = "quantum_receipt")] + crate::engine::planner::hold_class(request, &out)?; // A pulse run carries its own verdict (engine::pulse). if crate::engine::verdict::asked(request) && catalog::reads_own(reg, request).is_none() { out["verdict"] = crate::engine::verdict::of_run_in(reg, request, &out, plan.memory_bytes)?; diff --git a/wai/wai-quantum/src/engine/sets.rs b/wai/wai-quantum/src/engine/sets.rs index c665b34a1..c8e72b312 100644 --- a/wai/wai-quantum/src/engine/sets.rs +++ b/wai/wai-quantum/src/engine/sets.rs @@ -81,6 +81,15 @@ fn shared(request: &Value) -> Map { /// The items `request` gives, in order, or why it is not a set that reads. pub fn expand(request: &Value) -> Result, String> { + let items = expand_items(request)?; + // A contract's reasoning is one job's: a set's items would each drop it. + if items.iter().any(|i| super::planner::has_contract(&i.request)) { + return Err(super::refusal::tag(super::refusal::CONTRACT_HERE, "a contract is one job's: send each program alone under its own, since a set's receipt binds no planner's reasoning")); + } + Ok(items) +} + +fn expand_items(request: &Value) -> Result, String> { let programs = request.get("programs").filter(|v| !v.is_null()); let sweep = request.get("sweep").filter(|v| !v.is_null()); match (programs, sweep) { -- 2.54.0 (Apple Git-157) From e5ceaf5fa2f8ef0cdda2c0e632ca8982a67cca48 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Fri, 6 Nov 2026 02:22:36 -0500 Subject: [PATCH 02/42] wip: the planner's rules in section 8.6 and the second verifier (a working commit, before falsifying) Co-Authored-By: Claude Opus 5.5 --- wai/extensions/quantum-providers.md | 257 +- .../tools/receipt_differential.py | 3 +- .../tools/receipt_verify.py | 495 +- wai/wai-quantum-cli/docs/llms-full.txt | 152 +- wai/wai-quantum-cli/docs/llms.txt | 2 + wai/wai-quantum-cli/docs/local-mcp.json | 18496 +++++++++++++++- wai/wai-quantum-cli/docs/service-mcp.json | 10536 ++++++++- .../skills/wai-quantum/reference/tools.md | 2 + 8 files changed, 29911 insertions(+), 32 deletions(-) diff --git a/wai/extensions/quantum-providers.md b/wai/extensions/quantum-providers.md index 4ea8fe0e0..f593c9283 100644 --- a/wai/extensions/quantum-providers.md +++ b/wai/extensions/quantum-providers.md @@ -299,8 +299,9 @@ object holding `request`, the job as it was asked, and `result`, which carries its `receipt`. This section says what a provider's result carries (§8.1), how it is sealed and read (§8.2), what its counts' source and its `execution` say (§8.3), what a verifier checks and the reason it gives for each failure -(§8.4), and what the receipt proves (§8.5). A verifier of §8.2 and §8.4 checks -any job's receipt, a provider's or not. +(§8.4), what the receipt proves (§8.5), and what a job under a contract carries +beside it (§8.6). A verifier of §8.2, §8.4 and §8.6 checks any job's receipt, a +provider's or not. ### 8.1 What a provider's result carries @@ -534,7 +535,7 @@ as a set: none for a valid receipt. It is valid exactly when there is none. | `bad_signature` | the signature does not hold, strictly (§8.2), over the digest the receipt states (so a body changed after it was sealed gives `digest_mismatch` alone) | | `inexact_number` | a whole number written as one, in what the receipt seals (the request, and the result less its receipt) and sealed as a double (§8.2), is not a double. A receipt is of the first form when `receipt_form` is not reported and it has no `canon`; one that `receipt_form` refuses names no form, and its numbers are read as a canonical receipt's | | `provider_class` | a provider's result whose `accuracy.class` is not the one its form gives: `measured` in the earlier form; in the stated form, `measured` for `silicon` and `simulated` for a provenance whose part before any `:` is `simulator` or `emulator` (none for any other); or whose `accuracy.approximate` is present and not `true`, or `true` in the earlier form or on a class other than `simulated`. Or a result of another method whose class is `measured` or `simulated` | -| `request_provider` | a provider's result whose `provider.name` is not a string equal to the request's `provider` | +| `request_provider` | a provider's result whose `provider.name` is not a string equal to the request's `provider`; or, when the request gives none (or `null`) and its `contract.providers` is `allowed`, equal to what follows `provider:` in `planner.choice` (§8.6) | | `request_shots` | a provider's result whose `shots` is not the request's (1024 when the request gives none, or `null`) | | `counts` | a provider's result whose `counts` is not an object of outcomes, all of one length and each of `0` and `1` only, to whole numbers from 1 to 2^53 − 1; or whose `shots` (a whole number of at least 1), `omitted_shots` and `distinct_outcomes` (whole numbers of at least 0) are missing; or whose counts and `omitted_shots` do not sum to `shots`; or whose `distinct_outcomes` is not the number of outcomes listed when `omitted_shots` is 0; or, when it is not 0, lists other than 65,536 outcomes, or no more distinct outcomes than it lists | | `provider_members` | a stated provider's result (below) without, or with a wrong type of: `provider`'s `name`, `kind`, `protocol` and `device` (each a string not empty), `provenance` (as `provider_class` reads it), `describe` (64 lower-case hex digits), `qubits` (a whole number of at least 1) and `basis` (equal to `compiled.basis`); `calibration` (a string or `null`); `compiled`'s `basis` (`rzsxxcz`, `prxcz` or `gpizz`), `program` (64 lower-case hex digits), `qasm3` (a string), `native_gates`, `two_qubit_gates` and `swaps` (whole numbers of at least 0), `layout` and `final_layout` (arrays of whole numbers of at least 0) and `checked` (a string); `job`'s `id` (a string not empty) and `polls` (a whole number of at least 0); `ideal.computed` (`true` or `false`); `cost`'s `free` and `confirmed` (each `true` or `false`), `estimate` (an object) and `charged` (`null`, or an object whose `amount` and `currency` are strings); `energy.unmetered` (a string), and `energy.service_kwh_is` (a string) when there is `energy.service_kwh`; `schema` (`wai.quantum.job-result/1`); `engine.name` (`wai-quantum`) and `engine.version` (a string) | @@ -542,6 +543,7 @@ as a set: none for a valid receipt. It is valid exactly when there is none. | `execution` | a stated provider's result whose `execution` breaks a rule of §8.3; or, for a kind with rows, is none of the rows that hold for its provenance; or, for `http` and `process`, is not stated by `provider` or `nobody` | | `compiled_program` | a stated provider's result whose `compiled.program` is not the BLAKE3 of `compiled.qasm3`'s UTF-8 bytes, when `qasm3` is a string and `program` is 64 lower-case hex digits | | `cost_confirmation` | a stated provider's result whose `cost.confirmed` is `true` on a free run or `false` on one that is not free (§7), when both are `true` or `false` | +| `contract_form`, `planner_form`, `planner_route`, `planner_choice`, `planner_stable`, `planner_kept`, `contract_class`, `shadow` | §8.6, for any job's result, a provider's or not | A provider's result is one whose `method` is `provider`. It is *stated* when it carries a member `counts_source` or a member `execution` (whatever their @@ -557,7 +559,8 @@ counts' source and its `execution`, each as the result gives it. These are all the rules: what §8.1 names and this table does not check (`compiled.hash` and `placement`, the notes, the `ideal` figures, the -estimate's contents) is the host's word, unchecked. The schemas +estimate's contents, a route's price where §8.6 does not recompute from it) is +the host's word, unchecked. The schemas (`wai.quantum.job-result/1`, `wai.quantum.receipt/2`) describe what a host writes; a verifier judges by this section. @@ -590,6 +593,243 @@ counts are from what the circuit gives; a distance well above the sampling distance is the device's or the simulator's error, or a program not run as sent. +### 8.6 A job under a contract + +A job says what it wants of an answer in its request's `contract`, and the +planner that took it says why the route it chose was the one, in its result's +`planner`. A *contract job* is one whose request holds a `contract` member other +than `null`. A job with none carries neither `planner` nor `shadow`, and plans as +it did before this section was written, byte for byte. + +**The contract.** An object of these members, each optional; `null` is absent. + +| member | | +|---|---| +| `exactness` | the class wanted: a string of the table below | +| `max_cost` | the most it may cost: an object of exactly `amount`, an amount in decimals (one or more digits, optionally `.` and one or more digits), and `currency`, a string not empty | +| `deadline_seconds` | a number above 0: when it must be done by, in seconds | +| `max_joules` | a number above 0: the most energy it may take, in joules | +| `providers` | `never`, the default, or `allowed`: whether a route may be one of the person's providers. A request that names a `provider` under `never` is refused | + +A contract of any other form is refused (`J070`). So is any other member, which +read as absent would be a requirement dropped in silence. + +`exactness` is met by these classes of a result (§8.1, and the engine's own): + +| wanted | met by | +|---|---| +| `bit-exact` | `bit-exact` | +| `exact` | `bit-exact`, `exact` | +| `single` | `bit-exact`, `exact`, `single` | +| `bounded` | `bit-exact`, `exact`, `bounded` | +| `estimate` | `bit-exact`, `exact`, `bounded`, `estimate` | +| `heuristic` | `bit-exact`, `exact`, `single`, `bounded`, `estimate`, `heuristic` | +| `measured` | `measured` | +| `simulated` | `simulated`, on a result that is not `approximate` | +| `any` | every class | + +This is a table and not a ladder: `single` states no bound, so it does not meet +`bounded`, and a device's counts are in no classical class. + +**The reasoning.** `planner` is an object of: + +| member | | +|---|---| +| `format` | `wai.quantum.planner/1` | +| `routes` | every route the host could see, an array with at least one member, each route's name once | +| `auto` | the route `auto` picks for this job, or `null`: the job names a provider or a method, or `auto` picks none | +| `wanted`, `wanted_from` | the class the routes are held to, and where it comes from, as below | +| `host` | `job_bytes`, the memory one job may take on the host, a whole number; `providers`, the names of the providers it brought, an array of strings | +| `choice` | the name of the route chosen: a route of `routes` | +| `why` | a sentence | +| `stable` | below | +| `kept` | below | +| `shadow` | below: exactly when `choice` is a provider's | + +A route, an object of: + +| member | | +|---|---| +| `route` | its name: `method:`, or `provider:`, neither name empty | +| `kind` | `local` for a method, `provider` for a provider | +| `class` | a string: the class its result has at worst. A method that can be truncated says so: `mps` is `heuristic`, though a result that was not truncated says `exact`. A provider that cannot run the job is `unknown` | +| `host_dependent` | `true` or `false`: whether the route depends on the host. A provider's, a method on a GPU (`statevector_single`, `cutrank_single`) and a method the host registered are | +| `price` | `null`, or an object: below | +| `outcome` | `chosen`, `met` or `rejected`. Exactly one route is `chosen`, and it is `choice` | +| `rejected` | exactly when `outcome` is `rejected`: `code`, one of the codes below, and `why`, a sentence | +| `approximate` | `true`, on a provider's route whose provider states its simulator is approximate | + +and a provider's route may name its `provider`, `device` and `provenance`, a +method's its `method`, as words a person reads. + +A price, an object of: + +| member | | +|---|---| +| `money` | `free`: `true`, or `false` with `amount` and `currency` (strings, the amount as the provider gives it, with an optional `unit`), or `false` with `unknown`, a sentence. An unknown cost is not free (§7) | +| `time` | `seconds`, a number of at least 0 or `null`; with a number, `basis`: `nominal`, at the engine's rate for the method's work, or `provider`, the provider's own estimate, queue included; with `null`, `why` | +| `memory_bytes`, `work` | what a method takes, as whole numbers, a double past 2^53 − 1, or `null` on a provider's route | +| `energy` | `joules`, a number or `null`; with a number, `basis`; with `null`, `why`. No provider states a job's energy before it runs, so a provider's is `null`, and a host that estimates no job's energy states `null` for every route | +| `leaves_out` | what the price leaves out, an array of: `time`, it states no time; `amount`, it states no amount; `energy`, it states no energy; `mitigation`, what the provider's own mitigation costs or does, unless a client set it off or the device has none; `decoder`, any decoder's latency; `charged`, what the provider charges may differ from what it estimates | +| `program` | on a provider's route, optional: the `shots`, `native_gates`, `two_qubit_gates` and `swaps` of what would be sent, and `expected_success` when a calibration states one | + +**What is wanted.** `wanted` is the contract's `exactness` when it gives one, +with `wanted_from` `contract`. When it gives none, the job keeps what it would +have had: when the request names a `provider`, or a `method` other than `auto`, or +`routes` holds one route (a program its method reads itself, a job on a device +target), `wanted` is the class of that route, with `wanted_from` `named`; otherwise +it is the class of `auto`'s route, with `wanted_from` `auto`; and when `auto` is +`null`, both are `null`. + +**Each route's outcome.** A verifier recomputes it from the request, the route and +`host.job_bytes`, by these rules in this order: the first that applies is the +route's `rejected.code`, and a route to which none applies is not rejected. + +1. `not_named`: the request names a `provider` and this is not `provider:` that + name; or it names none, and names a method (a `method` other than `auto`, or + the one route of `routes`) and this is not `method:` that name. +2. `fabric`: the request names neither, and its `fabric` is neither absent, `null` + nor `auto`, and it is `cpu` and this is `method:statevector_single` or + `method:cutrank_single`, or it is anything else and this is not + `method:statevector`. +3. `cannot`: `class` is `unknown` and `price` is `null`. +4. `class`: `wanted` is not `null` and `class` does not meet it; or `wanted` is + `simulated` and `approximate` is `true`; or `wanted` is `null` and this is a + provider's route. +5. `cannot`: `price` is `null`. +6. `memory`: `memory_bytes` is above `host.job_bytes`. +7. `providers`: this is a provider's route, the request names no `provider`, and + `contract.providers` is not `allowed`. +8. `deadline_unknown`, `deadline`: the contract gives `deadline_seconds`, and + `time.seconds` is `null`, or above it. +9. For a provider's route whose `money.free` is not `true`: `cost_no_ceiling`, the + contract gives no `max_cost` and the request names no `provider`; + `cost_unknown`, it gives one and `money` has no `amount` that is an amount in + decimals, or no `currency`; `cost_currency`, the two currencies differ; + `cost`, the amount is above `max_cost.amount`. Amounts are compared exactly, as + decimals, with no double between them, and no currency is converted. A + provider the request names, with no `max_cost`, meets this rule: its cost is + the person's to confirm (§7), as it is with no contract. +10. `energy_unknown`, `energy`: the contract gives `max_joules`, and + `energy.joules` is `null`, or above it. + +So an unknown never passes where something is asked of it, and nothing falls back: +not from exact to approximate, since a less exact route does not meet `wanted`; not +from a simulator to a device or the reverse, since neither's class meets the +other's. A cost ceiling confirms nothing: a run that is not free still needs the +person's word for that run (§7). If no route is left, the job is refused (`J071`) +with each route's reason, and there is no result to seal. + +**The choice.** Of the routes these rules let through, the job runs the one this +picks, and `choice` names it: + +1. when the contract gives no `exactness` and `auto`'s route is let through, it + stands: a contract that names no class changes nothing a job already meets; +2. otherwise the least of them in this order: `money.free` `true` before not, and + then the lesser amount; a `time.seconds` before a `null`, and then the lesser + of each `seconds` × 1000 rounded up to a whole number; `local` before + `provider`; the lesser `memory_bytes`, a `null` read as 0; and the name, by its + UTF-8 bytes. + +`choice` must also be what ran: `method:` the result's `method`, or, when that is +`provider`, `provider:` its `provider.name`. + +**`stable`** says what is the same on every host. It is an object of `scope`, a +sentence; `routes`, the names of the routes whose `kind` is `local` and whose +`host_dependent` is `false`, in the order of `routes`; `digest`; and `choice`. + +- `digest` is the BLAKE3, as 64 lower-case hex digits, of the RFC 8785 text + (§8.2) of the object with `job_bytes`, `host.job_bytes`, and `routes`, an array + with one object for each of those routes in that order: `route`, `class`, and + `seconds`, `memory_bytes` and `work` from its price, each `null` when it has + none. It is the same for this request and `job_bytes` on every host of one + engine; a host that gives another has priced them otherwise, and a verifier that + holds the engine can price them again. +- `choice` is `true` exactly when `choice` names one of those routes, every route + with `host_dependent` `true` is rejected with `not_named`, `fabric` or `class`, + `contract.providers` is not `allowed`, and the contract gives no `max_joules`: + then the route chosen depends on nothing of the host. + +**`kept`** says what the contract asked, against what happened. It holds exactly a +member for each of these the contract gives. A result that missed one is still an +answer, and it says so: a `kept` of `false` breaks no rule. A host that can stop a +run stops it at its deadline (`J074`), and seals nothing. + +| member | | +|---|---| +| `deadline` | `seconds`, the contract's; `elapsed_ms`, a whole number or `null`: the result's `elapsed_ms` when its `method` is not `provider` (`null` when it has none), and otherwise the host's time from the job's submission to its counts; `kept`, whether `elapsed_ms` ≤ `seconds` × 1000, or `null` when `elapsed_ms` is `null` | +| `energy` | `max_joules`, the contract's; `joules`, the result's `energy.joules_micro` ÷ 10^6, or `null` when it has none; `kept`, whether `joules` ≤ `max_joules`, or `null` when `joules` is `null` | +| `cost` | `max_cost`, the contract's; `charged`, the result's `cost.charged`, or `null`; `kept`: with a `charged` in the ceiling's currency and an amount in decimals, whether it is at most the ceiling; with any other `charged`, `null`; with no `charged`, `true` when the result's `cost.free` is `true` or it has none, and otherwise `null` | + +**The class given.** The result's `accuracy.class` meets `wanted` when `wanted` is +not `null`, and a result whose `accuracy.approximate` is `true` does not meet +`simulated`. A method whose result falls short gives no answer (`J072`). + +**The shadow.** When a provider answers a contract job, a classical method that can +reach the same counts within the contract runs too. `planner.shadow` says which, +before anything runs, and the result's `shadow` carries what it gave. A shadow can +be run again by anyone; it is the one part of a provider's result that can. + +`planner.shadow` is an object with `route`, the name of the method, or `null`. With +a name: `class`; `budget_seconds`, what the contract leaves it, the deadline less +the provider's own time, or 300 seconds with no deadline; `price`; and `request`, +an object of `qasm`, the request's; `shots`, the result's; `seed`, the request's +`seed` (1 when it gives none) plus 2^32, modulo 2^53, a stream of its own so that a +seeded simulator's counts are not its counts by construction; and `method`, what +follows `method:` in `route`. With `null`: `code`, `budget`, `memory` or `none`; +`why`, a sentence; and optionally `tried`, each method's own. + +A result's `shadow` is one of: + +- `ran` `false`, with `code`, a string, and `why`, a sentence: when `planner.shadow` + has no `route`, `code` is its `code`; otherwise `failed`, the method's run did not + complete. The provider's answer stands, alone, and says so. +- `ran` `true`, with `route` and `request`, equal to those of `planner.shadow`; + `shots`, the result's; `accuracy`, an object whose `class` is a string; `counts`, + `distinct_outcomes` and `omitted_shots`, whose `counts` and `omitted_shots` sum to + the shots; optionally `elapsed_ms`; and `distance`. + +`distance` is an object. With `computed` `false`, it has `why`, and it is `false` +only when the provider's or the shadow's `omitted_shots` is not 0. Otherwise it is +`computed` `true` and, with a_k and b_k the provider's and the shadow's count of +each outcome k in either (0 when it has none), S the shots, and the outcomes taken +in the order of their UTF-8 bytes: + +- `numerator`, the sum of |a_k − b_k|, and `denominator`, 2·S, whole numbers; +- `total_variation`, `numerator` ÷ `denominator`; +- `hellinger_fidelity`, R·R ÷ (S·S), with R the sum, in that order, of √(a_k·b_k); +- `sampling_tvd_expected`, 0.5·F, with F the sum, in that order, of + √(4·p·(1 − p) ÷ (π·S)) and p = (a_k + b_k) ÷ (2·S): what these shots alone would + leave between two samples of one distribution, on average. + +Each is computed in IEEE 754 doubles in the order written, so that every verifier +gets the same bits. + +**Reasons.** A verifier reports each of these that applies, beside those of §8.4: + +| reason | when | +|---|---| +| `contract_form` | the request's `contract` is not of its form. Of §8.6, reported alone | +| `planner_form` | a contract job's result has no `planner`, or one not of the form above: `format`, `routes` and each route's members, `auto` and `choice` each naming a route of `routes`, `host`, `why`, `stable` and `kept` an object, each present; or `wanted` and `wanted_from` are not what the request and the routes give. Or a result with no contract carries a `planner`. Reported alone of §8.6 when the contract job has none | +| `planner_route` | a route's `rejected.code` is not what the rules above give it (or it is rejected when they let it through, or not when they do not), or the route `chosen` is not one and `choice` | +| `planner_choice` | `choice` is not the route the choice's rules pick from those the rules let through, whatever their `outcome` says; or it is not what ran | +| `planner_stable` | `stable.routes`, `digest` or `choice` is not what the routes give | +| `planner_kept` | `kept` does not hold exactly a member for each the contract gives, or any of those members is not what the table gives | +| `contract_class` | the result's class does not meet `wanted` | +| `shadow` | `planner.shadow` or the result's `shadow` is missing when `choice` is a provider's, or present when it is not; or the result's `shadow` is not of its form above, its `request` is not what `planner.shadow` gives and the request and result imply, its `distance` is not what its counts give. Or a result with no contract carries a `shadow` | + +A verifier also states, for a contract job, its `choice`, `wanted`, the class given, +`stable.choice`, `kept`, whether its shadow ran, and its `total_variation`. A price +is the host's word, as everything it says it received, sent and checked is (§8.5): +what a verifier recomputes is what follows from it. A verifier that holds the engine +can price the routes again and run the shadow again +(`wai-quantum verify --recheck`), which holds `digest` and the shadow's counts to +what a run here gives. + +The free job service reaches no provider. It lists none among its routes, a +contract that wants a device's class is refused there (`J071`), and a request that +names a provider is refused there as it always is (`J002`). + ## 9. Conformance `wai-quantum-qpu/conformance/provider-v1.json` holds the vectors: @@ -621,8 +861,8 @@ by the device. It states its counts' source and its `execution` (§5.5). verifier must say of each (§8.4): receipts made by the command line on this machine and by the job service, provider jobs of every built-in kind through services that follow their contracts, a provider's simulator reached through -a person's account, the earlier form and the first, and receipts sealed to -break one rule each. Two verifiers judge every one of them, and every receipt +a person's account, jobs under a contract (§8.6), the earlier form and the first, +and receipts sealed to break one rule each. Two verifiers judge every one of them, and every receipt made from a valid one by changing one member: `wai-quantum verify`, and `quantum-conformance/tools/receipt_verify.py`, written from §8 alone in another language and sharing no code with the engine. They must report the @@ -639,5 +879,6 @@ A result's receipt seals every member it holds, so a member a later text adds to the result is in no receipt sealed before it, and every such receipt verifies as it did (§8.4's earlier form). `counts_source`, `execution`, `compiled.qasm3`, the class `simulated` and `accuracy.approximate` were added -so, as were the answers' `counts_source` and `execution` and `describe`'s -`approximate`. +so, as were the answers' `counts_source` and `execution`, `describe`'s +`approximate`, and a request's `contract` with a result's `planner` and `shadow` +(§8.6): a receipt of a request with no contract verifies as it did. diff --git a/wai/quantum-conformance/tools/receipt_differential.py b/wai/quantum-conformance/tools/receipt_differential.py index 7ae7fdf51..74d6da495 100644 --- a/wai/quantum-conformance/tools/receipt_differential.py +++ b/wai/quantum-conformance/tools/receipt_differential.py @@ -87,7 +87,8 @@ def run_lines(cmd, path, n): def said(v): """What a verdict says that both verifiers must agree on.""" p = v.get("provider") or {} - return (tuple(sorted(v.get("reasons", []))), v.get("key"), v.get("form"), p.get("form"), p.get("read_as"), p.get("counts_source")) + c = v.get("planner") or {} + return (tuple(sorted(v.get("reasons", []))), v.get("key"), v.get("form"), p.get("form"), p.get("read_as"), p.get("counts_source"), c.get("choice"), c.get("wanted"), c.get("stable_choice"), c.get("shadow_ran")) # ----------------------------------------------------------------- one change at a time diff --git a/wai/quantum-conformance/tools/receipt_verify.py b/wai/quantum-conformance/tools/receipt_verify.py index 3df0a0738..c8f020af0 100644 --- a/wai/quantum-conformance/tools/receipt_verify.py +++ b/wai/quantum-conformance/tools/receipt_verify.py @@ -22,7 +22,9 @@ The reasons are exactly §8.4's: unreadable, not_a_job, no_receipt (each reported alone); receipt_form, digest_mismatch, bad_key, bad_signature; inexact_number; provider_class, request_provider, request_shots, counts (every provider result); provider_members, - counts_source, execution, compiled_program, cost_confirmation (the stated form). + counts_source, execution, compiled_program, cost_confirmation (the stated form); + contract_form, planner_form, planner_route, planner_choice, planner_stable, + planner_kept, contract_class, shadow (a job under a contract, section 8.6). --plant NAME exists only to prove that a differential against another verifier can fail: each plant breaks one rule on purpose, and a verifier run with one is @@ -32,12 +34,16 @@ wrong by design. NAME is one of: last-duplicate read a duplicated member name, keeping the last, not refusing no-inexact skip inexact_number measured-simulator accept class measured on a simulator's stated result + route-unchecked take each route's stated outcome as it stands (section 8.6) + choice-unchecked take the planner's choice as it stands (section 8.6) + distance-unchecked take a shadow's stated distance as it stands (section 8.6) Without --plant the verifier is exactly §8's. Its reader's questions of the text, gap by gap, are what §8 now says: where §8 left a choice, it was settled in the text, and this file follows the text. """ +import fractions import hashlib import json import math @@ -45,7 +51,8 @@ import re import struct import sys -PLANTS_KNOWN = ("lenient-key", "no-alg", "last-duplicate", "no-inexact", "measured-simulator") +PLANTS_KNOWN = ("lenient-key", "no-alg", "last-duplicate", "no-inexact", "measured-simulator", + "route-unchecked", "choice-unchecked", "distance-unchecked") PLANTS = set() MAX_DEPTH = 127 # §8.2: nesting deeper than 127 is unreadable @@ -932,7 +939,12 @@ def check_provider(request, result, reasons): stated = "counts_source" in result or "execution" in result check_class(result, True, stated, reasons) # §8.4 request_provider: provider.name a string equal to the request's provider. + # §8.4, §8.6: or, when the request gives none and its contract allows a provider, + # the one its planner chose. name, asked = _member(result, "provider", "name"), request.get("provider") + if asked is None and _member(request, "contract", "providers") == "allowed": + choice = _member(result, "planner", "choice") + asked = choice[len("provider:"):] if isinstance(choice, str) and choice.startswith("provider:") else None if not (isinstance(name, str) and isinstance(asked, str) and name == asked): reasons.add("request_provider") # §8.4 request_shots: the request's shots, 1024 when it gives none or null. @@ -971,6 +983,482 @@ def provider_statement(result): } +# ================================================== 6b. a job under a contract (§8.6) + +CONTRACT_MEMBERS = ("exactness", "max_cost", "deadline_seconds", "max_joules", "providers") +MEETS = { + "bit-exact": ("bit-exact",), + "exact": ("bit-exact", "exact"), + "single": ("bit-exact", "exact", "single"), + "bounded": ("bit-exact", "exact", "bounded"), + "estimate": ("bit-exact", "exact", "bounded", "estimate"), + "heuristic": ("bit-exact", "exact", "single", "bounded", "estimate", "heuristic"), + "measured": ("measured",), + "simulated": ("simulated",), +} +CLASSES_WANTED = tuple(MEETS) + ("any",) +LEAVES_OUT = ("time", "amount", "energy", "mitigation", "decoder", "charged") +_DECIMAL = re.compile(r"[0-9]+(?:\.[0-9]+)?") +_GPU_METHODS = ("method:statevector_single", "method:cutrank_single") + + +def meets(wanted, got): + """§8.6's table. `any` takes every class; a class nobody knows meets nothing else.""" + return wanted == "any" or (wanted in MEETS and got in MEETS[wanted]) + + +def _is_decimal(s): + return isinstance(s, str) and _DECIMAL.fullmatch(s) is not None + + +def read_contract(c): + """§8.6: the contract as (exactness, max_cost, deadline, joules, providers), or None + when it is not of its form. Null is absent.""" + if not isinstance(c, dict) or any(k not in CONTRACT_MEMBERS for k in c): + return None + exactness = c.get("exactness") + if exactness is not None and exactness not in CLASSES_WANTED: + return None + cost = c.get("max_cost") + if cost is not None: + if not (isinstance(cost, dict) and len(cost) == 2 and _is_decimal(cost.get("amount")) + and isinstance(cost.get("currency"), str) and cost["currency"]): + return None + for k in ("deadline_seconds", "max_joules"): + v = c.get(k) + if v is not None and not (isinstance(v, Num) and v.value > 0): + return None + providers = c.get("providers") + if providers is not None and providers not in ("never", "allowed"): + return None + return {"exactness": exactness, "max_cost": cost, + "deadline": c["deadline_seconds"].value if c.get("deadline_seconds") is not None else None, + "joules": c["max_joules"].value if c.get("max_joules") is not None else None, + "providers": providers} + + +def _number(v): + return v.value if isinstance(v, Num) else None + + +def _route_form(r): + if not isinstance(r, dict): + return False + name, kind = r.get("route"), r.get("kind") + if not isinstance(name, str): + return False + method, provider = name.startswith("method:"), name.startswith("provider:") + if not ((method and len(name) > 7 and kind == "local") or (provider and len(name) > 9 and kind == "provider")): + return False + outcome = r.get("outcome") + if outcome in ("chosen", "met"): + if "rejected" in r: + return False + elif outcome == "rejected": + rej = r.get("rejected") + if not (isinstance(rej, dict) and isinstance(rej.get("code"), str) and isinstance(rej.get("why"), str)): + return False + else: + return False + if "price" not in r: + return False + p = r["price"] + if p is not None: + if not isinstance(p, dict): + return False + m = p.get("money") + if not isinstance(m, dict): + return False + if m.get("free") is False: + if not (isinstance(m.get("unknown"), str) or (isinstance(m.get("amount"), str) and isinstance(m.get("currency"), str))): + return False + elif m.get("free") is not True: + return False + t = p.get("time") + if not isinstance(t, dict) or not (t.get("seconds") is None or (isinstance(t["seconds"], Num) and t["seconds"].value >= 0)): + return False + e = p.get("energy") + if not isinstance(e, dict) or not (e.get("joules") is None or isinstance(e["joules"], Num)): + return False + left = p.get("leaves_out") + if not isinstance(left, list) or any(w not in LEAVES_OUT for w in left): + return False + for k in ("memory_bytes", "work"): + if k not in p or not (p[k] is None or (_whole(p[k]) and p[k].value >= 0)): + return False + return isinstance(r.get("class"), str) and isinstance(r.get("host_dependent"), bool) + + +def _planner_form(p): + if not isinstance(p, dict) or p.get("format") != "wai.quantum.planner/1": + return False + if not (p.get("wanted") is None or isinstance(p["wanted"], str)): + return False + if "wanted_from" not in p: + return False + if p["wanted_from"] is None: + if p.get("wanted") is not None: + return False + elif p["wanted_from"] not in ("contract", "named", "auto"): + return False + routes = p.get("routes") + if not isinstance(routes, list) or not routes or not all(_route_form(r) for r in routes): + return False + names = [r["route"] for r in routes] + if len(set(names)) != len(names): + return False + if not (p.get("auto") is None or p["auto"] in names) or p.get("choice") not in names: + return False + host = p.get("host") + if not isinstance(host, dict) or not (_whole(host.get("job_bytes")) and host["job_bytes"].value >= 0): + return False + providers = host.get("providers") + if not isinstance(providers, list) or not all(isinstance(x, str) for x in providers): + return False + return isinstance(p.get("why"), str) and isinstance(p.get("stable"), dict) and isinstance(p.get("kept"), dict) + + +def _named(request, routes): + """§8.6: what a request names: a provider, or a method (or the one route of routes).""" + provider = request.get("provider") + provider = provider if isinstance(provider, str) else None + method = None + if provider is None: + m = request.get("method") + if isinstance(m, str) and m != "auto": + method = m + if len(routes) == 1: + name = routes[0]["route"] + method = name[len("method:"):] if name.startswith("method:") else None + return provider, method + + +def _gate(r, contract, request, provider, method, wanted, job_bytes): + """§8.6's rules, in order: the first that applies, or None.""" + name, price = r["route"], r["price"] + is_provider = name.startswith("provider:") + # 1 + if provider is not None: + if name != "provider:" + provider: + return "not_named" + elif method is not None and name != "method:" + method: + return "not_named" + # 2 + if provider is None and method is None: + fabric = request.get("fabric") + if fabric == "cpu": + if name in _GPU_METHODS: + return "fabric" + elif fabric is not None and fabric != "auto" and name != "method:statevector": + return "fabric" + cls = r["class"] + # 3 + if cls == "unknown" and price is None: + return "cannot" + # 4 + if wanted is not None: + if not meets(wanted, cls) or (wanted == "simulated" and r.get("approximate") is True): + return "class" + elif is_provider: + return "class" + # 5 + if price is None: + return "cannot" + # 6 + memory = _number(price["memory_bytes"]) + if memory is not None and memory > job_bytes: + return "memory" + # 7 + if is_provider and provider is None and contract["providers"] != "allowed": + return "providers" + # 8 + if contract["deadline"] is not None: + seconds = _number(price["time"].get("seconds")) + if seconds is None: + return "deadline_unknown" + if seconds > contract["deadline"]: + return "deadline" + # 9 + money = price["money"] + if is_provider and money.get("free") is not True: + ceiling = contract["max_cost"] + if ceiling is None: + if provider is None: + return "cost_no_ceiling" + else: + amount, currency = money.get("amount"), money.get("currency") + if not (_is_decimal(amount) and isinstance(currency, str)): + return "cost_unknown" + if currency != ceiling["currency"]: + return "cost_currency" + if fractions.Fraction(amount) > fractions.Fraction(ceiling["amount"]): + return "cost" + # 10 + if contract["joules"] is not None: + joules = _number(price["energy"].get("joules")) + if joules is None: + return "energy_unknown" + if joules > contract["joules"]: + return "energy" + return None + + +def _order_key(r): + """§8.6's order: money, time to the millisecond, local first, memory, name.""" + p = r["price"] + money = p["money"] + if money.get("free") is True: + cost = (0, fractions.Fraction(0)) + else: + amount = money.get("amount") + cost = (1, fractions.Fraction(amount) if _is_decimal(amount) else fractions.Fraction(0)) + seconds = _number(p["time"].get("seconds")) + time = (1, 0) if seconds is None else (0, math.ceil(seconds * 1000.0)) + return (cost, time, 0 if r["kind"] == "local" else 1, _number(p["memory_bytes"]) or 0.0, r["route"].encode("utf-8")) + + +def _picked(routes, auto, contract, passes): + """§8.6's choice, of the routes the rules let through.""" + let_through = [r for r in routes if passes(r)] + if contract["exactness"] is None and auto is not None: + for r in let_through: + if r["route"] == auto: + return r["route"] + return min(let_through, key=_order_key)["route"] if let_through else None + + +def _stable_holds(p, routes, contract): + """§8.6 stable: routes, digest and choice as the routes give them.""" + stable = p["stable"] + covered = [r for r in routes if r["kind"] == "local" and r["host_dependent"] is False] + facts = [] + for r in covered: + price = r["price"] if isinstance(r["price"], dict) else {} + facts.append({"route": r["route"], "class": r["class"], "seconds": _member(price, "time", "seconds"), + "memory_bytes": price.get("memory_bytes"), "work": price.get("work")}) + digest = blake3(text_of({"job_bytes": p["host"]["job_bytes"], "routes": facts}, True).encode("utf-8")).hex() + names = [r["route"] for r in covered] + others = all(_member(r, "rejected", "code") in ("not_named", "fabric", "class") for r in routes if r["host_dependent"] is not False) + choice = p["choice"] in names and others and contract["providers"] != "allowed" and contract["joules"] is None + return stable.get("routes") == names and stable.get("digest") == digest and stable.get("choice") is choice + + +def _kept_holds(p, contract, result): + """§8.6 kept: a member for each the contract gives, each as its table says.""" + kept = p["kept"] + asked = (("deadline", contract["deadline"] is not None), ("energy", contract["joules"] is not None), ("cost", contract["max_cost"] is not None)) + if len(kept) != sum(1 for _, a in asked if a) or any((n in kept) != a for n, a in asked): + return False + if contract["deadline"] is not None: + d = contract["deadline"] + k = kept["deadline"] + if not isinstance(k, dict): + return False + e = k.get("elapsed_ms") + if not (e is None or (_whole(e) and e.value >= 0)): + return False + want = None if e is None else e.value <= d * 1000.0 + if _number(k.get("seconds")) != d or k.get("kept") is not want: + return False + if result.get("method") != "provider" and _number(result.get("elapsed_ms")) != _number(e): + return False + if contract["joules"] is not None: + j = contract["joules"] + k = kept["energy"] + if not isinstance(k, dict): + return False + micro = _number(_member(result, "energy", "joules_micro")) + x = None if micro is None else micro / 1e6 + if _number(k.get("max_joules")) != j or _number(k.get("joules")) != x or k.get("kept") is not (None if x is None else x <= j): + return False + if contract["max_cost"] is not None: + ceiling = contract["max_cost"] + k = kept["cost"] + if not isinstance(k, dict): + return False + charged = _member(result, "cost", "charged") + free = _member(result, "cost", "free") + no_free_member = not (isinstance(result.get("cost"), dict) and "free" in result["cost"]) + if charged is not None: + amount = _member(charged, "amount") + if _is_decimal(amount) and _member(charged, "currency") == ceiling["currency"]: + held = fractions.Fraction(amount) <= fractions.Fraction(ceiling["amount"]) + else: + held = None + elif no_free_member or free is True: + held = True + else: + held = None + if (_member(k, "max_cost", "amount") != ceiling["amount"] or _member(k, "max_cost", "currency") != ceiling["currency"] + or k.get("kept") is not held or (k.get("charged") is None) != (charged is None)): + return False + return True + + +def _count(v): + """A count as a whole number written as one, at least 0, or 0.""" + return int(v.text) if isinstance(v, Num) and v.literal_whole() and not v.text.startswith("-") else 0 + + +def shadow_distance(a, b, shots): + """§8.6 distance: the numerator, the denominator, the total variation, the Hellinger + fidelity and what the shots alone leave, in order, or None when it cannot be taken.""" + if not (isinstance(a, dict) and isinstance(b, dict)) or shots <= 0: + return None + s = float(shots) + numerator, root, floor = 0, 0.0, 0.0 + for k in sorted(set(a) | set(b), key=lambda k: k.encode("utf-8")): + x, y = _count(a.get(k)), _count(b.get(k)) + numerator += abs(x - y) + root += math.sqrt(float(x * y)) + p = float(x + y) / (2.0 * s) + inner = 4.0 * p * (1.0 - p) / (math.pi * s) + if inner < 0: + return None + floor += math.sqrt(inner) + denominator = 2 * shots + return (numerator, denominator, float(numerator) / float(denominator), root * root / (s * s), 0.5 * floor) + + +def _shadow_holds(request, p, result): + """§8.6 shadow: of its form, what its plan and the job imply, its distance its counts'.""" + s, plan = result["shadow"], p["shadow"] + if not isinstance(s, dict) or not isinstance(plan, dict): + return False + ran = s.get("ran") + if ran is False: + if not (isinstance(s.get("code"), str) and isinstance(s.get("why"), str)): + return False + return s["code"] == plan.get("code") if plan.get("route") is None else s["code"] == "failed" + if ran is not True: + return False + shots_n = result.get("shots") + shots = _number(shots_n) + req = s.get("request") + if not isinstance(req, dict) or not _same(plan.get("request"), req) or not _same(req.get("qasm"), request.get("qasm")): + return False + if _number(req.get("shots")) != shots or shots is None: + return False + seed = request.get("seed") + seed = int(seed.text) if isinstance(seed, Num) and seed.literal_whole() and not seed.text.startswith("-") else 1 + want_seed = (seed + 2 ** 32) % 2 ** 53 + given = req.get("seed") + if not (isinstance(given, Num) and given.literal_whole() and not given.text.startswith("-") and int(given.text) == want_seed): + return False + route = plan.get("route") + if not (isinstance(route, str) and route.startswith("method:") and req.get("method") == route[len("method:"):]): + return False + counts = s.get("counts") + if not isinstance(counts, dict): + return False + listed = sum(v.value for v in counts.values() if isinstance(v, Num)) + if _number(s.get("omitted_shots")) is None or _number(s["omitted_shots"]) + listed != shots or not (_whole(s.get("distinct_outcomes")) and s["distinct_outcomes"].value >= 0): + return False + d = s.get("distance") + if not isinstance(d, dict): + return False + theirs, ours = _count(result.get("omitted_shots")), _count(s.get("omitted_shots")) + if d.get("computed") is False: + if not isinstance(d.get("why"), str) or (theirs == 0 and ours == 0): + return False + elif d.get("computed") is True: + if "distance-unchecked" not in PLANTS: # PLANT + want = shadow_distance(result.get("counts"), counts, int(shots)) + if want is None or theirs != 0 or ours != 0: + return False + for k, v in zip(("numerator", "denominator", "total_variation", "hellinger_fidelity", "sampling_tvd_expected"), want): + if _number(d.get(k)) != float(v): + return False + else: + return False + return (s.get("route") == route and isinstance(_member(s, "accuracy", "class"), str) and _number(s.get("shots")) == shots) + + +def check_contract(request, result, reasons): + # §8.6. A job with no contract carries neither a reasoning nor a shadow. + given = request.get("contract") + planner = result.get("planner") + if given is None: + if "planner" in result: + reasons.add("planner_form") + if "shadow" in result: + reasons.add("shadow") + return + contract = read_contract(given) + if contract is None: + reasons.add("contract_form") + return + if not _planner_form(planner): + reasons.add("planner_form") + return + routes = planner["routes"] + provider, method = _named(request, routes) + # What is wanted, and where from. + class_of = dict((r["route"], r["class"]) for r in routes) + if contract["exactness"] is not None: + wanted, source = contract["exactness"], "contract" + elif provider is not None: + wanted, source = class_of.get("provider:" + provider), "named" + elif method is not None: + wanted, source = class_of.get("method:" + method), "named" + elif planner.get("auto") is not None: + wanted, source = class_of.get(planner["auto"]), "auto" + else: + wanted, source = None, None + if planner.get("wanted") != wanted or planner["wanted_from"] != source: + reasons.add("planner_form") + return + job_bytes = planner["host"]["job_bytes"].value + + def gate(r): + return _gate(r, contract, request, provider, method, wanted, job_bytes) + + broken = False + chosen = [r["route"] for r in routes if r["outcome"] == "chosen"] + if "route-unchecked" not in PLANTS: # PLANT + for r in routes: + if _member(r, "rejected", "code") != gate(r): + broken = True + if len(chosen) != 1 or chosen[0] != planner["choice"]: + broken = True + if broken: + reasons.add("planner_route") + if result.get("method") == "provider": + name = _member(result, "provider", "name") + ran = "provider:" + name if isinstance(name, str) else None + else: + m = result.get("method") + ran = "method:" + m if isinstance(m, str) else None + if "choice-unchecked" not in PLANTS: # PLANT + if _picked(routes, planner.get("auto"), contract, lambda r: gate(r) is None) != planner["choice"] or ran != planner["choice"]: + reasons.add("planner_choice") + if not _stable_holds(planner, routes, contract): + reasons.add("planner_stable") + if not _kept_holds(planner, contract, result): + reasons.add("planner_kept") + if wanted is not None: + cls = _member(result, "accuracy", "class") + if not meets(wanted, cls) or (wanted == "simulated" and _member(result, "accuracy", "approximate") is True): + reasons.add("contract_class") + is_provider = planner["choice"].startswith("provider:") + if is_provider != ("shadow" in result) or is_provider != ("shadow" in planner) or (is_provider and not _shadow_holds(request, planner, result)): + reasons.add("shadow") + + +def contract_statement(result): + """§8.6: what a verifier states of a job under a contract.""" + p = result.get("planner") + return { + "choice": _plain(_member(p, "choice")), + "wanted": _plain(_member(p, "wanted")), + "class": _plain(_member(result, "accuracy", "class")), + "stable_choice": _plain(_member(p, "stable", "choice")), + "kept": _plain(_member(p, "kept")), + "shadow_ran": _plain(_member(result, "shadow", "ran")), + "shadow_total_variation": _plain(_member(result, "shadow", "distance", "total_variation")), + } + + # ===================================================================== 7. a job def judge(raw): @@ -990,6 +1478,8 @@ def judge(raw): provider = result.get("method") == "provider" if provider: verdict["provider"] = provider_statement(result) + if "planner" in result: + verdict["planner"] = contract_statement(result) if "receipt" not in result: verdict["reasons"] = ["no_receipt"] return verdict @@ -1000,6 +1490,7 @@ def judge(raw): check_provider(request, result, reasons) else: check_class(result, False, False, reasons) + check_contract(request, result, reasons) verdict["reasons"] = sorted(reasons) verdict["valid"] = not reasons return verdict diff --git a/wai/wai-quantum-cli/docs/llms-full.txt b/wai/wai-quantum-cli/docs/llms-full.txt index ff1d130f0..e20af46cb 100644 --- a/wai/wai-quantum-cli/docs/llms-full.txt +++ b/wai/wai-quantum-cli/docs/llms-full.txt @@ -43,7 +43,7 @@ Runs on this machine, signed with the user's key; nothing leaves the machine. ### `run_quantum_circuit`: Run a quantum program here -Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more. +Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `contract` (the class wanted, a deadline) and the planner prices every method here, runs the cheapest that meets it, seals its reasoning under `planner`, and refuses (J071) rather than fall back to less; this tool reaches no provider, and plan_routes and run_routed do. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more. Parameters: - `source` (object): The program in another format, in place of qasm: read to the job's qasm before the job is read (a module that does not read is refused with the reader's code, Q700 to Q721), the request keeping its source. @@ -64,10 +64,11 @@ Parameters: - `mitigate` (any): Mitigate the job's expectation values (or, for readout, its counts) under its own noise: zne (the whole program folded U(U†U)^k and extrapolated), pea (the noise learned as a sparse Pauli–Lindblad model and amplified), pec (the learned channels inverted and sampled), cdr (a line fitted over near-Clifford training circuits), vd (two copies), readout (the counts' flips inverted). Needs noise and observables (shots for readout), at most 8 qubits. The result's `mitigation` gives raw and mitigated values with standard errors, the ideal value (known because this is a simulation), the method's bias and variance assumptions and its cost. A method's name, or an object. - `pulse` (object): A pulse run's options (method "pulse"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0. - `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050). +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). ### `plan_quantum_circuit`: Plan a quantum program -The method a program would run on and why, the memory and work it would take, without running it. +The method a program would run on and why, the memory and work it would take, without running it. With a contract, every route's price or reason for rejection under planner, or the refusal (J071) when no route meets it. Parameters: - `source` (object): The program in another format, in place of qasm: read to the job's qasm before the job is read (a module that does not read is refused with the reader's code, Q700 to Q721), the request keeping its source. @@ -88,6 +89,7 @@ Parameters: - `mitigate` (any): Mitigate the job's expectation values (or, for readout, its counts) under its own noise: zne (the whole program folded U(U†U)^k and extrapolated), pea (the noise learned as a sparse Pauli–Lindblad model and amplified), pec (the learned channels inverted and sampled), cdr (a line fitted over near-Clifford training circuits), vd (two copies), readout (the counts' flips inverted). Needs noise and observables (shots for readout), at most 8 qubits. The result's `mitigation` gives raw and mitigated values with standard errors, the ideal value (known because this is a simulation), the method's bias and variance assumptions and its cost. A method's name, or an object. - `pulse` (object): A pulse run's options (method "pulse"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0. - `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050). +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). ### `lint_qasm`: Check an OpenQASM program @@ -224,10 +226,11 @@ Parameters: ### `verify_quantum_result`: Check a result's receipt -Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and which key signed it. +Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and which key signed it; for a job under a contract, every route's outcome and the choice recomputed from what it states, and with recheck its routes priced again and its shadow run again. Parameters: - `job` (object, required): The job: {"request": ..., "result": ...}, the result carrying its receipt. +- `recheck` (boolean): For a job under a contract: its routes priced again at the job's memory, held to the digest it sealed, and its shadow run again, held to its counts bit for bit. ### `discover_evaluate`: Judge a generator against a workbench specification @@ -440,6 +443,7 @@ Parameters: - `mitigate` (any): Mitigate the job's expectation values (or, for readout, its counts) under its own noise: zne (the whole program folded U(U†U)^k and extrapolated), pea (the noise learned as a sparse Pauli–Lindblad model and amplified), pec (the learned channels inverted and sampled), cdr (a line fitted over near-Clifford training circuits), vd (two copies), readout (the counts' flips inverted). Needs noise and observables (shots for readout), at most 8 qubits. The result's `mitigation` gives raw and mitigated values with standard errors, the ideal value (known because this is a simulation), the method's bias and variance assumptions and its cost. A method's name, or an object. - `pulse` (object): A pulse run's options (method "pulse"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0. - `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050). +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). ### `qec_code`: Show an error-correcting code and certify its distance @@ -585,6 +589,7 @@ Parameters: - `inputs` (object): A generator's inputs' values, as {"n": 5}. - `shots` (integer): Shots (default 1024). - `seed` (integer): A seed, for a provider that is a seeded simulator; a device ignores it. +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). ### `run_on_provider`: Run on a provider (can spend the person's money) @@ -596,8 +601,34 @@ Parameters: - `inputs` (object): A generator's inputs' values, as {"n": 5}. - `shots` (integer): Shots (default 1024). - `seed` (integer): A seed, for a provider that is a seeded simulator; a device ignores it. +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). - `confirm_cost` (boolean): true only when the person has agreed to this run's cost. A run that is not free is refused without it. +### `plan_routes`: Weigh a contract against every route + +Every route a job could take under its contract: the methods on this machine and each of the person's own providers, each with its price or why it was rejected, what a provider's estimate leaves out, and the route the planner would choose: the cheapest that meets the contract, or the refusal (J071) with every route's reason. Each provider is asked to describe its device and estimate the job. Nothing is submitted and nothing is spent. A device is chosen only when exactness asks for measured or any. + +Parameters: +- `qasm` (string, required): The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why. +- `inputs` (object): A generator's inputs' values, as {"n": 5}. +- `shots` (integer): Shots (default 1024). +- `seed` (integer): A seed. +- `observables` (array): Pauli observables: a provider's job answers counts, so a method here answers these. +- `contract` (any, required): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). + +### `run_routed`: Run a job on the route its contract chooses (can spend the person's money) + +Runs a job on the route plan_routes chooses: a method on this machine, or one of the person's own providers. THIS CAN SPEND THE PERSON'S MONEY OR QUOTA, when the contract allows a provider and one is chosen. A cost ceiling confirms nothing: a run that is not free is refused unless confirm_cost is true, set only after the person has seen the estimate and agreed to that run. The answer is a job in the service's form, its result carrying the planner's reasoning under planner; a provider's result also carries a classical method's counts and their distance under shadow, or why no classical method could reach them. If the job has not finished within this call the answer has status running and an id, and get_provider_job collects it later. Do not run it again to find out: that is a second job, and it can be a second bill. + +Parameters: +- `qasm` (string, required): The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why. +- `inputs` (object): A generator's inputs' values, as {"n": 5}. +- `shots` (integer): Shots (default 1024). +- `seed` (integer): A seed. +- `observables` (array): Pauli observables: a provider's job answers counts, so a method here answers these. +- `contract` (any, required): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). +- `confirm_cost` (boolean): true only when the person has agreed to this run's cost. A run that is not free is refused without it, whatever the contract's ceiling. + ### `get_provider_job`: Ask after a job on a provider Where a job on one of the person's providers stands, by the id run_on_provider gave: still running, or finished, with its counts then sealed in a receipt, or ended, with why. Asking spends nothing and can be repeated; a finished job gives the same answer every time. It asks once and does not wait, so ask again later rather than in a loop: a device's queue can take hours or days. @@ -642,6 +673,7 @@ Parameters: - `pulse` (object): A pulse run's options (method "pulse"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0. - `source` (object): The program in another format, in place of qasm: read to the job's qasm before the job is read (a module that does not read is refused with the reader's code, Q700 to Q721), the request keeping its source. - `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read; a parameter left without one is refused (J050). In a sweep, the parameters it fixes. +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). - `idempotency_key` (string): A key of your making that names this run, so that a call sent again is not a second job: the same key with the same arguments answers with the job it names, for as long as the job is kept, rather than running another; the same key with other arguments is refused (J034). Make it unguessable (a UUID). A job the service interrupted is run again under its key. Without a key, every call is a new job. ### `run_quantum_set`: Run a set of quantum programs, or one over a grid @@ -693,6 +725,7 @@ Parameters: - `programs` (array): The set's programs: each a program's text, or a job ({"qasm", …}) whose own fields win over the set's. - `sweep` (object): Each input of qasm and its values: every combination runs, the names in sorted order, the first varying slowest; an integer input's values are whole numbers. - `source` (object): The program in another format, in place of qasm: read to the job's qasm before the job is read (a module that does not read is refused with the reader's code, Q700 to Q721), the request keeping its source. +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). ### `get_quantum_job`: Read a quantum job @@ -825,7 +858,7 @@ Parameters: - `observables` (array): Pauli strings to take expectation values of, e.g. ["Z0", "Z0 Z1", "X2 Y3"]. Qubits count from 0. - `amplitudes` (array): Basis states to give amplitudes of: one character per qubit, qubit n-1 first, e.g. "0011". - `noise` (object): Optional noise, each a probability: depolarizing_1q, depolarizing_2q, amplitude_damping, dephasing (after each gate on its qubits), readout (each measured bit). -- `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read; a parameter left without one is refused (J050). In a sweep, the parameters it fixes. +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). - `seed` (integer): Sampling seed (default 1); the same job and seed give the same counts. - `options` (object): Advanced, per method: max_bond (mps), threshold and max_terms (pauli), fusion (statevector), trajectories. - `compile` (object): Compile the program first (as compile_qasm does) and run the compiled circuit: with basis clifford_t it runs bit-exact, and the result's `compiled` states its distance from the program. @@ -836,6 +869,7 @@ Parameters: - `mitigate` (any): Mitigate the job's expectation values (or, for readout, its counts) under its own noise: zne (the whole program folded U(U†U)^k and extrapolated), pea (the noise learned as a sparse Pauli–Lindblad model and amplified), pec (the learned channels inverted and sampled), cdr (a line fitted over near-Clifford training circuits), vd (two copies), readout (the counts' flips inverted). Needs noise and observables (shots for readout), at most 8 qubits. The result's `mitigation` gives raw and mitigated values with standard errors, the ideal value (known because this is a simulation), the method's bias and variance assumptions and its cost. A method's name, or an object. - `pulse` (object): A pulse run's options (method "pulse"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0. - `source` (object): The program in another format, in place of qasm: read to the job's qasm before the job is read (a module that does not read is refused with the reader's code, Q700 to Q721), the request keeping its source. +- `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read; a parameter left without one is refused (J050). In a sweep, the parameters it fixes. - `idempotency_key` (string): A key of your making that names this run, so that a call sent again is not a second job: the same key with the same arguments answers with the job it names, for as long as the job is kept, rather than running another; the same key with other arguments is refused (J034). Make it unguessable (a UUID). A job the service interrupted is run again under its key. Without a key, every call is a new job. ### `quantum_circuit_examples`: Ready-to-run quantum examples @@ -1836,6 +1870,37 @@ Options: them. A member certified bit-exact gives the CPU's answers; a placement this host cannot honour is refused (J013) + --exactness + The class the answer must be of: bit-exact, exact, single, bounded, estimate, heuristic; + measured (a processor's counts), simulated (a provider's simulator's), or any. Under a + contract (this, --max-cost, --deadline, --max-joules or --allow-providers) the planner + prices every route it can see, runs the cheapest that meets it, and seals its reasoning in + the receipt; with nothing to meet it, it refuses with each route's reason (J071), and + nothing falls back. Without a class the job keeps the class auto would give + + --max-cost + The most the run may cost, as 0.50:USD: a route with an unknown cost, or priced in another + currency, does not meet it. It confirms nothing: a run that is not free still takes --yes + + --deadline + When the run must be done by, in seconds: a route whose time is not known does not meet + it, and the receipt says whether it was kept (exit 4 when it was not) + + --max-joules + The most energy the run may take, in joules: a route whose energy is not known does not + meet it, and this command estimates none, so here every route is refused; the job service + estimates from what it has metered + + --allow-providers + Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods + here: each is asked to estimate the job, and nothing is sent unless one is chosen. A + device is chosen only when --exactness measured or any asks for its class. On the job + service, which reaches no provider, it changes nothing + + --contract + The contract itself, as JSON or a file of it: exactness, max_cost, deadline_seconds, + max_joules and providers; the options above are set over it + --json Print the job as the service returns it: request, plan, result and receipt @@ -1857,16 +1922,17 @@ Options: simulator --dry-run - With --provider: the plan (the exact compile to the device's gates and its check by - simulation) and the provider's estimate; nothing is submitted + With --provider or --allow-providers: the plan (the exact compile to the device's gates + and its check by simulation) and the provider's estimate, or every route's price or + reason; nothing is submitted --yes - With --provider: confirm a run that is not free, or whose cost is unknown; without it such - a run is refused (exit 3) + With --provider or --allow-providers: confirm a run that is not free, or whose cost is + unknown; without it such a run is refused (exit 3). A cost ceiling is no confirmation --no-wait - With --provider: send the job and answer with its handle, without waiting (`wai-quantum - providers collect`) + With --provider or --allow-providers: send the job and answer with its handle, without + waiting (`wai-quantum providers collect`) -h, --help Print help @@ -1990,6 +2056,37 @@ Options: them. A member certified bit-exact gives the CPU's answers; a placement this host cannot honour is refused (J013) + --exactness + The class the answer must be of: bit-exact, exact, single, bounded, estimate, heuristic; + measured (a processor's counts), simulated (a provider's simulator's), or any. Under a + contract (this, --max-cost, --deadline, --max-joules or --allow-providers) the planner + prices every route it can see, runs the cheapest that meets it, and seals its reasoning in + the receipt; with nothing to meet it, it refuses with each route's reason (J071), and + nothing falls back. Without a class the job keeps the class auto would give + + --max-cost + The most the run may cost, as 0.50:USD: a route with an unknown cost, or priced in another + currency, does not meet it. It confirms nothing: a run that is not free still takes --yes + + --deadline + When the run must be done by, in seconds: a route whose time is not known does not meet + it, and the receipt says whether it was kept (exit 4 when it was not) + + --max-joules + The most energy the run may take, in joules: a route whose energy is not known does not + meet it, and this command estimates none, so here every route is refused; the job service + estimates from what it has metered + + --allow-providers + Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods + here: each is asked to estimate the job, and nothing is sent unless one is chosen. A + device is chosen only when --exactness measured or any asks for its class. On the job + service, which reaches no provider, it changes nothing + + --contract + The contract itself, as JSON or a file of it: exactness, max_cost, deadline_seconds, + max_joules and providers; the options above are set over it + --json Print the plan as JSON @@ -3087,6 +3184,37 @@ Options: them. A member certified bit-exact gives the CPU's answers; a placement this host cannot honour is refused (J013) + --exactness + The class the answer must be of: bit-exact, exact, single, bounded, estimate, heuristic; + measured (a processor's counts), simulated (a provider's simulator's), or any. Under a + contract (this, --max-cost, --deadline, --max-joules or --allow-providers) the planner + prices every route it can see, runs the cheapest that meets it, and seals its reasoning in + the receipt; with nothing to meet it, it refuses with each route's reason (J071), and + nothing falls back. Without a class the job keeps the class auto would give + + --max-cost + The most the run may cost, as 0.50:USD: a route with an unknown cost, or priced in another + currency, does not meet it. It confirms nothing: a run that is not free still takes --yes + + --deadline + When the run must be done by, in seconds: a route whose time is not known does not meet + it, and the receipt says whether it was kept (exit 4 when it was not) + + --max-joules + The most energy the run may take, in joules: a route whose energy is not known does not + meet it, and this command estimates none, so here every route is refused; the job service + estimates from what it has metered + + --allow-providers + Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods + here: each is asked to estimate the job, and nothing is sent unless one is chosen. A + device is chosen only when --exactness measured or any asks for its class. On the job + service, which reaches no provider, it changes nothing + + --contract + The contract itself, as JSON or a file of it: exactness, max_cost, deadline_seconds, + max_joules and providers; the options above are set over it + --json Print the job as the service returns it: request, plan, result and receipt @@ -3591,6 +3719,10 @@ Options: One job a line, each judged as a job's receipt, one JSON verdict a line; the status is 1 when any is not valid + --recheck + For a job under a contract, also run again what can be: its routes priced again at the + job's memory, held to the digest it sealed, and its shadow, held to its counts bit for bit + -h, --help Print help diff --git a/wai/wai-quantum-cli/docs/llms.txt b/wai/wai-quantum-cli/docs/llms.txt index 4992acc46..2994557bc 100644 --- a/wai/wai-quantum-cli/docs/llms.txt +++ b/wai/wai-quantum-cli/docs/llms.txt @@ -92,6 +92,8 @@ Runs on this machine, signed with the user's key; nothing leaves the machine. - `providers_list`: List the person's quantum providers - `provider_estimate`: Plan a run on a provider, and its cost - `run_on_provider`: Run on a provider (can spend the person's money) +- `plan_routes`: Weigh a contract against every route +- `run_routed`: Run a job on the route its contract chooses (can spend the person's money) - `get_provider_job`: Ask after a job on a provider - `cancel_provider_job`: Cancel a job on a provider - `list_provider_jobs`: List the jobs on the person's providers diff --git a/wai/wai-quantum-cli/docs/local-mcp.json b/wai/wai-quantum-cli/docs/local-mcp.json index 49dfeef81..0aa8e53aa 100644 --- a/wai/wai-quantum-cli/docs/local-mcp.json +++ b/wai/wai-quantum-cli/docs/local-mcp.json @@ -4,7 +4,7 @@ { "name": "run_quantum_circuit", "title": "Run a quantum program here", - "description": "Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more.", + "description": "Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `contract` (the class wanted, a deadline) and the planner prices every method here, runs the cheapest that meets it, seals its reasoning under `planner`, and refuses (J071) rather than fall back to less; this tool reaches no provider, and plan_routes and run_routed do. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more.", "inputSchema": { "type": "object", "anyOf": [ @@ -531,6 +531,77 @@ "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -1348,6 +1419,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -4105,6 +4247,830 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -5105,6 +6071,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -7860,6 +8897,830 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -8720,7 +10581,7 @@ { "name": "plan_quantum_circuit", "title": "Plan a quantum program", - "description": "The method a program would run on and why, the memory and work it would take, without running it.", + "description": "The method a program would run on and why, the memory and work it would take, without running it. With a contract, every route's price or reason for rejection under planner, or the refusal (J071) when no route meets it.", "inputSchema": { "type": "object", "anyOf": [ @@ -9247,17 +11108,88 @@ "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, "outputSchema": { "$id": "wai-quantum://schemas/plan_quantum_circuit/1", "type": "object", - "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it.", + "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it. A job with a contract carries the planner's reasoning.", "anyOf": [ { "title": "wai.quantum.plan/1", - "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it.", + "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it. A job with a contract carries the planner's reasoning.", "type": "object", "required": [ "method", @@ -9334,6 +11266,622 @@ } } }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, "verdict": { "title": "wai.quantum.verdict/1", "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", @@ -21349,7 +23897,7 @@ { "name": "verify_quantum_result", "title": "Check a result's receipt", - "description": "Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and which key signed it.", + "description": "Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and which key signed it; for a job under a contract, every route's outcome and the choice recomputed from what it states, and with recheck its routes priced again and its shadow run again.", "inputSchema": { "type": "object", "required": [ @@ -21359,6 +23907,10 @@ "job": { "type": "object", "description": "The job: {\"request\": ..., \"result\": ...}, the result carrying its receipt." + }, + "recheck": { + "type": "boolean", + "description": "For a job under a contract: its routes priced again at the job's memory, held to the digest it sealed, and its shadow run again, held to its counts bit for bit." } } }, @@ -21387,6 +23939,28 @@ "null" ], "description": "The signing key, 32 bytes in hex." + }, + "planner": { + "type": "object", + "description": "For a job under a contract, what its reasoning says: the route chosen, the class wanted and given, what was kept, and the shadow." + }, + "recheck": { + "type": "object", + "description": "With recheck: whether the routes priced again and the shadow run again are what the job sealed.", + "properties": { + "holds": { + "type": "boolean" + }, + "engine": { + "type": "object" + }, + "priced": { + "type": "object" + }, + "shadow": { + "type": "object" + } + } } } }, @@ -30589,6 +33163,77 @@ "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } }, "required": [ @@ -31409,6 +34054,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -34166,6 +36882,830 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -35166,6 +38706,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -37921,6 +41532,830 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -50325,6 +54760,77 @@ "type": "integer", "minimum": 0, "description": "A seed, for a provider that is a seeded simulator; a device ignores it." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -50372,6 +54878,622 @@ "confirm": { "type": "string", "description": "What the person reads before confirming a run that is not free." + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } } } }, @@ -50457,6 +55579,77 @@ "minimum": 0, "description": "A seed, for a provider that is a seeded simulator; a device ignores it." }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } + }, "confirm_cost": { "type": "boolean", "description": "true only when the person has agreed to this run's cost. A run that is not free is refused without it." @@ -51280,6 +56473,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -54037,6 +59301,830 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -55037,6 +61125,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -57792,6 +63951,12333 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + }, + "error": { + "type": "string" + }, + "code": { + "type": "string", + "description": "A failed item's refusal code (engine::refusal)." + }, + "path": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The item's leaf's sibling digests up to the root, in hex." + } + } + } + } + } + } + ] + }, + "error": { + "type": "string", + "description": "Why a job failed, or why it was interrupted." + }, + "interruptions": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "The job service: each time it stopped while the job ran, in milliseconds since 1970. A job that was running when the service stopped is queued again, once, to run from its stored request." + }, + "submitted_ms": { + "type": "integer", + "description": "The job service: when it was submitted, in milliseconds since 1970." + }, + "started_ms": { + "type": "integer" + }, + "finished_ms": { + "type": "integer" + }, + "peak_rss_bytes": { + "type": "integer", + "description": "The job service: the most memory the job's process held." + }, + "digests": { + "type": "object", + "description": "The job service: the BLAKE3 digests its store keeps the job's objects under (the request, each program, the result and the receipt).", + "properties": { + "algorithm": { + "const": "blake3" + }, + "request": { + "type": [ + "string", + "null" + ] + }, + "programs": { + "type": "array", + "items": { + "type": "string" + } + }, + "result": { + "type": "string" + }, + "receipt": { + "type": "string" + } + } + } + } + }, + { + "type": "object", + "description": "A refusal as data: the message, every code in it (the last is the code), its outcome and meaning as the code's table gives them. A host that refuses for its own reasons gives the error alone.", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + } + ] + } + }, + { + "name": "plan_routes", + "title": "Weigh a contract against every route", + "description": "Every route a job could take under its contract: the methods on this machine and each of the person's own providers, each with its price or why it was rejected, what a provider's estimate leaves out, and the route the planner would choose: the cheapest that meets the contract, or the refusal (J071) with every route's reason. Each provider is asked to describe its device and estimate the job. Nothing is submitted and nothing is spent. A device is chosen only when exactness asks for measured or any.", + "inputSchema": { + "type": "object", + "required": [ + "qasm", + "contract" + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why." + }, + "inputs": { + "type": "object", + "additionalProperties": { + "type": "integer" + }, + "description": "A generator's inputs' values, as {\"n\": 5}." + }, + "shots": { + "type": "integer", + "minimum": 1, + "description": "Shots (default 1024)." + }, + "seed": { + "type": "integer", + "minimum": 0, + "description": "A seed." + }, + "observables": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Pauli observables: a provider's job answers counts, so a method here answers these." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } + } + } + }, + "outputSchema": { + "$id": "wai-quantum://schemas/plan_routes/1", + "type": "object", + "description": "Every route a job could take under its contract, each with its price or why it was rejected, and the route chosen: nothing submitted, nothing spent.", + "anyOf": [ + { + "type": "object", + "description": "Every route a job could take under its contract, each with its price or why it was rejected, and the route chosen: nothing submitted, nothing spent.", + "required": [ + "dry_run", + "planner" + ], + "properties": { + "dry_run": { + "const": true + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "plan": { + "title": "wai.quantum.plan/1", + "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it. A job with a contract carries the planner's reasoning.", + "type": "object", + "required": [ + "method", + "why", + "memory_bytes", + "work", + "qubits" + ], + "properties": { + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0 + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "target": { + "type": "object", + "description": "A run on a device target: which target (its hash, as its receipt binds it), its calibration snapshot, where the program was placed and why, and the noise derived from the target.", + "required": [ + "name", + "hash" + ], + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "hash_is": { + "type": "string" + }, + "calibration": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "source": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "note": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "description": "The native gate set, the layout and routes chosen, the swaps, the expected success beside the fewest-swaps layout's, and the check of the compiled program." + }, + "noise": { + "type": "object", + "description": "The noise model derived from the target's calibration: its channels, durations and idling, and each qubit's readout." + } + } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + } + } + }, + "provider_plan": { + "type": "object", + "description": "The dry run of a job on a provider: nothing submitted, nothing spent.", + "required": [ + "dry_run", + "provider", + "plan", + "estimate", + "free", + "confirm" + ], + "properties": { + "dry_run": { + "const": true + }, + "provider": { + "type": "object" + }, + "calibration": { + "type": [ + "string", + "null" + ] + }, + "billing": { + "type": "object" + }, + "plan": { + "type": "object" + }, + "estimate": { + "type": "object" + }, + "free": { + "type": "boolean" + }, + "confirm": { + "type": "string", + "description": "What the person reads before confirming a run that is not free." + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + } + } + } + } + }, + { + "type": "object", + "description": "A refusal as data: the message, every code in it (the last is the code), its outcome and meaning as the code's table gives them. A host that refuses for its own reasons gives the error alone.", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + } + ] + } + }, + { + "name": "run_routed", + "title": "Run a job on the route its contract chooses (can spend the person's money)", + "description": "Runs a job on the route plan_routes chooses: a method on this machine, or one of the person's own providers. THIS CAN SPEND THE PERSON'S MONEY OR QUOTA, when the contract allows a provider and one is chosen. A cost ceiling confirms nothing: a run that is not free is refused unless confirm_cost is true, set only after the person has seen the estimate and agreed to that run. The answer is a job in the service's form, its result carrying the planner's reasoning under planner; a provider's result also carries a classical method's counts and their distance under shadow, or why no classical method could reach them. If the job has not finished within this call the answer has status running and an id, and get_provider_job collects it later. Do not run it again to find out: that is a second job, and it can be a second bill.", + "inputSchema": { + "type": "object", + "required": [ + "qasm", + "contract" + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why." + }, + "inputs": { + "type": "object", + "additionalProperties": { + "type": "integer" + }, + "description": "A generator's inputs' values, as {\"n\": 5}." + }, + "shots": { + "type": "integer", + "minimum": 1, + "description": "Shots (default 1024)." + }, + "seed": { + "type": "integer", + "minimum": 0, + "description": "A seed." + }, + "observables": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Pauli observables: a provider's job answers counts, so a method here answers these." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } + }, + "confirm_cost": { + "type": "boolean", + "description": "true only when the person has agreed to this run's cost. A run that is not free is refused without it, whatever the contract's ceiling." + } + } + }, + "outputSchema": { + "$id": "wai-quantum://schemas/run_routed/1", + "type": "object", + "description": "A job as a host returns it: its status, the method its plan chose and why, the request as submitted, and, once it is done, the result with its receipt: a job's result, or for a set (a request with programs or a sweep, its method set) the set's result. The command line's run --json, the local MCP server's run_quantum_circuit and a run on the person's own provider give a finished job; the job service also gives its id and times, and a job still queued or running, or failed with its error. A job's receipt verifies from this document alone: request and result.", + "anyOf": [ + { + "title": "wai.quantum.job/1", + "description": "A job as a host returns it: its status, the method its plan chose and why, the request as submitted, and, once it is done, the result with its receipt: a job's result, or for a set (a request with programs or a sweep, its method set) the set's result. The command line's run --json, the local MCP server's run_quantum_circuit and a run on the person's own provider give a finished job; the job service also gives its id and times, and a job still queued or running, or failed with its error. A job's receipt verifies from this document alone: request and result.", + "type": "object", + "required": [ + "status", + "request" + ], + "properties": { + "id": { + "type": "string", + "description": "The job service's id for the job." + }, + "status": { + "enum": [ + "queued", + "running", + "done", + "failed", + "cancelled", + "interrupted" + ], + "description": "interrupted: the job service stopped while the job ran, after it had run it again once from its request, so it has no result; error says so." + }, + "method": { + "type": "string", + "description": "The method the plan chose; set for a set." + }, + "why": { + "type": "string", + "description": "Why the plan chose the method." + }, + "estimate": { + "type": "object", + "description": "What the plan admitted the job with.", + "required": [ + "memory_bytes", + "work" + ], + "properties": { + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0, + "description": "In the method's own unit." + } + } + }, + "request": { + "title": "wai.quantum.job-request/1", + "description": "A job as a client submits it: a program and what is asked of it, or a set: many programs (programs), or one over a grid of its inputs (sweep), run as one job. The command line, both MCP servers, the job service, the desktop app and the Studio read it alike, and a receipt seals it as it was given. A member the engine does not read is ignored, and sealed with the rest.", + "type": "object", + "anyOf": [ + { + "required": [ + "qasm" + ] + }, + { + "required": [ + "programs" + ] + }, + { + "required": [ + "source" + ] + } + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, in OpenQASM 3 or the OpenQASM 2 forms in common use." + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "description": "The program in another format, in place of qasm (engine::formats::expand): read to the job's qasm before the job is read, the request keeping its source.", + "properties": { + "format": { + "enum": [ + "qasm", + "qir", + "jeff" + ] + }, + "program": { + "type": "string", + "description": "The program's text (OpenQASM, QIR)." + }, + "program_base64": { + "type": "string", + "description": "The program's bytes as base64 (jeff)." + } + } + }, + "shots": { + "type": "integer", + "minimum": 0, + "maximum": 1000000, + "description": "Measurement shots; 1024 when no observables or amplitudes are asked for, otherwise 0." + }, + "seed": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991, + "description": "The sampling seed (1 when not given): the same job and seed give the same counts." + }, + "method": { + "type": "string", + "description": "auto (the default: the strongest method the program admits), or a method by its name as the methods list names it; pulse runs a pulse program (OpenPulse calibrations) under the pulse options." + }, + "observables": { + "type": "array", + "maxItems": 256, + "description": "Pauli observables to take the expectation values of.", + "items": { + "anyOf": [ + { + "type": "string", + "description": "A Pauli string, as \"Z0 Z1\"; qubits count from 0." + }, + { + "type": "object", + "required": [ + "pauli" + ], + "properties": { + "pauli": { + "type": "string", + "description": "A Pauli string, as \"X3\"." + }, + "coeff": { + "type": "number", + "description": "Its coefficient (1 when not given)." + } + } + } + ] + } + }, + "amplitudes": { + "type": "array", + "maxItems": 64, + "description": "Basis states whose amplitudes to return: one 0 or 1 per qubit, qubit n-1 first.", + "items": { + "type": "string" + } + }, + "noise": { + "type": "object", + "description": "A noise model, each channel a probability. A channel not listed here is refused.", + "additionalProperties": false, + "properties": { + "depolarizing_1q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "depolarizing_2q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "amplitude_damping": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "dephasing": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "readout": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + } + }, + "options": { + "type": "object", + "description": "Options of the method that runs the job, as the methods list names them (max_bond, cutoff, fusion, trajectories, threshold, max_weight, ladder, max_terms, path_restarts), and memory_gb." + }, + "compile": { + "type": "object", + "description": "What a compile is asked for, each optional: the most the output may differ from the program (epsilon, in the operator norm up to a global phase), the level (0 lowers and approximates; 1 also rewrites and folds phases; 2 also resynthesises), the basis, the gate set it writes the program in (clifford_t: every rotation off the multiples of π/4 a Clifford+T word; standard: nothing approximated), whether to give the circuit after each pass (stages), and the twirl and dd passes, last (twirl, with its seed; dd, with its sequence).", + "properties": { + "epsilon": { + "type": "number", + "exclusiveMinimum": 0 + }, + "level": { + "type": "integer", + "minimum": 0, + "maximum": 2 + }, + "basis": { + "enum": [ + "clifford_t", + "standard" + ] + }, + "stages": { + "type": "boolean" + }, + "twirl": { + "description": "Twirl each two-qubit Clifford gate with Paulis drawn from a seeded stream: true (seed 1), or {\"seed\": N}. One seed is one instance, checked to be the same circuit.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "required": [ + "seed" + ], + "properties": { + "seed": { + "type": "integer", + "minimum": 0 + } + } + } + ] + }, + "dd": { + "description": "Dynamical decoupling in each window where a qubit idles long enough: xx or xy4 (or {\"sequence\": …}), checked to change nothing without noise.", + "anyOf": [ + { + "enum": [ + "xx", + "xy4" + ] + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "sequence": { + "enum": [ + "xx", + "xy4" + ] + } + } + } + ] + } + } + }, + "intent": { + "description": "What the program must do, checked with the run: one intent or a list. The result's verdict says how far it was checked.", + "anyOf": [ + { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + } + ] + }, + "verdict": { + "type": "boolean", + "description": "true: the result carries a verdict even with no intent." + }, + "target": { + "description": "A device target: a built-in target's name, or a target document. The program is compiled to it, placed and simulated under its noise; noise may not be given beside it.", + "anyOf": [ + { + "type": "string" + }, + { + "title": "wai.quantum.target/1", + "description": "A device target: its qubits, the pairs it couples, its native gates with their errors and durations, and the calibration snapshot they come from. A value not known is left out, never written as zero. Every field but format, name, source, qubits, gates and coupling is optional, and a field the format does not name is refused, so a misspelt one never reads as absent. Its canonical text is its RFC 8785 form, and the BLAKE3 of that text, the target's hash, names the snapshot in a receipt.", + "type": "object", + "required": [ + "format", + "name", + "source", + "qubits", + "gates", + "coupling" + ], + "additionalProperties": false, + "properties": { + "format": { + "const": "wai.quantum.target/1" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "additionalProperties": false, + "properties": { + "format": { + "type": "string", + "description": "The format the target was read from (wai-quantum targets import --help lists them)." + }, + "note": { + "type": "string", + "maxLength": 400 + } + } + }, + "calibration": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "maxLength": 400, + "description": "The calibration snapshot's id, as the source names it, or a content id of the snapshot read." + }, + "timestamp": { + "type": "string", + "maxLength": 400, + "description": "When the snapshot was taken, as the source writes it." + } + } + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2048, + "description": "Every qubit, in order.", + "items": { + "type": "object", + "required": [ + "qubit" + ], + "additionalProperties": false, + "properties": { + "qubit": { + "type": "integer", + "minimum": 0, + "description": "Its index: its place in the list." + }, + "label": { + "type": "string", + "description": "The source's own name for it, when that is not its index." + }, + "t1_us": { + "type": "number", + "minimum": 0, + "description": "T1, microseconds." + }, + "t2_us": { + "type": "number", + "minimum": 0, + "description": "T2 (the echo or Ramsey time the source reports), microseconds." + }, + "frequency_ghz": { + "type": "number", + "minimum": 0, + "description": "Its frequency, gigahertz." + }, + "readout": { + "type": "object", + "required": [ + "p01", + "p10" + ], + "additionalProperties": false, + "properties": { + "p01": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 1 | holds 0)." + }, + "p10": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 0 | holds 1)." + } + } + }, + "measure_ns": { + "type": "number", + "minimum": 0, + "description": "The measurement's duration, nanoseconds." + } + } + } + }, + "gates": { + "type": "array", + "maxItems": 262144, + "description": "Each native gate where the device runs it, sorted by gate then qubits.", + "items": { + "type": "object", + "required": [ + "gate", + "qubits" + ], + "additionalProperties": false, + "properties": { + "gate": { + "type": "string", + "pattern": "^[a-z0-9_]{1,40}$" + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + }, + "error": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "The average gate infidelity." + }, + "duration_ns": { + "type": "number", + "minimum": 0, + "description": "Nanoseconds." + } + } + } + }, + "coupling": { + "type": "array", + "description": "The pairs a two-qubit gate may act on, each once, the lower qubit first, sorted.", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + ] + }, + "fabric": { + "description": "Where the statevector method's state runs: auto (the default: on a member only where the committed measurements show it faster than this host's CPU for the job's size and fusion width, otherwise on the CPU), cpu, accelerator (the first accelerator member certified bit-exact here that holds the state, falling back to the next if it fails during the run), a member's id or key (wai-quantum fabric lists them), or a list of members, a power of two of them, the state split by its top qubits into one partition on each (cpu is a member, and a member may be named more than once). A member certified bit-exact gives the CPU's bits. A placement this host cannot honour is refused (J013), never made elsewhere.", + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "array", + "minItems": 2, + "maxItems": 64, + "items": { + "type": "string", + "minLength": 1 + } + } + ] + }, + "repair": { + "description": "Repair the program first on its flagged lines: true, or the choices.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "max_iterations": { + "type": "integer", + "minimum": 1 + }, + "dyadic_bits": { + "type": "integer", + "minimum": 1, + "maximum": 32 + }, + "sizes": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + } + } + } + ] + }, + "history": { + "type": "object", + "description": "The program's history's account of the version the job runs: its digest, and the gates and lines in each hand. The receipt binds it; a history recomputes and checks it." + }, + "provider": { + "type": "string", + "description": "The person's own provider to run on, by the name their registry gives it. Only a host that holds their credentials runs such a job; every other host refuses it." + }, + "programs": { + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "type": "string", + "description": "A program's text." + }, + { + "type": "object", + "required": [ + "qasm" + ], + "description": "A job of its own, read as a job request is (no programs or sweep in it); each item of the set's result holds its request in full." + } + ] + }, + "description": "A set (engine::sets): the programs to run as one job, each a program's text or a job of its own; the request's other fields apply to every item that does not set them itself." + }, + "sweep": { + "type": "object", + "additionalProperties": { + "type": "array", + "minItems": 1, + "items": { + "type": "number" + } + }, + "description": "A set over the request's own qasm: values for each of the program's inputs (integer, float or angle), every combination run, the names in sorted order and the first varying slowest." + }, + "params": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "A value for each of the program's parameters (`input float theta;`, `input angle phi;`), bound exactly before the program is read: it runs as if each were written as a `const` at that double. A parameter left without a value is refused (Q114, J050). In a sweep, the parameters it fixes, each bound at every point." + }, + "dry_run": { + "type": "boolean", + "description": "With true: what the host would do with the job or set, running nothing." + }, + "mitigate": { + "description": "Mitigate the job's expectation values (or, for readout, its counts) under its noise (engine::mitigate): zne, pea, pec, cdr, vd or readout, or {\"method\", …} with its options. The result's mitigation gives each value raw and mitigated.", + "anyOf": [ + { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + { + "type": "object", + "required": [ + "method" + ] + } + ] + }, + "pulse": { + "type": "object", + "description": "A pulse run's options (method \"pulse\"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0.", + "additionalProperties": false, + "properties": { + "dt_ns": { + "type": "number", + "exclusiveMinimum": 0, + "maximum": 1000, + "description": "The sample period, ns (default 0.5)." + }, + "levels": { + "type": "integer", + "enum": [ + 2, + 3 + ], + "description": "Levels kept per qubit (default 2; 3 shows leakage)." + }, + "tolerance": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1, + "description": "The most the stated error may be (default 1e-6): a run whose bound and rounding estimate pass it is refused, naming the steps that would meet it." + }, + "substeps": { + "type": "integer", + "minimum": 1, + "maximum": 4096, + "description": "Steps per sample (default: chosen so each step times the generator's norm is at most 0.5)." + }, + "qubits": { + "type": "object", + "description": "Each qubit's parameters by its index, over the target's and the defaults.", + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "frequency_ghz": { + "type": "number", + "description": "Its frequency, GHz." + }, + "rabi_mhz": { + "type": "number", + "description": "Its Rabi frequency at full amplitude, MHz." + }, + "anharmonicity_mhz": { + "type": "number", + "description": "Its anharmonicity, MHz." + }, + "t1_us": { + "type": "number", + "description": "Its relaxation time, µs." + }, + "t2_us": { + "type": "number", + "description": "Its coherence time, µs (at most 2·T1)." + } + } + } + }, + "couplings": { + "type": "array", + "description": "Static ZZ couplings.", + "items": { + "type": "object", + "required": [ + "qubits", + "zz_khz" + ], + "additionalProperties": false, + "properties": { + "qubits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + }, + "minItems": 2, + "maxItems": 2 + }, + "zz_khz": { + "type": "number", + "description": "The coupling's rate, kHz." + } + } + } + }, + "ports": { + "type": "object", + "description": "Ports by name: what each is for and the qubit it reaches.", + "additionalProperties": { + "type": "object", + "required": [ + "kind", + "qubit" + ], + "additionalProperties": false, + "properties": { + "kind": { + "enum": [ + "drive", + "measure", + "acquire" + ] + }, + "qubit": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } + } + } + }, + "result": { + "anyOf": [ + { + "title": "wai.quantum.job-result/1", + "description": "A job's result as the engine gives it, on every host: what was asked of the program, computed by the method its plan chose, with that method's accuracy class. The receipt seals the result without its receipt member, beside the request. A result names the engine that made it and this schema (engine and schema); results made before results carried them have neither and follow this schema all the same.", + "type": "object", + "required": [ + "method", + "qubits", + "gates", + "accuracy" + ], + "properties": { + "engine": { + "type": "object", + "description": "The engine that made the result: the wai-quantum crate's name and version.", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "const": "wai-quantum" + }, + "version": { + "type": "string", + "description": "Its semantic version, as MAJOR.MINOR.PATCH." + } + } + }, + "schema": { + "const": "wai.quantum.job-result/1", + "description": "The schema the result follows." + }, + "components": { + "type": "array", + "description": "The identity of every component that made the result, when a registered one took part (engine::registry): its program's format, the passes its compile ran, the noise channels it names, its method; each registered one marked so. Sealed by the receipt with the rest.", + "items": { + "type": "object", + "description": "One component that made the result (engine::registry): its kind, name and version, the BLAKE3 digest of its descriptor, and whether it is built in. A result carries these only when a registered component took part; one made by built-ins alone names them as it always has (its method, its compile's passes, its noise's channels and the engine's version), the digests of that version listed by the components list.", + "required": [ + "kind", + "name", + "version", + "digest", + "origin" + ], + "properties": { + "kind": { + "enum": [ + "method", + "pass", + "channel", + "front_end" + ] + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "digest": { + "type": "string", + "pattern": "^[0-9a-f]{64}$", + "description": "BLAKE3 of the component's descriptor in its canonical JSON (engine::registry::digest_of)." + }, + "origin": { + "enum": [ + "built-in", + "registered" + ], + "description": "built-in: the engine's own; registered: a host's own, added in its process, not part of the engine." + }, + "certified": { + "const": false, + "description": "Beside a registered component: the engine does not certify it." + } + } + } + }, + "method": { + "type": "string", + "description": "The method that ran the job (provider for a run on the person's own provider)." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": "integer", + "minimum": 0 + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "state_hash": { + "type": "string", + "description": "The bit-exact method's statevector hash (BLAKE3, hex): the same on every machine." + }, + "counts": { + "type": "object", + "description": "Outcomes and their counts, keyed by the program's classical bits, the highest bit first. At most 65536 outcomes are listed; omitted_shots holds the rest.", + "additionalProperties": { + "type": "integer", + "minimum": 0 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "outcome_dimension": { + "type": "integer", + "minimum": 0, + "description": "The stabilizer method: the dimension of the measured outcomes' affine space." + }, + "shots": { + "type": "integer", + "minimum": 0, + "description": "The shots, where the method names them in the result (trajectories, provider)." + }, + "expectations": { + "type": "array", + "items": { + "type": "object", + "required": [ + "observable", + "coeff", + "value" + ], + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "value": { + "type": "number", + "description": "The coefficient times the expectation value." + }, + "stderr": { + "type": "number", + "description": "The standard error, for an estimate." + }, + "bound": { + "type": "number", + "description": "A bound on |exact − value|: rigorous for the bounded class; with confidence beside it, holding with that probability." + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + }, + "max_terms": { + "type": "integer" + }, + "ladder": { + "type": "array", + "description": "The value at thresholds a decade apart, the asked one last.", + "items": { + "type": "object", + "required": [ + "threshold", + "value", + "bound" + ], + "properties": { + "threshold": { + "type": "number" + }, + "value": { + "type": "number" + }, + "bound": { + "type": "number" + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + } + } + } + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds, for a bound that holds with a stated probability (stabilizer_rank's sampled mode)." + } + } + } + }, + "amplitudes": { + "type": "array", + "items": { + "type": "object", + "required": [ + "bits", + "re", + "im" + ], + "properties": { + "bits": { + "type": "string", + "description": "One 0 or 1 per qubit, qubit n-1 first." + }, + "re": { + "type": "number" + }, + "im": { + "type": "number" + }, + "bound": { + "type": "number", + "minimum": 0, + "description": "A bound on |exact − value| of the amplitude, holding with the probability confidence states (stabilizer_rank's sampled mode)." + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds." + } + } + } + }, + "global_phase": { + "type": "string", + "description": "Why the amplitudes' global phase is not fixed, when it is not." + }, + "warning": { + "type": "string" + }, + "contraction_flops": { + "type": "number", + "description": "The tensor network's contraction cost." + }, + "dynamic": { + "type": "object", + "description": "A program that measures in the middle, resets or branches on a measured bit: how it ran.", + "properties": { + "measurements_and_resets": { + "type": "integer", + "minimum": 0 + }, + "branches_run": { + "type": "integer", + "minimum": 0 + }, + "states_at_once": { + "type": "integer", + "minimum": 0 + }, + "branches_weighed": { + "type": "integer", + "minimum": 0 + } + } + }, + "outputs": { + "type": "array", + "description": "The program's output declarations: each its name and type, and its value, or the places of its bits in each outcome.", + "items": { + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "bits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + } + }, + "value": { + "description": "A number, a boolean, a bit string, a duration's text, {\"re\", \"im\"}, or an array of them." + } + } + } + }, + "timing": { + "type": "object", + "description": "A program that states durations (delay, box, stretch) the method does not apply: said so, with the reader's code.", + "required": [ + "applied", + "why" + ], + "properties": { + "applied": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "diagnostics": { + "type": "array", + "description": "The reader's warnings and notes on the program, each with its code.", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "compiled": { + "description": "How the program was compiled before it ran: on the person's own provider, to the device's gates; or, asked with compile, to a basis within a budget. Either way, basis is the gate set it was compiled to.", + "anyOf": [ + { + "type": "object", + "description": "A provider job: the program sent, compiled exactly to the device's own gates: its basis (the device's gate set), its OpenQASM 3 text (qasm3) and that text's BLAKE3 (program), its counts of gates and swaps, its layouts, and the check it passed before it was sent. Results sealed before qasm3 carry the hash alone.", + "required": [ + "basis", + "program" + ], + "properties": { + "basis": { + "type": "string" + }, + "program": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "qasm3": { + "type": "string", + "description": "The program sent, as OpenQASM 3 on physical qubits; program is the BLAKE3 of its UTF-8 bytes." + }, + "native_gates": { + "type": "integer" + }, + "two_qubit_gates": { + "type": "integer" + }, + "swaps": { + "type": "integer" + }, + "layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "final_layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "checked": { + "type": "string" + }, + "placement": { + "type": "object", + "description": "Where the program was placed on the device's qubits, and why." + } + } + }, + { + "type": "object", + "description": "A job asked to compile its program first: what ran is the compiled circuit, within distance of the program in the operator norm up to a global phase.", + "required": [ + "basis", + "verdict" + ], + "properties": { + "basis": { + "enum": [ + "clifford_t", + "standard" + ], + "description": "The gate set the program was compiled to." + }, + "level": { + "type": "integer", + "minimum": 0 + }, + "epsilon": { + "type": "number", + "description": "The budget asked for." + }, + "distance": { + "type": [ + "number", + "null" + ], + "description": "The bound the passes' distances add to." + }, + "verdict": { + "type": "string" + }, + "source": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "output": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ], + "description": "The BLAKE3 of the compile certificate's RFC 8785 text, in hex." + }, + "note": { + "type": "string" + } + } + } + ] + }, + "verdict": { + "title": "wai.quantum.verdict/1", + "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", + "type": "object", + "required": [ + "schema", + "level", + "rank", + "holds", + "statement", + "parsed", + "executed", + "intent", + "critique", + "repairs" + ], + "properties": { + "schema": { + "const": "wai.quantum.verdict/1" + }, + "level": { + "enum": [ + "refused", + "parsed", + "executed", + "evidence", + "proof" + ] + }, + "rank": { + "type": "integer", + "minimum": 0, + "maximum": 4, + "description": "The level's place on the ladder, from 0 (refused) to 4 (proof)." + }, + "holds": { + "type": [ + "boolean", + "null" + ] + }, + "statement": { + "type": "string", + "description": "The level in one plain line." + }, + "parsed": { + "type": "object", + "description": "Whether the reader took the program, and its warnings and notes with their codes, or its refusal.", + "required": [ + "ok" + ], + "properties": { + "ok": { + "type": "boolean" + }, + "diagnostics": { + "type": "array", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + }, + "text": { + "type": "string", + "description": "The refusal as the reader wrote it, with its line and code." + } + } + }, + "executed": { + "type": [ + "object", + "null" + ], + "description": "The method that ran and its accuracy class, and the distance a compile put between the program and what ran.", + "properties": { + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "compiled_distance": { + "type": [ + "number", + "null" + ] + } + } + }, + "intent": { + "type": "array", + "items": { + "type": "object", + "description": "One intent's check: what it asked, whether it held, how strong the check was and how it was made.", + "required": [ + "kind", + "outcome", + "strength", + "how" + ], + "properties": { + "kind": { + "enum": [ + "distribution", + "equivalent", + "prepares", + "sampled", + "compiled" + ] + }, + "outcome": { + "enum": [ + "holds", + "fails", + "unchecked" + ] + }, + "strength": { + "enum": [ + "proof", + "evidence", + "none" + ] + }, + "how": { + "type": "string" + }, + "why": { + "type": "string" + }, + "distance": { + "type": "number" + }, + "tolerance": { + "type": "number" + }, + "outcomes": { + "type": "integer", + "description": "The outcomes the distribution holds, or the samples' distinct outcomes." + }, + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The program's distribution, when its outcomes are few enough to list." + }, + "largest_gaps": { + "type": "array", + "items": { + "type": "object", + "properties": { + "outcome": { + "type": "string" + }, + "program": { + "type": "number" + }, + "intent": { + "type": "number" + } + } + } + }, + "global_phase": { + "type": [ + "number", + "null" + ] + }, + "method": { + "type": "string", + "description": "A sampled intent: the method the samples were run by." + }, + "seed": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "alpha": { + "type": "number" + }, + "fit": { + "type": "object", + "description": "A sampled intent: the test, its statistic, degrees of freedom and p-value, the level, and whether it rejected.", + "properties": { + "test": { + "type": "string" + }, + "statistic": { + "type": "number" + }, + "dof": { + "type": "integer" + }, + "p_value": { + "type": "number" + }, + "alpha": { + "type": "number" + }, + "shots": { + "type": "integer" + }, + "rejected": { + "type": "boolean" + }, + "smallest_expected": { + "type": [ + "number", + "null" + ] + }, + "impossible": { + "type": [ + "integer", + "array", + "boolean" + ] + }, + "note": { + "type": "string" + } + } + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "name": { + "type": "string" + }, + "note": { + "type": "string" + } + } + } + }, + "critique": { + "type": "array", + "description": "The program's smells, each with its lines.", + "items": { + "type": "object" + } + }, + "repairs": { + "type": "array", + "description": "Each edit a repair made, with the code it answered and the lines it changed.", + "items": { + "type": "object" + } + }, + "refusal": { + "type": "object", + "description": "For a refused job: its message and its codes.", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + }, + "sealed": { + "type": "boolean" + } + } + }, + "target": { + "type": "object", + "description": "A run on a device target: which target (its hash, as its receipt binds it), its calibration snapshot, where the program was placed and why, and the noise derived from the target.", + "required": [ + "name", + "hash" + ], + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "hash_is": { + "type": "string" + }, + "calibration": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "source": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "note": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "description": "The native gate set, the layout and routes chosen, the swaps, the expected success beside the fewest-swaps layout's, and the check of the compiled program." + }, + "noise": { + "type": "object", + "description": "The noise model derived from the target's calibration: its channels, durations and idling, and each qubit's readout." + } + } + }, + "fabric": { + "type": "object", + "description": "Where the state vector, or the pauli method's sum of terms, ran: the kernel, the placement the job asked for, the member that ran it (or each partition's), each with its certificate, and the energy. Present when the job asked for a placement, or when auto placed the state on a member by measurement (`auto`); a job auto leaves on the CPU names nothing; the receipt seals it with the rest of the result. Every member placed is certified bit-exact, so the answers are the CPU's, byte for byte.", + "required": [ + "kernel", + "asked", + "parity", + "energy" + ], + "properties": { + "kernel": { + "type": "string" + }, + "asked": { + "description": "The placement the job asked for, as it gave it.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "partitions": { + "type": "array", + "description": "Each partition's member, by the value of the state's top qubits: partition i holds the amplitudes whose top bits read i.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "partition_qubits": { + "type": "integer", + "minimum": 0 + }, + "local_qubits": { + "type": "integer", + "minimum": 0 + }, + "segments": { + "type": "integer", + "minimum": 0, + "description": "Runs of gates the partitions took in turn, between exchanges." + }, + "exchanges": { + "type": "integer", + "minimum": 0, + "description": "Partition qubits exchanged with local ones through the host's copy of the state." + }, + "fell_back_from": { + "type": "array", + "description": "An accelerator request whose member failed during the run: each member that failed, in turn, with how; the member named above ran the job.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "auto": { + "type": "object", + "description": "Why auto placed the state where it ran: the rule (a member is placed only where the committed measurements show it faster than this host's CPU for the job's size and fusion width) and the measured row it rests on, with the host, the day and the load it was measured under. Present only when auto placed a state on a member.", + "required": [ + "rule", + "host", + "fusion", + "from_qubits", + "to_qubits" + ], + "properties": { + "rule": { + "type": "string" + }, + "host": { + "type": "string", + "description": "The host's processor as the measurements name it (cpu--)." + }, + "measured": { + "type": "string", + "description": "The day the host was measured (UTC)." + }, + "about": { + "type": "string" + }, + "load": { + "type": "string" + }, + "discovery_ms": { + "type": "number", + "description": "What discovering and certifying the host's members took, once per process, as measured." + }, + "fusion": { + "type": "integer", + "minimum": 1 + }, + "from_qubits": { + "type": "integer", + "minimum": 0 + }, + "to_qubits": { + "type": "integer", + "minimum": 0 + }, + "min_launches": { + "type": "integer", + "minimum": 0 + }, + "basis": { + "type": "object", + "description": "The measured row the job is judged by: the largest measured size at or below its own, the launches of its plan, the runs of each, and the spread of the CPU's and the member's times in milliseconds.", + "required": [ + "qubits", + "launches", + "runs", + "cpu_ms", + "member_ms" + ], + "properties": { + "qubits": { + "type": "integer", + "minimum": 0 + }, + "launches": { + "type": "integer", + "minimum": 0 + }, + "runs": { + "type": "integer", + "minimum": 0 + }, + "cpu_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + }, + "member_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + } + } + } + } + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "why": { + "type": "string" + } + } + }, + "repaired": { + "type": "object", + "description": "A job asked to repair its program first: the program that ran, each repair, and what needs a person.", + "properties": { + "qasm": { + "type": "string" + }, + "repairs": { + "type": "array", + "items": { + "type": "object", + "required": [ + "code", + "by", + "edits" + ], + "properties": { + "code": { + "type": "string" + }, + "rule": { + "type": "string" + }, + "by": { + "enum": [ + "engine", + "proposal" + ] + }, + "flagged": { + "type": "array", + "items": { + "type": "integer" + } + }, + "edits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "line": { + "type": "integer" + }, + "before": { + "type": [ + "string", + "null" + ] + }, + "after": { + "type": [ + "string", + "null" + ] + } + } + } + } + } + } + }, + "needs_person": { + "type": "array", + "items": { + "type": "object" + } + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0, + "description": "Wall time of the run, where the host has a clock (not in a browser tab)." + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "receipt": { + "anyOf": [ + { + "title": "wai.quantum.receipt/2", + "description": "A result's receipt: an Ed25519 signature, by the key it names, over digest = BLAKE3(\"wai:quantum-service-receipt\\x02\" ‖ len ‖ request ‖ len ‖ result), each of request and result in its RFC 8785 canonical text (the result without its receipt member), each length 8 bytes big-endian. Whatever members the request and the result hold are sealed, the result's engine and schema among them. The first receipts (no canon member, $defs/first) sealed their writer's compact text under the domain ending \\x01; they still verify. wai/extensions/quantum-providers.md section 8.2 states the seal in full, and section 8.4 what a verifier checks.", + "type": "object", + "required": [ + "alg", + "canon", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "canon": { + "const": "rfc8785", + "description": "The canonical form the digest is taken over." + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The signing key, 32 bytes in lower-case hex." + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The digest signed, 32 bytes in lower-case hex." + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$", + "description": "The signature, 64 bytes in lower-case hex." + } + } + }, + { + "description": "The first form, before canon: the digest is over the compact text its writer wrote of each, members in the document's order (section 8.2 of wai/extensions/quantum-providers.md), under the domain ending \\x01. Never written now; still verified.", + "type": "object", + "required": [ + "alg", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$" + } + } + } + ] + }, + "provider": { + "type": "object", + "description": "A provider job: the provider's name, kind and protocol, the device, its provenance, and the hash of its description." + }, + "counts_source": { + "enum": [ + "shots", + "vendor_counts", + "probabilities" + ], + "description": "A provider job: where its counts come from (wai/extensions/quantum-providers.md section 8.3): tallied from one record a shot (shots), the provider's own counts (vendor_counts), or rebuilt from the probabilities it returned by largest remainders, derived and not shot records (probabilities). Results sealed before it carry neither it nor execution." + }, + "execution": { + "type": "object", + "description": "A provider job: how the device was asked to run the program (section 8.3): who states it (stated_by: client, provider or nobody); what the client sent (sent: the request's members and the settings among them); each of mitigation, twirling, decoupling, remapping and optimisation (off, on, default when the request sets nothing for it, none when the device has no such step, unknown when nobody states it); whether the gates were to run as written (verbatim); and a note.", + "required": [ + "stated_by", + "mitigation", + "twirling", + "decoupling", + "remapping", + "optimisation", + "verbatim" + ], + "properties": { + "stated_by": { + "enum": [ + "client", + "provider", + "nobody" + ] + }, + "sent": { + "type": "object", + "required": [ + "fields", + "settings" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "settings": { + "type": "object" + } + }, + "additionalProperties": false + }, + "mitigation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "twirling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "decoupling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "remapping": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "optimisation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "verbatim": { + "type": [ + "boolean", + "null" + ] + }, + "note": { + "type": "string" + } + }, + "additionalProperties": false + }, + "calibration": { + "type": [ + "string", + "null" + ], + "description": "A provider job: the calibration snapshot it ran under." + }, + "job": { + "type": "object", + "description": "A provider job: the provider's job id and its status checks." + }, + "ideal": { + "description": "A provider job: the circuit's exact distribution set beside the measured counts.", + "anyOf": [ + { + "type": "object", + "required": [ + "computed", + "total_variation_distance", + "hellinger_fidelity" + ], + "properties": { + "computed": { + "const": true + }, + "method": { + "type": "string" + }, + "total_variation_distance": { + "type": "number" + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number" + }, + "ideal_outcomes": { + "type": "integer" + }, + "note": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "computed", + "why" + ], + "properties": { + "computed": { + "const": false + }, + "why": { + "type": "string" + } + } + } + ] + }, + "cost": { + "type": "object", + "description": "A provider job: the estimate shown before it was sent, what the provider says it charged, and whether the person confirmed a run that was not free." + }, + "provenance": { + "title": "wai.quantum.provenance/1", + "description": "What a result came from, under the five categories cross-platform provenance surveys use: the circuit, the computer, the compilation, the execution and the software. A host adds it to the results it seals (the job service does, and each item of a set); a result without it reads as it always did. wai-quantum-service/docs/provenance.md maps every field to where it is and whether the receipt seals it.", + "type": "object", + "required": [ + "schema", + "circuit", + "computer", + "compilation", + "execution", + "software" + ], + "properties": { + "schema": { + "const": "wai.quantum.provenance/1" + }, + "circuit": { + "type": "object", + "description": "The program: the BLAKE3 digest of its text as given, its qubits and its gates.", + "required": [ + "program" + ], + "properties": { + "program": { + "type": "string", + "description": "BLAKE3 of the program's text, in hex." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": [ + "integer", + "null" + ] + } + } + }, + "computer": { + "type": "object", + "description": "What ran it: a classical simulator, the method and its accuracy class, a device target's hash when the job named one, and the fabric's members when the result names where its state ran.", + "required": [ + "kind", + "method" + ], + "properties": { + "kind": { + "const": "simulator" + }, + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "target": { + "type": "string", + "description": "The device target's hash; its layout, routes and noise are in the result's own target." + }, + "fabric": { + "type": "object", + "description": "The kernel and the member that ran the state, or each partition's, as the result's fabric names them.", + "properties": { + "kernel": { + "type": "string" + }, + "members": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "compilation": { + "type": "object", + "description": "Whether the job asked to be compiled; if it did, each pass in order with its check's verdict, the certificate's digest, the gate set compiled to (its basis), the level, the ε budget and the distance the result carries, and that no pass draws a random number.", + "required": [ + "asked" + ], + "properties": { + "asked": { + "type": "boolean" + }, + "passes": { + "type": [ + "array", + "null" + ], + "items": { + "type": "object", + "properties": { + "pass": { + "type": "string" + }, + "verdict": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ] + }, + "basis": { + "type": [ + "string", + "null" + ], + "description": "The gate set compiled to: clifford_t or standard." + }, + "level": { + "type": [ + "integer", + "null" + ] + }, + "epsilon": { + "type": [ + "number", + "null" + ] + }, + "distance": { + "type": [ + "number", + "null" + ] + }, + "seeded": { + "const": false + }, + "device": { + "type": "string", + "description": "A job on a device target, compiled exactly to its gates: where its layout and routes are." + }, + "status": { + "const": "not-applicable" + }, + "why": { + "type": "string" + } + } + }, + "execution": { + "type": "object", + "description": "The shots, the seed and the plan the job ran under; its identifier and times are the host's, outside the result.", + "required": [ + "plan" + ], + "properties": { + "shots": { + "type": [ + "integer", + "null" + ] + }, + "seed": { + "type": [ + "integer", + "null" + ] + }, + "plan": { + "type": "object", + "properties": { + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0 + } + } + } + } + }, + "software": { + "type": "object", + "description": "The engine's name and version, and the host's.", + "required": [ + "engine", + "host" + ], + "properties": { + "engine": { + "type": "string" + }, + "host": { + "type": "string" + } + } + } + } + }, + "mitigation": { + "title": "wai.quantum.mitigation/1", + "description": "A job's mitigation (its request's mitigate, engine::mitigate), in its result: the method and the options it ran with, its bias and variance assumptions, each observable raw and mitigated with a standard error each and the ideal value (or, for readout, the counts inverted as a quasi-distribution), the method's own details and what it spent. docs/qec.md describes each method.", + "type": "object", + "required": [ + "method", + "options", + "assumptions" + ], + "properties": { + "method": { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + "options": { + "type": "object", + "description": "The options it ran with, the defaults filled in.", + "properties": { + "method": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "factors": { + "type": "array", + "items": { + "type": "number" + } + }, + "extrapolation": { + "enum": [ + "richardson", + "linear", + "exponential" + ] + }, + "samples": { + "type": "integer" + }, + "training": { + "type": "integer" + }, + "keep": { + "type": "integer" + }, + "learn_shots": { + "type": "integer" + } + } + }, + "assumptions": { + "type": "object", + "properties": { + "bias": { + "type": "string" + }, + "variance": { + "type": "string" + } + } + }, + "noise": { + "type": "string", + "description": "How the job's noise model is read for the method." + }, + "note": { + "type": "string" + }, + "observables": { + "type": "array", + "items": { + "type": "object", + "description": "One observable: its raw value and the mitigated one, each with its standard error, and the ideal value a simulation knows.", + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "raw": { + "type": "number" + }, + "raw_stderr": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + }, + "ideal": { + "type": "number" + } + } + } + }, + "distribution": { + "type": "array", + "description": "readout: each outcome's raw share and its mitigated quasi-probability, with its standard error.", + "items": { + "type": "object", + "properties": { + "bits": { + "type": "string" + }, + "raw": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + } + } + } + }, + "details": { + "type": "object", + "description": "The method's own: the folded scales and the folding check (zne), the learned model and the amplified values (pea), the quasi-probability and the value it converges to (pec), the training fits (cdr), the purity (vd), the flip and its amplification (readout).", + "additionalProperties": true + }, + "cost": { + "type": "object", + "description": "The circuits and shots it spent beyond the job's own.", + "properties": { + "circuits": { + "type": "integer", + "minimum": 0 + }, + "shots": { + "type": "integer", + "minimum": 0 + }, + "note": { + "type": "string" + } + } + } + } + }, + "pulse": { + "type": "object", + "description": "A pulse run (method pulse, engine::pulse): what was read and its distribution, the final populations, each capture's reading, the final density matrix's digest, the schedule's length, the integrator and its step, the device and where each parameter came from, and what the receipt binds (calibration).", + "required": [ + "read", + "outcome_bits", + "populations", + "simulated_qubits", + "density_hash", + "integrator", + "device", + "calibration" + ], + "properties": { + "read": { + "type": "string", + "description": "What the distribution reads: the captures together (into the program's bits when each writes one), or the final state." + }, + "outcome_bits": { + "type": "array", + "items": { + "type": "string" + }, + "description": "What each character of an outcome is, left to right: a program bit (c[0]) or a qubit ($0)." + }, + "distribution": { + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "number" + }, + "description": "The probability of each outcome, which the counts sample; null when the captures start at different samples." + }, + "populations": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The final state read on every simulated qubit, the highest qubit first, a level above 0 read as 1." + }, + "simulated_qubits": { + "type": "array", + "items": { + "type": "integer" + } + }, + "captures": { + "type": "array", + "items": { + "type": "object", + "properties": { + "frame": { + "type": "string" + }, + "qubit": { + "type": "integer" + }, + "start": { + "type": "integer" + }, + "start_ns": { + "type": "number" + }, + "bit": { + "type": [ + "string", + "null" + ] + }, + "p1": { + "type": "number" + }, + "p2": { + "type": "number" + } + } + } + }, + "leakage": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "p2": { + "type": "number" + } + } + }, + "description": "With three levels: each qubit's final probability of level 2." + }, + "trace": { + "type": "number" + }, + "density_hash": { + "type": "string", + "description": "The BLAKE3 of the final density matrix's bits: the same on every platform." + }, + "duration": { + "type": "integer" + }, + "duration_ns": { + "type": "number" + }, + "integrator": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "order": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "substeps": { + "type": "integer" + }, + "step_ns": { + "type": "number" + }, + "steps": { + "type": "integer" + }, + "norm_max": { + "type": "number" + }, + "frame": { + "type": "string" + } + } + }, + "device": { + "type": "object", + "properties": { + "levels": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "qubits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "frequency_hz": { + "type": "number" + }, + "rabi_hz": { + "type": "number" + }, + "anharmonicity_hz": { + "type": "number" + }, + "t1_ns": { + "type": "number" + }, + "t2_ns": { + "type": "number" + }, + "from": { + "type": "object", + "additionalProperties": { + "enum": [ + "pulse", + "target", + "default", + "none" + ] + } + } + } + } + }, + "couplings": { + "type": "array" + }, + "model": { + "type": "string" + } + } + }, + "calibration": { + "type": "object", + "description": "What the receipt binds: the program's, its calibrations', the schedule's and the device's digests, and the target snapshot.", + "properties": { + "program": { + "type": "string" + }, + "calibrations": { + "type": "string" + }, + "schedule": { + "type": "string" + }, + "device": { + "type": "string" + }, + "target": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "calibration": { + "type": "object" + } + } + } + } + }, + "not_modelled": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + }, + { + "title": "wai.quantum.set/1", + "description": "A set's result: many programs, or one program over a grid of its inputs, run as one job (engine::sets). Its head holds the count, how many items finished and failed, the Merkle root over the items' leaves, the set's energy and time; the set's receipt seals the set's request and its head. Each item is a plain job with its own receipt, its index, its point in a sweep, and its path to the root, so it is shown sealed by the set alone. A result names the engine that made it and this schema (engine and schema).", + "type": "object", + "required": [ + "format", + "count", + "done", + "failed", + "root", + "items" + ], + "properties": { + "engine": { + "type": "object", + "description": "The engine that made the result: the wai-quantum crate's name and version.", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "const": "wai-quantum" + }, + "version": { + "type": "string" + } + } + }, + "schema": { + "const": "wai.quantum.set/1" + }, + "format": { + "const": "wai.quantum.set/1" + }, + "count": { + "type": "integer", + "minimum": 1 + }, + "done": { + "type": "integer", + "minimum": 0 + }, + "failed": { + "type": "integer", + "minimum": 0 + }, + "root": { + "type": "string", + "description": "The Merkle root of the items' leaves, in hex (domains moq-jwp:merkle-leaf and moq-jwp:merkle-node, version 1)." + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "receipt": { + "title": "wai.quantum.receipt/2", + "description": "A result's receipt: an Ed25519 signature, by the key it names, over digest = BLAKE3(\"wai:quantum-service-receipt\\x02\" ‖ len ‖ request ‖ len ‖ result), each of request and result in its RFC 8785 canonical text (the result without its receipt member), each length 8 bytes big-endian. Whatever members the request and the result hold are sealed, the result's engine and schema among them. The first receipts (no canon member, $defs/first) sealed their writer's compact text under the domain ending \\x01; they still verify. wai/extensions/quantum-providers.md section 8.2 states the seal in full, and section 8.4 what a verifier checks.", + "type": "object", + "required": [ + "alg", + "canon", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "canon": { + "const": "rfc8785", + "description": "The canonical form the digest is taken over." + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The signing key, 32 bytes in lower-case hex." + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The digest signed, 32 bytes in lower-case hex." + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$", + "description": "The signature, 64 bytes in lower-case hex." + } + } + }, + "items": { + "type": "array", + "items": { + "type": "object", + "description": "One item: its index, its point in a sweep, its request (a plain job, complete in itself), and its result with its own receipt, or why it failed; and its path to the set's root.", + "required": [ + "index", + "request", + "status", + "path" + ], + "properties": { + "index": { + "type": "integer", + "minimum": 0 + }, + "point": { + "type": "object", + "description": "A sweep's item: the value of each input it was run at." + }, + "status": { + "enum": [ + "done", + "failed" + ] + }, + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "request": { + "title": "wai.quantum.job-request/1", + "description": "A job as a client submits it: a program and what is asked of it, or a set: many programs (programs), or one over a grid of its inputs (sweep), run as one job. The command line, both MCP servers, the job service, the desktop app and the Studio read it alike, and a receipt seals it as it was given. A member the engine does not read is ignored, and sealed with the rest.", + "type": "object", + "anyOf": [ + { + "required": [ + "qasm" + ] + }, + { + "required": [ + "programs" + ] + }, + { + "required": [ + "source" + ] + } + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, in OpenQASM 3 or the OpenQASM 2 forms in common use." + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "description": "The program in another format, in place of qasm (engine::formats::expand): read to the job's qasm before the job is read, the request keeping its source.", + "properties": { + "format": { + "enum": [ + "qasm", + "qir", + "jeff" + ] + }, + "program": { + "type": "string", + "description": "The program's text (OpenQASM, QIR)." + }, + "program_base64": { + "type": "string", + "description": "The program's bytes as base64 (jeff)." + } + } + }, + "shots": { + "type": "integer", + "minimum": 0, + "maximum": 1000000, + "description": "Measurement shots; 1024 when no observables or amplitudes are asked for, otherwise 0." + }, + "seed": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991, + "description": "The sampling seed (1 when not given): the same job and seed give the same counts." + }, + "method": { + "type": "string", + "description": "auto (the default: the strongest method the program admits), or a method by its name as the methods list names it; pulse runs a pulse program (OpenPulse calibrations) under the pulse options." + }, + "observables": { + "type": "array", + "maxItems": 256, + "description": "Pauli observables to take the expectation values of.", + "items": { + "anyOf": [ + { + "type": "string", + "description": "A Pauli string, as \"Z0 Z1\"; qubits count from 0." + }, + { + "type": "object", + "required": [ + "pauli" + ], + "properties": { + "pauli": { + "type": "string", + "description": "A Pauli string, as \"X3\"." + }, + "coeff": { + "type": "number", + "description": "Its coefficient (1 when not given)." + } + } + } + ] + } + }, + "amplitudes": { + "type": "array", + "maxItems": 64, + "description": "Basis states whose amplitudes to return: one 0 or 1 per qubit, qubit n-1 first.", + "items": { + "type": "string" + } + }, + "noise": { + "type": "object", + "description": "A noise model, each channel a probability. A channel not listed here is refused.", + "additionalProperties": false, + "properties": { + "depolarizing_1q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "depolarizing_2q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "amplitude_damping": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "dephasing": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "readout": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + } + }, + "options": { + "type": "object", + "description": "Options of the method that runs the job, as the methods list names them (max_bond, cutoff, fusion, trajectories, threshold, max_weight, ladder, max_terms, path_restarts), and memory_gb." + }, + "compile": { + "type": "object", + "description": "What a compile is asked for, each optional: the most the output may differ from the program (epsilon, in the operator norm up to a global phase), the level (0 lowers and approximates; 1 also rewrites and folds phases; 2 also resynthesises), the basis, the gate set it writes the program in (clifford_t: every rotation off the multiples of π/4 a Clifford+T word; standard: nothing approximated), whether to give the circuit after each pass (stages), and the twirl and dd passes, last (twirl, with its seed; dd, with its sequence).", + "properties": { + "epsilon": { + "type": "number", + "exclusiveMinimum": 0 + }, + "level": { + "type": "integer", + "minimum": 0, + "maximum": 2 + }, + "basis": { + "enum": [ + "clifford_t", + "standard" + ] + }, + "stages": { + "type": "boolean" + }, + "twirl": { + "description": "Twirl each two-qubit Clifford gate with Paulis drawn from a seeded stream: true (seed 1), or {\"seed\": N}. One seed is one instance, checked to be the same circuit.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "required": [ + "seed" + ], + "properties": { + "seed": { + "type": "integer", + "minimum": 0 + } + } + } + ] + }, + "dd": { + "description": "Dynamical decoupling in each window where a qubit idles long enough: xx or xy4 (or {\"sequence\": …}), checked to change nothing without noise.", + "anyOf": [ + { + "enum": [ + "xx", + "xy4" + ] + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "sequence": { + "enum": [ + "xx", + "xy4" + ] + } + } + } + ] + } + } + }, + "intent": { + "description": "What the program must do, checked with the run: one intent or a list. The result's verdict says how far it was checked.", + "anyOf": [ + { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + } + ] + }, + "verdict": { + "type": "boolean", + "description": "true: the result carries a verdict even with no intent." + }, + "target": { + "description": "A device target: a built-in target's name, or a target document. The program is compiled to it, placed and simulated under its noise; noise may not be given beside it.", + "anyOf": [ + { + "type": "string" + }, + { + "title": "wai.quantum.target/1", + "description": "A device target: its qubits, the pairs it couples, its native gates with their errors and durations, and the calibration snapshot they come from. A value not known is left out, never written as zero. Every field but format, name, source, qubits, gates and coupling is optional, and a field the format does not name is refused, so a misspelt one never reads as absent. Its canonical text is its RFC 8785 form, and the BLAKE3 of that text, the target's hash, names the snapshot in a receipt.", + "type": "object", + "required": [ + "format", + "name", + "source", + "qubits", + "gates", + "coupling" + ], + "additionalProperties": false, + "properties": { + "format": { + "const": "wai.quantum.target/1" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "additionalProperties": false, + "properties": { + "format": { + "type": "string", + "description": "The format the target was read from (wai-quantum targets import --help lists them)." + }, + "note": { + "type": "string", + "maxLength": 400 + } + } + }, + "calibration": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "maxLength": 400, + "description": "The calibration snapshot's id, as the source names it, or a content id of the snapshot read." + }, + "timestamp": { + "type": "string", + "maxLength": 400, + "description": "When the snapshot was taken, as the source writes it." + } + } + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2048, + "description": "Every qubit, in order.", + "items": { + "type": "object", + "required": [ + "qubit" + ], + "additionalProperties": false, + "properties": { + "qubit": { + "type": "integer", + "minimum": 0, + "description": "Its index: its place in the list." + }, + "label": { + "type": "string", + "description": "The source's own name for it, when that is not its index." + }, + "t1_us": { + "type": "number", + "minimum": 0, + "description": "T1, microseconds." + }, + "t2_us": { + "type": "number", + "minimum": 0, + "description": "T2 (the echo or Ramsey time the source reports), microseconds." + }, + "frequency_ghz": { + "type": "number", + "minimum": 0, + "description": "Its frequency, gigahertz." + }, + "readout": { + "type": "object", + "required": [ + "p01", + "p10" + ], + "additionalProperties": false, + "properties": { + "p01": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 1 | holds 0)." + }, + "p10": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 0 | holds 1)." + } + } + }, + "measure_ns": { + "type": "number", + "minimum": 0, + "description": "The measurement's duration, nanoseconds." + } + } + } + }, + "gates": { + "type": "array", + "maxItems": 262144, + "description": "Each native gate where the device runs it, sorted by gate then qubits.", + "items": { + "type": "object", + "required": [ + "gate", + "qubits" + ], + "additionalProperties": false, + "properties": { + "gate": { + "type": "string", + "pattern": "^[a-z0-9_]{1,40}$" + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + }, + "error": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "The average gate infidelity." + }, + "duration_ns": { + "type": "number", + "minimum": 0, + "description": "Nanoseconds." + } + } + } + }, + "coupling": { + "type": "array", + "description": "The pairs a two-qubit gate may act on, each once, the lower qubit first, sorted.", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + ] + }, + "fabric": { + "description": "Where the statevector method's state runs: auto (the default: on a member only where the committed measurements show it faster than this host's CPU for the job's size and fusion width, otherwise on the CPU), cpu, accelerator (the first accelerator member certified bit-exact here that holds the state, falling back to the next if it fails during the run), a member's id or key (wai-quantum fabric lists them), or a list of members, a power of two of them, the state split by its top qubits into one partition on each (cpu is a member, and a member may be named more than once). A member certified bit-exact gives the CPU's bits. A placement this host cannot honour is refused (J013), never made elsewhere.", + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "array", + "minItems": 2, + "maxItems": 64, + "items": { + "type": "string", + "minLength": 1 + } + } + ] + }, + "repair": { + "description": "Repair the program first on its flagged lines: true, or the choices.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "max_iterations": { + "type": "integer", + "minimum": 1 + }, + "dyadic_bits": { + "type": "integer", + "minimum": 1, + "maximum": 32 + }, + "sizes": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + } + } + } + ] + }, + "history": { + "type": "object", + "description": "The program's history's account of the version the job runs: its digest, and the gates and lines in each hand. The receipt binds it; a history recomputes and checks it." + }, + "provider": { + "type": "string", + "description": "The person's own provider to run on, by the name their registry gives it. Only a host that holds their credentials runs such a job; every other host refuses it." + }, + "programs": { + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "type": "string", + "description": "A program's text." + }, + { + "type": "object", + "required": [ + "qasm" + ], + "description": "A job of its own, read as a job request is (no programs or sweep in it); each item of the set's result holds its request in full." + } + ] + }, + "description": "A set (engine::sets): the programs to run as one job, each a program's text or a job of its own; the request's other fields apply to every item that does not set them itself." + }, + "sweep": { + "type": "object", + "additionalProperties": { + "type": "array", + "minItems": 1, + "items": { + "type": "number" + } + }, + "description": "A set over the request's own qasm: values for each of the program's inputs (integer, float or angle), every combination run, the names in sorted order and the first varying slowest." + }, + "params": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "A value for each of the program's parameters (`input float theta;`, `input angle phi;`), bound exactly before the program is read: it runs as if each were written as a `const` at that double. A parameter left without a value is refused (Q114, J050). In a sweep, the parameters it fixes, each bound at every point." + }, + "dry_run": { + "type": "boolean", + "description": "With true: what the host would do with the job or set, running nothing." + }, + "mitigate": { + "description": "Mitigate the job's expectation values (or, for readout, its counts) under its noise (engine::mitigate): zne, pea, pec, cdr, vd or readout, or {\"method\", …} with its options. The result's mitigation gives each value raw and mitigated.", + "anyOf": [ + { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + { + "type": "object", + "required": [ + "method" + ] + } + ] + }, + "pulse": { + "type": "object", + "description": "A pulse run's options (method \"pulse\"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0.", + "additionalProperties": false, + "properties": { + "dt_ns": { + "type": "number", + "exclusiveMinimum": 0, + "maximum": 1000, + "description": "The sample period, ns (default 0.5)." + }, + "levels": { + "type": "integer", + "enum": [ + 2, + 3 + ], + "description": "Levels kept per qubit (default 2; 3 shows leakage)." + }, + "tolerance": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1, + "description": "The most the stated error may be (default 1e-6): a run whose bound and rounding estimate pass it is refused, naming the steps that would meet it." + }, + "substeps": { + "type": "integer", + "minimum": 1, + "maximum": 4096, + "description": "Steps per sample (default: chosen so each step times the generator's norm is at most 0.5)." + }, + "qubits": { + "type": "object", + "description": "Each qubit's parameters by its index, over the target's and the defaults.", + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "frequency_ghz": { + "type": "number", + "description": "Its frequency, GHz." + }, + "rabi_mhz": { + "type": "number", + "description": "Its Rabi frequency at full amplitude, MHz." + }, + "anharmonicity_mhz": { + "type": "number", + "description": "Its anharmonicity, MHz." + }, + "t1_us": { + "type": "number", + "description": "Its relaxation time, µs." + }, + "t2_us": { + "type": "number", + "description": "Its coherence time, µs (at most 2·T1)." + } + } + } + }, + "couplings": { + "type": "array", + "description": "Static ZZ couplings.", + "items": { + "type": "object", + "required": [ + "qubits", + "zz_khz" + ], + "additionalProperties": false, + "properties": { + "qubits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + }, + "minItems": 2, + "maxItems": 2 + }, + "zz_khz": { + "type": "number", + "description": "The coupling's rate, kHz." + } + } + } + }, + "ports": { + "type": "object", + "description": "Ports by name: what each is for and the qubit it reaches.", + "additionalProperties": { + "type": "object", + "required": [ + "kind", + "qubit" + ], + "additionalProperties": false, + "properties": { + "kind": { + "enum": [ + "drive", + "measure", + "acquire" + ] + }, + "qubit": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } + } + } + }, + "result": { + "title": "wai.quantum.job-result/1", + "description": "A job's result as the engine gives it, on every host: what was asked of the program, computed by the method its plan chose, with that method's accuracy class. The receipt seals the result without its receipt member, beside the request. A result names the engine that made it and this schema (engine and schema); results made before results carried them have neither and follow this schema all the same.", + "type": "object", + "required": [ + "method", + "qubits", + "gates", + "accuracy" + ], + "properties": { + "engine": { + "type": "object", + "description": "The engine that made the result: the wai-quantum crate's name and version.", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "const": "wai-quantum" + }, + "version": { + "type": "string", + "description": "Its semantic version, as MAJOR.MINOR.PATCH." + } + } + }, + "schema": { + "const": "wai.quantum.job-result/1", + "description": "The schema the result follows." + }, + "components": { + "type": "array", + "description": "The identity of every component that made the result, when a registered one took part (engine::registry): its program's format, the passes its compile ran, the noise channels it names, its method; each registered one marked so. Sealed by the receipt with the rest.", + "items": { + "type": "object", + "description": "One component that made the result (engine::registry): its kind, name and version, the BLAKE3 digest of its descriptor, and whether it is built in. A result carries these only when a registered component took part; one made by built-ins alone names them as it always has (its method, its compile's passes, its noise's channels and the engine's version), the digests of that version listed by the components list.", + "required": [ + "kind", + "name", + "version", + "digest", + "origin" + ], + "properties": { + "kind": { + "enum": [ + "method", + "pass", + "channel", + "front_end" + ] + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "digest": { + "type": "string", + "pattern": "^[0-9a-f]{64}$", + "description": "BLAKE3 of the component's descriptor in its canonical JSON (engine::registry::digest_of)." + }, + "origin": { + "enum": [ + "built-in", + "registered" + ], + "description": "built-in: the engine's own; registered: a host's own, added in its process, not part of the engine." + }, + "certified": { + "const": false, + "description": "Beside a registered component: the engine does not certify it." + } + } + } + }, + "method": { + "type": "string", + "description": "The method that ran the job (provider for a run on the person's own provider)." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": "integer", + "minimum": 0 + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "state_hash": { + "type": "string", + "description": "The bit-exact method's statevector hash (BLAKE3, hex): the same on every machine." + }, + "counts": { + "type": "object", + "description": "Outcomes and their counts, keyed by the program's classical bits, the highest bit first. At most 65536 outcomes are listed; omitted_shots holds the rest.", + "additionalProperties": { + "type": "integer", + "minimum": 0 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "outcome_dimension": { + "type": "integer", + "minimum": 0, + "description": "The stabilizer method: the dimension of the measured outcomes' affine space." + }, + "shots": { + "type": "integer", + "minimum": 0, + "description": "The shots, where the method names them in the result (trajectories, provider)." + }, + "expectations": { + "type": "array", + "items": { + "type": "object", + "required": [ + "observable", + "coeff", + "value" + ], + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "value": { + "type": "number", + "description": "The coefficient times the expectation value." + }, + "stderr": { + "type": "number", + "description": "The standard error, for an estimate." + }, + "bound": { + "type": "number", + "description": "A bound on |exact − value|: rigorous for the bounded class; with confidence beside it, holding with that probability." + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + }, + "max_terms": { + "type": "integer" + }, + "ladder": { + "type": "array", + "description": "The value at thresholds a decade apart, the asked one last.", + "items": { + "type": "object", + "required": [ + "threshold", + "value", + "bound" + ], + "properties": { + "threshold": { + "type": "number" + }, + "value": { + "type": "number" + }, + "bound": { + "type": "number" + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + } + } + } + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds, for a bound that holds with a stated probability (stabilizer_rank's sampled mode)." + } + } + } + }, + "amplitudes": { + "type": "array", + "items": { + "type": "object", + "required": [ + "bits", + "re", + "im" + ], + "properties": { + "bits": { + "type": "string", + "description": "One 0 or 1 per qubit, qubit n-1 first." + }, + "re": { + "type": "number" + }, + "im": { + "type": "number" + }, + "bound": { + "type": "number", + "minimum": 0, + "description": "A bound on |exact − value| of the amplitude, holding with the probability confidence states (stabilizer_rank's sampled mode)." + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds." + } + } + } + }, + "global_phase": { + "type": "string", + "description": "Why the amplitudes' global phase is not fixed, when it is not." + }, + "warning": { + "type": "string" + }, + "contraction_flops": { + "type": "number", + "description": "The tensor network's contraction cost." + }, + "dynamic": { + "type": "object", + "description": "A program that measures in the middle, resets or branches on a measured bit: how it ran.", + "properties": { + "measurements_and_resets": { + "type": "integer", + "minimum": 0 + }, + "branches_run": { + "type": "integer", + "minimum": 0 + }, + "states_at_once": { + "type": "integer", + "minimum": 0 + }, + "branches_weighed": { + "type": "integer", + "minimum": 0 + } + } + }, + "outputs": { + "type": "array", + "description": "The program's output declarations: each its name and type, and its value, or the places of its bits in each outcome.", + "items": { + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "bits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + } + }, + "value": { + "description": "A number, a boolean, a bit string, a duration's text, {\"re\", \"im\"}, or an array of them." + } + } + } + }, + "timing": { + "type": "object", + "description": "A program that states durations (delay, box, stretch) the method does not apply: said so, with the reader's code.", + "required": [ + "applied", + "why" + ], + "properties": { + "applied": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "diagnostics": { + "type": "array", + "description": "The reader's warnings and notes on the program, each with its code.", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "compiled": { + "description": "How the program was compiled before it ran: on the person's own provider, to the device's gates; or, asked with compile, to a basis within a budget. Either way, basis is the gate set it was compiled to.", + "anyOf": [ + { + "type": "object", + "description": "A provider job: the program sent, compiled exactly to the device's own gates: its basis (the device's gate set), its OpenQASM 3 text (qasm3) and that text's BLAKE3 (program), its counts of gates and swaps, its layouts, and the check it passed before it was sent. Results sealed before qasm3 carry the hash alone.", + "required": [ + "basis", + "program" + ], + "properties": { + "basis": { + "type": "string" + }, + "program": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "qasm3": { + "type": "string", + "description": "The program sent, as OpenQASM 3 on physical qubits; program is the BLAKE3 of its UTF-8 bytes." + }, + "native_gates": { + "type": "integer" + }, + "two_qubit_gates": { + "type": "integer" + }, + "swaps": { + "type": "integer" + }, + "layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "final_layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "checked": { + "type": "string" + }, + "placement": { + "type": "object", + "description": "Where the program was placed on the device's qubits, and why." + } + } + }, + { + "type": "object", + "description": "A job asked to compile its program first: what ran is the compiled circuit, within distance of the program in the operator norm up to a global phase.", + "required": [ + "basis", + "verdict" + ], + "properties": { + "basis": { + "enum": [ + "clifford_t", + "standard" + ], + "description": "The gate set the program was compiled to." + }, + "level": { + "type": "integer", + "minimum": 0 + }, + "epsilon": { + "type": "number", + "description": "The budget asked for." + }, + "distance": { + "type": [ + "number", + "null" + ], + "description": "The bound the passes' distances add to." + }, + "verdict": { + "type": "string" + }, + "source": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "output": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ], + "description": "The BLAKE3 of the compile certificate's RFC 8785 text, in hex." + }, + "note": { + "type": "string" + } + } + } + ] + }, + "verdict": { + "title": "wai.quantum.verdict/1", + "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", + "type": "object", + "required": [ + "schema", + "level", + "rank", + "holds", + "statement", + "parsed", + "executed", + "intent", + "critique", + "repairs" + ], + "properties": { + "schema": { + "const": "wai.quantum.verdict/1" + }, + "level": { + "enum": [ + "refused", + "parsed", + "executed", + "evidence", + "proof" + ] + }, + "rank": { + "type": "integer", + "minimum": 0, + "maximum": 4, + "description": "The level's place on the ladder, from 0 (refused) to 4 (proof)." + }, + "holds": { + "type": [ + "boolean", + "null" + ] + }, + "statement": { + "type": "string", + "description": "The level in one plain line." + }, + "parsed": { + "type": "object", + "description": "Whether the reader took the program, and its warnings and notes with their codes, or its refusal.", + "required": [ + "ok" + ], + "properties": { + "ok": { + "type": "boolean" + }, + "diagnostics": { + "type": "array", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + }, + "text": { + "type": "string", + "description": "The refusal as the reader wrote it, with its line and code." + } + } + }, + "executed": { + "type": [ + "object", + "null" + ], + "description": "The method that ran and its accuracy class, and the distance a compile put between the program and what ran.", + "properties": { + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "compiled_distance": { + "type": [ + "number", + "null" + ] + } + } + }, + "intent": { + "type": "array", + "items": { + "type": "object", + "description": "One intent's check: what it asked, whether it held, how strong the check was and how it was made.", + "required": [ + "kind", + "outcome", + "strength", + "how" + ], + "properties": { + "kind": { + "enum": [ + "distribution", + "equivalent", + "prepares", + "sampled", + "compiled" + ] + }, + "outcome": { + "enum": [ + "holds", + "fails", + "unchecked" + ] + }, + "strength": { + "enum": [ + "proof", + "evidence", + "none" + ] + }, + "how": { + "type": "string" + }, + "why": { + "type": "string" + }, + "distance": { + "type": "number" + }, + "tolerance": { + "type": "number" + }, + "outcomes": { + "type": "integer", + "description": "The outcomes the distribution holds, or the samples' distinct outcomes." + }, + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The program's distribution, when its outcomes are few enough to list." + }, + "largest_gaps": { + "type": "array", + "items": { + "type": "object", + "properties": { + "outcome": { + "type": "string" + }, + "program": { + "type": "number" + }, + "intent": { + "type": "number" + } + } + } + }, + "global_phase": { + "type": [ + "number", + "null" + ] + }, + "method": { + "type": "string", + "description": "A sampled intent: the method the samples were run by." + }, + "seed": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "alpha": { + "type": "number" + }, + "fit": { + "type": "object", + "description": "A sampled intent: the test, its statistic, degrees of freedom and p-value, the level, and whether it rejected.", + "properties": { + "test": { + "type": "string" + }, + "statistic": { + "type": "number" + }, + "dof": { + "type": "integer" + }, + "p_value": { + "type": "number" + }, + "alpha": { + "type": "number" + }, + "shots": { + "type": "integer" + }, + "rejected": { + "type": "boolean" + }, + "smallest_expected": { + "type": [ + "number", + "null" + ] + }, + "impossible": { + "type": [ + "integer", + "array", + "boolean" + ] + }, + "note": { + "type": "string" + } + } + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "name": { + "type": "string" + }, + "note": { + "type": "string" + } + } + } + }, + "critique": { + "type": "array", + "description": "The program's smells, each with its lines.", + "items": { + "type": "object" + } + }, + "repairs": { + "type": "array", + "description": "Each edit a repair made, with the code it answered and the lines it changed.", + "items": { + "type": "object" + } + }, + "refusal": { + "type": "object", + "description": "For a refused job: its message and its codes.", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + }, + "sealed": { + "type": "boolean" + } + } + }, + "target": { + "type": "object", + "description": "A run on a device target: which target (its hash, as its receipt binds it), its calibration snapshot, where the program was placed and why, and the noise derived from the target.", + "required": [ + "name", + "hash" + ], + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "hash_is": { + "type": "string" + }, + "calibration": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "source": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "note": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "description": "The native gate set, the layout and routes chosen, the swaps, the expected success beside the fewest-swaps layout's, and the check of the compiled program." + }, + "noise": { + "type": "object", + "description": "The noise model derived from the target's calibration: its channels, durations and idling, and each qubit's readout." + } + } + }, + "fabric": { + "type": "object", + "description": "Where the state vector, or the pauli method's sum of terms, ran: the kernel, the placement the job asked for, the member that ran it (or each partition's), each with its certificate, and the energy. Present when the job asked for a placement, or when auto placed the state on a member by measurement (`auto`); a job auto leaves on the CPU names nothing; the receipt seals it with the rest of the result. Every member placed is certified bit-exact, so the answers are the CPU's, byte for byte.", + "required": [ + "kernel", + "asked", + "parity", + "energy" + ], + "properties": { + "kernel": { + "type": "string" + }, + "asked": { + "description": "The placement the job asked for, as it gave it.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "partitions": { + "type": "array", + "description": "Each partition's member, by the value of the state's top qubits: partition i holds the amplitudes whose top bits read i.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "partition_qubits": { + "type": "integer", + "minimum": 0 + }, + "local_qubits": { + "type": "integer", + "minimum": 0 + }, + "segments": { + "type": "integer", + "minimum": 0, + "description": "Runs of gates the partitions took in turn, between exchanges." + }, + "exchanges": { + "type": "integer", + "minimum": 0, + "description": "Partition qubits exchanged with local ones through the host's copy of the state." + }, + "fell_back_from": { + "type": "array", + "description": "An accelerator request whose member failed during the run: each member that failed, in turn, with how; the member named above ran the job.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "auto": { + "type": "object", + "description": "Why auto placed the state where it ran: the rule (a member is placed only where the committed measurements show it faster than this host's CPU for the job's size and fusion width) and the measured row it rests on, with the host, the day and the load it was measured under. Present only when auto placed a state on a member.", + "required": [ + "rule", + "host", + "fusion", + "from_qubits", + "to_qubits" + ], + "properties": { + "rule": { + "type": "string" + }, + "host": { + "type": "string", + "description": "The host's processor as the measurements name it (cpu--)." + }, + "measured": { + "type": "string", + "description": "The day the host was measured (UTC)." + }, + "about": { + "type": "string" + }, + "load": { + "type": "string" + }, + "discovery_ms": { + "type": "number", + "description": "What discovering and certifying the host's members took, once per process, as measured." + }, + "fusion": { + "type": "integer", + "minimum": 1 + }, + "from_qubits": { + "type": "integer", + "minimum": 0 + }, + "to_qubits": { + "type": "integer", + "minimum": 0 + }, + "min_launches": { + "type": "integer", + "minimum": 0 + }, + "basis": { + "type": "object", + "description": "The measured row the job is judged by: the largest measured size at or below its own, the launches of its plan, the runs of each, and the spread of the CPU's and the member's times in milliseconds.", + "required": [ + "qubits", + "launches", + "runs", + "cpu_ms", + "member_ms" + ], + "properties": { + "qubits": { + "type": "integer", + "minimum": 0 + }, + "launches": { + "type": "integer", + "minimum": 0 + }, + "runs": { + "type": "integer", + "minimum": 0 + }, + "cpu_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + }, + "member_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + } + } + } + } + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "why": { + "type": "string" + } + } + }, + "repaired": { + "type": "object", + "description": "A job asked to repair its program first: the program that ran, each repair, and what needs a person.", + "properties": { + "qasm": { + "type": "string" + }, + "repairs": { + "type": "array", + "items": { + "type": "object", + "required": [ + "code", + "by", + "edits" + ], + "properties": { + "code": { + "type": "string" + }, + "rule": { + "type": "string" + }, + "by": { + "enum": [ + "engine", + "proposal" + ] + }, + "flagged": { + "type": "array", + "items": { + "type": "integer" + } + }, + "edits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "line": { + "type": "integer" + }, + "before": { + "type": [ + "string", + "null" + ] + }, + "after": { + "type": [ + "string", + "null" + ] + } + } + } + } + } + } + }, + "needs_person": { + "type": "array", + "items": { + "type": "object" + } + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0, + "description": "Wall time of the run, where the host has a clock (not in a browser tab)." + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "receipt": { + "anyOf": [ + { + "title": "wai.quantum.receipt/2", + "description": "A result's receipt: an Ed25519 signature, by the key it names, over digest = BLAKE3(\"wai:quantum-service-receipt\\x02\" ‖ len ‖ request ‖ len ‖ result), each of request and result in its RFC 8785 canonical text (the result without its receipt member), each length 8 bytes big-endian. Whatever members the request and the result hold are sealed, the result's engine and schema among them. The first receipts (no canon member, $defs/first) sealed their writer's compact text under the domain ending \\x01; they still verify. wai/extensions/quantum-providers.md section 8.2 states the seal in full, and section 8.4 what a verifier checks.", + "type": "object", + "required": [ + "alg", + "canon", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "canon": { + "const": "rfc8785", + "description": "The canonical form the digest is taken over." + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The signing key, 32 bytes in lower-case hex." + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The digest signed, 32 bytes in lower-case hex." + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$", + "description": "The signature, 64 bytes in lower-case hex." + } + } + }, + { + "description": "The first form, before canon: the digest is over the compact text its writer wrote of each, members in the document's order (section 8.2 of wai/extensions/quantum-providers.md), under the domain ending \\x01. Never written now; still verified.", + "type": "object", + "required": [ + "alg", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$" + } + } + } + ] + }, + "provider": { + "type": "object", + "description": "A provider job: the provider's name, kind and protocol, the device, its provenance, and the hash of its description." + }, + "counts_source": { + "enum": [ + "shots", + "vendor_counts", + "probabilities" + ], + "description": "A provider job: where its counts come from (wai/extensions/quantum-providers.md section 8.3): tallied from one record a shot (shots), the provider's own counts (vendor_counts), or rebuilt from the probabilities it returned by largest remainders, derived and not shot records (probabilities). Results sealed before it carry neither it nor execution." + }, + "execution": { + "type": "object", + "description": "A provider job: how the device was asked to run the program (section 8.3): who states it (stated_by: client, provider or nobody); what the client sent (sent: the request's members and the settings among them); each of mitigation, twirling, decoupling, remapping and optimisation (off, on, default when the request sets nothing for it, none when the device has no such step, unknown when nobody states it); whether the gates were to run as written (verbatim); and a note.", + "required": [ + "stated_by", + "mitigation", + "twirling", + "decoupling", + "remapping", + "optimisation", + "verbatim" + ], + "properties": { + "stated_by": { + "enum": [ + "client", + "provider", + "nobody" + ] + }, + "sent": { + "type": "object", + "required": [ + "fields", + "settings" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "settings": { + "type": "object" + } + }, + "additionalProperties": false + }, + "mitigation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "twirling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "decoupling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "remapping": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "optimisation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "verbatim": { + "type": [ + "boolean", + "null" + ] + }, + "note": { + "type": "string" + } + }, + "additionalProperties": false + }, + "calibration": { + "type": [ + "string", + "null" + ], + "description": "A provider job: the calibration snapshot it ran under." + }, + "job": { + "type": "object", + "description": "A provider job: the provider's job id and its status checks." + }, + "ideal": { + "description": "A provider job: the circuit's exact distribution set beside the measured counts.", + "anyOf": [ + { + "type": "object", + "required": [ + "computed", + "total_variation_distance", + "hellinger_fidelity" + ], + "properties": { + "computed": { + "const": true + }, + "method": { + "type": "string" + }, + "total_variation_distance": { + "type": "number" + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number" + }, + "ideal_outcomes": { + "type": "integer" + }, + "note": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "computed", + "why" + ], + "properties": { + "computed": { + "const": false + }, + "why": { + "type": "string" + } + } + } + ] + }, + "cost": { + "type": "object", + "description": "A provider job: the estimate shown before it was sent, what the provider says it charged, and whether the person confirmed a run that was not free." + }, + "provenance": { + "title": "wai.quantum.provenance/1", + "description": "What a result came from, under the five categories cross-platform provenance surveys use: the circuit, the computer, the compilation, the execution and the software. A host adds it to the results it seals (the job service does, and each item of a set); a result without it reads as it always did. wai-quantum-service/docs/provenance.md maps every field to where it is and whether the receipt seals it.", + "type": "object", + "required": [ + "schema", + "circuit", + "computer", + "compilation", + "execution", + "software" + ], + "properties": { + "schema": { + "const": "wai.quantum.provenance/1" + }, + "circuit": { + "type": "object", + "description": "The program: the BLAKE3 digest of its text as given, its qubits and its gates.", + "required": [ + "program" + ], + "properties": { + "program": { + "type": "string", + "description": "BLAKE3 of the program's text, in hex." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": [ + "integer", + "null" + ] + } + } + }, + "computer": { + "type": "object", + "description": "What ran it: a classical simulator, the method and its accuracy class, a device target's hash when the job named one, and the fabric's members when the result names where its state ran.", + "required": [ + "kind", + "method" + ], + "properties": { + "kind": { + "const": "simulator" + }, + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "target": { + "type": "string", + "description": "The device target's hash; its layout, routes and noise are in the result's own target." + }, + "fabric": { + "type": "object", + "description": "The kernel and the member that ran the state, or each partition's, as the result's fabric names them.", + "properties": { + "kernel": { + "type": "string" + }, + "members": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "compilation": { + "type": "object", + "description": "Whether the job asked to be compiled; if it did, each pass in order with its check's verdict, the certificate's digest, the gate set compiled to (its basis), the level, the ε budget and the distance the result carries, and that no pass draws a random number.", + "required": [ + "asked" + ], + "properties": { + "asked": { + "type": "boolean" + }, + "passes": { + "type": [ + "array", + "null" + ], + "items": { + "type": "object", + "properties": { + "pass": { + "type": "string" + }, + "verdict": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ] + }, + "basis": { + "type": [ + "string", + "null" + ], + "description": "The gate set compiled to: clifford_t or standard." + }, + "level": { + "type": [ + "integer", + "null" + ] + }, + "epsilon": { + "type": [ + "number", + "null" + ] + }, + "distance": { + "type": [ + "number", + "null" + ] + }, + "seeded": { + "const": false + }, + "device": { + "type": "string", + "description": "A job on a device target, compiled exactly to its gates: where its layout and routes are." + }, + "status": { + "const": "not-applicable" + }, + "why": { + "type": "string" + } + } + }, + "execution": { + "type": "object", + "description": "The shots, the seed and the plan the job ran under; its identifier and times are the host's, outside the result.", + "required": [ + "plan" + ], + "properties": { + "shots": { + "type": [ + "integer", + "null" + ] + }, + "seed": { + "type": [ + "integer", + "null" + ] + }, + "plan": { + "type": "object", + "properties": { + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0 + } + } + } + } + }, + "software": { + "type": "object", + "description": "The engine's name and version, and the host's.", + "required": [ + "engine", + "host" + ], + "properties": { + "engine": { + "type": "string" + }, + "host": { + "type": "string" + } + } + } + } + }, + "mitigation": { + "title": "wai.quantum.mitigation/1", + "description": "A job's mitigation (its request's mitigate, engine::mitigate), in its result: the method and the options it ran with, its bias and variance assumptions, each observable raw and mitigated with a standard error each and the ideal value (or, for readout, the counts inverted as a quasi-distribution), the method's own details and what it spent. docs/qec.md describes each method.", + "type": "object", + "required": [ + "method", + "options", + "assumptions" + ], + "properties": { + "method": { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + "options": { + "type": "object", + "description": "The options it ran with, the defaults filled in.", + "properties": { + "method": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "factors": { + "type": "array", + "items": { + "type": "number" + } + }, + "extrapolation": { + "enum": [ + "richardson", + "linear", + "exponential" + ] + }, + "samples": { + "type": "integer" + }, + "training": { + "type": "integer" + }, + "keep": { + "type": "integer" + }, + "learn_shots": { + "type": "integer" + } + } + }, + "assumptions": { + "type": "object", + "properties": { + "bias": { + "type": "string" + }, + "variance": { + "type": "string" + } + } + }, + "noise": { + "type": "string", + "description": "How the job's noise model is read for the method." + }, + "note": { + "type": "string" + }, + "observables": { + "type": "array", + "items": { + "type": "object", + "description": "One observable: its raw value and the mitigated one, each with its standard error, and the ideal value a simulation knows.", + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "raw": { + "type": "number" + }, + "raw_stderr": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + }, + "ideal": { + "type": "number" + } + } + } + }, + "distribution": { + "type": "array", + "description": "readout: each outcome's raw share and its mitigated quasi-probability, with its standard error.", + "items": { + "type": "object", + "properties": { + "bits": { + "type": "string" + }, + "raw": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + } + } + } + }, + "details": { + "type": "object", + "description": "The method's own: the folded scales and the folding check (zne), the learned model and the amplified values (pea), the quasi-probability and the value it converges to (pec), the training fits (cdr), the purity (vd), the flip and its amplification (readout).", + "additionalProperties": true + }, + "cost": { + "type": "object", + "description": "The circuits and shots it spent beyond the job's own.", + "properties": { + "circuits": { + "type": "integer", + "minimum": 0 + }, + "shots": { + "type": "integer", + "minimum": 0 + }, + "note": { + "type": "string" + } + } + } + } + }, + "pulse": { + "type": "object", + "description": "A pulse run (method pulse, engine::pulse): what was read and its distribution, the final populations, each capture's reading, the final density matrix's digest, the schedule's length, the integrator and its step, the device and where each parameter came from, and what the receipt binds (calibration).", + "required": [ + "read", + "outcome_bits", + "populations", + "simulated_qubits", + "density_hash", + "integrator", + "device", + "calibration" + ], + "properties": { + "read": { + "type": "string", + "description": "What the distribution reads: the captures together (into the program's bits when each writes one), or the final state." + }, + "outcome_bits": { + "type": "array", + "items": { + "type": "string" + }, + "description": "What each character of an outcome is, left to right: a program bit (c[0]) or a qubit ($0)." + }, + "distribution": { + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "number" + }, + "description": "The probability of each outcome, which the counts sample; null when the captures start at different samples." + }, + "populations": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The final state read on every simulated qubit, the highest qubit first, a level above 0 read as 1." + }, + "simulated_qubits": { + "type": "array", + "items": { + "type": "integer" + } + }, + "captures": { + "type": "array", + "items": { + "type": "object", + "properties": { + "frame": { + "type": "string" + }, + "qubit": { + "type": "integer" + }, + "start": { + "type": "integer" + }, + "start_ns": { + "type": "number" + }, + "bit": { + "type": [ + "string", + "null" + ] + }, + "p1": { + "type": "number" + }, + "p2": { + "type": "number" + } + } + } + }, + "leakage": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "p2": { + "type": "number" + } + } + }, + "description": "With three levels: each qubit's final probability of level 2." + }, + "trace": { + "type": "number" + }, + "density_hash": { + "type": "string", + "description": "The BLAKE3 of the final density matrix's bits: the same on every platform." + }, + "duration": { + "type": "integer" + }, + "duration_ns": { + "type": "number" + }, + "integrator": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "order": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "substeps": { + "type": "integer" + }, + "step_ns": { + "type": "number" + }, + "steps": { + "type": "integer" + }, + "norm_max": { + "type": "number" + }, + "frame": { + "type": "string" + } + } + }, + "device": { + "type": "object", + "properties": { + "levels": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "qubits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "frequency_hz": { + "type": "number" + }, + "rabi_hz": { + "type": "number" + }, + "anharmonicity_hz": { + "type": "number" + }, + "t1_ns": { + "type": "number" + }, + "t2_ns": { + "type": "number" + }, + "from": { + "type": "object", + "additionalProperties": { + "enum": [ + "pulse", + "target", + "default", + "none" + ] + } + } + } + } + }, + "couplings": { + "type": "array" + }, + "model": { + "type": "string" + } + } + }, + "calibration": { + "type": "object", + "description": "What the receipt binds: the program's, its calibrations', the schedule's and the device's digests, and the target snapshot.", + "properties": { + "program": { + "type": "string" + }, + "calibrations": { + "type": "string" + }, + "schedule": { + "type": "string" + }, + "device": { + "type": "string" + }, + "target": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "calibration": { + "type": "object" + } + } + } + } + }, + "not_modelled": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, diff --git a/wai/wai-quantum-cli/docs/service-mcp.json b/wai/wai-quantum-cli/docs/service-mcp.json index 6a753f468..f88b40697 100644 --- a/wai/wai-quantum-cli/docs/service-mcp.json +++ b/wai/wai-quantum-cli/docs/service-mcp.json @@ -530,6 +530,77 @@ }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read; a parameter left without one is refused (J050). In a sweep, the parameters it fixes." }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } + }, "idempotency_key": { "type": "string", "minLength": 1, @@ -1364,6 +1435,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -4121,6 +4263,830 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -5121,6 +6087,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -7876,6 +8913,830 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -8521,6 +10382,622 @@ } } }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, "verdict": { "title": "wai.quantum.verdict/1", "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", @@ -11444,6 +13921,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -14201,6 +16749,830 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -15201,6 +18573,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -17956,6 +21399,830 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -18601,6 +22868,622 @@ } } }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, "verdict": { "title": "wai.quantum.verdict/1", "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", @@ -20715,6 +25598,77 @@ "description": "The program's bytes as base64: jeff." } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -20928,6 +25882,622 @@ } } }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, "verdict": { "title": "wai.quantum.verdict/1", "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", @@ -22544,6 +28114,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -25301,6 +30942,830 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -26301,6 +32766,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -29056,6 +35592,830 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -29701,6 +37061,622 @@ } } }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, "verdict": { "title": "wai.quantum.verdict/1", "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", @@ -43936,12 +51912,76 @@ } } }, - "params": { - "type": "object", - "additionalProperties": { - "type": "number" - }, - "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read; a parameter left without one is refused (J050). In a sweep, the parameters it fixes." + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } }, "seed": { "type": "integer", @@ -44381,6 +52421,13 @@ } } }, + "params": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read; a parameter left without one is refused (J050). In a sweep, the parameters it fixes." + }, "idempotency_key": { "type": "string", "minLength": 1, @@ -45215,6 +53262,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -47972,6 +56090,830 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -48972,6 +57914,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -51727,6 +60740,830 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -52006,6 +61843,622 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } } } }, @@ -52913,6 +63366,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } } diff --git a/wai/wai-quantum-cli/skills/wai-quantum/reference/tools.md b/wai/wai-quantum-cli/skills/wai-quantum/reference/tools.md index 02c4a3468..8bd99be2d 100644 --- a/wai/wai-quantum-cli/skills/wai-quantum/reference/tools.md +++ b/wai/wai-quantum-cli/skills/wai-quantum/reference/tools.md @@ -55,6 +55,8 @@ Generated by `wai-quantum docs skill` from the servers' own lists; `wai-quantum - `providers_list`: List the person's quantum providers - `provider_estimate`: Plan a run on a provider, and its cost - `run_on_provider`: Run on a provider (can spend the person's money) +- `plan_routes`: Weigh a contract against every route +- `run_routed`: Run a job on the route its contract chooses (can spend the person's money) - `get_provider_job`: Ask after a job on a provider - `cancel_provider_job`: Cancel a job on a provider - `list_provider_jobs`: List the jobs on the person's providers -- 2.54.0 (Apple Git-157) From 83d16c50dca3377eee6870aedde507e65e47dbf0 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Fri, 6 Nov 2026 03:49:26 -0500 Subject: [PATCH 03/42] wai-quantum: the planner under a contract, held to section 8.6 by both verifiers A job's contract (the class wanted, a cost ceiling, a deadline, an energy ceiling, whether a provider may be used) is weighed against every route a host can see; the cheapest that meets it runs, and its reasoning is sealed. This finishes the working commits before it, and falsifies them. What reading and falsifying found, each now fixed and held by a test that fails without the fix (shown by reverting each fix on the build host): - An estimate that is the least a job can come to (a simulator billed by the minute) met a cost ceiling: it is now cost_at_least, in the engine, the second verifier, section 8.6 and the schema. - A route's class for a method declaring two classes was the stronger-numbered one, so single and bounded gave bounded and a single result broke its own receipt: it is now the first class both meet. A result short of the class its reasoning wants, from the contract or kept from auto, gives no answer (J072), and every host checks a contract job before it seals it. - The shadow's distance multiplied two counts in a machine word, and the verifiers read omitted_shots of 0.0, a missing elapsed_ms and the shadow's request differently: the reference now reads them by value as section 8.6 says, sums exactly and multiplies doubles. The differential found the elapsed_ms case on 3 of 16,560 changed receipts. - The second verifier's 8.6 helper shadowed its own number reader, failing 87 of its self-test's checks; renamed, and the self-test now holds a contract job and each of three new plants. - A pulse job refused any contract member (J040). A queued contract job on the service lost its reasoning at a restart and was decided again with no energy estimate. The service looked at a worker every 200 ms, so a run could pass a contract's deadline by that much and be sealed: it now looks at the deadline. The service's verify schema did not describe the planner statement. The corpus gains five made receipts under a contract and 36 crafted ones, each expectation written from section 8.6; route-unchecked, choice-unchecked and distance-unchecked are caught by the differential. The qpu library's pins rise to 81 and 16, and the CLI, registry and service workflows require the new tests by name. Co-Authored-By: Claude Opus 5.5 --- .../verifiers/quantum-receipts.sh | 2 +- .github/workflows/wai-quantum-cli.yml | 11 +- .github/workflows/wai-quantum-qpu.yml | 14 +- .github/workflows/wai-quantum-registry.yml | 11 +- .github/workflows/wai-quantum-service.yml | 6 + ...06-wai-quantum-planner-under-a-contract.md | 40 + wai/extensions/quantum-providers.md | 46 +- wai/quantum-conformance/receipts/README.md | 9 +- wai/quantum-conformance/receipts/generate.py | 99 + .../receipts/jobs/cli-contract-auto.json | 1 + .../receipts/jobs/cli-contract-local.json | 1 + .../jobs/cli-contract-provider-priced.json | 1 + .../receipts/jobs/cli-contract-routed.json | 1 + .../crafted-contract-at-least-claimed.json | 435 + .../jobs/crafted-contract-at-least-false.json | 530 + .../crafted-contract-charged-over-stated.json | 434 + .../jobs/crafted-contract-charged-over.json | 434 + .../jobs/crafted-contract-choice-dearer.json | 328 + .../jobs/crafted-contract-choice-not-run.json | 328 + .../jobs/crafted-contract-class-short.json | 328 + .../jobs/crafted-contract-form-cost.json | 328 + .../jobs/crafted-contract-form-exactness.json | 328 + .../jobs/crafted-contract-form-member.json | 329 + .../jobs/crafted-contract-kept-dropped.json | 320 + .../jobs/crafted-contract-kept-false.json | 328 + .../crafted-contract-kept-missed-stated.json | 328 + .../jobs/crafted-contract-planner-format.json | 328 + .../crafted-contract-planner-missing.json | 53 + .../crafted-contract-planner-on-plain.json | 336 + .../crafted-contract-planner-wanted-from.json | 297 + .../jobs/crafted-contract-planner-wanted.json | 328 + .../crafted-contract-provider-not-chosen.json | 529 + ...rafted-contract-providers-not-allowed.json | 528 + .../jobs/crafted-contract-route-claimed.json | 324 + .../jobs/crafted-contract-route-code.json | 328 + .../crafted-contract-route-price-memory.json | 328 + .../crafted-contract-route-price-work.json | 328 + ...afted-contract-route-provider-claimed.json | 525 + .../jobs/crafted-contract-shadow-missing.json | 500 + .../crafted-contract-shadow-not-computed.json | 525 + .../crafted-contract-shadow-numerator.json | 529 + ...crafted-contract-shadow-omitted-spelt.json | 529 + .../crafted-contract-shadow-on-local.json | 333 + .../crafted-contract-shadow-on-plain.json | 66 + .../crafted-contract-shadow-plan-missing.json | 502 + .../crafted-contract-shadow-said-none.json | 505 + .../jobs/crafted-contract-shadow-seed.json | 529 + .../jobs/crafted-contract-stable-choice.json | 328 + .../jobs/crafted-contract-stable-digest.json | 328 + .../jobs/scripted-contract-prx-circuits.json | 420 + .../receipts/made.lock.json | 5 + wai/quantum-conformance/receipts/make.sh | 7 + .../receipts/manifest.json | 317 + .../tools/receipt_verify.py | 128 +- wai/wai-quantum-cli/README.md | 2 + wai/wai-quantum-cli/README.zh-CN.md | 2 + wai/wai-quantum-cli/docs/llms-full.txt | 152 +- wai/wai-quantum-cli/docs/local-mcp.json | 18629 +++++++++++++++- wai/wai-quantum-cli/docs/service-mcp.json | 121 + .../schemas/local-tools.v1.json | 2 +- wai/wai-quantum-cli/src/main.rs | 2 +- wai/wai-quantum-cli/src/providers.rs | 18 +- wai/wai-quantum-qpu/src/job.rs | 16 +- wai/wai-quantum-qpu/tests/clients.rs | 27 + wai/wai-quantum-service/README.md | 4 + .../schemas/service-tools.v1.json | 4 + wai/wai-quantum-service/src/jobs.rs | 59 +- wai/wai-quantum-service/src/mcp.rs | 5 +- wai/wai-quantum-service/tests/contract.rs | 4 +- wai/wai-quantum/docs/job-refusals.md | 2 +- wai/wai-quantum/schemas/job-result.v1.json | 5 + wai/wai-quantum/src/engine/planner.rs | 139 +- wai/wai-quantum/src/engine/planner/tests.rs | 114 +- wai/wai-quantum/src/engine/pulse.rs | 6 +- wai/wai-quantum/src/engine/refusal.rs | 2 +- 75 files changed, 33989 insertions(+), 129 deletions(-) create mode 100644 wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md create mode 100644 wai/quantum-conformance/receipts/jobs/cli-contract-auto.json create mode 100644 wai/quantum-conformance/receipts/jobs/cli-contract-local.json create mode 100644 wai/quantum-conformance/receipts/jobs/cli-contract-provider-priced.json create mode 100644 wai/quantum-conformance/receipts/jobs/cli-contract-routed.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-claimed.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-false.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over-stated.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-choice-dearer.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-choice-not-run.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-class-short.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-form-cost.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-form-exactness.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-form-member.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-kept-dropped.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-kept-false.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-kept-missed-stated.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-planner-format.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-planner-missing.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-planner-on-plain.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-planner-wanted-from.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-planner-wanted.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-provider-not-chosen.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-providers-not-allowed.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-route-claimed.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-route-code.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-route-price-memory.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-route-price-work.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-route-provider-claimed.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-missing.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-not-computed.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-numerator.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-omitted-spelt.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-on-local.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-on-plain.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-missing.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-none.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-seed.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-stable-choice.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-stable-digest.json create mode 100644 wai/quantum-conformance/receipts/jobs/scripted-contract-prx-circuits.json diff --git a/.github/wai-conformance/verifiers/quantum-receipts.sh b/.github/wai-conformance/verifiers/quantum-receipts.sh index ccd42b773..47d47ccd9 100644 --- a/.github/wai-conformance/verifiers/quantum-receipts.sh +++ b/.github/wai-conformance/verifiers/quantum-receipts.sh @@ -16,6 +16,6 @@ python3 -I wai/quantum-conformance/receipts/generate.py --check python3 -I wai/quantum-conformance/receipts/generate.py --self-test python3 -I wai/quantum-conformance/tools/receipt_verify.py --self-test wai/wai-quantum/src/engine/testdata/es-number-tostring.txt python3 -I wai/quantum-conformance/tools/receipt_differential.py --second-only -for plant in lenient-key no-alg last-duplicate no-inexact measured-simulator whole-cap lax-small-order-r; do +for plant in lenient-key no-alg last-duplicate no-inexact measured-simulator whole-cap lax-small-order-r route-unchecked choice-unchecked distance-unchecked; do python3 -I wai/quantum-conformance/tools/receipt_differential.py --second-only --plant "$plant" | tail -1 done diff --git a/.github/workflows/wai-quantum-cli.yml b/.github/workflows/wai-quantum-cli.yml index e0f837be7..0216792d9 100644 --- a/.github/workflows/wai-quantum-cli.yml +++ b/.github/workflows/wai-quantum-cli.yml @@ -104,7 +104,9 @@ jobs: an_agent_lists_estimates_is_refused_and_runs_only_with_confirm_cost \ an_agent_runs_on_a_provider_as_a_task_and_the_server_answers_while_it_waits \ providers::tasks::tests::a_job_reads_as_its_task \ - providers::tasks::tests::a_cancelled_request_ends_its_wait_and_a_change_wakes_it; do + providers::tasks::tests::a_cancelled_request_ends_its_wait_and_a_change_wakes_it \ + a_contract_weighs_every_route_and_its_receipt_says_why \ + an_agent_weighs_a_contract_and_runs_on_the_route_it_chooses; do grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/test.log" || { echo "::error::$t did not run and pass"; exit 1; } done # The model harness and the views in an agent's host, each test by name. @@ -136,8 +138,9 @@ jobs: # valid one by changing one member, or by setting a number past a double's whole numbers. # Each planted defect of the second verifier (a lenient key check, alg unchecked, the last # of a duplicate member kept, inexact numbers let through, a simulator's counts let pass as - # measured, a ceiling on every whole number, R of small order let through) must make the - # differential fail: the proof that it can. A plant that the corpus alone catches is caught + # measured, a ceiling on every whole number, R of small order let through, and under a + # contract each route's outcome, the planner's choice or a shadow's distance taken as it + # stands) must make the differential fail: the proof that it can. A plant that the corpus alone catches is caught # by the second-only run too, in the independent verifiers' step. - name: Job receipts, two verifiers shell: bash @@ -147,7 +150,7 @@ jobs: python3 -I wai/quantum-conformance/receipts/generate.py --self-test python3 -I wai/quantum-conformance/tools/receipt_verify.py --self-test wai/wai-quantum/src/engine/testdata/es-number-tostring.txt python3 -I wai/quantum-conformance/tools/receipt_differential.py --reference wai/wai-quantum-cli/target/release/wai-quantum - for plant in lenient-key no-alg last-duplicate no-inexact measured-simulator whole-cap lax-small-order-r; do + for plant in lenient-key no-alg last-duplicate no-inexact measured-simulator whole-cap lax-small-order-r route-unchecked choice-unchecked distance-unchecked; do python3 -I wai/quantum-conformance/tools/receipt_differential.py --reference wai/wai-quantum-cli/target/release/wai-quantum --plant "$plant" | tail -1 done # The release binary, pinned by version and SHA-256, rather than a build from source. diff --git a/.github/workflows/wai-quantum-qpu.yml b/.github/workflows/wai-quantum-qpu.yml index 24bf6ad47..d9797212a 100644 --- a/.github/workflows/wai-quantum-qpu.yml +++ b/.github/workflows/wai-quantum-qpu.yml @@ -79,10 +79,10 @@ jobs: # tests never touch one but the macOS leg's own. export WAI_QUANTUM_CREDENTIALS=file cargo test --locked 2>&1 | tee "$RUNNER_TEMP/test.log" - # The library (76, the cloud-tasks client's 22 among them), the clients - # against their contracts (14), and the providers end to end (12), each - # binary's count pinned. - for n in 76 14 12; do + # The library (81, the cloud-tasks client's 22 and a job under a contract's + # 5 among them), the clients against their contracts (16), and the providers + # end to end (12), each binary's count pinned. + for n in 81 16 12; do grep -qE "^test result: ok\. $n passed; 0 failed" "$RUNNER_TEMP/test.log" || { echo "::error::a test binary did not pass all $n of its tests"; exit 1; } done for t in curl_carries_a_request_to_a_server_and_back every_operation_over_http every_operation_over_a_local_process \ @@ -104,7 +104,11 @@ jobs: sampler_v2::tests::a_simulated_backend_is_not_silicon \ a_job_recorded_by_the_last_release_is_sealed_with_a_receipt_this_one_accepts \ a_receipt_names_the_device_s_qubits_as_the_program_was_sent_on_them \ - cloud_tasks_round_trip_through_their_contract a_job_collected_later_is_read_through_the_qubits_it_was_sent_on; do + cloud_tasks_round_trip_through_their_contract a_job_collected_later_is_read_through_the_qubits_it_was_sent_on \ + job::tests::a_contract_is_weighed_before_anything_is_sent job::tests::a_cost_ceiling_holds_the_estimate_and_is_no_confirmation \ + job::tests::every_provider_is_weighed_against_the_engine_s_own_methods job::tests::a_shadow_and_its_reasoning_outlive_what_sent_the_job \ + job::tests::a_deadline_it_cannot_be_held_to_is_refused_and_one_that_leaves_no_time_says_so \ + a_built_in_kind_runs_under_a_contract_and_a_classical_method_shadows_it a_cost_estimated_at_the_least_it_can_come_to_meets_no_ceiling; do grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/test.log" || { echo "::error::$t did not run and pass"; exit 1; } done - name: Clippy diff --git a/.github/workflows/wai-quantum-registry.yml b/.github/workflows/wai-quantum-registry.yml index b81a47c15..ed8a20cbb 100644 --- a/.github/workflows/wai-quantum-registry.yml +++ b/.github/workflows/wai-quantum-registry.yml @@ -97,15 +97,20 @@ jobs: grep -q "^test engine::registry::tests::$t \.\.\. ok$" "$RUNNER_TEMP/$log.log" || { echo "::error::$t did not run ($log)"; exit 1; } done done - - name: The built-ins' bytes, the refusal table and the job layer beside them + - name: The built-ins' bytes, the refusal table, the job layer and the planner under a contract beside them shell: bash working-directory: wai/wai-quantum run: | set -euo pipefail - cargo test --locked --release --features full --lib -- engine::job:: engine::refusal:: engine::catalog:: engine::compile:: engine::formats:: 2>&1 | tee "$RUNNER_TEMP/engine.log" + cargo test --locked --release --features full --lib -- engine::job:: engine::refusal:: engine::catalog:: engine::compile:: engine::formats:: engine::planner:: 2>&1 | tee "$RUNNER_TEMP/engine.log" grep -qE '^test result: ok\. [1-9][0-9]* passed; 0 failed' "$RUNNER_TEMP/engine.log" || { echo "::error::the engine's tests did not pass"; exit 1; } for t in engine::job::tests::a_job_that_asks_for_no_verdict_gives_the_bytes_it_gave \ - engine::refusal::tests::the_documented_table_is_the_table; do + engine::refusal::tests::the_documented_table_is_the_table \ + engine::planner::tests::what_the_routes_cost_is_the_same_bytes_on_every_host \ + engine::planner::tests::nothing_falls_back_from_exact_to_approximate \ + engine::planner::tests::nothing_falls_back_between_a_simulator_and_a_device \ + engine::planner::tests::every_rule_a_verifier_holds_a_local_contract_job_to_is_broken_once_and_found_alone \ + engine::planner::tests::every_rule_a_verifier_holds_a_provider_s_contract_job_to_is_broken_once_and_found_alone; do grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/engine.log" || { echo "::error::$t did not run"; exit 1; } done - name: The example, tested and run diff --git a/.github/workflows/wai-quantum-service.yml b/.github/workflows/wai-quantum-service.yml index d060ff04a..25f17a0da 100644 --- a/.github/workflows/wai-quantum-service.yml +++ b/.github/workflows/wai-quantum-service.yml @@ -80,6 +80,12 @@ jobs: cargo test --locked --release 2>&1 | tee "$RUNNER_TEMP/test.log" grep -qE '^test result: ok\. [1-9][0-9]* passed; 0 failed' "$RUNNER_TEMP/test.log" || { echo "::error::no test ran"; exit 1; } grep -q '^test the_service_gives_every_receipt_the_verdict_the_corpus_gives_it \.\.\. ok$' "$RUNNER_TEMP/test.log" || { echo "::error::the service was not held to the corpus of receipts"; exit 1; } + # A job under a contract: met or refused with every route's reason, never routed to a + # provider, stopped at its deadline, and its reasoning kept across a restart. + for t in a_contract_is_met_or_refused_and_the_service_never_reaches_a_provider \ + jobs::tests::a_contract_job_keeps_its_reasoning_across_a_restart; do + grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/test.log" || { echo "::error::$t did not run and pass"; exit 1; } + done cargo clippy --locked --release --all-targets -- -D warnings # The engine's parts of the service, each required by name: sets and # sweeps and their Merkle paths, a result's provenance, the package diff --git a/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md b/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md new file mode 100644 index 000000000..ef9964191 --- /dev/null +++ b/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md @@ -0,0 +1,40 @@ +### wai-quantum: the planner under a contract, its reasoning sealed, and a provider's answer shadowed + +- **A contract in the job request** (`contract`, [quantum-providers.md §8.6](extensions/quantum-providers.md)): the + class wanted (`exactness`), a cost ceiling (`max_cost`, an amount in decimals and its currency), a deadline + (`deadline_seconds`), an energy ceiling (`max_joules`) and whether a provider may be used (`providers`: `never`, the + default, or `allowed`). A job without one plans as it did, byte for byte. A contract that does not read is refused + (`J070`), member by member, rather than read as absent; a set refuses one (`J073`). +- **The planner** (`engine::planner`) lists every route the host can see: each method here, and each of the person's + providers a host brings. It prices each with what is known: a method's memory and work as the planner counts them, its + time at the planner's nominal rate where its work predicts it, its energy where the host estimates one; a provider's + own estimate, with what it leaves out (`time`, `amount`, `energy`, `mitigation`, `decoder`, `charged`). It rejects + every route that cannot meet the contract, each with a code and a sentence, and runs the cheapest of the rest. An + unknown never passes: a time nobody states does not meet a deadline, nor an unknown cost a ceiling, nor an estimate + that is only the least a job can come to (`cost_at_least`), nor an energy nobody estimates. Nothing falls back, from + exact to approximate or between a simulator and a device. With no route left, the job is refused with every route's + reason (`J071`). A contract that names no class keeps `auto`'s pick while it meets the rest, and only a route at least + as exact may take its place. +- **The reasoning is sealed** in the result as `planner` (`wai.quantum.planner/1`): every route, its price or why it was + rejected, the choice, what is the same on every host (`stable`: a digest of what the host-independent routes cost, + pinned by a test on x86_64 and arm64), and what the contract kept against what happened (`kept`: the deadline, the + energy and the charge). Both verifiers recompute each route's outcome and the choice from what the receipt states, + and give eight new reasons (`contract_form`, `planner_form`, `planner_route`, `planner_choice`, `planner_stable`, + `planner_kept`, `contract_class`, `shadow`). The corpus gains five made receipts under a contract and thirty-six + crafted ones, and three plants prove the differential sees a route, a choice and a distance taken as they stand. +- **A provider's answer is shadowed.** When a provider answers a contract job, the most exact classical method that can + reach the same counts within the time the contract leaves runs too, on a seed of its own, and the result carries both + with their distance (total variation exactly, as whole numbers; Hellinger fidelity; what the shots alone would + leave). Where none can, the result says which tried and why. `wai-quantum verify --recheck` prices the routes again + and runs the shadow again. +- **Every host seals only what its verifier accepts.** A result short of the class its reasoning wants gives no answer + (`J072`), and each host checks a contract job's reasoning before it seals it. A run past its contract's deadline on the + job service is stopped (`J074`). +- **Surfaces.** `wai-quantum run` and `plan` take `--exactness`, `--max-cost`, `--deadline`, `--max-joules`, + `--allow-providers` and `--contract`; a run that kept less than it asked exits 4. The local MCP server gains + `plan_routes` and `run_routed`, which weigh the person's providers beside the methods here; the engine's run and plan + tools take a contract and reach no provider. The free job service takes a contract, lists no provider among its + routes, holds `max_joules` to what it has metered, and keeps a queued job's reasoning across a restart. +- **Found on the way.** A pulse job refused any `contract` member (`J040`): it now takes one. A route's class for a + method that declares several is the first class each of them meets, so `single` and `bounded` together are + `heuristic`. diff --git a/wai/extensions/quantum-providers.md b/wai/extensions/quantum-providers.md index 797ec9b2b..5c53c713e 100644 --- a/wai/extensions/quantum-providers.md +++ b/wai/extensions/quantum-providers.md @@ -686,7 +686,7 @@ A route, an object of: |---|---| | `route` | its name: `method:`, or `provider:`, neither name empty | | `kind` | `local` for a method, `provider` for a provider | -| `class` | a string: the class its result has at worst. A method that can be truncated says so: `mps` is `heuristic`, though a result that was not truncated says `exact`. A provider that cannot run the job is `unknown` | +| `class` | a string: the class its result has at worst. A method that declares one class has that one; one that declares several has the first of `bit-exact`, `exact`, `single`, `bounded`, `estimate` and `heuristic` that each of them meets (so `single` and `bounded` together are `heuristic`). A method that can be truncated says so: `mps` is `heuristic`, though a result that was not truncated says `exact`. A provider that cannot run the job is `unknown` | | `host_dependent` | `true` or `false`: whether the route depends on the host. A provider's, a method on a GPU (`statevector_single`, `cutrank_single`) and a method the host registered are | | `price` | `null`, or an object: below | | `outcome` | `chosen`, `met` or `rejected`. Exactly one route is `chosen`, and it is `choice` | @@ -700,7 +700,7 @@ A price, an object of: | member | | |---|---| -| `money` | `free`: `true`, or `false` with `amount` and `currency` (strings, the amount as the provider gives it, with an optional `unit`), or `false` with `unknown`, a sentence. An unknown cost is not free (§7) | +| `money` | `free`: `true`, or `false` with `amount` and `currency` (strings, the amount as the provider gives it, with an optional `unit`), or `false` with `unknown`, a sentence. An unknown cost is not free (§7). `at_least`, absent or `true`: the amount is the least the job can come to, and what it takes decides the rest | | `time` | `seconds`, a number of at least 0 or `null`; with a number, `basis`: `nominal`, at the engine's rate for the method's work, or `provider`, the provider's own estimate, queue included; with `null`, `why` | | `memory_bytes`, `work` | what a method takes, as whole numbers, a double past 2^53 − 1, or `null` on a provider's route | | `energy` | `joules`, a number or `null`; with a number, `basis`; with `null`, `why`. No provider states a job's energy before it runs, so a provider's is `null`, and a host that estimates no job's energy states `null` for every route | @@ -740,8 +740,10 @@ route's `rejected.code`, and a route to which none applies is not rejected. contract gives no `max_cost` and the request names no `provider`; `cost_unknown`, it gives one and `money` has no `amount` that is an amount in decimals, or no `currency`; `cost_currency`, the two currencies differ; - `cost`, the amount is above `max_cost.amount`. Amounts are compared exactly, as - decimals, with no double between them, and no currency is converted. A + `cost`, the amount is above `max_cost.amount`; `cost_at_least`, `money.at_least` + is `true`, so what it will come to is not known to be within the ceiling. + Amounts are compared exactly, as decimals, with no double between them, and no + currency is converted. A provider the request names, with no `max_cost`, meets this rule: its cost is the person's to confirm (§7), as it is with no contract. 10. `energy_unknown`, `energy`: the contract gives `max_joules`, and @@ -791,13 +793,15 @@ run stops it at its deadline (`J074`), and seals nothing. | member | | |---|---| -| `deadline` | `seconds`, the contract's; `elapsed_ms`, a whole number or `null`: the result's `elapsed_ms` when its `method` is not `provider` (`null` when it has none), and otherwise the host's time from the job's submission to its counts; `kept`, whether `elapsed_ms` ≤ `seconds` × 1000, or `null` when `elapsed_ms` is `null` | +| `deadline` | `seconds`, the contract's; `elapsed_ms`, a whole number or `null`: the result's `elapsed_ms` by value when its `method` is not `provider` (`null` when it has none or it is not a number), and otherwise the host's time from the job's submission to its counts; `kept`, whether `elapsed_ms` ≤ `seconds` × 1000, or `null` when `elapsed_ms` is `null` | | `energy` | `max_joules`, the contract's; `joules`, the result's `energy.joules_micro` ÷ 10^6, or `null` when it has none; `kept`, whether `joules` ≤ `max_joules`, or `null` when `joules` is `null` | | `cost` | `max_cost`, the contract's; `charged`, the result's `cost.charged`, or `null`; `kept`: with a `charged` in the ceiling's currency and an amount in decimals, whether it is at most the ceiling; with any other `charged`, `null`; with no `charged`, `true` when the result's `cost.free` is `true` or it has none, and otherwise `null` | **The class given.** The result's `accuracy.class` meets `wanted` when `wanted` is not `null`, and a result whose `accuracy.approximate` is `true` does not meet -`simulated`. A method whose result falls short gives no answer (`J072`). +`simulated`. A route whose result falls short of `wanted`, whether the contract +named it or the job keeps what it would have had, gives no answer (`J072`): a +host seals no result this rule refuses. **The shadow.** When a provider answers a contract job, a classical method that can reach the same counts within the contract runs too. `planner.shadow` says which, @@ -818,26 +822,34 @@ A result's `shadow` is one of: - `ran` `false`, with `code`, a string, and `why`, a sentence: when `planner.shadow` has no `route`, `code` is its `code`; otherwise `failed`, the method's run did not complete. The provider's answer stands, alone, and says so. -- `ran` `true`, with `route` and `request`, equal to those of `planner.shadow`; +- `ran` `true`, with `route` and `request`, equal to those of `planner.shadow` + (numbers by value); `shots`, the result's; `accuracy`, an object whose `class` is a string; `counts`, `distinct_outcomes` and `omitted_shots`, whose `counts` and `omitted_shots` sum to the shots; optionally `elapsed_ms`; and `distance`. `distance` is an object. With `computed` `false`, it has `why`, and it is `false` -only when the provider's or the shadow's `omitted_shots` is not 0. Otherwise it is -`computed` `true` and, with a_k and b_k the provider's and the shadow's count of -each outcome k in either (0 when it has none), S the shots, and the outcomes taken -in the order of their UTF-8 bytes: +only when the provider's or the shadow's `omitted_shots` is not 0 (by value: `0` +however it is written is 0). Otherwise it is `computed` `true` and, with a_k and b_k +the provider's and the shadow's count of each outcome k in either, S the result's +`shots` read as a whole number from 0 to 2^64 − 1 (its double's whole part, and +2^64 − 1 past it), and the outcomes taken in the order of their UTF-8 bytes: -- `numerator`, the sum of |a_k − b_k|, and `denominator`, 2·S, whole numbers; +- `numerator`, the sum of |a_k − b_k|, and `denominator`, 2·S, whole numbers, + each exact and written as a double past 2^53 − 1; - `total_variation`, `numerator` ÷ `denominator`; -- `hellinger_fidelity`, R·R ÷ (S·S), with R the sum, in that order, of √(a_k·b_k); +- `hellinger_fidelity`, R·R ÷ (S·S), with R the sum, in that order, of √(a_k × b_k), + each count taken as a double and the product a double's; - `sampling_tvd_expected`, 0.5·F, with F the sum, in that order, of - √(4·p·(1 − p) ÷ (π·S)) and p = (a_k + b_k) ÷ (2·S): what these shots alone would - leave between two samples of one distribution, on average. + √(4·p·(1 − p) ÷ (π·S)) and p = (a_k + b_k) ÷ (2·S), the sum exact and then taken + as a double: what these shots alone would leave between two samples of one + distribution, on average. -Each is computed in IEEE 754 doubles in the order written, so that every verifier -gets the same bits. +A count is a whole number written as one (no fraction, no exponent) from 0 to +2^64 − 1, and 0 when it is anything else or absent. S of 0, or a p that leaves +4·p·(1 − p) below 0, gives no distance, and a `distance` that states one then does +not hold. Each double is IEEE 754, rounded to nearest, computed in the order +written, so that every verifier gets the same bits. **Reasons.** A verifier reports each of these that applies, beside those of §8.4: diff --git a/wai/quantum-conformance/receipts/README.md b/wai/quantum-conformance/receipts/README.md index 605f35a8e..fb2c52dea 100644 --- a/wai/quantum-conformance/receipts/README.md +++ b/wai/quantum-conformance/receipts/README.md @@ -7,9 +7,9 @@ exactly the reasons the manifest names (§8.4): none for a valid one. | file | what | |---|---| | `manifest.json` | every receipt in `jobs/`, the reasons a verifier must give it, how it was made, and what it is. Every expectation is written by hand from §8.4; none is copied from a verifier's output | -| `jobs/cli-*.json` | made by the command line on this machine, sealed with the published demo key (`make.sh`): runs by several methods, a compile, and runs on the reference provider over a local process, free and priced | +| `jobs/cli-*.json` | made by the command line on this machine, sealed with the published demo key (`make.sh`): runs by several methods, a compile, runs on the reference provider over a local process, free and priced, and jobs under a contract (§8.6), here, routed to the person's providers and on a provider named under a ceiling | | `jobs/service-*.json` | made by the free job service, sealed with its key (`make.sh`) | -| `jobs/scripted-*.json` | provider jobs of every built-in kind (`sampler-v2`, `prx-circuits`, `native-turns` with and without a noise model, `cloud-tasks` on a processor and on its simulator, with rows of shots and with probabilities), each through a service that follows that provider's published contract, sealed with the demo key (`wai-quantum-qpu/tests/clients.rs`, `every_built_in_kind_states_what_it_sent_and_its_receipt_keeps_every_rule`, with `WAI_QUANTUM_RECEIPT_CORPUS` set to this directory) | +| `jobs/scripted-*.json` | provider jobs of every built-in kind (`sampler-v2`, `prx-circuits`, `native-turns` with and without a noise model, `cloud-tasks` on a processor and on its simulator, with rows of shots and with probabilities), each through a service that follows that provider's published contract, sealed with the demo key (`wai-quantum-qpu/tests/clients.rs`, `every_built_in_kind_states_what_it_sent_and_its_receipt_keeps_every_rule`, with `WAI_QUANTUM_RECEIPT_CORPUS` set to this directory); and `prx-circuits` under a contract, its device's counts with a classical method's beside them (`a_built_in_kind_runs_under_a_contract_and_a_classical_method_shadows_it`) | | `jobs/first-form-*.json` | sealed by the job service as it was on 18 October 2026 (commit 72d18742d), so by the first form's own writer, not by a restatement of it | | `jobs/fixture-*.json` | the engine's pinned fixtures, sealed by earlier engines: a run before results named their engine, a provider job of the earlier form, and a compile | | `jobs/crafted-*.json` | made by `generate.py` from the receipts above, each changed one way: the seal's form, the strict signature (a weak-key forgery, `S + ℓ`, a mixed-order key, …), the first form, what any JSON reader and writer may do (and so must change nothing), the strict reader, and each rule of a provider's result, each sealed again with the demo key where the change is inside the seal so that one rule alone breaks | @@ -55,7 +55,8 @@ says and not only by its digest. `--plant NAME` runs the second verifier with a defect planted in it: a lenient key check, `alg` unchecked, the last of a member named twice kept, inexact numbers let through, a simulator's counts let pass as measured, a ceiling on every whole number, `R` of small order -let through. The differential succeeds only when it catches the plant. That is the proof that +let through, and under a contract (§8.6) each route's outcome, the planner's choice or a +shadow's distance taken as it stands. The differential succeeds only when it catches the plant. That is the proof that it can fail. `--extra DIR` adds receipts a person holds and does not publish: both verifiers must find each @@ -73,7 +74,7 @@ the manifest, with its plants, among the independent verifiers ```sh bash receipts/make.sh PATH/wai-quantum receipts/jobs # the command line's and the service's (cd ../wai-quantum-qpu && WAI_QUANTUM_RECEIPT_CORPUS=$PWD/../quantum-conformance/receipts/jobs \ - cargo test --test clients every_built_in_kind) # the built-in kinds' + cargo test --test clients -- every_built_in_kind a_built_in_kind_runs_under_a_contract) # the built-in kinds' python3 -I receipts/generate.py # the crafted half and the manifest ``` diff --git a/wai/quantum-conformance/receipts/generate.py b/wai/quantum-conformance/receipts/generate.py index 5f2c941f1..fb0052770 100644 --- a/wai/quantum-conformance/receipts/generate.py +++ b/wai/quantum-conformance/receipts/generate.py @@ -571,6 +571,100 @@ def cases(): add("method-measured", edited(run, at(R + ("accuracy", "class"), "measured")), ["provider_class"], "the engine's own result labelled measured") add("method-simulated", edited(run, at(R + ("accuracy", "class"), "simulated")), ["provider_class"], "the engine's own result labelled simulated") add("method-class-unknown", edited(run, at(R + ("accuracy", "class"), "quasi-exact")), [], "a class a verifier does not know: not a reason, since a later version may add one") + out.extend(contract_cases(run, at, drop)) + return out + + +def contract_cases(run, at, drop): + """Section 8.6: a job under a contract, each rule broken once and sealed again, and + what a host may state and still be valid. Each expectation is written from 8.6.""" + local = load("cli-contract-local.json") + auto = load("cli-contract-auto.json") + routed = load("cli-contract-routed.json") + named = load("cli-contract-provider-priced.json") + out = [] + + def add(name, body, reasons, what): + out.append(("crafted-contract-" + name + ".json", dump(body) + "\n", sorted(reasons), what)) + + R, P = ("result",), ("result", "planner") + + def route(name, f): + def g(b): + f(next(r for r in b["result"]["planner"]["routes"] if r["route"] == name)) + return g + + def both(*fs): + def g(b): + for f in fs: + f(b) + return g + + def met(r): + r["outcome"] = "met" + r.pop("rejected", None) + + # --- the contract and the reasoning's form + add("form-member", edited(local, at(("request", "contract", "deadline"), 1)), ["contract_form"], "a member no contract has: read as absent, a requirement would drop in silence") + add("form-exactness", edited(local, at(("request", "contract", "exactness"), "nearly")), ["contract_form"], "an exactness that is no class") + add("form-cost", edited(local, at(("request", "contract", "max_cost", "amount"), "1e3")), ["contract_form"], "a ceiling's amount that is not in decimals") + add("planner-missing", edited(local, drop(P)), ["planner_form"], "a contract job sealed without its reasoning") + add("planner-format", edited(local, at(P + ("format",), "wai.quantum.planner/2")), ["planner_form"], "a reasoning of another format") + add("planner-wanted", edited(local, at(P + ("wanted",), "heuristic")), ["planner_form"], "a class wanted that is not the contract's") + add("planner-wanted-from", edited(auto, at(P + ("wanted_from",), "contract")), ["planner_form"], "a class said to be the contract's, where the contract names none and the job keeps auto's") + add("planner-on-plain", edited(run, at(R + ("planner",), local["result"]["planner"])), ["planner_form"], "a job with no contract that carries a reasoning") + add("shadow-on-plain", edited(run, at(R + ("shadow",), {"ran": False, "code": "none", "why": "no provider answered"})), ["shadow"], "a job with no contract that carries a shadow") + # --- each route's outcome and the choice, recomputed + add("route-claimed", edited(local, route("method:mps", met)), ["planner_route"], "a heuristic route said to meet exact") + add("route-code", edited(local, route("method:mps", lambda r: r["rejected"].update(code="deadline"))), ["planner_route"], "a route rejected for a reason the rules do not give it") + + def dearer(b): + route("method:stabilizer", lambda r: r.update(outcome="met"))(b) + route("method:statevector", lambda r: r.update(outcome="chosen"))(b) + b["result"]["planner"]["choice"] = "method:statevector" + b["result"]["method"] = "statevector" + add("choice-dearer", edited(local, dearer), ["planner_choice"], "another route that meets the contract chosen and run, where the rule picks the cheaper") + add("choice-not-run", edited(local, at(R + ("method",), "statevector")), ["planner_choice"], "the route chosen is not what ran") + add("stable-digest", edited(local, at(P + ("stable", "digest"), "00" * 32)), ["planner_stable"], "a digest that is not what the routes' prices give") + add("stable-choice", edited(local, at(P + ("stable", "choice"), False)), ["planner_stable"], "a choice said to depend on the host, where it depends on nothing of it") + add("route-price-work", edited(local, route("method:stabilizer", lambda r: r["price"].update(work=r["price"]["work"] + 1))), ["planner_stable"], "a price changed that the digest covers and the order does not: the rule still picks the route") + add("route-price-memory", edited(local, route("method:stabilizer", lambda r: r["price"].update(memory_bytes=1 << 29))), ["planner_choice", "planner_stable"], "a price changed that the digest covers and the order reads: another route that meets the contract now comes first") + # --- what the contract kept, and the class given + add("kept-false", edited(local, at(P + ("kept", "deadline", "kept"), False)), ["planner_kept"], "a deadline said missed that was kept") + add("kept-dropped", edited(local, drop(P + ("kept", "cost"))), ["planner_kept"], "a ceiling the contract gives, and kept does not state") + + def late(b): + b["result"]["elapsed_ms"] = 61000 + b["result"]["planner"]["kept"]["deadline"]["elapsed_ms"] = 61000 + b["result"]["planner"]["kept"]["deadline"]["kept"] = False + add("kept-missed-stated", edited(local, late), [], "a deadline missed and said so: an answer all the same, and valid") + add("class-short", edited(local, at(R + ("accuracy", "class"), "estimate")), ["contract_class"], "a result whose class does not meet the class wanted") + add("shadow-on-local", edited(local, at(R + ("shadow",), {"ran": False, "code": "none", "why": "no provider answered"})), ["shadow"], "a local route's result that carries a shadow") + # --- a provider's answer and its shadow + S = R + ("shadow",) + add("shadow-missing", edited(routed, drop(S)), ["shadow"], "a provider's answer without its shadow") + add("shadow-plan-missing", edited(routed, drop(P + ("shadow",))), ["shadow"], "a provider's answer whose reasoning planned no shadow") + add("shadow-numerator", edited(routed, lambda b: b["result"]["shadow"]["distance"].update(numerator=b["result"]["shadow"]["distance"]["numerator"] + 1)), ["shadow"], "a distance that is not what the two lists of counts give") + add("shadow-not-computed", edited(routed, at(S + ("distance",), {"computed": False, "why": "said so"})), ["shadow"], "a distance not computed, with every shot listed on both sides") + + def reseeded(b): + for p in (b["result"]["shadow"]["request"], b["result"]["planner"]["shadow"]["request"]): + p["seed"] = 4 + add("shadow-seed", edited(routed, reseeded), ["shadow"], "a shadow sampled on the job's own stream, not one of its own") + add("shadow-said-none", edited(routed, at(S, {"ran": False, "code": "none", "why": "said none"})), ["shadow"], "a shadow said not to have run, where its plan had a route") + add("shadow-omitted-spelt", edited(routed, at(S + ("omitted_shots",), 0.0)), [], "a shadow's omitted_shots of 0 written as 0.0: 0 by value, and valid") + add("route-provider-claimed", edited(routed, route("provider:priced", met)), ["planner_route"], "a provider that costs money, with no ceiling to hold it to, said to meet the contract") + add("provider-not-chosen", edited(routed, at(R + ("provider", "name"), "priced")), ["planner_choice", "request_provider"], "an answer from a provider the planner did not choose") + add("providers-not-allowed", edited(routed, drop(("request", "contract", "providers"))), ["planner_choice", "planner_route", "request_provider"], "a provider's answer to a contract that does not allow one") + add("at-least-false", edited(routed, route("provider:priced", lambda r: r["price"]["money"].update(at_least=False))), ["planner_form"], "at_least given and not true") + add("at-least-claimed", edited(named, route("provider:priced", lambda r: r["price"]["money"].update(at_least=True))), ["planner_choice", "planner_route"], "a cost that is the least it can come to, under the ceiling, said to meet it") + add("charged-over", edited(named, at(R + ("cost", "charged", "amount"), "1.5")), ["planner_kept"], "charged past the ceiling, and kept said to hold") + + def over(b): + b["result"]["cost"]["charged"]["amount"] = "1.5" + b["result"]["planner"]["kept"]["cost"]["charged"]["amount"] = "1.5" + b["result"]["planner"]["kept"]["cost"]["kept"] = False + add("charged-over-stated", edited(named, over), [], "charged past the ceiling, and said so: valid") return out @@ -584,10 +678,15 @@ MADE = { "cli-compile.json": ("the command line: a compile, its certificate and its receipt", []), "cli-provider-reference.json": ("the command line, on the reference provider over a local process: a simulator's stated result", []), "cli-provider-reference-priced.json": ("the command line, on the reference provider with a price, confirmed with --yes", []), + "cli-contract-local.json": ("the command line under a contract: exact, a deadline and a ceiling, the cheapest route here chosen and its reasoning sealed", []), + "cli-contract-auto.json": ("the command line under a contract that names no class: auto's pick kept, held to a deadline", []), + "cli-contract-routed.json": ("the command line under a contract that allows the person's providers and wants a simulator's counts: the free one chosen, a classical method's counts and their distance beside its own", []), + "cli-contract-provider-priced.json": ("the command line on a provider it names, under a ceiling, confirmed with --yes: the estimate held to the ceiling, the charge to it after, and the shadow", []), "service-run.json": ("the free job service, signed with its key", []), "service-run-stabilizer.json": ("the free job service: a stabilizer job with observables", []), "scripted-sampler-v2.json": ("sampler-v2 through a service that follows its contract", []), "scripted-prx-circuits.json": ("prx-circuits through a service that follows its contract", []), + "scripted-contract-prx-circuits.json": ("prx-circuits named under a contract that wants a device's counts, confirmed: its counts, the planner's reasoning, and a classical method's counts and their distance beside them", []), "scripted-native-turns.json": ("native-turns, its simulator, through a service that follows its contract", []), "scripted-native-turns-noise.json": ("native-turns, its simulator under a device's noise model", []), "scripted-cloud-tasks-processor.json": ("cloud-tasks on a processor: a verbatim box, rows of shots", []), diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-auto.json b/wai/quantum-conformance/receipts/jobs/cli-contract-auto.json new file mode 100644 index 000000000..105a3f024 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-auto.json @@ -0,0 +1 @@ +{"status":"done","method":"exact","why":"bit-exact state vector of 3 qubits; what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)","estimate":{"memory_bytes":134218112,"work":40},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[3] q;\nbit[3] c;\nh q[0];\nt q[0];\ncx q[0], q[1];\nrz(pi/8) q[2];\ncx q[1], q[2];\nc = measure q;\n","shots":500,"seed":3,"contract":{"deadline_seconds":600.0}},"result":{"method":"exact","qubits":3,"gates":5,"accuracy":{"class":"bit-exact"},"state_hash":"5f1ae3e98c0555290986daf0d573de16a34ba01d1993f13f134e0b1daf6f1ab5","counts":{"000":254,"111":246},"distinct_outcomes":2,"omitted_shots":0,"elapsed_ms":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"bit-exact","wanted_from":"auto","auto":"method:exact","host":{"job_bytes":17179869184,"providers":[]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":2e-7,"basis":"nominal"},"memory_bytes":134218112,"work":40,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"chosen"},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":268447588,"work":40,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants bit-exact"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants bit-exact"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":0.024723456,"basis":"nominal"},"memory_bytes":270794752,"work":16482304,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants bit-exact"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants bit-exact"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is estimate, and the job wants bit-exact"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants bit-exact"}}],"choice":"method:exact","why":"what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"d859d0ec175157bdd2b0e221a569afd4d2d94e347cbd550027c714ab35bdb061","choice":true},"kept":{"deadline":{"seconds":600.0,"elapsed_ms":0,"kept":true}}},"energy":{"unmetered":"the command line does not meter a run's energy"},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"7fbcec2023294f5dd41b5de98fdb25c4507b99a51b15a37ce5a91516b731d303","signature":"cf1186c4834195871fa985d73ec64adccd26ae5166da0ea9fbf579d44a6f7dd059fdad4af3aee99bda5d63328523dc1a1aed42bd3e66a22640ead9d20ea23001"}}} diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-local.json b/wai/quantum-conformance/receipts/jobs/cli-contract-local.json new file mode 100644 index 000000000..4c0f0ef9d --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-local.json @@ -0,0 +1 @@ +{"status":"done","method":"stabilizer","why":"Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract","estimate":{"memory_bytes":67172870,"work":2008},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":1000,"seed":7,"contract":{"exactness":"exact","max_cost":{"amount":"1","currency":"USD"},"deadline_seconds":60.0}},"result":{"method":"stabilizer","qubits":2,"gates":2,"accuracy":{"class":"exact"},"counts":{"11":505,"00":495},"distinct_outcomes":2,"omitted_shots":0,"outcome_dimension":1,"elapsed_ms":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"exact","wanted_from":"contract","auto":"method:stabilizer","host":{"job_bytes":17179869184,"providers":[]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"met"},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":8e-9,"basis":"nominal"},"memory_bytes":268459522,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"met"},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants exact"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":2.4096e-7,"basis":"nominal"},"memory_bytes":67172870,"work":2008,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"chosen"},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants exact"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":0.027721728,"basis":"nominal"},"memory_bytes":270532608,"work":18481152,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"stabilizer_rank answers amplitudes and expectation values"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"tensor_network answers amplitudes only"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":1.35e-6,"basis":"nominal"},"memory_bytes":268435554,"work":9000,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"met"},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants exact"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"density_matrix is for noisy circuits (give \"noise\")"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is estimate, and the job wants exact"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants exact"}}],"choice":"method:stabilizer","why":"the cheapest of the 4 of 13 routes that meet the contract","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e","choice":true},"kept":{"deadline":{"seconds":60.0,"elapsed_ms":0,"kept":true},"cost":{"max_cost":{"amount":"1","currency":"USD"},"charged":null,"kept":true}}},"energy":{"unmetered":"the command line does not meter a run's energy"},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"ef613b1d460b70a7ddc2683acc890f28f38ecde575263229b2a9f1859d2b40b5","signature":"a5c9455ca9e6073296a1eb5f1c2a1a416c6f0b3943f013a961df2fbbb543886d1625e640cfc60a9eee0427464dbf34eb4a2141e4341cc966d5fe8018da28d90c"}}} diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-provider-priced.json b/wai/quantum-conformance/receipts/jobs/cli-contract-provider-priced.json new file mode 100644 index 000000000..a29847254 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-provider-priced.json @@ -0,0 +1 @@ +{"status":"done","method":"provider","why":"on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4,"contract":{"max_cost":{"amount":"1","currency":"USD"}},"provider":"priced"},"result":{"method":"provider","qubits":2,"gates":2,"accuracy":{"class":"simulated","note":"counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would"},"shots":300,"provider":{"name":"priced","kind":"process","protocol":"wai.quantum.provider/1","device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","qubits":5,"basis":"rzsxxcz","describe":"c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439"},"calibration":"reference-f2d9fe570421","compiled":{"basis":"rzsxxcz","program":"b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9","hash":"BLAKE3 of the program's OpenQASM 3 text, qasm3","qasm3":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n","native_gates":9,"two_qubit_gates":1,"swaps":0,"layout":[0,1],"final_layout":[0,1],"checked":"the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent","placement":{"chosen":"the compiler's own layout, the fewest swaps: the description states no errors"}},"job":{"id":"ref-1","polls":1},"ideal":{"computed":true,"method":"exact","total_variation_distance":0.03666666666666665,"hellinger_fidelity":0.998653743148044,"sampling_tvd_expected":0.023032943298089033,"ideal_outcomes":2,"note":"the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent"},"cost":{"free":false,"estimate":{"free":false,"amount":"0.09","currency":"USD","unit":"shot","seconds":0.0},"charged":{"amount":"0.09","currency":"USD"},"confirmed":true},"energy":{"unmetered":"the work ran at the provider; this host's meter would read only the wait"},"counts_source":"shots","execution":{"stated_by":"provider","mitigation":"none","twirling":"none","decoupling":"none","remapping":"none","optimisation":"none","verbatim":true,"note":"the reference simulates the program's gates as written, on the qubits named, and corrects nothing"},"counts":{"11":161,"00":139},"distinct_outcomes":2,"omitted_shots":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"simulated","wanted_from":"named","auto":null,"host":{"job_bytes":17179869184,"providers":["priced"]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"estimate","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"estimate","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"provider:priced","kind":"provider","provider":"priced","class":"simulated","host_dependent":true,"price":{"money":{"free":false,"amount":"0.09","currency":"USD","unit":"shot"},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder","charged"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"chosen"}],"choice":"provider:priced","why":"the route the job names, which meets its contract (1 of 14 routes)","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c","choice":false},"shadow":{"route":"method:exact","class":"bit-exact","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"budget_seconds":300.0,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]}},"kept":{"cost":{"max_cost":{"amount":"1","currency":"USD"},"charged":{"amount":"0.09","currency":"USD"},"kept":true}}},"shadow":{"ran":true,"route":"method:exact","accuracy":{"class":"bit-exact"},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"shots":300,"counts":{"00":161,"11":139},"distinct_outcomes":2,"omitted_shots":0,"distance":{"computed":true,"numerator":44,"denominator":600,"total_variation":0.07333333333333333,"hellinger_fidelity":0.9946222222222221,"sampling_tvd_expected":0.032573500793528},"elapsed_ms":0},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"05586382ac2c7005dfcbf9b65a5bbe99dbbff33b75923c119f6f4f0e46d3674f","signature":"44cf2408639ff97f6228449762f3a4ccbd481c3ad38d83eccb90d4ee4760814be58a98356cc9ef584f47598d04ffd87fa4aea88464b4c9ffac33b2ff5cdc6b08"}},"id":"pj-95909ba10d2d9f13","submitted_ms":1793951019928,"finished_ms":1793951019934} diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-routed.json b/wai/quantum-conformance/receipts/jobs/cli-contract-routed.json new file mode 100644 index 000000000..43aa27c2f --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-routed.json @@ -0,0 +1 @@ +{"status":"done","method":"provider","why":"on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4,"contract":{"exactness":"simulated","providers":"allowed"}},"result":{"method":"provider","qubits":2,"gates":2,"accuracy":{"class":"simulated","note":"counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would"},"shots":300,"provider":{"name":"ref","kind":"process","protocol":"wai.quantum.provider/1","device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","qubits":5,"basis":"rzsxxcz","describe":"0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0"},"calibration":"reference-f2d9fe570421","compiled":{"basis":"rzsxxcz","program":"b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9","hash":"BLAKE3 of the program's OpenQASM 3 text, qasm3","qasm3":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n","native_gates":9,"two_qubit_gates":1,"swaps":0,"layout":[0,1],"final_layout":[0,1],"checked":"the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent","placement":{"chosen":"the compiler's own layout, the fewest swaps: the description states no errors"}},"job":{"id":"ref-1","polls":1},"ideal":{"computed":true,"method":"exact","total_variation_distance":0.03666666666666665,"hellinger_fidelity":0.998653743148044,"sampling_tvd_expected":0.023032943298089033,"ideal_outcomes":2,"note":"the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent"},"cost":{"free":true,"estimate":{"free":true,"seconds":0.0},"charged":null,"confirmed":false},"energy":{"unmetered":"the work ran at the provider; this host's meter would read only the wait"},"counts_source":"shots","execution":{"stated_by":"provider","mitigation":"none","twirling":"none","decoupling":"none","remapping":"none","optimisation":"none","verbatim":true,"note":"the reference simulates the program's gates as written, on the qubits named, and corrects nothing"},"counts":{"11":161,"00":139},"distinct_outcomes":2,"omitted_shots":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"simulated","wanted_from":"contract","auto":"method:stabilizer","host":{"job_bytes":17179869184,"providers":["ref","priced"]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is bit-exact, and the job wants simulated"}},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":8e-9,"basis":"nominal"},"memory_bytes":268442722,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants simulated"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":7.296e-8,"basis":"nominal"},"memory_bytes":67128070,"work":608,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants simulated"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":0.010518528000000001,"basis":"nominal"},"memory_bytes":270532608,"work":7012352,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is heuristic, and the job wants simulated"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":4.05e-7,"basis":"nominal"},"memory_bytes":268435554,"work":2700,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants simulated"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is estimate, and the job wants simulated"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants simulated"}},{"route":"provider:ref","kind":"provider","provider":"ref","class":"simulated","host_dependent":true,"price":{"money":{"free":true},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"chosen"},{"route":"provider:priced","kind":"provider","provider":"priced","class":"simulated","host_dependent":true,"price":{"money":{"free":false,"amount":"0.09","currency":"USD","unit":"shot"},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder","charged"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"rejected","rejected":{"code":"cost_no_ceiling","why":"0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider"}}],"choice":"provider:ref","why":"the cheapest of the 1 of 15 routes that meet the contract","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a","choice":false},"shadow":{"route":"method:exact","class":"bit-exact","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"budget_seconds":300.0,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]}},"kept":{}},"shadow":{"ran":true,"route":"method:exact","accuracy":{"class":"bit-exact"},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"shots":300,"counts":{"00":161,"11":139},"distinct_outcomes":2,"omitted_shots":0,"distance":{"computed":true,"numerator":44,"denominator":600,"total_variation":0.07333333333333333,"hellinger_fidelity":0.9946222222222221,"sampling_tvd_expected":0.032573500793528},"elapsed_ms":0},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"43a1345cab6a823054aad8325eeefac68c7a6bb8a6aedf5942d517bfbd697a26","signature":"e2c4edbd35b960bbe83427a8949916b12d0dc16978a8dd142ae10426054d54f68a9e9e0ac70c65ba4ab170134cf6dda56998f4a9ad271e9c86dc9e4115985d00"}},"id":"pj-ef8b7cfb5f9601bc","submitted_ms":1793951019912,"finished_ms":1793951019919} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-claimed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-claimed.json new file mode 100644 index 000000000..4e6bfb3ef --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-claimed.json @@ -0,0 +1,435 @@ +{ + "status": "done", + "method": "provider", + "why": "on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "max_cost": { + "amount": "1", + "currency": "USD" + } + }, + "provider": "priced" + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "priced", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": false, + "estimate": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot", + "seconds": 0.0 + }, + "charged": { + "amount": "0.09", + "currency": "USD" + }, + "confirmed": true + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "named", + "auto": null, + "host": { + "job_bytes": 17179869184, + "providers": [ + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot", + "at_least": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + } + ], + "choice": "provider:priced", + "why": "the route the job names, which meets its contract (1 of 14 routes)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": { + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": { + "amount": "0.09", + "currency": "USD" + }, + "kept": true + } + } + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_expected": 0.032573500793528 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "80a5efb2b9393e4ceefb4c0a3337b4a246bb9fe71604215ef1030a9ab4cbe2b4", + "signature": "2e31e43bb0ebe3d1f8b28903754604845b3ac2dc6cdc8dd78ca09ef8c96284e95d30b528b961a98b4125b216e71d8a93eba7e5bb10011a33e2b50fb3672cf20f" + } + }, + "id": "pj-95909ba10d2d9f13", + "submitted_ms": 1793951019928, + "finished_ms": 1793951019934 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-false.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-false.json new file mode 100644 index 000000000..b0b997d06 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-false.json @@ -0,0 +1,530 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot", + "at_least": false + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_expected": 0.032573500793528 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "10fd84c59f77c28e172e7a50c0564f19c5c043df6c7bef32255c7de680f22e05", + "signature": "f1cef0682159106750366334bcb87d97ea25b29d3a4e4553d29cc751221406cf0260059d8cd9460b73b693b7235f33b47cbdecbdf0f653f3dec98b513d00170d" + } + }, + "id": "pj-ef8b7cfb5f9601bc", + "submitted_ms": 1793951019912, + "finished_ms": 1793951019919 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over-stated.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over-stated.json new file mode 100644 index 000000000..f9752e15c --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over-stated.json @@ -0,0 +1,434 @@ +{ + "status": "done", + "method": "provider", + "why": "on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "max_cost": { + "amount": "1", + "currency": "USD" + } + }, + "provider": "priced" + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "priced", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": false, + "estimate": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot", + "seconds": 0.0 + }, + "charged": { + "amount": "1.5", + "currency": "USD" + }, + "confirmed": true + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "named", + "auto": null, + "host": { + "job_bytes": 17179869184, + "providers": [ + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + } + ], + "choice": "provider:priced", + "why": "the route the job names, which meets its contract (1 of 14 routes)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": { + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": { + "amount": "1.5", + "currency": "USD" + }, + "kept": false + } + } + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_expected": 0.032573500793528 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "76ad5f1e6f1fc20de95c0529d09f7fb918916bf7a2cda3573cdc1e0de0c0f071", + "signature": "ba5155d131fa1d9b3661a61128940d25d7a411a503488600c23737f4c28a8a03e1a7cae56fd1d351ff1794e2def0ebdd7fd891a7fdd4584e395bb8b1c8278e0b" + } + }, + "id": "pj-95909ba10d2d9f13", + "submitted_ms": 1793951019928, + "finished_ms": 1793951019934 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over.json new file mode 100644 index 000000000..e160ba64c --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over.json @@ -0,0 +1,434 @@ +{ + "status": "done", + "method": "provider", + "why": "on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "max_cost": { + "amount": "1", + "currency": "USD" + } + }, + "provider": "priced" + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "priced", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": false, + "estimate": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot", + "seconds": 0.0 + }, + "charged": { + "amount": "1.5", + "currency": "USD" + }, + "confirmed": true + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "named", + "auto": null, + "host": { + "job_bytes": 17179869184, + "providers": [ + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + } + ], + "choice": "provider:priced", + "why": "the route the job names, which meets its contract (1 of 14 routes)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": { + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": { + "amount": "0.09", + "currency": "USD" + }, + "kept": true + } + } + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_expected": 0.032573500793528 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "b98c3902ba4a67de23fd47814acea6db7556d7734d4c38d233e4ba222f5a7f71", + "signature": "0218198823c62b20b0bfb4e919b817e6385421dd0133a07eac1ab9698582cd17299c4f95e58f4127b4cd458a8d5c946232fd01a3f20108936ec0b3aa91c48f0e" + } + }, + "id": "pj-95909ba10d2d9f13", + "submitted_ms": 1793951019928, + "finished_ms": 1793951019934 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-choice-dearer.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-choice-dearer.json new file mode 100644 index 000000000..0ac511cbc --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-choice-dearer.json @@ -0,0 +1,328 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "statevector", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:statevector", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "370d0daff76feaa1ad3a817688237c50e6a3e2771237ba7230eb696c6802da13", + "signature": "8c2f4f85b6c92b49d0026db616621ea025cbaf005a22bf00ce59b9f10b6a5d93a39af0365d739d1cf3451da7a6c30ec1c032e0355308f41a6d7889939b148e03" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-choice-not-run.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-choice-not-run.json new file mode 100644 index 000000000..02c8548f6 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-choice-not-run.json @@ -0,0 +1,328 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "statevector", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "9d73fdcb70eb6b1139081a09871f00ea1db015e897b0b0e496b92a9ce513f543", + "signature": "811f32d57a197598d5819929ef0c9226945c4ce17e7b81c12a970ca298821070e95730a5ff62dfb5e247a1d1a3ce2b538a722adf15a31bcf61dc57fc7380ac0d" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-class-short.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-class-short.json new file mode 100644 index 000000000..ca9801225 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-class-short.json @@ -0,0 +1,328 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "estimate" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "fcb8a0de271dcb5c79e38afbd6246f25134b1ac1052ddb7c96178df4613f463c", + "signature": "ba2606483da0f6ab63997202f05de44c823c3e93ff6ce31d77d997cf46be1e6cf07c9f4ef59605be22667844393fe7f8bdd030b9699465fc854fc19b566a8100" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-form-cost.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-form-cost.json new file mode 100644 index 000000000..c80eb8d87 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-form-cost.json @@ -0,0 +1,328 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1e3", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "71fae81f4fd43a8a972a1d3d7882be3eeabee5f126d71dea4e15ebf9f737eaf0", + "signature": "643a541fe275e6e2e54d816f8a2e85ec2e2a3a842e56387639610e532dd931d4d06c4fd438a4a0c9a7531568c62b0e64ec43fd67c93d07b24f2e5ba499b3180d" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-form-exactness.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-form-exactness.json new file mode 100644 index 000000000..acbc6fffa --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-form-exactness.json @@ -0,0 +1,328 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "nearly", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "f6717aaa6cf2471f4f1f1fd8feb78f5c40424e2ab44c92f2d620f89db39a301f", + "signature": "f1053a342c5254e962949efba3c60a53d188fd4025a16699a8ef48b6d0baa6919a96be4f2922c6c271ea447a01d1afaaf77ab87905634f3c00d458b05d518007" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-form-member.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-form-member.json new file mode 100644 index 000000000..07d2c5d29 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-form-member.json @@ -0,0 +1,329 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0, + "deadline": 1 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "ab091fe78b35dcd45b331b340acd7a75c3382f7a75fb987fc43a76c5666ae767", + "signature": "e24ffae02a6f4953cc43031fb6ed6696de4fd5753fd6de4b4785fef577a7a27c95ec58eff3cd2ace87aa4800c1e5fae682b139bd7a7885ae33c524d9cf9f0902" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-dropped.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-dropped.json new file mode 100644 index 000000000..08601b3e9 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-dropped.json @@ -0,0 +1,320 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "119246e24dc6542284c5ab7376d15cc307a13e98ac520cfd658fe975f852511e", + "signature": "c5fc9885ca5eee5347ae682752d2d9823952330e4a092f041e1ed67598824750ae433b75b4744b4058595d3f094505c775c46937c5f9c4d8f2289e984d207a06" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-false.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-false.json new file mode 100644 index 000000000..cf9bf6db8 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-false.json @@ -0,0 +1,328 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": false + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "82869a465a80472bdbd217bb2f91a32f8cd0fd97d283101155a90f0a0492e4ee", + "signature": "de3767cf310fde9c09f4ede2bc889c3f7bf4113ce869c65c4dcb009cbab710fb0aa26ea1bbb08fb895f97b62341a65887ec5d805ebbf3bd624c05ecf8c41920d" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-missed-stated.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-missed-stated.json new file mode 100644 index 000000000..0289495d1 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-missed-stated.json @@ -0,0 +1,328 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 61000, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 61000, + "kept": false + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "ee6e449631c73ebdd4024219533f775ae5b30c5b4b0a5eccbd7d760c154fe7ea", + "signature": "777fe8b49ede42a4200e0bf1b2843434dc7aa4c0b136ff4a1c2c53da0915da3e62318747b14ce73666e8a936b70e1d0cc0f9437b29ff075a0f868fc70c34c909" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-format.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-format.json new file mode 100644 index 000000000..1bbe04055 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-format.json @@ -0,0 +1,328 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/2", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "a831c3bfbcd09e0603c3ef6905c94f145ae5321efc4c42942d8dfe125b11644e", + "signature": "41886b5692e81f33d0073baf504297ca0c8f5ed88a9804a658c8588f1058fb476a3e80aa10ff46fa1c1a67c0de73d43d68e8bf2f68d6e9dfcd69c2a53361000b" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-missing.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-missing.json new file mode 100644 index 000000000..467296bf7 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-missing.json @@ -0,0 +1,53 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "31fbf6c42cea955cf95cdb31f0f719cc0c58f75439d234cdcf1f14a18b5f3ddb", + "signature": "67a78a0cb81b864a403630042d9fb653576185af190a2696398828cfe35996f5c00769a0caa236fe0b7a41bdf88eb871a3ffc9526ed52d094e37c65171ab0506" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-on-plain.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-on-plain.json new file mode 100644 index 000000000..03c0babc2 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-on-plain.json @@ -0,0 +1,336 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits", + "estimate": { + "memory_bytes": 67172870, + "work": 2016 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "observables": [ + "Z0 Z1", + "X0" + ] + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "expectations": [ + { + "observable": "Z0 Z1", + "coeff": 1.0, + "value": 1.0 + }, + { + "observable": "X0", + "coeff": 1.0, + "value": 0.0 + } + ], + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "d039ad3c5f565d444cea86061ebdad16a38a0c3d3fd70da2327196d7fade4b07", + "signature": "62ce367bb487bd7c65ad683ff1233f95d169692050d60103ab8a61f4ac7a8d91478209fb985ec024315ada1d2af77d0b0c9a7e5caf4a732de31eb9ed51144f0b" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-wanted-from.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-wanted-from.json new file mode 100644 index 000000000..f7084f9fe --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-wanted-from.json @@ -0,0 +1,297 @@ +{ + "status": "done", + "method": "exact", + "why": "bit-exact state vector of 3 qubits; what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)", + "estimate": { + "memory_bytes": 134218112, + "work": 40 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[3] q;\nbit[3] c;\nh q[0];\nt q[0];\ncx q[0], q[1];\nrz(pi/8) q[2];\ncx q[1], q[2];\nc = measure q;\n", + "shots": 500, + "seed": 3, + "contract": { + "deadline_seconds": 600.0 + } + }, + "result": { + "method": "exact", + "qubits": 3, + "gates": 5, + "accuracy": { + "class": "bit-exact" + }, + "state_hash": "5f1ae3e98c0555290986daf0d573de16a34ba01d1993f13f134e0b1daf6f1ab5", + "counts": { + "000": 254, + "111": 246 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "bit-exact", + "wanted_from": "contract", + "auto": "method:exact", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2e-07, + "basis": "nominal" + }, + "memory_bytes": 134218112, + "work": 40, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 268447588, + "work": 40, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants bit-exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants bit-exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.024723456, + "basis": "nominal" + }, + "memory_bytes": 270794752, + "work": 16482304, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants bit-exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants bit-exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants bit-exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants bit-exact" + } + } + ], + "choice": "method:exact", + "why": "what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "d859d0ec175157bdd2b0e221a569afd4d2d94e347cbd550027c714ab35bdb061", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 600.0, + "elapsed_ms": 0, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "f8f9ab0572ff3f5534db507f92d7363b351052594244dca8b8ddc51d579ba27f", + "signature": "02a26c78553fd52a9a356930229cb86daef30cf2bfdf224026acbbf83aa88130cf8126830b479fdcf5733812fdf3a6c852f9637700583920e60a8da4e7e50d03" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-wanted.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-wanted.json new file mode 100644 index 000000000..f02e52b98 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-wanted.json @@ -0,0 +1,328 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "heuristic", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "884e03b6ed7d9f4e823cbd913ab1f9dc853c0cf4fdf37e1cf196e425bd0a3c96", + "signature": "8d92165b05fe57a7be73fc53311fdd61aaa4259e3887001f4ca75453730a1ab92e67970a48262143fc9bec0f2d4524a754ba359ae204c3b0e7d7867da28f9607" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-not-chosen.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-not-chosen.json new file mode 100644 index 000000000..5dcfaebf7 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-not-chosen.json @@ -0,0 +1,529 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "priced", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_expected": 0.032573500793528 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "d6dc7de2013037b505a6faa67cac125da65f771e092e231452342b00cca3fc1d", + "signature": "3cb0f49862ab18e91dd8b3917bdad3139ec2762a1c69ac719779b23f99f6d23500d70d98c78c0c8c65255e0e38d0fa25335464d26fe49b6c28787b3c69ce5a0d" + } + }, + "id": "pj-ef8b7cfb5f9601bc", + "submitted_ms": 1793951019912, + "finished_ms": 1793951019919 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-providers-not-allowed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-providers-not-allowed.json new file mode 100644 index 000000000..4eab468ec --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-providers-not-allowed.json @@ -0,0 +1,528 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_expected": 0.032573500793528 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "a3ced2e7936b178a2174356f0534202354e49489151e323e4e784d27db6117df", + "signature": "f920de7a55b724ea1839630afe558d81b0c2f8fbe5637ecb7306da98c0c3aac24224140f00227a82f7443bb6c703f22a1627d32e557777976cbc2ee8d3268f07" + } + }, + "id": "pj-ef8b7cfb5f9601bc", + "submitted_ms": 1793951019912, + "finished_ms": 1793951019919 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-claimed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-claimed.json new file mode 100644 index 000000000..f160e195c --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-claimed.json @@ -0,0 +1,324 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "720107c633699bc992b3830fd8c0e92a50e6ca4b87f4c0eceae955b7950ae223", + "signature": "3be5edb0f101648c0ffb79da1a674fa37241c8deee0614efda868aba617213742f51226791c5f06582da34cc2eb647ed1f58c45702d5a7e47943fe690e71e40b" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-code.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-code.json new file mode 100644 index 000000000..55fc4b192 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-code.json @@ -0,0 +1,328 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "deadline", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "f2d94d45853c5fc84284b2294081d6035c86869d9de36c0e3a6d1d5da234e916", + "signature": "cd22da5ca864240a12224b8dfb701814b4b2e0fac0b29cfb3850c35c7aaf194707cb94a07af57176fed8e3e60d738b6ed47f61e15e852b21e1cf5fdf0fa8f00e" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-price-memory.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-price-memory.json new file mode 100644 index 000000000..474c29720 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-price-memory.json @@ -0,0 +1,328 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 536870912, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "f78c0dc9f3942eec1591f227a653caf024682a8f9bc9db8bed8758782bb190a4", + "signature": "b31ff76f9abd1fca7d0301ca92948c6f97f7362dd016579bd8e0d1415bfa6bc12c2719734d0799551a7b9edc024f49b8423fd1e4e60827744a44a0af105fb10b" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-price-work.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-price-work.json new file mode 100644 index 000000000..49368bb1c --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-price-work.json @@ -0,0 +1,328 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2009, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "656c7320f73afc62b7ba8b0ccbf2bfa5ae4b2cfc811d5933c78a05ec733223cf", + "signature": "e0e933b4a15a3b45dab2094749835eb24febd0bd6decdc3e33dc1d55dd564c7b05a0efbfc70804a74af54d919891d22e20212eac8b083205826a41a603c59103" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provider-claimed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provider-claimed.json new file mode 100644 index 000000000..7b9b1ca43 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provider-claimed.json @@ -0,0 +1,525 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "met" + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_expected": 0.032573500793528 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "722f6b1be18e58ff3fb491046e9c78bc372286f2941b152623ec680f1bb4cbf6", + "signature": "3aeaeabe49c9cfcd7d850c74733969de0d8f8fdde6633716d2949a23320e65e70dd76f957fd309a528ec4db368e20c6d0af15aafc69d7fa82ef1d0ce9b1e1501" + } + }, + "id": "pj-ef8b7cfb5f9601bc", + "submitted_ms": 1793951019912, + "finished_ms": 1793951019919 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-missing.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-missing.json new file mode 100644 index 000000000..4c2c908b1 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-missing.json @@ -0,0 +1,500 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "211b603f5d02256ed9c67ff118282180804d8612ebe90b7875b521b7cc6176f8", + "signature": "2fe2e24c206a73eca6fb008e21f81c097ce94a997829aed2a28c6cc4a587fd166b515bfa645599c052100a8baa2e12bc250d65a92bebaae90a482cccc8c1050a" + } + }, + "id": "pj-ef8b7cfb5f9601bc", + "submitted_ms": 1793951019912, + "finished_ms": 1793951019919 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-not-computed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-not-computed.json new file mode 100644 index 000000000..f0dd925da --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-not-computed.json @@ -0,0 +1,525 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": false, + "why": "said so" + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "6d8d745f5fbc1b3c2e22eba7cd306fa768fbe9ba08ee9ce6473607dd6390708f", + "signature": "d94f156c26ddde59445b3cf733d768b281748d5ea308e0192a73e95b28db696f6b4fd2cc4343c67c5dc1d93f3fa35afaa0ff63d3353e23e2337eb77d1cb5b20c" + } + }, + "id": "pj-ef8b7cfb5f9601bc", + "submitted_ms": 1793951019912, + "finished_ms": 1793951019919 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-numerator.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-numerator.json new file mode 100644 index 000000000..2cb2ea80e --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-numerator.json @@ -0,0 +1,529 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 45, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_expected": 0.032573500793528 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "7722d0ee7dbbd9f8aaa64c11bcf3b1274468dac372b54e3b0b56b1fb893e90dc", + "signature": "738fa5783c0651d7f9c8d85efea3024367758af1cbbded44a4370dddfc3f093d23df8c4296e61bde45fb571deeb2479da1f181c1e75888fa243dcb8ed7f9750e" + } + }, + "id": "pj-ef8b7cfb5f9601bc", + "submitted_ms": 1793951019912, + "finished_ms": 1793951019919 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-omitted-spelt.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-omitted-spelt.json new file mode 100644 index 000000000..b292d78f2 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-omitted-spelt.json @@ -0,0 +1,529 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0.0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_expected": 0.032573500793528 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "43a1345cab6a823054aad8325eeefac68c7a6bb8a6aedf5942d517bfbd697a26", + "signature": "e2c4edbd35b960bbe83427a8949916b12d0dc16978a8dd142ae10426054d54f68a9e9e0ac70c65ba4ab170134cf6dda56998f4a9ad271e9c86dc9e4115985d00" + } + }, + "id": "pj-ef8b7cfb5f9601bc", + "submitted_ms": 1793951019912, + "finished_ms": 1793951019919 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-on-local.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-on-local.json new file mode 100644 index 000000000..d65b33098 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-on-local.json @@ -0,0 +1,333 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "shadow": { + "ran": false, + "code": "none", + "why": "no provider answered" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "312383afaba8a8466195d2a49f4c924694060996e544d87ab736bb659f9f0610", + "signature": "621fa3c6e86aa8c380e8becddfe6c73b4fed2f0445e508dbad06558f137e3558290146a991258bdd5a6b26d3bcafa63d26ec3250fa4ba481bed727225d07ad09" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-on-plain.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-on-plain.json new file mode 100644 index 000000000..a9b5fa845 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-on-plain.json @@ -0,0 +1,66 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits", + "estimate": { + "memory_bytes": 67172870, + "work": 2016 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "observables": [ + "Z0 Z1", + "X0" + ] + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "expectations": [ + { + "observable": "Z0 Z1", + "coeff": 1.0, + "value": 1.0 + }, + { + "observable": "X0", + "coeff": 1.0, + "value": 0.0 + } + ], + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "shadow": { + "ran": false, + "code": "none", + "why": "no provider answered" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "41752598a89bedab7bb51e517bbc0a2219e48eedadf3c796b58276349e9834f4", + "signature": "a407363b148b44cc99bc9dd5441eab9ee1b15c3f28b2ca78f17e7492ac17ec8e44482e7b44134bd8067a4b332ba0994afdfbd64bfd1321b4a4eb75662b7f5302" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-missing.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-missing.json new file mode 100644 index 000000000..e9d453d02 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-missing.json @@ -0,0 +1,502 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_expected": 0.032573500793528 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "d563171591a0c70640883efedd6bbe698b25aaa291555e1b05a440644e96f0a2", + "signature": "321f9cde669ff900364826058dc920860ce0d87ae80538a03453dfac77cb80aa808f69aa894134c3855fc0cb9ae7e8219455ec00fa3adeb02d0dc4d07f8e2e05" + } + }, + "id": "pj-ef8b7cfb5f9601bc", + "submitted_ms": 1793951019912, + "finished_ms": 1793951019919 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-none.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-none.json new file mode 100644 index 000000000..9f7c007b6 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-none.json @@ -0,0 +1,505 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": false, + "code": "none", + "why": "said none" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "b9535112e12c8dba74cbe248f0895cbed527ebf801fb2d8bc8c6bd4706e9cf81", + "signature": "aebd1b19a617395ebb6277c540860d0d72be04dbdd24c6c986aa5eac34fee93455e1f5588119e8aa7f5734729b2109306aadc9d922bcc5ae64f07083e320200d" + } + }, + "id": "pj-ef8b7cfb5f9601bc", + "submitted_ms": 1793951019912, + "finished_ms": 1793951019919 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-seed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-seed.json new file mode 100644 index 000000000..2f01abe46 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-seed.json @@ -0,0 +1,529 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_expected": 0.032573500793528 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "8d51d7db31462977aae7bc2369bd9e79327f7d694c5964b5b61380ecb11a2911", + "signature": "1b93b284f9336df24ced3bf08880cd21edcd2e732f8dcb600dd5be49f497006e04afb07aa7e7b3e2df0683046a32dfbe76dfb8fff0b6e6aa0b6e35da2c517e0f" + } + }, + "id": "pj-ef8b7cfb5f9601bc", + "submitted_ms": 1793951019912, + "finished_ms": 1793951019919 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-stable-choice.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-stable-choice.json new file mode 100644 index 000000000..a045aa5f4 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-stable-choice.json @@ -0,0 +1,328 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": false + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "bf0e784f75354b4deb8a2eaf3fba0e03df5e352ea4865a3ee812c40cf0409201", + "signature": "31972adecacb1645a11305284c4bdaffa39d2d6b38479608065c99059e5123435a15a43a6c36aa15851b8efda0686746393a5022340586cce25bd3f2ad9c8c0c" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-stable-digest.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-stable-digest.json new file mode 100644 index 000000000..3eded6575 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-stable-digest.json @@ -0,0 +1,328 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "0000000000000000000000000000000000000000000000000000000000000000", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "0bf2e99293ac7a30c14a42859bff04f66284a9842e830875d07e99a7e4ae7eea", + "signature": "552cf92128cf9c50b5090d2bfabb0c3cd40e3ce3c4774297d7f162842d39f676e2701a09adf03cea0da9a76ff153189f6429be1a524f66d0c11a83f47267f205" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/scripted-contract-prx-circuits.json b/wai/quantum-conformance/receipts/jobs/scripted-contract-prx-circuits.json new file mode 100644 index 000000000..4c303b8ba --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/scripted-contract-prx-circuits.json @@ -0,0 +1,420 @@ +{ + "status": "done", + "method": "provider", + "why": "on lab, prx-circuits:test-qc (prx-circuits): compiled exactly to prxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "provider": "lab", + "shots": 400, + "seed": 5, + "contract": { + "exactness": "measured" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "measured", + "note": "counts from the processor the provider names, read as counts_source says (shot records, the provider's own counts, or counts rebuilt from probabilities); not reproducible by recomputation: the same job run again gives other counts, and no simulation stands in for them; what was set off at the provider, and what was left to its defaults, is in execution" + }, + "shots": 400, + "provider": { + "name": "lab", + "kind": "prx-circuits", + "protocol": "prx-circuits", + "device": "prx-circuits:test-qc", + "provenance": "silicon", + "qubits": 5, + "basis": "prxcz", + "describe": "1f6d996884468f37481db4e20932d6c0ecb84ebbbf4232f734080c61ab9fae66" + }, + "calibration": null, + "compiled": { + "basis": "prxcz", + "program": "12123632bbbc70df6b58c3103f50479a72211ba109a01d9e3a581c703f160dad", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\ngate prx(theta, phi) a { rz(-phi) a; rx(theta) a; rz(phi) a; }\nbit[2] c;\nprx(pi/2, -pi/2) $0;\nprx(pi/2, -pi/2) $1;\ncz $0, $1;\nprx(pi/2, pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 4, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "qubit_names": { + "0": "QB1", + "1": "QB2" + }, + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description does not read as a device target (describe: native_gates lists the device's gates)" + } + }, + "job": { + "id": "prx-0", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.0, + "hellinger_fidelity": 1.0, + "sampling_tvd_expected": 0.019947114020071634, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": false, + "estimate": { + "unknown": "the provider gives no estimate" + }, + "charged": null, + "confirmed": true + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "vendor_counts", + "execution": { + "stated_by": "client", + "sent": { + "fields": [ + "circuits", + "shots" + ], + "settings": {} + }, + "verbatim": false, + "note": "this client sends only circuits and shots: it sets nothing, so every step is the service's default, whatever that is", + "mitigation": "default", + "twirling": "default", + "decoupling": "default", + "remapping": "default", + "optimisation": "default" + }, + "counts": { + "00": 200, + "11": 200 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "measured", + "wanted_from": "contract", + "auto": null, + "host": { + "job_bytes": 8589934592, + "providers": [ + "lab" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "provider:lab", + "kind": "provider", + "provider": "lab", + "class": "measured", + "host_dependent": true, + "price": { + "money": { + "free": false, + "unknown": "the service states its prices in the person's account, not through this protocol" + }, + "time": { + "seconds": null, + "why": "the provider's estimate states no time" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 400, + "native_gates": 4, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "prx-circuits:test-qc", + "provenance": "silicon", + "outcome": "chosen" + } + ], + "choice": "provider:lab", + "why": "the cheapest of the 1 of 14 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "3e22ca81f2ba0b868442a8909bce52f4731136875b2d3305be07332444b8cfbd", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 400, + "seed": 4294967301, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-8, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 400, + "seed": 4294967301, + "method": "exact" + }, + "shots": 400, + "counts": { + "11": 211, + "00": 189 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 22, + "denominator": 800, + "total_variation": 0.0275, + "hellinger_fidelity": 0.9992431772192786, + "sampling_tvd_expected": 0.028198810450636217 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "1ec69219cfceace4fdadbd7ea08eea4769753ed34a7704f893e6cb6954a7981d", + "signature": "d0b09e4b2e1270cf907093c45e006e5c45f921c3a29018c4b80f5e060fb8923eeb8f0dc7b9fb565af2a1e84904a790a5d438f7c1c74f91e664947efc50341f03" + } + } +} diff --git a/wai/quantum-conformance/receipts/made.lock.json b/wai/quantum-conformance/receipts/made.lock.json index ef84e8334..71103537c 100644 --- a/wai/quantum-conformance/receipts/made.lock.json +++ b/wai/quantum-conformance/receipts/made.lock.json @@ -1,5 +1,9 @@ { "cli-compile.json": "1afbddc31dd54eb98a28df16b472769b5e6b12915d8cc72eb5d0093cd8c29593", + "cli-contract-auto.json": "8d44fc2fa9bf3846fa85048939cb408e395cf824a9f44236a478a2a765a28db4", + "cli-contract-local.json": "48fce7687fdf6934f415664316518fae774f95099daccaa4a9ad293fe7471fff", + "cli-contract-provider-priced.json": "a43ab21fde2040504888718de0485d5d80d94778b5500be9a8af2da0c2da7ea4", + "cli-contract-routed.json": "6e9ded06170571ce8b6b325a742f1bed371d5a1a7206aaa8f5fdbe3fc61bde36", "cli-provider-reference-priced.json": "e569e1810da66580c9da4c4fb1185490919d03066f104de8332f99ac214a728b", "cli-provider-reference.json": "ade872d1a9e34a70f9f3928218b64b91ef2df8c21229778d79cd9cbbbb436f0c", "cli-run-mps.json": "9f8fdd7f57566b63e66e979769caae330a32fe01520d909a82f1ecba5c5a6f04", @@ -14,6 +18,7 @@ "scripted-cloud-tasks-processor-probabilities.json": "63f457f817d940d8af7e161b66aeb6b089e46c80a06c8b640b0a8ad3bd4c46cb", "scripted-cloud-tasks-processor.json": "1eb499584183085209fa4597e0f8956826f18cf29d0885e7ad9a1c55a656f66d", "scripted-cloud-tasks-simulator.json": "cc99f5d91138569f7584f913c88293a8581085ef6a38944f7425ad86591252c4", + "scripted-contract-prx-circuits.json": "7a81903f4e805d340f8cc938ad592d9ba002f6ce4ffc12fd02ef40ba8992529b", "scripted-native-turns-noise.json": "8a6c1bac37f1b6a856d891dbc657d91c252a40eb7a5a09ab0ec9474233425385", "scripted-native-turns.json": "9cc3b887aba07437b2a3ad6e20e7f656853c63bf8c94c21c715efdfddf95ee77", "scripted-prx-circuits.json": "d1c74db10b01a23a7b66d90356a33b8f7afc37efd7c75a5af26fbd87f99cda6b", diff --git a/wai/quantum-conformance/receipts/make.sh b/wai/quantum-conformance/receipts/make.sh index aaacfa11c..f20712024 100644 --- a/wai/quantum-conformance/receipts/make.sh +++ b/wai/quantum-conformance/receipts/make.sh @@ -30,6 +30,13 @@ printf 'OPENQASM 3.0;\ninclude "stdgates.inc";\nqubit[1] q;\nrx(0.4) q[0];\n' > "$B" run bell.qasm --provider ref --shots 300 --seed 4 --demo-key --json > "$OUT/cli-provider-reference.json" "$B" providers add priced --kind process -- "$B" providers reference --stdio --price 0.0003 --currency USD > /dev/null "$B" run bell.qasm --provider priced --shots 300 --seed 4 --yes --demo-key --json > "$OUT/cli-provider-reference-priced.json" +# Jobs under a contract (section 8.6): the cheapest exact route here, under a deadline and a +# ceiling; auto's class kept; every route weighed with the person's providers, the free +# simulator chosen by its class and shadowed; and a provider named, under a ceiling, confirmed. +"$B" run bell.qasm --shots 1000 --seed 7 --exactness exact --deadline 60 --max-cost 1:USD --demo-key --json > "$OUT/cli-contract-local.json" +"$B" run three.qasm --shots 500 --seed 3 --deadline 600 --demo-key --json > "$OUT/cli-contract-auto.json" +"$B" run bell.qasm --shots 300 --seed 4 --exactness simulated --allow-providers --demo-key --json > "$OUT/cli-contract-routed.json" +"$B" run bell.qasm --provider priced --shots 300 --seed 4 --max-cost 1:USD --yes --demo-key --json > "$OUT/cli-contract-provider-priced.json" "$B" submit bell.qasm --shots 200 --seed 11 --json > "$OUT/service-run.json" "$B" submit bell.qasm --shots 200 -o "Z0 Z1" --json > "$OUT/service-run-stabilizer.json" for f in "$OUT"/cli-*.json "$OUT"/service-*.json; do "$B" verify "$f" > /dev/null || { echo "make.sh: $f does not verify" >&2; exit 1; }; done diff --git a/wai/quantum-conformance/receipts/manifest.json b/wai/quantum-conformance/receipts/manifest.json index fd8046cdc..e6409dab0 100644 --- a/wai/quantum-conformance/receipts/manifest.json +++ b/wai/quantum-conformance/receipts/manifest.json @@ -7,6 +7,30 @@ "made_by": "made", "what": "the command line: a compile, its certificate and its receipt" }, + { + "file": "jobs/cli-contract-auto.json", + "reasons": [], + "made_by": "made", + "what": "the command line under a contract that names no class: auto's pick kept, held to a deadline" + }, + { + "file": "jobs/cli-contract-local.json", + "reasons": [], + "made_by": "made", + "what": "the command line under a contract: exact, a deadline and a ceiling, the cheapest route here chosen and its reasoning sealed" + }, + { + "file": "jobs/cli-contract-provider-priced.json", + "reasons": [], + "made_by": "made", + "what": "the command line on a provider it names, under a ceiling, confirmed with --yes: the estimate held to the ceiling, the charge to it after, and the shadow" + }, + { + "file": "jobs/cli-contract-routed.json", + "reasons": [], + "made_by": "made", + "what": "the command line under a contract that allows the person's providers and wants a simulator's counts: the free one chosen, a classical method's counts and their distance beside its own" + }, { "file": "jobs/cli-provider-reference-priced.json", "reasons": [], @@ -91,6 +115,12 @@ "made_by": "made", "what": "cloud-tasks on its simulator: simulated" }, + { + "file": "jobs/scripted-contract-prx-circuits.json", + "reasons": [], + "made_by": "made", + "what": "prx-circuits named under a contract that wants a device's counts, confirmed: its counts, the planner's reasoning, and a classical method's counts and their distance beside them" + }, { "file": "jobs/scripted-native-turns-noise.json", "reasons": [], @@ -990,6 +1020,293 @@ "reasons": [], "made_by": "crafted", "what": "a class a verifier does not know: not a reason, since a later version may add one" + }, + { + "file": "jobs/crafted-contract-form-member.json", + "reasons": [ + "contract_form" + ], + "made_by": "crafted", + "what": "a member no contract has: read as absent, a requirement would drop in silence" + }, + { + "file": "jobs/crafted-contract-form-exactness.json", + "reasons": [ + "contract_form" + ], + "made_by": "crafted", + "what": "an exactness that is no class" + }, + { + "file": "jobs/crafted-contract-form-cost.json", + "reasons": [ + "contract_form" + ], + "made_by": "crafted", + "what": "a ceiling's amount that is not in decimals" + }, + { + "file": "jobs/crafted-contract-planner-missing.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "a contract job sealed without its reasoning" + }, + { + "file": "jobs/crafted-contract-planner-format.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "a reasoning of another format" + }, + { + "file": "jobs/crafted-contract-planner-wanted.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "a class wanted that is not the contract's" + }, + { + "file": "jobs/crafted-contract-planner-wanted-from.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "a class said to be the contract's, where the contract names none and the job keeps auto's" + }, + { + "file": "jobs/crafted-contract-planner-on-plain.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "a job with no contract that carries a reasoning" + }, + { + "file": "jobs/crafted-contract-shadow-on-plain.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a job with no contract that carries a shadow" + }, + { + "file": "jobs/crafted-contract-route-claimed.json", + "reasons": [ + "planner_route" + ], + "made_by": "crafted", + "what": "a heuristic route said to meet exact" + }, + { + "file": "jobs/crafted-contract-route-code.json", + "reasons": [ + "planner_route" + ], + "made_by": "crafted", + "what": "a route rejected for a reason the rules do not give it" + }, + { + "file": "jobs/crafted-contract-choice-dearer.json", + "reasons": [ + "planner_choice" + ], + "made_by": "crafted", + "what": "another route that meets the contract chosen and run, where the rule picks the cheaper" + }, + { + "file": "jobs/crafted-contract-choice-not-run.json", + "reasons": [ + "planner_choice" + ], + "made_by": "crafted", + "what": "the route chosen is not what ran" + }, + { + "file": "jobs/crafted-contract-stable-digest.json", + "reasons": [ + "planner_stable" + ], + "made_by": "crafted", + "what": "a digest that is not what the routes' prices give" + }, + { + "file": "jobs/crafted-contract-stable-choice.json", + "reasons": [ + "planner_stable" + ], + "made_by": "crafted", + "what": "a choice said to depend on the host, where it depends on nothing of it" + }, + { + "file": "jobs/crafted-contract-route-price-work.json", + "reasons": [ + "planner_stable" + ], + "made_by": "crafted", + "what": "a price changed that the digest covers and the order does not: the rule still picks the route" + }, + { + "file": "jobs/crafted-contract-route-price-memory.json", + "reasons": [ + "planner_choice", + "planner_stable" + ], + "made_by": "crafted", + "what": "a price changed that the digest covers and the order reads: another route that meets the contract now comes first" + }, + { + "file": "jobs/crafted-contract-kept-false.json", + "reasons": [ + "planner_kept" + ], + "made_by": "crafted", + "what": "a deadline said missed that was kept" + }, + { + "file": "jobs/crafted-contract-kept-dropped.json", + "reasons": [ + "planner_kept" + ], + "made_by": "crafted", + "what": "a ceiling the contract gives, and kept does not state" + }, + { + "file": "jobs/crafted-contract-kept-missed-stated.json", + "reasons": [], + "made_by": "crafted", + "what": "a deadline missed and said so: an answer all the same, and valid" + }, + { + "file": "jobs/crafted-contract-class-short.json", + "reasons": [ + "contract_class" + ], + "made_by": "crafted", + "what": "a result whose class does not meet the class wanted" + }, + { + "file": "jobs/crafted-contract-shadow-on-local.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a local route's result that carries a shadow" + }, + { + "file": "jobs/crafted-contract-shadow-missing.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a provider's answer without its shadow" + }, + { + "file": "jobs/crafted-contract-shadow-plan-missing.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a provider's answer whose reasoning planned no shadow" + }, + { + "file": "jobs/crafted-contract-shadow-numerator.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a distance that is not what the two lists of counts give" + }, + { + "file": "jobs/crafted-contract-shadow-not-computed.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a distance not computed, with every shot listed on both sides" + }, + { + "file": "jobs/crafted-contract-shadow-seed.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a shadow sampled on the job's own stream, not one of its own" + }, + { + "file": "jobs/crafted-contract-shadow-said-none.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a shadow said not to have run, where its plan had a route" + }, + { + "file": "jobs/crafted-contract-shadow-omitted-spelt.json", + "reasons": [], + "made_by": "crafted", + "what": "a shadow's omitted_shots of 0 written as 0.0: 0 by value, and valid" + }, + { + "file": "jobs/crafted-contract-route-provider-claimed.json", + "reasons": [ + "planner_route" + ], + "made_by": "crafted", + "what": "a provider that costs money, with no ceiling to hold it to, said to meet the contract" + }, + { + "file": "jobs/crafted-contract-provider-not-chosen.json", + "reasons": [ + "planner_choice", + "request_provider" + ], + "made_by": "crafted", + "what": "an answer from a provider the planner did not choose" + }, + { + "file": "jobs/crafted-contract-providers-not-allowed.json", + "reasons": [ + "planner_choice", + "planner_route", + "request_provider" + ], + "made_by": "crafted", + "what": "a provider's answer to a contract that does not allow one" + }, + { + "file": "jobs/crafted-contract-at-least-false.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "at_least given and not true" + }, + { + "file": "jobs/crafted-contract-at-least-claimed.json", + "reasons": [ + "planner_choice", + "planner_route" + ], + "made_by": "crafted", + "what": "a cost that is the least it can come to, under the ceiling, said to meet it" + }, + { + "file": "jobs/crafted-contract-charged-over.json", + "reasons": [ + "planner_kept" + ], + "made_by": "crafted", + "what": "charged past the ceiling, and kept said to hold" + }, + { + "file": "jobs/crafted-contract-charged-over-stated.json", + "reasons": [], + "made_by": "crafted", + "what": "charged past the ceiling, and said so: valid" } ] } diff --git a/wai/quantum-conformance/tools/receipt_verify.py b/wai/quantum-conformance/tools/receipt_verify.py index 6038b16de..680dd13bc 100644 --- a/wai/quantum-conformance/tools/receipt_verify.py +++ b/wai/quantum-conformance/tools/receipt_verify.py @@ -1073,7 +1073,7 @@ def read_contract(c): "providers": providers} -def _number(v): +def _value_of(v): return v.value if isinstance(v, Num) else None @@ -1110,6 +1110,8 @@ def _route_form(r): return False elif m.get("free") is not True: return False + if "at_least" in m and m["at_least"] is not True: + return False t = p.get("time") if not isinstance(t, dict) or not (t.get("seconds") is None or (isinstance(t["seconds"], Num) and t["seconds"].value >= 0)): return False @@ -1201,7 +1203,7 @@ def _gate(r, contract, request, provider, method, wanted, job_bytes): if price is None: return "cannot" # 6 - memory = _number(price["memory_bytes"]) + memory = _value_of(price["memory_bytes"]) if memory is not None and memory > job_bytes: return "memory" # 7 @@ -1209,7 +1211,7 @@ def _gate(r, contract, request, provider, method, wanted, job_bytes): return "providers" # 8 if contract["deadline"] is not None: - seconds = _number(price["time"].get("seconds")) + seconds = _value_of(price["time"].get("seconds")) if seconds is None: return "deadline_unknown" if seconds > contract["deadline"]: @@ -1229,9 +1231,11 @@ def _gate(r, contract, request, provider, method, wanted, job_bytes): return "cost_currency" if fractions.Fraction(amount) > fractions.Fraction(ceiling["amount"]): return "cost" + if money.get("at_least") is True: + return "cost_at_least" # 10 if contract["joules"] is not None: - joules = _number(price["energy"].get("joules")) + joules = _value_of(price["energy"].get("joules")) if joules is None: return "energy_unknown" if joules > contract["joules"]: @@ -1248,9 +1252,9 @@ def _order_key(r): else: amount = money.get("amount") cost = (1, fractions.Fraction(amount) if _is_decimal(amount) else fractions.Fraction(0)) - seconds = _number(p["time"].get("seconds")) + seconds = _value_of(p["time"].get("seconds")) time = (1, 0) if seconds is None else (0, math.ceil(seconds * 1000.0)) - return (cost, time, 0 if r["kind"] == "local" else 1, _number(p["memory_bytes"]) or 0.0, r["route"].encode("utf-8")) + return (cost, time, 0 if r["kind"] == "local" else 1, _value_of(p["memory_bytes"]) or 0.0, r["route"].encode("utf-8")) def _picked(routes, auto, contract, passes): @@ -1294,18 +1298,18 @@ def _kept_holds(p, contract, result): if not (e is None or (_whole(e) and e.value >= 0)): return False want = None if e is None else e.value <= d * 1000.0 - if _number(k.get("seconds")) != d or k.get("kept") is not want: + if _value_of(k.get("seconds")) != d or k.get("kept") is not want: return False - if result.get("method") != "provider" and _number(result.get("elapsed_ms")) != _number(e): + if result.get("method") != "provider" and _value_of(result.get("elapsed_ms")) != _value_of(e): return False if contract["joules"] is not None: j = contract["joules"] k = kept["energy"] if not isinstance(k, dict): return False - micro = _number(_member(result, "energy", "joules_micro")) + micro = _value_of(_member(result, "energy", "joules_micro")) x = None if micro is None else micro / 1e6 - if _number(k.get("max_joules")) != j or _number(k.get("joules")) != x or k.get("kept") is not (None if x is None else x <= j): + if _value_of(k.get("max_joules")) != j or _value_of(k.get("joules")) != x or k.get("kept") is not (None if x is None else x <= j): return False if contract["max_cost"] is not None: ceiling = contract["max_cost"] @@ -1332,8 +1336,11 @@ def _kept_holds(p, contract, result): def _count(v): - """A count as a whole number written as one, at least 0, or 0.""" - return int(v.text) if isinstance(v, Num) and v.literal_whole() and not v.text.startswith("-") else 0 + """§8.6: a count as a whole number written as one, from 0 to 2^64 − 1, or 0.""" + if isinstance(v, Num) and v.literal_whole() and not v.text.startswith("-"): + n = int(v.text) + return n if n <= 2 ** 64 - 1 else 0 + return 0 def shadow_distance(a, b, shots): @@ -1345,11 +1352,12 @@ def shadow_distance(a, b, shots): numerator, root, floor = 0, 0.0, 0.0 for k in sorted(set(a) | set(b), key=lambda k: k.encode("utf-8")): x, y = _count(a.get(k)), _count(b.get(k)) + # Sums of whole numbers exact; each product and quotient a double's. numerator += abs(x - y) - root += math.sqrt(float(x * y)) + root += math.sqrt(float(x) * float(y)) p = float(x + y) / (2.0 * s) inner = 4.0 * p * (1.0 - p) / (math.pi * s) - if inner < 0: + if inner != inner or inner < 0: return None floor += math.sqrt(inner) denominator = 2 * shots @@ -1369,14 +1377,16 @@ def _shadow_holds(request, p, result): if ran is not True: return False shots_n = result.get("shots") - shots = _number(shots_n) + shots = _value_of(shots_n) req = s.get("request") if not isinstance(req, dict) or not _same(plan.get("request"), req) or not _same(req.get("qasm"), request.get("qasm")): return False - if _number(req.get("shots")) != shots or shots is None: + if _value_of(req.get("shots")) != shots or shots is None: return False seed = request.get("seed") + # The request's seed as a whole number from 0 to 2^64 − 1 written as one, else 1. seed = int(seed.text) if isinstance(seed, Num) and seed.literal_whole() and not seed.text.startswith("-") else 1 + seed = seed if seed <= 2 ** 64 - 1 else 1 want_seed = (seed + 2 ** 32) % 2 ** 53 given = req.get("seed") if not (isinstance(given, Num) and given.literal_whole() and not given.text.startswith("-") and int(given.text) == want_seed): @@ -1388,26 +1398,28 @@ def _shadow_holds(request, p, result): if not isinstance(counts, dict): return False listed = sum(v.value for v in counts.values() if isinstance(v, Num)) - if _number(s.get("omitted_shots")) is None or _number(s["omitted_shots"]) + listed != shots or not (_whole(s.get("distinct_outcomes")) and s["distinct_outcomes"].value >= 0): + if _value_of(s.get("omitted_shots")) is None or _value_of(s["omitted_shots"]) + listed != shots or not (_whole(s.get("distinct_outcomes")) and s["distinct_outcomes"].value >= 0): return False d = s.get("distance") if not isinstance(d, dict): return False - theirs, ours = _count(result.get("omitted_shots")), _count(s.get("omitted_shots")) + # By value: an omitted_shots of 0 however it is written. + theirs, ours = _value_of(result.get("omitted_shots")), _value_of(s.get("omitted_shots")) if d.get("computed") is False: if not isinstance(d.get("why"), str) or (theirs == 0 and ours == 0): return False elif d.get("computed") is True: if "distance-unchecked" not in PLANTS: # PLANT - want = shadow_distance(result.get("counts"), counts, int(shots)) + # S as a whole number of at most 2^64 − 1, as §8.6 reads it. + want = shadow_distance(result.get("counts"), counts, min(max(int(shots), 0), 2 ** 64 - 1)) if want is None or theirs != 0 or ours != 0: return False for k, v in zip(("numerator", "denominator", "total_variation", "hellinger_fidelity", "sampling_tvd_expected"), want): - if _number(d.get(k)) != float(v): + if _value_of(d.get(k)) != float(v): return False else: return False - return (s.get("route") == route and isinstance(_member(s, "accuracy", "class"), str) and _number(s.get("shots")) == shots) + return (s.get("route") == route and isinstance(_member(s, "accuracy", "class"), str) and _value_of(s.get("shots")) == shots) def check_contract(request, result, reasons): @@ -1746,6 +1758,52 @@ def _provider_result(**changes): _DELETE = object() +def _contract_job(**changes): + """§8.6: the provider job above, named under a contract that wants a simulator's counts, + with its reasoning and its shadow, for the self-test only: (request text, result text).""" + request = json.loads(_PROVIDER_REQUEST) + request["contract"] = {"exactness": "simulated"} + job_bytes = 1 << 30 + facts = {"job_bytes": job_bytes, "routes": [ + {"route": "method:exact", "class": "bit-exact", "seconds": None, "memory_bytes": None, "work": None}]} + digest = blake3(text_of(read_json(json.dumps(facts).encode()), True).encode("utf-8")).hex() + shadow_request = {"qasm": request["qasm"], "shots": 4, "seed": 1 + 2 ** 32, "method": "exact"} + planner = { + "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "contract", "auto": None, + "host": {"job_bytes": job_bytes, "providers": ["lab"]}, + "routes": [ + {"route": "method:exact", "kind": "local", "method": "exact", "class": "bit-exact", "host_dependent": False, + "price": None, "outcome": "rejected", "rejected": {"code": "not_named", "why": "the job names another route"}}, + {"route": "provider:lab", "kind": "provider", "provider": "lab", "class": "simulated", "host_dependent": True, + "price": {"money": {"free": True}, "time": {"seconds": 1.5, "basis": "provider"}, "memory_bytes": None, + "work": None, "energy": {"joules": None, "why": "no provider states it"}, "leaves_out": ["energy"]}, + "outcome": "chosen"}, + ], + "choice": "provider:lab", "why": "the route the job names", + "stable": {"scope": "the host-independent routes", "routes": ["method:exact"], "digest": digest, "choice": False}, + "kept": {}, + "shadow": {"route": "method:exact", "class": "bit-exact", "budget_seconds": 300, "price": None, "request": shadow_request}, + } + shadow = {"ran": True, "route": "method:exact", "request": shadow_request, "shots": 4, + "accuracy": {"class": "bit-exact"}, "counts": {"1": 4}, "distinct_outcomes": 1, "omitted_shots": 0, + "distance": {"computed": True, "numerator": 0, "denominator": 8, "total_variation": 0.0, + "hellinger_fidelity": 1.0, "sampling_tvd_expected": 0.0}} + result = json.loads(_provider_result()) + result["planner"], result["shadow"] = planner, shadow + both = {"request": request, "result": result} + for path, value in changes.items(): + node = both + parts = path.split("__") + for part in parts[:-1]: + node = node[int(part)] if isinstance(node, list) else node[part] + last = int(parts[-1]) if isinstance(node, list) else parts[-1] + if value is _DELETE: + node.pop(last) + else: + node[last] = value + return json.dumps(both["request"], separators=(",", ":")), json.dumps(both["result"], separators=(",", ":")) + + def self_test(args): results = [] @@ -2044,6 +2102,31 @@ def self_test(args): finally: PLANTS.discard(plant) + # §8.6: a job under a contract, as it is and broken one way at a time. + def contract_body(**changes): + return _seal(seed, *_contract_job(**changes)) + + contract_ok = contract_body() + check("a contract job's reasoning and shadow", reasons_of(contract_ok) == []) + for name, raw_case, want in ( + ("a contract that does not read", contract_body(request__contract={"exactness": "nearly"}), ["contract_form"]), + ("a reasoning dropped", contract_body(result__planner=_DELETE), ["planner_form"]), + ("a digest not the routes'", contract_body(result__planner__stable__digest="00" * 32), ["planner_stable"]), + ("a choice said to be the host's own", contract_body(result__planner__stable__choice=True), ["planner_stable"]), + ("a kept the contract does not ask", contract_body(result__planner__kept={"deadline": {}}), ["planner_kept"]), + ("a class short of what is wanted", contract_body(result__accuracy__approximate=True), ["contract_class"]), + ("a shadow on another seed", contract_body(result__shadow__request__seed=4), ["shadow"]), + ("a shadow's omitted_shots of 0.0", contract_body(result__shadow__omitted_shots=0.0), []), + ("a distance not computed, every shot listed", contract_body( + result__shadow__distance={"computed": False, "why": "said so"}), ["shadow"]), + ("the least it can come to, on a free route", contract_body( + result__planner__routes__1__price__money={"free": True, "at_least": False}), ["planner_form"]), + ): + check(name, reasons_of(raw_case) == want) + unnamed_route = contract_body(result__planner__routes__0__outcome="met", result__planner__routes__0__rejected=_DELETE) + another_answered = contract_body(result__provider__name="other") + distance_said = contract_body(result__shadow__distance__numerator=1) + simulator_measured = provider_body(accuracy__class="measured") duplicated = body.replace(b'{"request"', b'{"why":"a","why":"b","request"') plant_cases = ( @@ -2054,6 +2137,9 @@ def self_test(args): ("measured-simulator", simulator_measured, ["provider_class"], []), ("whole-cap", provider_body(job__polls=two_to_53), [], ["provider_members"]), ("lax-small-order-r", identity_r_body, ["bad_signature"], []), + ("route-unchecked", unnamed_route, ["planner_route"], []), + ("choice-unchecked", another_answered, ["planner_choice", "request_provider"], ["request_provider"]), + ("distance-unchecked", distance_said, ["shadow"], []), ) for plant, raw, strict, lenient in plant_cases: check("plant %s: strict verdict" % plant, reasons_of(raw) == strict) diff --git a/wai/wai-quantum-cli/README.md b/wai/wai-quantum-cli/README.md index 4f1fada1e..9164f9cc9 100644 --- a/wai/wai-quantum-cli/README.md +++ b/wai/wai-quantum-cli/README.md @@ -109,6 +109,8 @@ wai-quantum run circuit.qasm --method statevector --fabric cpu --fabric cpu --sh wai-quantum run prog.qasm --fabric a-member-elsewhere # exits 1 ``` +**Under a contract.** `--exactness CLASS`, `--deadline SECONDS`, `--max-cost 0.50:USD`, `--max-joules J` and `--allow-providers` (or `--contract` with the JSON of [the provider protocol's section 8.6](../extensions/quantum-providers.md)) say what the answer must be. The planner then prices every route it can see: each method here, at its memory and the time its work predicts, and with `--allow-providers` each of your own providers, by its own estimate and what that leaves out (each is asked, and sent nothing). It rejects every route that cannot meet the contract, runs the cheapest of the rest, and seals its reasoning in the receipt. An unknown never passes: a time nobody states does not meet a deadline, nor an unknown cost a ceiling, nor an estimate that is only the least a job can come to. Nothing falls back, from exact to approximate or between a simulator and a device, and with no route left the job is refused with every route's reason (`J071`). A contract that names no class keeps the class `auto` would give, and a device's counts are reached only by asking for `measured` (or `any`). A provider's answer carries a classical method's counts beside it, with their distance, wherever a method here can reach them in the time the contract leaves, and the receipt says why where none can. A ceiling confirms nothing: a run that is not free still takes `--yes`. `wai-quantum plan` with the same options shows every route's price or reason and sends nothing; `wai-quantum verify --recheck` prices the routes again here and runs the shadow again; a run that kept less than its contract asked is still sealed, says so, and exits 4. + Each result names: - its method, and why that method was chosen; diff --git a/wai/wai-quantum-cli/README.zh-CN.md b/wai/wai-quantum-cli/README.zh-CN.md index 761d8811c..f32c931c7 100644 --- a/wai/wai-quantum-cli/README.zh-CN.md +++ b/wai/wai-quantum-cli/README.zh-CN.md @@ -112,6 +112,8 @@ wai-quantum run circuit.qasm --method statevector --fabric cpu --fabric cpu --sh wai-quantum run prog.qasm --fabric a-member-elsewhere # exits 1:别处的成员,被拒绝 ``` +**在契约之下。** `--exactness CLASS`、`--deadline SECONDS`、`--max-cost 0.50:USD`、`--max-joules J` 和 `--allow-providers`(或用 `--contract` 给出 [提供方协议第 8.6 节](../extensions/quantum-providers.md) 的 JSON)说明答案必须满足什么。规划器随后为它能看到的每条路径定价:本机的每个方法,按其内存和其工作量所预示的时间;加上 `--allow-providers` 时,还有你自己的每个提供方,按其自身的估算以及该估算未包含的内容(每个都会被询问,但不会发送任何东西)。它拒绝每条无法满足契约的路径,运行其余路径中最便宜的一条,并把它的推理封入收据。未知量从不算作满足:无人说明的时间不满足截止时间,未知的费用不满足上限,只是作业最低可能费用的估算也不满足。不会回退:既不会从精确退到近似,也不会在模拟器与设备之间互换;没有路径剩下时,作业被拒绝,并列出每条路径的原因(`J071`)。未指明类别的契约保留 `auto` 会给出的类别;只有请求 `measured`(或 `any`)才会用到设备的计数。提供方的答案旁边附有经典方法的计数及两者的距离,只要本机有方法能在契约留下的时间内得到它们;没有方法能做到时,收据会说明原因。上限不构成确认:不免费的运行仍需要 `--yes`。带相同选项的 `wai-quantum plan` 显示每条路径的价格或原因,不发送任何东西;`wai-quantum verify --recheck` 在本机重新为路径定价并重新运行影子运行;未能满足契约全部要求的运行仍会被封存,并如实说明,退出状态为 4。 + 每个结果都注明: - 所用的方法,以及选择该方法的原因; diff --git a/wai/wai-quantum-cli/docs/llms-full.txt b/wai/wai-quantum-cli/docs/llms-full.txt index cdeb21728..20a8608e1 100644 --- a/wai/wai-quantum-cli/docs/llms-full.txt +++ b/wai/wai-quantum-cli/docs/llms-full.txt @@ -43,7 +43,7 @@ Runs on this machine, signed with the user's key; nothing leaves the machine. ### `run_quantum_circuit`: Run a quantum program here -Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more. +Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `contract` (the class wanted, a deadline) and the planner prices every method here, runs the cheapest that meets it, seals its reasoning under `planner`, and refuses (J071) rather than fall back to less; this tool reaches no provider, and plan_routes and run_routed do. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more. Parameters: - `source` (object): The program in another format, in place of qasm: read to the job's qasm before the job is read (a module that does not read is refused with the reader's code, Q700 to Q721), the request keeping its source. @@ -64,10 +64,11 @@ Parameters: - `mitigate` (any): Mitigate the job's expectation values (or, for readout, its counts) under its own noise: zne (the whole program folded U(U†U)^k and extrapolated), pea (the noise learned as a sparse Pauli–Lindblad model and amplified), pec (the learned channels inverted and sampled), cdr (a line fitted over near-Clifford training circuits), vd (two copies), readout (the counts' flips inverted). Needs noise and observables (shots for readout), at most 8 qubits. The result's `mitigation` gives raw and mitigated values with standard errors, the ideal value (known because this is a simulation), the method's bias and variance assumptions and its cost. A method's name, or an object. - `pulse` (object): A pulse run's options (method "pulse"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0. - `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050). +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). ### `plan_quantum_circuit`: Plan a quantum program -The method a program would run on and why, the memory and work it would take, without running it. +The method a program would run on and why, the memory and work it would take, without running it. With a contract, every route's price or reason for rejection under planner, or the refusal (J071) when no route meets it. Parameters: - `source` (object): The program in another format, in place of qasm: read to the job's qasm before the job is read (a module that does not read is refused with the reader's code, Q700 to Q721), the request keeping its source. @@ -88,6 +89,7 @@ Parameters: - `mitigate` (any): Mitigate the job's expectation values (or, for readout, its counts) under its own noise: zne (the whole program folded U(U†U)^k and extrapolated), pea (the noise learned as a sparse Pauli–Lindblad model and amplified), pec (the learned channels inverted and sampled), cdr (a line fitted over near-Clifford training circuits), vd (two copies), readout (the counts' flips inverted). Needs noise and observables (shots for readout), at most 8 qubits. The result's `mitigation` gives raw and mitigated values with standard errors, the ideal value (known because this is a simulation), the method's bias and variance assumptions and its cost. A method's name, or an object. - `pulse` (object): A pulse run's options (method "pulse"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0. - `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050). +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). ### `lint_qasm`: Check an OpenQASM program @@ -224,10 +226,11 @@ Parameters: ### `verify_quantum_result`: Check a result's receipt -Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and every rule of its form holds (`reasons` names what does not), and which key signed it. +Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and every rule of its form holds (`reasons` names what does not), and which key signed it; for a job under a contract, every route's outcome and the choice recomputed from what it states, and with recheck its routes priced again and its shadow run again. Parameters: - `job` (object, required): The job: {"request": ..., "result": ...}, the result carrying its receipt. +- `recheck` (boolean): For a job under a contract: its routes priced again at the job's memory, held to the digest it sealed, and its shadow run again, held to its counts bit for bit. ### `discover_evaluate`: Judge a generator against a workbench specification @@ -440,6 +443,7 @@ Parameters: - `mitigate` (any): Mitigate the job's expectation values (or, for readout, its counts) under its own noise: zne (the whole program folded U(U†U)^k and extrapolated), pea (the noise learned as a sparse Pauli–Lindblad model and amplified), pec (the learned channels inverted and sampled), cdr (a line fitted over near-Clifford training circuits), vd (two copies), readout (the counts' flips inverted). Needs noise and observables (shots for readout), at most 8 qubits. The result's `mitigation` gives raw and mitigated values with standard errors, the ideal value (known because this is a simulation), the method's bias and variance assumptions and its cost. A method's name, or an object. - `pulse` (object): A pulse run's options (method "pulse"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0. - `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050). +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). ### `qec_code`: Show an error-correcting code and certify its distance @@ -585,6 +589,7 @@ Parameters: - `inputs` (object): A generator's inputs' values, as {"n": 5}. - `shots` (integer): Shots (default 1024). - `seed` (integer): A seed, for a provider that is a seeded simulator; a device ignores it. +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). ### `run_on_provider`: Run on a provider (can spend the person's money) @@ -596,8 +601,34 @@ Parameters: - `inputs` (object): A generator's inputs' values, as {"n": 5}. - `shots` (integer): Shots (default 1024). - `seed` (integer): A seed, for a provider that is a seeded simulator; a device ignores it. +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). - `confirm_cost` (boolean): true only when the person has agreed to this run's cost. A run that is not free is refused without it. +### `plan_routes`: Weigh a contract against every route + +Every route a job could take under its contract: the methods on this machine and each of the person's own providers, each with its price or why it was rejected, what a provider's estimate leaves out, and the route the planner would choose: the cheapest that meets the contract, or the refusal (J071) with every route's reason. Each provider is asked to describe its device and estimate the job. Nothing is submitted and nothing is spent. A device is chosen only when exactness asks for measured or any. + +Parameters: +- `qasm` (string, required): The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why. +- `inputs` (object): A generator's inputs' values, as {"n": 5}. +- `shots` (integer): Shots (default 1024). +- `seed` (integer): A seed. +- `observables` (array): Pauli observables: a provider's job answers counts, so a method here answers these. +- `contract` (any, required): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). + +### `run_routed`: Run a job on the route its contract chooses (can spend the person's money) + +Runs a job on the route plan_routes chooses: a method on this machine, or one of the person's own providers. THIS CAN SPEND THE PERSON'S MONEY OR QUOTA, when the contract allows a provider and one is chosen. A cost ceiling confirms nothing: a run that is not free is refused unless confirm_cost is true, set only after the person has seen the estimate and agreed to that run. The answer is a job in the service's form, its result carrying the planner's reasoning under planner; a provider's result also carries a classical method's counts and their distance under shadow, or why no classical method could reach them. If the job has not finished within this call the answer has status running and an id, and get_provider_job collects it later. Do not run it again to find out: that is a second job, and it can be a second bill. + +Parameters: +- `qasm` (string, required): The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why. +- `inputs` (object): A generator's inputs' values, as {"n": 5}. +- `shots` (integer): Shots (default 1024). +- `seed` (integer): A seed. +- `observables` (array): Pauli observables: a provider's job answers counts, so a method here answers these. +- `contract` (any, required): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). +- `confirm_cost` (boolean): true only when the person has agreed to this run's cost. A run that is not free is refused without it, whatever the contract's ceiling. + ### `get_provider_job`: Ask after a job on a provider Where a job on one of the person's providers stands, by the id run_on_provider gave: still running, or finished, with its counts then sealed in a receipt, or ended, with why. Asking spends nothing and can be repeated; a finished job gives the same answer every time. It asks once and does not wait, so ask again later rather than in a loop: a device's queue can take hours or days. @@ -642,6 +673,7 @@ Parameters: - `pulse` (object): A pulse run's options (method "pulse"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0. - `source` (object): The program in another format, in place of qasm: read to the job's qasm before the job is read (a module that does not read is refused with the reader's code, Q700 to Q721), the request keeping its source. - `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read; a parameter left without one is refused (J050). In a sweep, the parameters it fixes. +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). - `idempotency_key` (string): A key of your making that names this run, so that a call sent again is not a second job: the same key with the same arguments answers with the job it names, for as long as the job is kept, rather than running another; the same key with other arguments is refused (J034). Make it unguessable (a UUID). A job the service interrupted is run again under its key. Without a key, every call is a new job. ### `run_quantum_set`: Run a set of quantum programs, or one over a grid @@ -693,6 +725,7 @@ Parameters: - `programs` (array): The set's programs: each a program's text, or a job ({"qasm", …}) whose own fields win over the set's. - `sweep` (object): Each input of qasm and its values: every combination runs, the names in sorted order, the first varying slowest; an integer input's values are whole numbers. - `source` (object): The program in another format, in place of qasm: read to the job's qasm before the job is read (a module that does not read is refused with the reader's code, Q700 to Q721), the request keeping its source. +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). ### `get_quantum_job`: Read a quantum job @@ -825,7 +858,7 @@ Parameters: - `observables` (array): Pauli strings to take expectation values of, e.g. ["Z0", "Z0 Z1", "X2 Y3"]. Qubits count from 0. - `amplitudes` (array): Basis states to give amplitudes of: one character per qubit, qubit n-1 first, e.g. "0011". - `noise` (object): Optional noise, each a probability: depolarizing_1q, depolarizing_2q, amplitude_damping, dephasing (after each gate on its qubits), readout (each measured bit). -- `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read; a parameter left without one is refused (J050). In a sweep, the parameters it fixes. +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). - `seed` (integer): Sampling seed (default 1); the same job and seed give the same counts. - `options` (object): Advanced, per method: max_bond (mps), threshold and max_terms (pauli), fusion (statevector), trajectories. - `compile` (object): Compile the program first (as compile_qasm does) and run the compiled circuit: with basis clifford_t it runs bit-exact, and the result's `compiled` states its distance from the program. @@ -836,6 +869,7 @@ Parameters: - `mitigate` (any): Mitigate the job's expectation values (or, for readout, its counts) under its own noise: zne (the whole program folded U(U†U)^k and extrapolated), pea (the noise learned as a sparse Pauli–Lindblad model and amplified), pec (the learned channels inverted and sampled), cdr (a line fitted over near-Clifford training circuits), vd (two copies), readout (the counts' flips inverted). Needs noise and observables (shots for readout), at most 8 qubits. The result's `mitigation` gives raw and mitigated values with standard errors, the ideal value (known because this is a simulation), the method's bias and variance assumptions and its cost. A method's name, or an object. - `pulse` (object): A pulse run's options (method "pulse"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0. - `source` (object): The program in another format, in place of qasm: read to the job's qasm before the job is read (a module that does not read is refused with the reader's code, Q700 to Q721), the request keeping its source. +- `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read; a parameter left without one is refused (J050). In a sweep, the parameters it fixes. - `idempotency_key` (string): A key of your making that names this run, so that a call sent again is not a second job: the same key with the same arguments answers with the job it names, for as long as the job is kept, rather than running another; the same key with other arguments is refused (J034). Make it unguessable (a UUID). A job the service interrupted is run again under its key. Without a key, every call is a new job. ### `quantum_circuit_examples`: Ready-to-run quantum examples @@ -1836,6 +1870,37 @@ Options: them. A member certified bit-exact gives the CPU's answers; a placement this host cannot honour is refused (J013) + --exactness + The class the answer must be of: bit-exact, exact, single, bounded, estimate, heuristic; + measured (a processor's counts), simulated (a provider's simulator's), or any. Under a + contract (this, --max-cost, --deadline, --max-joules or --allow-providers) the planner + prices every route it can see, runs the cheapest that meets it, and seals its reasoning in + the receipt; with nothing to meet it, it refuses with each route's reason (J071), and + nothing falls back. Without a class the job keeps the class auto would give + + --max-cost + The most the run may cost, as 0.50:USD: a route with an unknown cost, or priced in another + currency, does not meet it. It confirms nothing: a run that is not free still takes --yes + + --deadline + When the run must be done by, in seconds: a route whose time is not known does not meet + it, and the receipt says whether it was kept (exit 4 when it was not) + + --max-joules + The most energy the run may take, in joules: a route whose energy is not known does not + meet it, and this command estimates none, so here every route is refused; the job service + estimates from what it has metered + + --allow-providers + Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods + here: each is asked to estimate the job, and nothing is sent unless one is chosen. A + device is chosen only when --exactness measured or any asks for its class. On the job + service, which reaches no provider, it changes nothing + + --contract + The contract itself, as JSON or a file of it: exactness, max_cost, deadline_seconds, + max_joules and providers; the options above are set over it + --json Print the job as the service returns it: request, plan, result and receipt @@ -1857,16 +1922,17 @@ Options: simulator --dry-run - With --provider: the plan (the exact compile to the device's gates and its check by - simulation) and the provider's estimate; nothing is submitted + With --provider or --allow-providers: the plan (the exact compile to the device's gates + and its check by simulation) and the provider's estimate, or every route's price or + reason; nothing is submitted --yes - With --provider: confirm a run that is not free, or whose cost is unknown; without it such - a run is refused (exit 3) + With --provider or --allow-providers: confirm a run that is not free, or whose cost is + unknown; without it such a run is refused (exit 3). A cost ceiling is no confirmation --no-wait - With --provider: send the job and answer with its handle, without waiting (`wai-quantum - providers collect`) + With --provider or --allow-providers: send the job and answer with its handle, without + waiting (`wai-quantum providers collect`) -h, --help Print help @@ -1990,6 +2056,37 @@ Options: them. A member certified bit-exact gives the CPU's answers; a placement this host cannot honour is refused (J013) + --exactness + The class the answer must be of: bit-exact, exact, single, bounded, estimate, heuristic; + measured (a processor's counts), simulated (a provider's simulator's), or any. Under a + contract (this, --max-cost, --deadline, --max-joules or --allow-providers) the planner + prices every route it can see, runs the cheapest that meets it, and seals its reasoning in + the receipt; with nothing to meet it, it refuses with each route's reason (J071), and + nothing falls back. Without a class the job keeps the class auto would give + + --max-cost + The most the run may cost, as 0.50:USD: a route with an unknown cost, or priced in another + currency, does not meet it. It confirms nothing: a run that is not free still takes --yes + + --deadline + When the run must be done by, in seconds: a route whose time is not known does not meet + it, and the receipt says whether it was kept (exit 4 when it was not) + + --max-joules + The most energy the run may take, in joules: a route whose energy is not known does not + meet it, and this command estimates none, so here every route is refused; the job service + estimates from what it has metered + + --allow-providers + Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods + here: each is asked to estimate the job, and nothing is sent unless one is chosen. A + device is chosen only when --exactness measured or any asks for its class. On the job + service, which reaches no provider, it changes nothing + + --contract + The contract itself, as JSON or a file of it: exactness, max_cost, deadline_seconds, + max_joules and providers; the options above are set over it + --json Print the plan as JSON @@ -3087,6 +3184,37 @@ Options: them. A member certified bit-exact gives the CPU's answers; a placement this host cannot honour is refused (J013) + --exactness + The class the answer must be of: bit-exact, exact, single, bounded, estimate, heuristic; + measured (a processor's counts), simulated (a provider's simulator's), or any. Under a + contract (this, --max-cost, --deadline, --max-joules or --allow-providers) the planner + prices every route it can see, runs the cheapest that meets it, and seals its reasoning in + the receipt; with nothing to meet it, it refuses with each route's reason (J071), and + nothing falls back. Without a class the job keeps the class auto would give + + --max-cost + The most the run may cost, as 0.50:USD: a route with an unknown cost, or priced in another + currency, does not meet it. It confirms nothing: a run that is not free still takes --yes + + --deadline + When the run must be done by, in seconds: a route whose time is not known does not meet + it, and the receipt says whether it was kept (exit 4 when it was not) + + --max-joules + The most energy the run may take, in joules: a route whose energy is not known does not + meet it, and this command estimates none, so here every route is refused; the job service + estimates from what it has metered + + --allow-providers + Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods + here: each is asked to estimate the job, and nothing is sent unless one is chosen. A + device is chosen only when --exactness measured or any asks for its class. On the job + service, which reaches no provider, it changes nothing + + --contract + The contract itself, as JSON or a file of it: exactness, max_cost, deadline_seconds, + max_joules and providers; the options above are set over it + --json Print the job as the service returns it: request, plan, result and receipt @@ -3591,6 +3719,10 @@ Options: One job a line, each judged as a job's receipt, one JSON verdict a line; the status is 1 when any is not valid + --recheck + For a job under a contract, also run again what can be: its routes priced again at the + job's memory, held to the digest it sealed, and its shadow, held to its counts bit for bit + -h, --help Print help diff --git a/wai/wai-quantum-cli/docs/local-mcp.json b/wai/wai-quantum-cli/docs/local-mcp.json index 77d0b1d5a..727f0a218 100644 --- a/wai/wai-quantum-cli/docs/local-mcp.json +++ b/wai/wai-quantum-cli/docs/local-mcp.json @@ -4,7 +4,7 @@ { "name": "run_quantum_circuit", "title": "Run a quantum program here", - "description": "Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more.", + "description": "Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `contract` (the class wanted, a deadline) and the planner prices every method here, runs the cheapest that meets it, seals its reasoning under `planner`, and refuses (J071) rather than fall back to less; this tool reaches no provider, and plan_routes and run_routed do. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more.", "inputSchema": { "type": "object", "anyOf": [ @@ -531,6 +531,77 @@ "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -1348,6 +1419,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -4113,6 +4255,839 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -5113,6 +6088,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -7876,6 +8922,839 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -8736,7 +10615,7 @@ { "name": "plan_quantum_circuit", "title": "Plan a quantum program", - "description": "The method a program would run on and why, the memory and work it would take, without running it.", + "description": "The method a program would run on and why, the memory and work it would take, without running it. With a contract, every route's price or reason for rejection under planner, or the refusal (J071) when no route meets it.", "inputSchema": { "type": "object", "anyOf": [ @@ -9263,17 +11142,88 @@ "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, "outputSchema": { "$id": "wai-quantum://schemas/plan_quantum_circuit/1", "type": "object", - "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it.", + "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it. A job with a contract carries the planner's reasoning.", "anyOf": [ { "title": "wai.quantum.plan/1", - "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it.", + "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it. A job with a contract carries the planner's reasoning.", "type": "object", "required": [ "method", @@ -9350,6 +11300,631 @@ } } }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, "verdict": { "title": "wai.quantum.verdict/1", "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", @@ -21365,7 +23940,7 @@ { "name": "verify_quantum_result", "title": "Check a result's receipt", - "description": "Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and every rule of its form holds (`reasons` names what does not), and which key signed it.", + "description": "Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and every rule of its form holds (`reasons` names what does not), and which key signed it; for a job under a contract, every route's outcome and the choice recomputed from what it states, and with recheck its routes priced again and its shadow run again.", "inputSchema": { "type": "object", "required": [ @@ -21375,6 +23950,10 @@ "job": { "type": "object", "description": "The job: {\"request\": ..., \"result\": ...}, the result carrying its receipt." + }, + "recheck": { + "type": "boolean", + "description": "For a job under a contract: its routes priced again at the job's memory, held to the digest it sealed, and its shadow run again, held to its counts bit for bit." } } }, @@ -21428,6 +24007,28 @@ "null" ], "description": "That key as a did:key." + }, + "planner": { + "type": "object", + "description": "For a job under a contract, what its reasoning says: the route chosen, the class wanted and given, whether the choice depends on the host, what was kept, and the shadow." + }, + "recheck": { + "type": "object", + "description": "With recheck: whether the routes priced again and the shadow run again are what the job sealed.", + "properties": { + "holds": { + "type": "boolean" + }, + "engine": { + "type": "object" + }, + "priced": { + "type": "object" + }, + "shadow": { + "type": "object" + } + } } } }, @@ -30676,6 +33277,77 @@ "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } }, "required": [ @@ -31496,6 +34168,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -34261,6 +37004,839 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -35261,6 +38837,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -38024,6 +41671,839 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -50428,6 +54908,77 @@ "type": "integer", "minimum": 0, "description": "A seed, for a provider that is a seeded simulator; a device ignores it." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -50475,6 +55026,631 @@ "confirm": { "type": "string", "description": "What the person reads before confirming a run that is not free." + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } } } }, @@ -50560,6 +55736,77 @@ "minimum": 0, "description": "A seed, for a provider that is a seeded simulator; a device ignores it." }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } + }, "confirm_cost": { "type": "boolean", "description": "true only when the person has agreed to this run's cost. A run that is not free is refused without it." @@ -51383,6 +56630,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -54148,6 +59466,839 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -55148,6 +61299,77 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -57911,6 +64133,12403 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + }, + "error": { + "type": "string" + }, + "code": { + "type": "string", + "description": "A failed item's refusal code (engine::refusal)." + }, + "path": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The item's leaf's sibling digests up to the root, in hex." + } + } + } + } + } + } + ] + }, + "error": { + "type": "string", + "description": "Why a job failed, or why it was interrupted." + }, + "interruptions": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "The job service: each time it stopped while the job ran, in milliseconds since 1970. A job that was running when the service stopped is queued again, once, to run from its stored request." + }, + "submitted_ms": { + "type": "integer", + "description": "The job service: when it was submitted, in milliseconds since 1970." + }, + "started_ms": { + "type": "integer" + }, + "finished_ms": { + "type": "integer" + }, + "peak_rss_bytes": { + "type": "integer", + "description": "The job service: the most memory the job's process held." + }, + "digests": { + "type": "object", + "description": "The job service: the BLAKE3 digests its store keeps the job's objects under (the request, each program, the result and the receipt).", + "properties": { + "algorithm": { + "const": "blake3" + }, + "request": { + "type": [ + "string", + "null" + ] + }, + "programs": { + "type": "array", + "items": { + "type": "string" + } + }, + "result": { + "type": "string" + }, + "receipt": { + "type": "string" + } + } + } + } + }, + { + "type": "object", + "description": "A refusal as data: the message, every code in it (the last is the code), its outcome and meaning as the code's table gives them. A host that refuses for its own reasons gives the error alone.", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + } + ] + } + }, + { + "name": "plan_routes", + "title": "Weigh a contract against every route", + "description": "Every route a job could take under its contract: the methods on this machine and each of the person's own providers, each with its price or why it was rejected, what a provider's estimate leaves out, and the route the planner would choose: the cheapest that meets the contract, or the refusal (J071) with every route's reason. Each provider is asked to describe its device and estimate the job. Nothing is submitted and nothing is spent. A device is chosen only when exactness asks for measured or any.", + "inputSchema": { + "type": "object", + "required": [ + "qasm", + "contract" + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why." + }, + "inputs": { + "type": "object", + "additionalProperties": { + "type": "integer" + }, + "description": "A generator's inputs' values, as {\"n\": 5}." + }, + "shots": { + "type": "integer", + "minimum": 1, + "description": "Shots (default 1024)." + }, + "seed": { + "type": "integer", + "minimum": 0, + "description": "A seed." + }, + "observables": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Pauli observables: a provider's job answers counts, so a method here answers these." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } + } + } + }, + "outputSchema": { + "$id": "wai-quantum://schemas/plan_routes/1", + "type": "object", + "description": "Every route a job could take under its contract, each with its price or why it was rejected, and the route chosen: nothing submitted, nothing spent.", + "anyOf": [ + { + "type": "object", + "description": "Every route a job could take under its contract, each with its price or why it was rejected, and the route chosen: nothing submitted, nothing spent.", + "required": [ + "dry_run", + "planner" + ], + "properties": { + "dry_run": { + "const": true + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "plan": { + "title": "wai.quantum.plan/1", + "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it. A job with a contract carries the planner's reasoning.", + "type": "object", + "required": [ + "method", + "why", + "memory_bytes", + "work", + "qubits" + ], + "properties": { + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0 + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "target": { + "type": "object", + "description": "A run on a device target: which target (its hash, as its receipt binds it), its calibration snapshot, where the program was placed and why, and the noise derived from the target.", + "required": [ + "name", + "hash" + ], + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "hash_is": { + "type": "string" + }, + "calibration": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "source": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "note": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "description": "The native gate set, the layout and routes chosen, the swaps, the expected success beside the fewest-swaps layout's, and the check of the compiled program." + }, + "noise": { + "type": "object", + "description": "The noise model derived from the target's calibration: its channels, durations and idling, and each qubit's readout." + } + } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + } + } + }, + "provider_plan": { + "type": "object", + "description": "The dry run of a job on a provider: nothing submitted, nothing spent.", + "required": [ + "dry_run", + "provider", + "plan", + "estimate", + "free", + "confirm" + ], + "properties": { + "dry_run": { + "const": true + }, + "provider": { + "type": "object" + }, + "calibration": { + "type": [ + "string", + "null" + ] + }, + "billing": { + "type": "object" + }, + "plan": { + "type": "object" + }, + "estimate": { + "type": "object" + }, + "free": { + "type": "boolean" + }, + "confirm": { + "type": "string", + "description": "What the person reads before confirming a run that is not free." + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + } + } + } + } + }, + { + "type": "object", + "description": "A refusal as data: the message, every code in it (the last is the code), its outcome and meaning as the code's table gives them. A host that refuses for its own reasons gives the error alone.", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + } + ] + } + }, + { + "name": "run_routed", + "title": "Run a job on the route its contract chooses (can spend the person's money)", + "description": "Runs a job on the route plan_routes chooses: a method on this machine, or one of the person's own providers. THIS CAN SPEND THE PERSON'S MONEY OR QUOTA, when the contract allows a provider and one is chosen. A cost ceiling confirms nothing: a run that is not free is refused unless confirm_cost is true, set only after the person has seen the estimate and agreed to that run. The answer is a job in the service's form, its result carrying the planner's reasoning under planner; a provider's result also carries a classical method's counts and their distance under shadow, or why no classical method could reach them. If the job has not finished within this call the answer has status running and an id, and get_provider_job collects it later. Do not run it again to find out: that is a second job, and it can be a second bill.", + "inputSchema": { + "type": "object", + "required": [ + "qasm", + "contract" + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why." + }, + "inputs": { + "type": "object", + "additionalProperties": { + "type": "integer" + }, + "description": "A generator's inputs' values, as {\"n\": 5}." + }, + "shots": { + "type": "integer", + "minimum": 1, + "description": "Shots (default 1024)." + }, + "seed": { + "type": "integer", + "minimum": 0, + "description": "A seed." + }, + "observables": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Pauli observables: a provider's job answers counts, so a method here answers these." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } + }, + "confirm_cost": { + "type": "boolean", + "description": "true only when the person has agreed to this run's cost. A run that is not free is refused without it, whatever the contract's ceiling." + } + } + }, + "outputSchema": { + "$id": "wai-quantum://schemas/run_routed/1", + "type": "object", + "description": "A job as a host returns it: its status, the method its plan chose and why, the request as submitted, and, once it is done, the result with its receipt: a job's result, or for a set (a request with programs or a sweep, its method set) the set's result. The command line's run --json, the local MCP server's run_quantum_circuit and a run on the person's own provider give a finished job; the job service also gives its id and times, and a job still queued or running, or failed with its error. A job's receipt verifies from this document alone: request and result.", + "anyOf": [ + { + "title": "wai.quantum.job/1", + "description": "A job as a host returns it: its status, the method its plan chose and why, the request as submitted, and, once it is done, the result with its receipt: a job's result, or for a set (a request with programs or a sweep, its method set) the set's result. The command line's run --json, the local MCP server's run_quantum_circuit and a run on the person's own provider give a finished job; the job service also gives its id and times, and a job still queued or running, or failed with its error. A job's receipt verifies from this document alone: request and result.", + "type": "object", + "required": [ + "status", + "request" + ], + "properties": { + "id": { + "type": "string", + "description": "The job service's id for the job." + }, + "status": { + "enum": [ + "queued", + "running", + "done", + "failed", + "cancelled", + "interrupted" + ], + "description": "interrupted: the job service stopped while the job ran, after it had run it again once from its request, so it has no result; error says so." + }, + "method": { + "type": "string", + "description": "The method the plan chose; set for a set." + }, + "why": { + "type": "string", + "description": "Why the plan chose the method." + }, + "estimate": { + "type": "object", + "description": "What the plan admitted the job with.", + "required": [ + "memory_bytes", + "work" + ], + "properties": { + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0, + "description": "In the method's own unit." + } + } + }, + "request": { + "title": "wai.quantum.job-request/1", + "description": "A job as a client submits it: a program and what is asked of it, or a set: many programs (programs), or one over a grid of its inputs (sweep), run as one job. The command line, both MCP servers, the job service, the desktop app and the Studio read it alike, and a receipt seals it as it was given. A member the engine does not read is ignored, and sealed with the rest.", + "type": "object", + "anyOf": [ + { + "required": [ + "qasm" + ] + }, + { + "required": [ + "programs" + ] + }, + { + "required": [ + "source" + ] + } + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, in OpenQASM 3 or the OpenQASM 2 forms in common use." + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "description": "The program in another format, in place of qasm (engine::formats::expand): read to the job's qasm before the job is read, the request keeping its source.", + "properties": { + "format": { + "enum": [ + "qasm", + "qir", + "jeff" + ] + }, + "program": { + "type": "string", + "description": "The program's text (OpenQASM, QIR)." + }, + "program_base64": { + "type": "string", + "description": "The program's bytes as base64 (jeff)." + } + } + }, + "shots": { + "type": "integer", + "minimum": 0, + "maximum": 1000000, + "description": "Measurement shots; 1024 when no observables or amplitudes are asked for, otherwise 0." + }, + "seed": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991, + "description": "The sampling seed (1 when not given): the same job and seed give the same counts." + }, + "method": { + "type": "string", + "description": "auto (the default: the strongest method the program admits), or a method by its name as the methods list names it; pulse runs a pulse program (OpenPulse calibrations) under the pulse options." + }, + "observables": { + "type": "array", + "maxItems": 256, + "description": "Pauli observables to take the expectation values of.", + "items": { + "anyOf": [ + { + "type": "string", + "description": "A Pauli string, as \"Z0 Z1\"; qubits count from 0." + }, + { + "type": "object", + "required": [ + "pauli" + ], + "properties": { + "pauli": { + "type": "string", + "description": "A Pauli string, as \"X3\"." + }, + "coeff": { + "type": "number", + "description": "Its coefficient (1 when not given)." + } + } + } + ] + } + }, + "amplitudes": { + "type": "array", + "maxItems": 64, + "description": "Basis states whose amplitudes to return: one 0 or 1 per qubit, qubit n-1 first.", + "items": { + "type": "string" + } + }, + "noise": { + "type": "object", + "description": "A noise model, each channel a probability. A channel not listed here is refused.", + "additionalProperties": false, + "properties": { + "depolarizing_1q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "depolarizing_2q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "amplitude_damping": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "dephasing": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "readout": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + } + }, + "options": { + "type": "object", + "description": "Options of the method that runs the job, as the methods list names them (max_bond, cutoff, fusion, trajectories, threshold, max_weight, ladder, max_terms, path_restarts), and memory_gb." + }, + "compile": { + "type": "object", + "description": "What a compile is asked for, each optional: the most the output may differ from the program (epsilon, in the operator norm up to a global phase), the level (0 lowers and approximates; 1 also rewrites and folds phases; 2 also resynthesises), the basis, the gate set it writes the program in (clifford_t: every rotation off the multiples of π/4 a Clifford+T word; standard: nothing approximated), whether to give the circuit after each pass (stages), and the twirl and dd passes, last (twirl, with its seed; dd, with its sequence).", + "properties": { + "epsilon": { + "type": "number", + "exclusiveMinimum": 0 + }, + "level": { + "type": "integer", + "minimum": 0, + "maximum": 2 + }, + "basis": { + "enum": [ + "clifford_t", + "standard" + ] + }, + "stages": { + "type": "boolean" + }, + "twirl": { + "description": "Twirl each two-qubit Clifford gate with Paulis drawn from a seeded stream: true (seed 1), or {\"seed\": N}. One seed is one instance, checked to be the same circuit.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "required": [ + "seed" + ], + "properties": { + "seed": { + "type": "integer", + "minimum": 0 + } + } + } + ] + }, + "dd": { + "description": "Dynamical decoupling in each window where a qubit idles long enough: xx or xy4 (or {\"sequence\": …}), checked to change nothing without noise.", + "anyOf": [ + { + "enum": [ + "xx", + "xy4" + ] + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "sequence": { + "enum": [ + "xx", + "xy4" + ] + } + } + } + ] + } + } + }, + "intent": { + "description": "What the program must do, checked with the run: one intent or a list. The result's verdict says how far it was checked.", + "anyOf": [ + { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + } + ] + }, + "verdict": { + "type": "boolean", + "description": "true: the result carries a verdict even with no intent." + }, + "target": { + "description": "A device target: a built-in target's name, or a target document. The program is compiled to it, placed and simulated under its noise; noise may not be given beside it.", + "anyOf": [ + { + "type": "string" + }, + { + "title": "wai.quantum.target/1", + "description": "A device target: its qubits, the pairs it couples, its native gates with their errors and durations, and the calibration snapshot they come from. A value not known is left out, never written as zero. Every field but format, name, source, qubits, gates and coupling is optional, and a field the format does not name is refused, so a misspelt one never reads as absent. Its canonical text is its RFC 8785 form, and the BLAKE3 of that text, the target's hash, names the snapshot in a receipt.", + "type": "object", + "required": [ + "format", + "name", + "source", + "qubits", + "gates", + "coupling" + ], + "additionalProperties": false, + "properties": { + "format": { + "const": "wai.quantum.target/1" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "additionalProperties": false, + "properties": { + "format": { + "type": "string", + "description": "The format the target was read from (wai-quantum targets import --help lists them)." + }, + "note": { + "type": "string", + "maxLength": 400 + } + } + }, + "calibration": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "maxLength": 400, + "description": "The calibration snapshot's id, as the source names it, or a content id of the snapshot read." + }, + "timestamp": { + "type": "string", + "maxLength": 400, + "description": "When the snapshot was taken, as the source writes it." + } + } + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2048, + "description": "Every qubit, in order.", + "items": { + "type": "object", + "required": [ + "qubit" + ], + "additionalProperties": false, + "properties": { + "qubit": { + "type": "integer", + "minimum": 0, + "description": "Its index: its place in the list." + }, + "label": { + "type": "string", + "description": "The source's own name for it, when that is not its index." + }, + "t1_us": { + "type": "number", + "minimum": 0, + "description": "T1, microseconds." + }, + "t2_us": { + "type": "number", + "minimum": 0, + "description": "T2 (the echo or Ramsey time the source reports), microseconds." + }, + "frequency_ghz": { + "type": "number", + "minimum": 0, + "description": "Its frequency, gigahertz." + }, + "readout": { + "type": "object", + "required": [ + "p01", + "p10" + ], + "additionalProperties": false, + "properties": { + "p01": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 1 | holds 0)." + }, + "p10": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 0 | holds 1)." + } + } + }, + "measure_ns": { + "type": "number", + "minimum": 0, + "description": "The measurement's duration, nanoseconds." + } + } + } + }, + "gates": { + "type": "array", + "maxItems": 262144, + "description": "Each native gate where the device runs it, sorted by gate then qubits.", + "items": { + "type": "object", + "required": [ + "gate", + "qubits" + ], + "additionalProperties": false, + "properties": { + "gate": { + "type": "string", + "pattern": "^[a-z0-9_]{1,40}$" + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + }, + "error": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "The average gate infidelity." + }, + "duration_ns": { + "type": "number", + "minimum": 0, + "description": "Nanoseconds." + } + } + } + }, + "coupling": { + "type": "array", + "description": "The pairs a two-qubit gate may act on, each once, the lower qubit first, sorted.", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + ] + }, + "fabric": { + "description": "Where the statevector method's state runs: auto (the default: on a member only where the committed measurements show it faster than this host's CPU for the job's size and fusion width, otherwise on the CPU), cpu, accelerator (the first accelerator member certified bit-exact here that holds the state, falling back to the next if it fails during the run), a member's id or key (wai-quantum fabric lists them), or a list of members, a power of two of them, the state split by its top qubits into one partition on each (cpu is a member, and a member may be named more than once). A member certified bit-exact gives the CPU's bits. A placement this host cannot honour is refused (J013), never made elsewhere.", + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "array", + "minItems": 2, + "maxItems": 64, + "items": { + "type": "string", + "minLength": 1 + } + } + ] + }, + "repair": { + "description": "Repair the program first on its flagged lines: true, or the choices.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "max_iterations": { + "type": "integer", + "minimum": 1 + }, + "dyadic_bits": { + "type": "integer", + "minimum": 1, + "maximum": 32 + }, + "sizes": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + } + } + } + ] + }, + "history": { + "type": "object", + "description": "The program's history's account of the version the job runs: its digest, and the gates and lines in each hand. The receipt binds it; a history recomputes and checks it." + }, + "provider": { + "type": "string", + "description": "The person's own provider to run on, by the name their registry gives it. Only a host that holds their credentials runs such a job; every other host refuses it." + }, + "programs": { + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "type": "string", + "description": "A program's text." + }, + { + "type": "object", + "required": [ + "qasm" + ], + "description": "A job of its own, read as a job request is (no programs or sweep in it); each item of the set's result holds its request in full." + } + ] + }, + "description": "A set (engine::sets): the programs to run as one job, each a program's text or a job of its own; the request's other fields apply to every item that does not set them itself." + }, + "sweep": { + "type": "object", + "additionalProperties": { + "type": "array", + "minItems": 1, + "items": { + "type": "number" + } + }, + "description": "A set over the request's own qasm: values for each of the program's inputs (integer, float or angle), every combination run, the names in sorted order and the first varying slowest." + }, + "params": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "A value for each of the program's parameters (`input float theta;`, `input angle phi;`), bound exactly before the program is read: it runs as if each were written as a `const` at that double. A parameter left without a value is refused (Q114, J050). In a sweep, the parameters it fixes, each bound at every point." + }, + "dry_run": { + "type": "boolean", + "description": "With true: what the host would do with the job or set, running nothing." + }, + "mitigate": { + "description": "Mitigate the job's expectation values (or, for readout, its counts) under its noise (engine::mitigate): zne, pea, pec, cdr, vd or readout, or {\"method\", …} with its options. The result's mitigation gives each value raw and mitigated.", + "anyOf": [ + { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + { + "type": "object", + "required": [ + "method" + ] + } + ] + }, + "pulse": { + "type": "object", + "description": "A pulse run's options (method \"pulse\"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0.", + "additionalProperties": false, + "properties": { + "dt_ns": { + "type": "number", + "exclusiveMinimum": 0, + "maximum": 1000, + "description": "The sample period, ns (default 0.5)." + }, + "levels": { + "type": "integer", + "enum": [ + 2, + 3 + ], + "description": "Levels kept per qubit (default 2; 3 shows leakage)." + }, + "tolerance": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1, + "description": "The most the stated error may be (default 1e-6): a run whose bound and rounding estimate pass it is refused, naming the steps that would meet it." + }, + "substeps": { + "type": "integer", + "minimum": 1, + "maximum": 4096, + "description": "Steps per sample (default: chosen so each step times the generator's norm is at most 0.5)." + }, + "qubits": { + "type": "object", + "description": "Each qubit's parameters by its index, over the target's and the defaults.", + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "frequency_ghz": { + "type": "number", + "description": "Its frequency, GHz." + }, + "rabi_mhz": { + "type": "number", + "description": "Its Rabi frequency at full amplitude, MHz." + }, + "anharmonicity_mhz": { + "type": "number", + "description": "Its anharmonicity, MHz." + }, + "t1_us": { + "type": "number", + "description": "Its relaxation time, µs." + }, + "t2_us": { + "type": "number", + "description": "Its coherence time, µs (at most 2·T1)." + } + } + } + }, + "couplings": { + "type": "array", + "description": "Static ZZ couplings.", + "items": { + "type": "object", + "required": [ + "qubits", + "zz_khz" + ], + "additionalProperties": false, + "properties": { + "qubits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + }, + "minItems": 2, + "maxItems": 2 + }, + "zz_khz": { + "type": "number", + "description": "The coupling's rate, kHz." + } + } + } + }, + "ports": { + "type": "object", + "description": "Ports by name: what each is for and the qubit it reaches.", + "additionalProperties": { + "type": "object", + "required": [ + "kind", + "qubit" + ], + "additionalProperties": false, + "properties": { + "kind": { + "enum": [ + "drive", + "measure", + "acquire" + ] + }, + "qubit": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } + } + } + }, + "result": { + "anyOf": [ + { + "title": "wai.quantum.job-result/1", + "description": "A job's result as the engine gives it, on every host: what was asked of the program, computed by the method its plan chose, with that method's accuracy class. The receipt seals the result without its receipt member, beside the request. A result names the engine that made it and this schema (engine and schema); results made before results carried them have neither and follow this schema all the same.", + "type": "object", + "required": [ + "method", + "qubits", + "gates", + "accuracy" + ], + "properties": { + "engine": { + "type": "object", + "description": "The engine that made the result: the wai-quantum crate's name and version.", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "const": "wai-quantum" + }, + "version": { + "type": "string", + "description": "Its semantic version, as MAJOR.MINOR.PATCH." + } + } + }, + "schema": { + "const": "wai.quantum.job-result/1", + "description": "The schema the result follows." + }, + "components": { + "type": "array", + "description": "The identity of every component that made the result, when a registered one took part (engine::registry): its program's format, the passes its compile ran, the noise channels it names, its method; each registered one marked so. Sealed by the receipt with the rest.", + "items": { + "type": "object", + "description": "One component that made the result (engine::registry): its kind, name and version, the BLAKE3 digest of its descriptor, and whether it is built in. A result carries these only when a registered component took part; one made by built-ins alone names them as it always has (its method, its compile's passes, its noise's channels and the engine's version), the digests of that version listed by the components list.", + "required": [ + "kind", + "name", + "version", + "digest", + "origin" + ], + "properties": { + "kind": { + "enum": [ + "method", + "pass", + "channel", + "front_end" + ] + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "digest": { + "type": "string", + "pattern": "^[0-9a-f]{64}$", + "description": "BLAKE3 of the component's descriptor in its canonical JSON (engine::registry::digest_of)." + }, + "origin": { + "enum": [ + "built-in", + "registered" + ], + "description": "built-in: the engine's own; registered: a host's own, added in its process, not part of the engine." + }, + "certified": { + "const": false, + "description": "Beside a registered component: the engine does not certify it." + } + } + } + }, + "method": { + "type": "string", + "description": "The method that ran the job (provider for a run on the person's own provider)." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": "integer", + "minimum": 0 + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "state_hash": { + "type": "string", + "description": "The bit-exact method's statevector hash (BLAKE3, hex): the same on every machine." + }, + "counts": { + "type": "object", + "description": "Outcomes and their counts, keyed by the program's classical bits, the highest bit first. At most 65536 outcomes are listed; omitted_shots holds the rest.", + "additionalProperties": { + "type": "integer", + "minimum": 0 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "outcome_dimension": { + "type": "integer", + "minimum": 0, + "description": "The stabilizer method: the dimension of the measured outcomes' affine space." + }, + "shots": { + "type": "integer", + "minimum": 0, + "description": "The shots, where the method names them in the result (trajectories, provider)." + }, + "expectations": { + "type": "array", + "items": { + "type": "object", + "required": [ + "observable", + "coeff", + "value" + ], + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "value": { + "type": "number", + "description": "The coefficient times the expectation value." + }, + "stderr": { + "type": "number", + "description": "The standard error, for an estimate." + }, + "bound": { + "type": "number", + "description": "A bound on |exact − value|: rigorous for the bounded class; with confidence beside it, holding with that probability." + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + }, + "max_terms": { + "type": "integer" + }, + "ladder": { + "type": "array", + "description": "The value at thresholds a decade apart, the asked one last.", + "items": { + "type": "object", + "required": [ + "threshold", + "value", + "bound" + ], + "properties": { + "threshold": { + "type": "number" + }, + "value": { + "type": "number" + }, + "bound": { + "type": "number" + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + } + } + } + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds, for a bound that holds with a stated probability (stabilizer_rank's sampled mode)." + } + } + } + }, + "amplitudes": { + "type": "array", + "items": { + "type": "object", + "required": [ + "bits", + "re", + "im" + ], + "properties": { + "bits": { + "type": "string", + "description": "One 0 or 1 per qubit, qubit n-1 first." + }, + "re": { + "type": "number" + }, + "im": { + "type": "number" + }, + "bound": { + "type": "number", + "minimum": 0, + "description": "A bound on |exact − value| of the amplitude, holding with the probability confidence states (stabilizer_rank's sampled mode)." + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds." + } + } + } + }, + "global_phase": { + "type": "string", + "description": "Why the amplitudes' global phase is not fixed, when it is not." + }, + "warning": { + "type": "string" + }, + "contraction_flops": { + "type": "number", + "description": "The tensor network's contraction cost." + }, + "dynamic": { + "type": "object", + "description": "A program that measures in the middle, resets or branches on a measured bit: how it ran.", + "properties": { + "measurements_and_resets": { + "type": "integer", + "minimum": 0 + }, + "branches_run": { + "type": "integer", + "minimum": 0 + }, + "states_at_once": { + "type": "integer", + "minimum": 0 + }, + "branches_weighed": { + "type": "integer", + "minimum": 0 + } + } + }, + "outputs": { + "type": "array", + "description": "The program's output declarations: each its name and type, and its value, or the places of its bits in each outcome.", + "items": { + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "bits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + } + }, + "value": { + "description": "A number, a boolean, a bit string, a duration's text, {\"re\", \"im\"}, or an array of them." + } + } + } + }, + "timing": { + "type": "object", + "description": "A program that states durations (delay, box, stretch) the method does not apply: said so, with the reader's code.", + "required": [ + "applied", + "why" + ], + "properties": { + "applied": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "diagnostics": { + "type": "array", + "description": "The reader's warnings and notes on the program, each with its code.", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "compiled": { + "description": "How the program was compiled before it ran: on the person's own provider, to the device's gates; or, asked with compile, to a basis within a budget. Either way, basis is the gate set it was compiled to.", + "anyOf": [ + { + "type": "object", + "description": "A provider job: the program sent, compiled exactly to the device's own gates: its basis (the device's gate set), its OpenQASM 3 text (qasm3) and that text's BLAKE3 (program), its counts of gates and swaps, its layouts, and the check it passed before it was sent. Results sealed before qasm3 carry the hash alone.", + "required": [ + "basis", + "program" + ], + "properties": { + "basis": { + "type": "string" + }, + "program": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "qasm3": { + "type": "string", + "description": "The program sent, as OpenQASM 3, $i being index i of the coupling map the provider described; program is the BLAKE3 of its UTF-8 bytes." + }, + "qubit_names": { + "type": "object", + "additionalProperties": { + "type": "string", + "minLength": 1 + }, + "description": "The device's own name for each index the program uses, as it was when the job was sent, where a client sends it under those names." + }, + "native_gates": { + "type": "integer" + }, + "two_qubit_gates": { + "type": "integer" + }, + "swaps": { + "type": "integer" + }, + "layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "final_layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "checked": { + "type": "string" + }, + "placement": { + "type": "object", + "description": "Where the program was placed on the device's qubits, and why." + } + } + }, + { + "type": "object", + "description": "A job asked to compile its program first: what ran is the compiled circuit, within distance of the program in the operator norm up to a global phase.", + "required": [ + "basis", + "verdict" + ], + "properties": { + "basis": { + "enum": [ + "clifford_t", + "standard" + ], + "description": "The gate set the program was compiled to." + }, + "level": { + "type": "integer", + "minimum": 0 + }, + "epsilon": { + "type": "number", + "description": "The budget asked for." + }, + "distance": { + "type": [ + "number", + "null" + ], + "description": "The bound the passes' distances add to." + }, + "verdict": { + "type": "string" + }, + "source": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "output": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ], + "description": "The BLAKE3 of the compile certificate's RFC 8785 text, in hex." + }, + "note": { + "type": "string" + } + } + } + ] + }, + "verdict": { + "title": "wai.quantum.verdict/1", + "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", + "type": "object", + "required": [ + "schema", + "level", + "rank", + "holds", + "statement", + "parsed", + "executed", + "intent", + "critique", + "repairs" + ], + "properties": { + "schema": { + "const": "wai.quantum.verdict/1" + }, + "level": { + "enum": [ + "refused", + "parsed", + "executed", + "evidence", + "proof" + ] + }, + "rank": { + "type": "integer", + "minimum": 0, + "maximum": 4, + "description": "The level's place on the ladder, from 0 (refused) to 4 (proof)." + }, + "holds": { + "type": [ + "boolean", + "null" + ] + }, + "statement": { + "type": "string", + "description": "The level in one plain line." + }, + "parsed": { + "type": "object", + "description": "Whether the reader took the program, and its warnings and notes with their codes, or its refusal.", + "required": [ + "ok" + ], + "properties": { + "ok": { + "type": "boolean" + }, + "diagnostics": { + "type": "array", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + }, + "text": { + "type": "string", + "description": "The refusal as the reader wrote it, with its line and code." + } + } + }, + "executed": { + "type": [ + "object", + "null" + ], + "description": "The method that ran and its accuracy class, and the distance a compile put between the program and what ran.", + "properties": { + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "compiled_distance": { + "type": [ + "number", + "null" + ] + } + } + }, + "intent": { + "type": "array", + "items": { + "type": "object", + "description": "One intent's check: what it asked, whether it held, how strong the check was and how it was made.", + "required": [ + "kind", + "outcome", + "strength", + "how" + ], + "properties": { + "kind": { + "enum": [ + "distribution", + "equivalent", + "prepares", + "sampled", + "compiled" + ] + }, + "outcome": { + "enum": [ + "holds", + "fails", + "unchecked" + ] + }, + "strength": { + "enum": [ + "proof", + "evidence", + "none" + ] + }, + "how": { + "type": "string" + }, + "why": { + "type": "string" + }, + "distance": { + "type": "number" + }, + "tolerance": { + "type": "number" + }, + "outcomes": { + "type": "integer", + "description": "The outcomes the distribution holds, or the samples' distinct outcomes." + }, + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The program's distribution, when its outcomes are few enough to list." + }, + "largest_gaps": { + "type": "array", + "items": { + "type": "object", + "properties": { + "outcome": { + "type": "string" + }, + "program": { + "type": "number" + }, + "intent": { + "type": "number" + } + } + } + }, + "global_phase": { + "type": [ + "number", + "null" + ] + }, + "method": { + "type": "string", + "description": "A sampled intent: the method the samples were run by." + }, + "seed": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "alpha": { + "type": "number" + }, + "fit": { + "type": "object", + "description": "A sampled intent: the test, its statistic, degrees of freedom and p-value, the level, and whether it rejected.", + "properties": { + "test": { + "type": "string" + }, + "statistic": { + "type": "number" + }, + "dof": { + "type": "integer" + }, + "p_value": { + "type": "number" + }, + "alpha": { + "type": "number" + }, + "shots": { + "type": "integer" + }, + "rejected": { + "type": "boolean" + }, + "smallest_expected": { + "type": [ + "number", + "null" + ] + }, + "impossible": { + "type": [ + "integer", + "array", + "boolean" + ] + }, + "note": { + "type": "string" + } + } + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "name": { + "type": "string" + }, + "note": { + "type": "string" + } + } + } + }, + "critique": { + "type": "array", + "description": "The program's smells, each with its lines.", + "items": { + "type": "object" + } + }, + "repairs": { + "type": "array", + "description": "Each edit a repair made, with the code it answered and the lines it changed.", + "items": { + "type": "object" + } + }, + "refusal": { + "type": "object", + "description": "For a refused job: its message and its codes.", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + }, + "sealed": { + "type": "boolean" + } + } + }, + "target": { + "type": "object", + "description": "A run on a device target: which target (its hash, as its receipt binds it), its calibration snapshot, where the program was placed and why, and the noise derived from the target.", + "required": [ + "name", + "hash" + ], + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "hash_is": { + "type": "string" + }, + "calibration": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "source": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "note": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "description": "The native gate set, the layout and routes chosen, the swaps, the expected success beside the fewest-swaps layout's, and the check of the compiled program." + }, + "noise": { + "type": "object", + "description": "The noise model derived from the target's calibration: its channels, durations and idling, and each qubit's readout." + } + } + }, + "fabric": { + "type": "object", + "description": "Where the state vector, or the pauli method's sum of terms, ran: the kernel, the placement the job asked for, the member that ran it (or each partition's), each with its certificate, and the energy. Present when the job asked for a placement, or when auto placed the state on a member by measurement (`auto`); a job auto leaves on the CPU names nothing; the receipt seals it with the rest of the result. Every member placed is certified bit-exact, so the answers are the CPU's, byte for byte.", + "required": [ + "kernel", + "asked", + "parity", + "energy" + ], + "properties": { + "kernel": { + "type": "string" + }, + "asked": { + "description": "The placement the job asked for, as it gave it.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "partitions": { + "type": "array", + "description": "Each partition's member, by the value of the state's top qubits: partition i holds the amplitudes whose top bits read i.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "partition_qubits": { + "type": "integer", + "minimum": 0 + }, + "local_qubits": { + "type": "integer", + "minimum": 0 + }, + "segments": { + "type": "integer", + "minimum": 0, + "description": "Runs of gates the partitions took in turn, between exchanges." + }, + "exchanges": { + "type": "integer", + "minimum": 0, + "description": "Partition qubits exchanged with local ones through the host's copy of the state." + }, + "fell_back_from": { + "type": "array", + "description": "An accelerator request whose member failed during the run: each member that failed, in turn, with how; the member named above ran the job.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "auto": { + "type": "object", + "description": "Why auto placed the state where it ran: the rule (a member is placed only where the committed measurements show it faster than this host's CPU for the job's size and fusion width) and the measured row it rests on, with the host, the day and the load it was measured under. Present only when auto placed a state on a member.", + "required": [ + "rule", + "host", + "fusion", + "from_qubits", + "to_qubits" + ], + "properties": { + "rule": { + "type": "string" + }, + "host": { + "type": "string", + "description": "The host's processor as the measurements name it (cpu--)." + }, + "measured": { + "type": "string", + "description": "The day the host was measured (UTC)." + }, + "about": { + "type": "string" + }, + "load": { + "type": "string" + }, + "discovery_ms": { + "type": "number", + "description": "What discovering and certifying the host's members took, once per process, as measured." + }, + "fusion": { + "type": "integer", + "minimum": 1 + }, + "from_qubits": { + "type": "integer", + "minimum": 0 + }, + "to_qubits": { + "type": "integer", + "minimum": 0 + }, + "min_launches": { + "type": "integer", + "minimum": 0 + }, + "basis": { + "type": "object", + "description": "The measured row the job is judged by: the largest measured size at or below its own, the launches of its plan, the runs of each, and the spread of the CPU's and the member's times in milliseconds.", + "required": [ + "qubits", + "launches", + "runs", + "cpu_ms", + "member_ms" + ], + "properties": { + "qubits": { + "type": "integer", + "minimum": 0 + }, + "launches": { + "type": "integer", + "minimum": 0 + }, + "runs": { + "type": "integer", + "minimum": 0 + }, + "cpu_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + }, + "member_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + } + } + } + } + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "why": { + "type": "string" + } + } + }, + "repaired": { + "type": "object", + "description": "A job asked to repair its program first: the program that ran, each repair, and what needs a person.", + "properties": { + "qasm": { + "type": "string" + }, + "repairs": { + "type": "array", + "items": { + "type": "object", + "required": [ + "code", + "by", + "edits" + ], + "properties": { + "code": { + "type": "string" + }, + "rule": { + "type": "string" + }, + "by": { + "enum": [ + "engine", + "proposal" + ] + }, + "flagged": { + "type": "array", + "items": { + "type": "integer" + } + }, + "edits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "line": { + "type": "integer" + }, + "before": { + "type": [ + "string", + "null" + ] + }, + "after": { + "type": [ + "string", + "null" + ] + } + } + } + } + } + } + }, + "needs_person": { + "type": "array", + "items": { + "type": "object" + } + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0, + "description": "Wall time of the run, where the host has a clock (not in a browser tab)." + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "receipt": { + "anyOf": [ + { + "title": "wai.quantum.receipt/2", + "description": "A result's receipt: an Ed25519 signature, by the key it names, over digest = BLAKE3(\"wai:quantum-service-receipt\\x02\" ‖ len ‖ request ‖ len ‖ result), each of request and result in its RFC 8785 canonical text (the result without its receipt member), each length 8 bytes big-endian. Whatever members the request and the result hold are sealed, the result's engine and schema among them. The first receipts (no canon member, $defs/first) sealed their writer's compact text under the domain ending \\x01; they still verify. wai/extensions/quantum-providers.md section 8.2 states the seal in full, and section 8.4 what a verifier checks.", + "type": "object", + "required": [ + "alg", + "canon", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "canon": { + "const": "rfc8785", + "description": "The canonical form the digest is taken over." + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The signing key, 32 bytes in lower-case hex." + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The digest signed, 32 bytes in lower-case hex." + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$", + "description": "The signature, 64 bytes in lower-case hex." + } + } + }, + { + "description": "The first form, before canon: the digest is over the compact text its writer wrote of each, members in the document's order (section 8.2 of wai/extensions/quantum-providers.md), under the domain ending \\x01. Never written now; still verified.", + "type": "object", + "required": [ + "alg", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$" + } + } + } + ] + }, + "provider": { + "type": "object", + "description": "A provider job: the provider's name, kind and protocol, the device, its provenance, and the hash of its description." + }, + "counts_source": { + "enum": [ + "shots", + "vendor_counts", + "probabilities" + ], + "description": "A provider job: where its counts come from (wai/extensions/quantum-providers.md section 8.3): tallied from one record a shot (shots), the provider's own counts (vendor_counts), or rebuilt from the probabilities it returned by largest remainders, derived and not shot records (probabilities). Results sealed before it carry neither it nor execution." + }, + "execution": { + "type": "object", + "description": "A provider job: how the device was asked to run the program (section 8.3): who states it (stated_by: client, provider or nobody); what the client sent (sent: the request's members and the settings among them); each of mitigation, twirling, decoupling, remapping and optimisation (off, on, default when the request sets nothing for it, none when the device has no such step, unknown when nobody states it); whether the gates were to run as written (verbatim); and a note.", + "required": [ + "stated_by", + "mitigation", + "twirling", + "decoupling", + "remapping", + "optimisation", + "verbatim" + ], + "properties": { + "stated_by": { + "enum": [ + "client", + "provider", + "nobody" + ] + }, + "sent": { + "type": "object", + "required": [ + "fields", + "settings" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "settings": { + "type": "object" + } + }, + "additionalProperties": false + }, + "mitigation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "twirling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "decoupling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "remapping": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "optimisation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "verbatim": { + "type": [ + "boolean", + "null" + ] + }, + "note": { + "type": "string" + } + }, + "additionalProperties": false + }, + "calibration": { + "type": [ + "string", + "null" + ], + "description": "A provider job: the calibration snapshot it ran under." + }, + "job": { + "type": "object", + "description": "A provider job: the provider's job id and its status checks." + }, + "ideal": { + "description": "A provider job: the circuit's exact distribution set beside the measured counts.", + "anyOf": [ + { + "type": "object", + "required": [ + "computed", + "total_variation_distance", + "hellinger_fidelity" + ], + "properties": { + "computed": { + "const": true + }, + "method": { + "type": "string" + }, + "total_variation_distance": { + "type": "number" + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number" + }, + "ideal_outcomes": { + "type": "integer" + }, + "note": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "computed", + "why" + ], + "properties": { + "computed": { + "const": false + }, + "why": { + "type": "string" + } + } + } + ] + }, + "cost": { + "type": "object", + "description": "A provider job: the estimate shown before it was sent, what the provider says it charged, and whether the person confirmed a run that was not free." + }, + "provenance": { + "title": "wai.quantum.provenance/1", + "description": "What a result came from, under the five categories cross-platform provenance surveys use: the circuit, the computer, the compilation, the execution and the software. A host adds it to the results it seals (the job service does, and each item of a set); a result without it reads as it always did. wai-quantum-service/docs/provenance.md maps every field to where it is and whether the receipt seals it.", + "type": "object", + "required": [ + "schema", + "circuit", + "computer", + "compilation", + "execution", + "software" + ], + "properties": { + "schema": { + "const": "wai.quantum.provenance/1" + }, + "circuit": { + "type": "object", + "description": "The program: the BLAKE3 digest of its text as given, its qubits and its gates.", + "required": [ + "program" + ], + "properties": { + "program": { + "type": "string", + "description": "BLAKE3 of the program's text, in hex." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": [ + "integer", + "null" + ] + } + } + }, + "computer": { + "type": "object", + "description": "What ran it: a classical simulator, the method and its accuracy class, a device target's hash when the job named one, and the fabric's members when the result names where its state ran.", + "required": [ + "kind", + "method" + ], + "properties": { + "kind": { + "const": "simulator" + }, + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "target": { + "type": "string", + "description": "The device target's hash; its layout, routes and noise are in the result's own target." + }, + "fabric": { + "type": "object", + "description": "The kernel and the member that ran the state, or each partition's, as the result's fabric names them.", + "properties": { + "kernel": { + "type": "string" + }, + "members": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "compilation": { + "type": "object", + "description": "Whether the job asked to be compiled; if it did, each pass in order with its check's verdict, the certificate's digest, the gate set compiled to (its basis), the level, the ε budget and the distance the result carries, and that no pass draws a random number.", + "required": [ + "asked" + ], + "properties": { + "asked": { + "type": "boolean" + }, + "passes": { + "type": [ + "array", + "null" + ], + "items": { + "type": "object", + "properties": { + "pass": { + "type": "string" + }, + "verdict": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ] + }, + "basis": { + "type": [ + "string", + "null" + ], + "description": "The gate set compiled to: clifford_t or standard." + }, + "level": { + "type": [ + "integer", + "null" + ] + }, + "epsilon": { + "type": [ + "number", + "null" + ] + }, + "distance": { + "type": [ + "number", + "null" + ] + }, + "seeded": { + "const": false + }, + "device": { + "type": "string", + "description": "A job on a device target, compiled exactly to its gates: where its layout and routes are." + }, + "status": { + "const": "not-applicable" + }, + "why": { + "type": "string" + } + } + }, + "execution": { + "type": "object", + "description": "The shots, the seed and the plan the job ran under; its identifier and times are the host's, outside the result.", + "required": [ + "plan" + ], + "properties": { + "shots": { + "type": [ + "integer", + "null" + ] + }, + "seed": { + "type": [ + "integer", + "null" + ] + }, + "plan": { + "type": "object", + "properties": { + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0 + } + } + } + } + }, + "software": { + "type": "object", + "description": "The engine's name and version, and the host's.", + "required": [ + "engine", + "host" + ], + "properties": { + "engine": { + "type": "string" + }, + "host": { + "type": "string" + } + } + } + } + }, + "mitigation": { + "title": "wai.quantum.mitigation/1", + "description": "A job's mitigation (its request's mitigate, engine::mitigate), in its result: the method and the options it ran with, its bias and variance assumptions, each observable raw and mitigated with a standard error each and the ideal value (or, for readout, the counts inverted as a quasi-distribution), the method's own details and what it spent. docs/qec.md describes each method.", + "type": "object", + "required": [ + "method", + "options", + "assumptions" + ], + "properties": { + "method": { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + "options": { + "type": "object", + "description": "The options it ran with, the defaults filled in.", + "properties": { + "method": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "factors": { + "type": "array", + "items": { + "type": "number" + } + }, + "extrapolation": { + "enum": [ + "richardson", + "linear", + "exponential" + ] + }, + "samples": { + "type": "integer" + }, + "training": { + "type": "integer" + }, + "keep": { + "type": "integer" + }, + "learn_shots": { + "type": "integer" + } + } + }, + "assumptions": { + "type": "object", + "properties": { + "bias": { + "type": "string" + }, + "variance": { + "type": "string" + } + } + }, + "noise": { + "type": "string", + "description": "How the job's noise model is read for the method." + }, + "note": { + "type": "string" + }, + "observables": { + "type": "array", + "items": { + "type": "object", + "description": "One observable: its raw value and the mitigated one, each with its standard error, and the ideal value a simulation knows.", + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "raw": { + "type": "number" + }, + "raw_stderr": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + }, + "ideal": { + "type": "number" + } + } + } + }, + "distribution": { + "type": "array", + "description": "readout: each outcome's raw share and its mitigated quasi-probability, with its standard error.", + "items": { + "type": "object", + "properties": { + "bits": { + "type": "string" + }, + "raw": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + } + } + } + }, + "details": { + "type": "object", + "description": "The method's own: the folded scales and the folding check (zne), the learned model and the amplified values (pea), the quasi-probability and the value it converges to (pec), the training fits (cdr), the purity (vd), the flip and its amplification (readout).", + "additionalProperties": true + }, + "cost": { + "type": "object", + "description": "The circuits and shots it spent beyond the job's own.", + "properties": { + "circuits": { + "type": "integer", + "minimum": 0 + }, + "shots": { + "type": "integer", + "minimum": 0 + }, + "note": { + "type": "string" + } + } + } + } + }, + "pulse": { + "type": "object", + "description": "A pulse run (method pulse, engine::pulse): what was read and its distribution, the final populations, each capture's reading, the final density matrix's digest, the schedule's length, the integrator and its step, the device and where each parameter came from, and what the receipt binds (calibration).", + "required": [ + "read", + "outcome_bits", + "populations", + "simulated_qubits", + "density_hash", + "integrator", + "device", + "calibration" + ], + "properties": { + "read": { + "type": "string", + "description": "What the distribution reads: the captures together (into the program's bits when each writes one), or the final state." + }, + "outcome_bits": { + "type": "array", + "items": { + "type": "string" + }, + "description": "What each character of an outcome is, left to right: a program bit (c[0]) or a qubit ($0)." + }, + "distribution": { + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "number" + }, + "description": "The probability of each outcome, which the counts sample; null when the captures start at different samples." + }, + "populations": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The final state read on every simulated qubit, the highest qubit first, a level above 0 read as 1." + }, + "simulated_qubits": { + "type": "array", + "items": { + "type": "integer" + } + }, + "captures": { + "type": "array", + "items": { + "type": "object", + "properties": { + "frame": { + "type": "string" + }, + "qubit": { + "type": "integer" + }, + "start": { + "type": "integer" + }, + "start_ns": { + "type": "number" + }, + "bit": { + "type": [ + "string", + "null" + ] + }, + "p1": { + "type": "number" + }, + "p2": { + "type": "number" + } + } + } + }, + "leakage": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "p2": { + "type": "number" + } + } + }, + "description": "With three levels: each qubit's final probability of level 2." + }, + "trace": { + "type": "number" + }, + "density_hash": { + "type": "string", + "description": "The BLAKE3 of the final density matrix's bits: the same on every platform." + }, + "duration": { + "type": "integer" + }, + "duration_ns": { + "type": "number" + }, + "integrator": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "order": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "substeps": { + "type": "integer" + }, + "step_ns": { + "type": "number" + }, + "steps": { + "type": "integer" + }, + "norm_max": { + "type": "number" + }, + "frame": { + "type": "string" + } + } + }, + "device": { + "type": "object", + "properties": { + "levels": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "qubits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "frequency_hz": { + "type": "number" + }, + "rabi_hz": { + "type": "number" + }, + "anharmonicity_hz": { + "type": "number" + }, + "t1_ns": { + "type": "number" + }, + "t2_ns": { + "type": "number" + }, + "from": { + "type": "object", + "additionalProperties": { + "enum": [ + "pulse", + "target", + "default", + "none" + ] + } + } + } + } + }, + "couplings": { + "type": "array" + }, + "model": { + "type": "string" + } + } + }, + "calibration": { + "type": "object", + "description": "What the receipt binds: the program's, its calibrations', the schedule's and the device's digests, and the target snapshot.", + "properties": { + "program": { + "type": "string" + }, + "calibrations": { + "type": "string" + }, + "schedule": { + "type": "string" + }, + "device": { + "type": "string" + }, + "target": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "calibration": { + "type": "object" + } + } + } + } + }, + "not_modelled": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + }, + { + "title": "wai.quantum.set/1", + "description": "A set's result: many programs, or one program over a grid of its inputs, run as one job (engine::sets). Its head holds the count, how many items finished and failed, the Merkle root over the items' leaves, the set's energy and time; the set's receipt seals the set's request and its head. Each item is a plain job with its own receipt, its index, its point in a sweep, and its path to the root, so it is shown sealed by the set alone. A result names the engine that made it and this schema (engine and schema).", + "type": "object", + "required": [ + "format", + "count", + "done", + "failed", + "root", + "items" + ], + "properties": { + "engine": { + "type": "object", + "description": "The engine that made the result: the wai-quantum crate's name and version.", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "const": "wai-quantum" + }, + "version": { + "type": "string" + } + } + }, + "schema": { + "const": "wai.quantum.set/1" + }, + "format": { + "const": "wai.quantum.set/1" + }, + "count": { + "type": "integer", + "minimum": 1 + }, + "done": { + "type": "integer", + "minimum": 0 + }, + "failed": { + "type": "integer", + "minimum": 0 + }, + "root": { + "type": "string", + "description": "The Merkle root of the items' leaves, in hex (domains moq-jwp:merkle-leaf and moq-jwp:merkle-node, version 1)." + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "receipt": { + "title": "wai.quantum.receipt/2", + "description": "A result's receipt: an Ed25519 signature, by the key it names, over digest = BLAKE3(\"wai:quantum-service-receipt\\x02\" ‖ len ‖ request ‖ len ‖ result), each of request and result in its RFC 8785 canonical text (the result without its receipt member), each length 8 bytes big-endian. Whatever members the request and the result hold are sealed, the result's engine and schema among them. The first receipts (no canon member, $defs/first) sealed their writer's compact text under the domain ending \\x01; they still verify. wai/extensions/quantum-providers.md section 8.2 states the seal in full, and section 8.4 what a verifier checks.", + "type": "object", + "required": [ + "alg", + "canon", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "canon": { + "const": "rfc8785", + "description": "The canonical form the digest is taken over." + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The signing key, 32 bytes in lower-case hex." + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The digest signed, 32 bytes in lower-case hex." + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$", + "description": "The signature, 64 bytes in lower-case hex." + } + } + }, + "items": { + "type": "array", + "items": { + "type": "object", + "description": "One item: its index, its point in a sweep, its request (a plain job, complete in itself), and its result with its own receipt, or why it failed; and its path to the set's root.", + "required": [ + "index", + "request", + "status", + "path" + ], + "properties": { + "index": { + "type": "integer", + "minimum": 0 + }, + "point": { + "type": "object", + "description": "A sweep's item: the value of each input it was run at." + }, + "status": { + "enum": [ + "done", + "failed" + ] + }, + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "request": { + "title": "wai.quantum.job-request/1", + "description": "A job as a client submits it: a program and what is asked of it, or a set: many programs (programs), or one over a grid of its inputs (sweep), run as one job. The command line, both MCP servers, the job service, the desktop app and the Studio read it alike, and a receipt seals it as it was given. A member the engine does not read is ignored, and sealed with the rest.", + "type": "object", + "anyOf": [ + { + "required": [ + "qasm" + ] + }, + { + "required": [ + "programs" + ] + }, + { + "required": [ + "source" + ] + } + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, in OpenQASM 3 or the OpenQASM 2 forms in common use." + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "description": "The program in another format, in place of qasm (engine::formats::expand): read to the job's qasm before the job is read, the request keeping its source.", + "properties": { + "format": { + "enum": [ + "qasm", + "qir", + "jeff" + ] + }, + "program": { + "type": "string", + "description": "The program's text (OpenQASM, QIR)." + }, + "program_base64": { + "type": "string", + "description": "The program's bytes as base64 (jeff)." + } + } + }, + "shots": { + "type": "integer", + "minimum": 0, + "maximum": 1000000, + "description": "Measurement shots; 1024 when no observables or amplitudes are asked for, otherwise 0." + }, + "seed": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991, + "description": "The sampling seed (1 when not given): the same job and seed give the same counts." + }, + "method": { + "type": "string", + "description": "auto (the default: the strongest method the program admits), or a method by its name as the methods list names it; pulse runs a pulse program (OpenPulse calibrations) under the pulse options." + }, + "observables": { + "type": "array", + "maxItems": 256, + "description": "Pauli observables to take the expectation values of.", + "items": { + "anyOf": [ + { + "type": "string", + "description": "A Pauli string, as \"Z0 Z1\"; qubits count from 0." + }, + { + "type": "object", + "required": [ + "pauli" + ], + "properties": { + "pauli": { + "type": "string", + "description": "A Pauli string, as \"X3\"." + }, + "coeff": { + "type": "number", + "description": "Its coefficient (1 when not given)." + } + } + } + ] + } + }, + "amplitudes": { + "type": "array", + "maxItems": 64, + "description": "Basis states whose amplitudes to return: one 0 or 1 per qubit, qubit n-1 first.", + "items": { + "type": "string" + } + }, + "noise": { + "type": "object", + "description": "A noise model, each channel a probability. A channel not listed here is refused.", + "additionalProperties": false, + "properties": { + "depolarizing_1q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "depolarizing_2q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "amplitude_damping": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "dephasing": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "readout": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + } + }, + "options": { + "type": "object", + "description": "Options of the method that runs the job, as the methods list names them (max_bond, cutoff, fusion, trajectories, threshold, max_weight, ladder, max_terms, path_restarts), and memory_gb." + }, + "compile": { + "type": "object", + "description": "What a compile is asked for, each optional: the most the output may differ from the program (epsilon, in the operator norm up to a global phase), the level (0 lowers and approximates; 1 also rewrites and folds phases; 2 also resynthesises), the basis, the gate set it writes the program in (clifford_t: every rotation off the multiples of π/4 a Clifford+T word; standard: nothing approximated), whether to give the circuit after each pass (stages), and the twirl and dd passes, last (twirl, with its seed; dd, with its sequence).", + "properties": { + "epsilon": { + "type": "number", + "exclusiveMinimum": 0 + }, + "level": { + "type": "integer", + "minimum": 0, + "maximum": 2 + }, + "basis": { + "enum": [ + "clifford_t", + "standard" + ] + }, + "stages": { + "type": "boolean" + }, + "twirl": { + "description": "Twirl each two-qubit Clifford gate with Paulis drawn from a seeded stream: true (seed 1), or {\"seed\": N}. One seed is one instance, checked to be the same circuit.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "required": [ + "seed" + ], + "properties": { + "seed": { + "type": "integer", + "minimum": 0 + } + } + } + ] + }, + "dd": { + "description": "Dynamical decoupling in each window where a qubit idles long enough: xx or xy4 (or {\"sequence\": …}), checked to change nothing without noise.", + "anyOf": [ + { + "enum": [ + "xx", + "xy4" + ] + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "sequence": { + "enum": [ + "xx", + "xy4" + ] + } + } + } + ] + } + } + }, + "intent": { + "description": "What the program must do, checked with the run: one intent or a list. The result's verdict says how far it was checked.", + "anyOf": [ + { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + } + ] + }, + "verdict": { + "type": "boolean", + "description": "true: the result carries a verdict even with no intent." + }, + "target": { + "description": "A device target: a built-in target's name, or a target document. The program is compiled to it, placed and simulated under its noise; noise may not be given beside it.", + "anyOf": [ + { + "type": "string" + }, + { + "title": "wai.quantum.target/1", + "description": "A device target: its qubits, the pairs it couples, its native gates with their errors and durations, and the calibration snapshot they come from. A value not known is left out, never written as zero. Every field but format, name, source, qubits, gates and coupling is optional, and a field the format does not name is refused, so a misspelt one never reads as absent. Its canonical text is its RFC 8785 form, and the BLAKE3 of that text, the target's hash, names the snapshot in a receipt.", + "type": "object", + "required": [ + "format", + "name", + "source", + "qubits", + "gates", + "coupling" + ], + "additionalProperties": false, + "properties": { + "format": { + "const": "wai.quantum.target/1" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "additionalProperties": false, + "properties": { + "format": { + "type": "string", + "description": "The format the target was read from (wai-quantum targets import --help lists them)." + }, + "note": { + "type": "string", + "maxLength": 400 + } + } + }, + "calibration": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "maxLength": 400, + "description": "The calibration snapshot's id, as the source names it, or a content id of the snapshot read." + }, + "timestamp": { + "type": "string", + "maxLength": 400, + "description": "When the snapshot was taken, as the source writes it." + } + } + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2048, + "description": "Every qubit, in order.", + "items": { + "type": "object", + "required": [ + "qubit" + ], + "additionalProperties": false, + "properties": { + "qubit": { + "type": "integer", + "minimum": 0, + "description": "Its index: its place in the list." + }, + "label": { + "type": "string", + "description": "The source's own name for it, when that is not its index." + }, + "t1_us": { + "type": "number", + "minimum": 0, + "description": "T1, microseconds." + }, + "t2_us": { + "type": "number", + "minimum": 0, + "description": "T2 (the echo or Ramsey time the source reports), microseconds." + }, + "frequency_ghz": { + "type": "number", + "minimum": 0, + "description": "Its frequency, gigahertz." + }, + "readout": { + "type": "object", + "required": [ + "p01", + "p10" + ], + "additionalProperties": false, + "properties": { + "p01": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 1 | holds 0)." + }, + "p10": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 0 | holds 1)." + } + } + }, + "measure_ns": { + "type": "number", + "minimum": 0, + "description": "The measurement's duration, nanoseconds." + } + } + } + }, + "gates": { + "type": "array", + "maxItems": 262144, + "description": "Each native gate where the device runs it, sorted by gate then qubits.", + "items": { + "type": "object", + "required": [ + "gate", + "qubits" + ], + "additionalProperties": false, + "properties": { + "gate": { + "type": "string", + "pattern": "^[a-z0-9_]{1,40}$" + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + }, + "error": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "The average gate infidelity." + }, + "duration_ns": { + "type": "number", + "minimum": 0, + "description": "Nanoseconds." + } + } + } + }, + "coupling": { + "type": "array", + "description": "The pairs a two-qubit gate may act on, each once, the lower qubit first, sorted.", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + ] + }, + "fabric": { + "description": "Where the statevector method's state runs: auto (the default: on a member only where the committed measurements show it faster than this host's CPU for the job's size and fusion width, otherwise on the CPU), cpu, accelerator (the first accelerator member certified bit-exact here that holds the state, falling back to the next if it fails during the run), a member's id or key (wai-quantum fabric lists them), or a list of members, a power of two of them, the state split by its top qubits into one partition on each (cpu is a member, and a member may be named more than once). A member certified bit-exact gives the CPU's bits. A placement this host cannot honour is refused (J013), never made elsewhere.", + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "array", + "minItems": 2, + "maxItems": 64, + "items": { + "type": "string", + "minLength": 1 + } + } + ] + }, + "repair": { + "description": "Repair the program first on its flagged lines: true, or the choices.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "max_iterations": { + "type": "integer", + "minimum": 1 + }, + "dyadic_bits": { + "type": "integer", + "minimum": 1, + "maximum": 32 + }, + "sizes": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + } + } + } + ] + }, + "history": { + "type": "object", + "description": "The program's history's account of the version the job runs: its digest, and the gates and lines in each hand. The receipt binds it; a history recomputes and checks it." + }, + "provider": { + "type": "string", + "description": "The person's own provider to run on, by the name their registry gives it. Only a host that holds their credentials runs such a job; every other host refuses it." + }, + "programs": { + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "type": "string", + "description": "A program's text." + }, + { + "type": "object", + "required": [ + "qasm" + ], + "description": "A job of its own, read as a job request is (no programs or sweep in it); each item of the set's result holds its request in full." + } + ] + }, + "description": "A set (engine::sets): the programs to run as one job, each a program's text or a job of its own; the request's other fields apply to every item that does not set them itself." + }, + "sweep": { + "type": "object", + "additionalProperties": { + "type": "array", + "minItems": 1, + "items": { + "type": "number" + } + }, + "description": "A set over the request's own qasm: values for each of the program's inputs (integer, float or angle), every combination run, the names in sorted order and the first varying slowest." + }, + "params": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "A value for each of the program's parameters (`input float theta;`, `input angle phi;`), bound exactly before the program is read: it runs as if each were written as a `const` at that double. A parameter left without a value is refused (Q114, J050). In a sweep, the parameters it fixes, each bound at every point." + }, + "dry_run": { + "type": "boolean", + "description": "With true: what the host would do with the job or set, running nothing." + }, + "mitigate": { + "description": "Mitigate the job's expectation values (or, for readout, its counts) under its noise (engine::mitigate): zne, pea, pec, cdr, vd or readout, or {\"method\", …} with its options. The result's mitigation gives each value raw and mitigated.", + "anyOf": [ + { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + { + "type": "object", + "required": [ + "method" + ] + } + ] + }, + "pulse": { + "type": "object", + "description": "A pulse run's options (method \"pulse\"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0.", + "additionalProperties": false, + "properties": { + "dt_ns": { + "type": "number", + "exclusiveMinimum": 0, + "maximum": 1000, + "description": "The sample period, ns (default 0.5)." + }, + "levels": { + "type": "integer", + "enum": [ + 2, + 3 + ], + "description": "Levels kept per qubit (default 2; 3 shows leakage)." + }, + "tolerance": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1, + "description": "The most the stated error may be (default 1e-6): a run whose bound and rounding estimate pass it is refused, naming the steps that would meet it." + }, + "substeps": { + "type": "integer", + "minimum": 1, + "maximum": 4096, + "description": "Steps per sample (default: chosen so each step times the generator's norm is at most 0.5)." + }, + "qubits": { + "type": "object", + "description": "Each qubit's parameters by its index, over the target's and the defaults.", + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "frequency_ghz": { + "type": "number", + "description": "Its frequency, GHz." + }, + "rabi_mhz": { + "type": "number", + "description": "Its Rabi frequency at full amplitude, MHz." + }, + "anharmonicity_mhz": { + "type": "number", + "description": "Its anharmonicity, MHz." + }, + "t1_us": { + "type": "number", + "description": "Its relaxation time, µs." + }, + "t2_us": { + "type": "number", + "description": "Its coherence time, µs (at most 2·T1)." + } + } + } + }, + "couplings": { + "type": "array", + "description": "Static ZZ couplings.", + "items": { + "type": "object", + "required": [ + "qubits", + "zz_khz" + ], + "additionalProperties": false, + "properties": { + "qubits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + }, + "minItems": 2, + "maxItems": 2 + }, + "zz_khz": { + "type": "number", + "description": "The coupling's rate, kHz." + } + } + } + }, + "ports": { + "type": "object", + "description": "Ports by name: what each is for and the qubit it reaches.", + "additionalProperties": { + "type": "object", + "required": [ + "kind", + "qubit" + ], + "additionalProperties": false, + "properties": { + "kind": { + "enum": [ + "drive", + "measure", + "acquire" + ] + }, + "qubit": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits." + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "enum": [ + "never", + "allowed", + null + ] + } + } + } + } + }, + "result": { + "title": "wai.quantum.job-result/1", + "description": "A job's result as the engine gives it, on every host: what was asked of the program, computed by the method its plan chose, with that method's accuracy class. The receipt seals the result without its receipt member, beside the request. A result names the engine that made it and this schema (engine and schema); results made before results carried them have neither and follow this schema all the same.", + "type": "object", + "required": [ + "method", + "qubits", + "gates", + "accuracy" + ], + "properties": { + "engine": { + "type": "object", + "description": "The engine that made the result: the wai-quantum crate's name and version.", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "const": "wai-quantum" + }, + "version": { + "type": "string", + "description": "Its semantic version, as MAJOR.MINOR.PATCH." + } + } + }, + "schema": { + "const": "wai.quantum.job-result/1", + "description": "The schema the result follows." + }, + "components": { + "type": "array", + "description": "The identity of every component that made the result, when a registered one took part (engine::registry): its program's format, the passes its compile ran, the noise channels it names, its method; each registered one marked so. Sealed by the receipt with the rest.", + "items": { + "type": "object", + "description": "One component that made the result (engine::registry): its kind, name and version, the BLAKE3 digest of its descriptor, and whether it is built in. A result carries these only when a registered component took part; one made by built-ins alone names them as it always has (its method, its compile's passes, its noise's channels and the engine's version), the digests of that version listed by the components list.", + "required": [ + "kind", + "name", + "version", + "digest", + "origin" + ], + "properties": { + "kind": { + "enum": [ + "method", + "pass", + "channel", + "front_end" + ] + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "digest": { + "type": "string", + "pattern": "^[0-9a-f]{64}$", + "description": "BLAKE3 of the component's descriptor in its canonical JSON (engine::registry::digest_of)." + }, + "origin": { + "enum": [ + "built-in", + "registered" + ], + "description": "built-in: the engine's own; registered: a host's own, added in its process, not part of the engine." + }, + "certified": { + "const": false, + "description": "Beside a registered component: the engine does not certify it." + } + } + } + }, + "method": { + "type": "string", + "description": "The method that ran the job (provider for a run on the person's own provider)." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": "integer", + "minimum": 0 + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "state_hash": { + "type": "string", + "description": "The bit-exact method's statevector hash (BLAKE3, hex): the same on every machine." + }, + "counts": { + "type": "object", + "description": "Outcomes and their counts, keyed by the program's classical bits, the highest bit first. At most 65536 outcomes are listed; omitted_shots holds the rest.", + "additionalProperties": { + "type": "integer", + "minimum": 0 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "outcome_dimension": { + "type": "integer", + "minimum": 0, + "description": "The stabilizer method: the dimension of the measured outcomes' affine space." + }, + "shots": { + "type": "integer", + "minimum": 0, + "description": "The shots, where the method names them in the result (trajectories, provider)." + }, + "expectations": { + "type": "array", + "items": { + "type": "object", + "required": [ + "observable", + "coeff", + "value" + ], + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "value": { + "type": "number", + "description": "The coefficient times the expectation value." + }, + "stderr": { + "type": "number", + "description": "The standard error, for an estimate." + }, + "bound": { + "type": "number", + "description": "A bound on |exact − value|: rigorous for the bounded class; with confidence beside it, holding with that probability." + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + }, + "max_terms": { + "type": "integer" + }, + "ladder": { + "type": "array", + "description": "The value at thresholds a decade apart, the asked one last.", + "items": { + "type": "object", + "required": [ + "threshold", + "value", + "bound" + ], + "properties": { + "threshold": { + "type": "number" + }, + "value": { + "type": "number" + }, + "bound": { + "type": "number" + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + } + } + } + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds, for a bound that holds with a stated probability (stabilizer_rank's sampled mode)." + } + } + } + }, + "amplitudes": { + "type": "array", + "items": { + "type": "object", + "required": [ + "bits", + "re", + "im" + ], + "properties": { + "bits": { + "type": "string", + "description": "One 0 or 1 per qubit, qubit n-1 first." + }, + "re": { + "type": "number" + }, + "im": { + "type": "number" + }, + "bound": { + "type": "number", + "minimum": 0, + "description": "A bound on |exact − value| of the amplitude, holding with the probability confidence states (stabilizer_rank's sampled mode)." + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds." + } + } + } + }, + "global_phase": { + "type": "string", + "description": "Why the amplitudes' global phase is not fixed, when it is not." + }, + "warning": { + "type": "string" + }, + "contraction_flops": { + "type": "number", + "description": "The tensor network's contraction cost." + }, + "dynamic": { + "type": "object", + "description": "A program that measures in the middle, resets or branches on a measured bit: how it ran.", + "properties": { + "measurements_and_resets": { + "type": "integer", + "minimum": 0 + }, + "branches_run": { + "type": "integer", + "minimum": 0 + }, + "states_at_once": { + "type": "integer", + "minimum": 0 + }, + "branches_weighed": { + "type": "integer", + "minimum": 0 + } + } + }, + "outputs": { + "type": "array", + "description": "The program's output declarations: each its name and type, and its value, or the places of its bits in each outcome.", + "items": { + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "bits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + } + }, + "value": { + "description": "A number, a boolean, a bit string, a duration's text, {\"re\", \"im\"}, or an array of them." + } + } + } + }, + "timing": { + "type": "object", + "description": "A program that states durations (delay, box, stretch) the method does not apply: said so, with the reader's code.", + "required": [ + "applied", + "why" + ], + "properties": { + "applied": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "diagnostics": { + "type": "array", + "description": "The reader's warnings and notes on the program, each with its code.", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "compiled": { + "description": "How the program was compiled before it ran: on the person's own provider, to the device's gates; or, asked with compile, to a basis within a budget. Either way, basis is the gate set it was compiled to.", + "anyOf": [ + { + "type": "object", + "description": "A provider job: the program sent, compiled exactly to the device's own gates: its basis (the device's gate set), its OpenQASM 3 text (qasm3) and that text's BLAKE3 (program), its counts of gates and swaps, its layouts, and the check it passed before it was sent. Results sealed before qasm3 carry the hash alone.", + "required": [ + "basis", + "program" + ], + "properties": { + "basis": { + "type": "string" + }, + "program": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "qasm3": { + "type": "string", + "description": "The program sent, as OpenQASM 3, $i being index i of the coupling map the provider described; program is the BLAKE3 of its UTF-8 bytes." + }, + "qubit_names": { + "type": "object", + "additionalProperties": { + "type": "string", + "minLength": 1 + }, + "description": "The device's own name for each index the program uses, as it was when the job was sent, where a client sends it under those names." + }, + "native_gates": { + "type": "integer" + }, + "two_qubit_gates": { + "type": "integer" + }, + "swaps": { + "type": "integer" + }, + "layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "final_layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "checked": { + "type": "string" + }, + "placement": { + "type": "object", + "description": "Where the program was placed on the device's qubits, and why." + } + } + }, + { + "type": "object", + "description": "A job asked to compile its program first: what ran is the compiled circuit, within distance of the program in the operator norm up to a global phase.", + "required": [ + "basis", + "verdict" + ], + "properties": { + "basis": { + "enum": [ + "clifford_t", + "standard" + ], + "description": "The gate set the program was compiled to." + }, + "level": { + "type": "integer", + "minimum": 0 + }, + "epsilon": { + "type": "number", + "description": "The budget asked for." + }, + "distance": { + "type": [ + "number", + "null" + ], + "description": "The bound the passes' distances add to." + }, + "verdict": { + "type": "string" + }, + "source": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "output": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ], + "description": "The BLAKE3 of the compile certificate's RFC 8785 text, in hex." + }, + "note": { + "type": "string" + } + } + } + ] + }, + "verdict": { + "title": "wai.quantum.verdict/1", + "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", + "type": "object", + "required": [ + "schema", + "level", + "rank", + "holds", + "statement", + "parsed", + "executed", + "intent", + "critique", + "repairs" + ], + "properties": { + "schema": { + "const": "wai.quantum.verdict/1" + }, + "level": { + "enum": [ + "refused", + "parsed", + "executed", + "evidence", + "proof" + ] + }, + "rank": { + "type": "integer", + "minimum": 0, + "maximum": 4, + "description": "The level's place on the ladder, from 0 (refused) to 4 (proof)." + }, + "holds": { + "type": [ + "boolean", + "null" + ] + }, + "statement": { + "type": "string", + "description": "The level in one plain line." + }, + "parsed": { + "type": "object", + "description": "Whether the reader took the program, and its warnings and notes with their codes, or its refusal.", + "required": [ + "ok" + ], + "properties": { + "ok": { + "type": "boolean" + }, + "diagnostics": { + "type": "array", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + }, + "text": { + "type": "string", + "description": "The refusal as the reader wrote it, with its line and code." + } + } + }, + "executed": { + "type": [ + "object", + "null" + ], + "description": "The method that ran and its accuracy class, and the distance a compile put between the program and what ran.", + "properties": { + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "compiled_distance": { + "type": [ + "number", + "null" + ] + } + } + }, + "intent": { + "type": "array", + "items": { + "type": "object", + "description": "One intent's check: what it asked, whether it held, how strong the check was and how it was made.", + "required": [ + "kind", + "outcome", + "strength", + "how" + ], + "properties": { + "kind": { + "enum": [ + "distribution", + "equivalent", + "prepares", + "sampled", + "compiled" + ] + }, + "outcome": { + "enum": [ + "holds", + "fails", + "unchecked" + ] + }, + "strength": { + "enum": [ + "proof", + "evidence", + "none" + ] + }, + "how": { + "type": "string" + }, + "why": { + "type": "string" + }, + "distance": { + "type": "number" + }, + "tolerance": { + "type": "number" + }, + "outcomes": { + "type": "integer", + "description": "The outcomes the distribution holds, or the samples' distinct outcomes." + }, + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The program's distribution, when its outcomes are few enough to list." + }, + "largest_gaps": { + "type": "array", + "items": { + "type": "object", + "properties": { + "outcome": { + "type": "string" + }, + "program": { + "type": "number" + }, + "intent": { + "type": "number" + } + } + } + }, + "global_phase": { + "type": [ + "number", + "null" + ] + }, + "method": { + "type": "string", + "description": "A sampled intent: the method the samples were run by." + }, + "seed": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "alpha": { + "type": "number" + }, + "fit": { + "type": "object", + "description": "A sampled intent: the test, its statistic, degrees of freedom and p-value, the level, and whether it rejected.", + "properties": { + "test": { + "type": "string" + }, + "statistic": { + "type": "number" + }, + "dof": { + "type": "integer" + }, + "p_value": { + "type": "number" + }, + "alpha": { + "type": "number" + }, + "shots": { + "type": "integer" + }, + "rejected": { + "type": "boolean" + }, + "smallest_expected": { + "type": [ + "number", + "null" + ] + }, + "impossible": { + "type": [ + "integer", + "array", + "boolean" + ] + }, + "note": { + "type": "string" + } + } + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "name": { + "type": "string" + }, + "note": { + "type": "string" + } + } + } + }, + "critique": { + "type": "array", + "description": "The program's smells, each with its lines.", + "items": { + "type": "object" + } + }, + "repairs": { + "type": "array", + "description": "Each edit a repair made, with the code it answered and the lines it changed.", + "items": { + "type": "object" + } + }, + "refusal": { + "type": "object", + "description": "For a refused job: its message and its codes.", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + }, + "sealed": { + "type": "boolean" + } + } + }, + "target": { + "type": "object", + "description": "A run on a device target: which target (its hash, as its receipt binds it), its calibration snapshot, where the program was placed and why, and the noise derived from the target.", + "required": [ + "name", + "hash" + ], + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "hash_is": { + "type": "string" + }, + "calibration": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "source": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "note": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "description": "The native gate set, the layout and routes chosen, the swaps, the expected success beside the fewest-swaps layout's, and the check of the compiled program." + }, + "noise": { + "type": "object", + "description": "The noise model derived from the target's calibration: its channels, durations and idling, and each qubit's readout." + } + } + }, + "fabric": { + "type": "object", + "description": "Where the state vector, or the pauli method's sum of terms, ran: the kernel, the placement the job asked for, the member that ran it (or each partition's), each with its certificate, and the energy. Present when the job asked for a placement, or when auto placed the state on a member by measurement (`auto`); a job auto leaves on the CPU names nothing; the receipt seals it with the rest of the result. Every member placed is certified bit-exact, so the answers are the CPU's, byte for byte.", + "required": [ + "kernel", + "asked", + "parity", + "energy" + ], + "properties": { + "kernel": { + "type": "string" + }, + "asked": { + "description": "The placement the job asked for, as it gave it.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "partitions": { + "type": "array", + "description": "Each partition's member, by the value of the state's top qubits: partition i holds the amplitudes whose top bits read i.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "partition_qubits": { + "type": "integer", + "minimum": 0 + }, + "local_qubits": { + "type": "integer", + "minimum": 0 + }, + "segments": { + "type": "integer", + "minimum": 0, + "description": "Runs of gates the partitions took in turn, between exchanges." + }, + "exchanges": { + "type": "integer", + "minimum": 0, + "description": "Partition qubits exchanged with local ones through the host's copy of the state." + }, + "fell_back_from": { + "type": "array", + "description": "An accelerator request whose member failed during the run: each member that failed, in turn, with how; the member named above ran the job.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "auto": { + "type": "object", + "description": "Why auto placed the state where it ran: the rule (a member is placed only where the committed measurements show it faster than this host's CPU for the job's size and fusion width) and the measured row it rests on, with the host, the day and the load it was measured under. Present only when auto placed a state on a member.", + "required": [ + "rule", + "host", + "fusion", + "from_qubits", + "to_qubits" + ], + "properties": { + "rule": { + "type": "string" + }, + "host": { + "type": "string", + "description": "The host's processor as the measurements name it (cpu--)." + }, + "measured": { + "type": "string", + "description": "The day the host was measured (UTC)." + }, + "about": { + "type": "string" + }, + "load": { + "type": "string" + }, + "discovery_ms": { + "type": "number", + "description": "What discovering and certifying the host's members took, once per process, as measured." + }, + "fusion": { + "type": "integer", + "minimum": 1 + }, + "from_qubits": { + "type": "integer", + "minimum": 0 + }, + "to_qubits": { + "type": "integer", + "minimum": 0 + }, + "min_launches": { + "type": "integer", + "minimum": 0 + }, + "basis": { + "type": "object", + "description": "The measured row the job is judged by: the largest measured size at or below its own, the launches of its plan, the runs of each, and the spread of the CPU's and the member's times in milliseconds.", + "required": [ + "qubits", + "launches", + "runs", + "cpu_ms", + "member_ms" + ], + "properties": { + "qubits": { + "type": "integer", + "minimum": 0 + }, + "launches": { + "type": "integer", + "minimum": 0 + }, + "runs": { + "type": "integer", + "minimum": 0 + }, + "cpu_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + }, + "member_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + } + } + } + } + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "why": { + "type": "string" + } + } + }, + "repaired": { + "type": "object", + "description": "A job asked to repair its program first: the program that ran, each repair, and what needs a person.", + "properties": { + "qasm": { + "type": "string" + }, + "repairs": { + "type": "array", + "items": { + "type": "object", + "required": [ + "code", + "by", + "edits" + ], + "properties": { + "code": { + "type": "string" + }, + "rule": { + "type": "string" + }, + "by": { + "enum": [ + "engine", + "proposal" + ] + }, + "flagged": { + "type": "array", + "items": { + "type": "integer" + } + }, + "edits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "line": { + "type": "integer" + }, + "before": { + "type": [ + "string", + "null" + ] + }, + "after": { + "type": [ + "string", + "null" + ] + } + } + } + } + } + } + }, + "needs_person": { + "type": "array", + "items": { + "type": "object" + } + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0, + "description": "Wall time of the run, where the host has a clock (not in a browser tab)." + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "receipt": { + "anyOf": [ + { + "title": "wai.quantum.receipt/2", + "description": "A result's receipt: an Ed25519 signature, by the key it names, over digest = BLAKE3(\"wai:quantum-service-receipt\\x02\" ‖ len ‖ request ‖ len ‖ result), each of request and result in its RFC 8785 canonical text (the result without its receipt member), each length 8 bytes big-endian. Whatever members the request and the result hold are sealed, the result's engine and schema among them. The first receipts (no canon member, $defs/first) sealed their writer's compact text under the domain ending \\x01; they still verify. wai/extensions/quantum-providers.md section 8.2 states the seal in full, and section 8.4 what a verifier checks.", + "type": "object", + "required": [ + "alg", + "canon", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "canon": { + "const": "rfc8785", + "description": "The canonical form the digest is taken over." + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The signing key, 32 bytes in lower-case hex." + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The digest signed, 32 bytes in lower-case hex." + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$", + "description": "The signature, 64 bytes in lower-case hex." + } + } + }, + { + "description": "The first form, before canon: the digest is over the compact text its writer wrote of each, members in the document's order (section 8.2 of wai/extensions/quantum-providers.md), under the domain ending \\x01. Never written now; still verified.", + "type": "object", + "required": [ + "alg", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$" + } + } + } + ] + }, + "provider": { + "type": "object", + "description": "A provider job: the provider's name, kind and protocol, the device, its provenance, and the hash of its description." + }, + "counts_source": { + "enum": [ + "shots", + "vendor_counts", + "probabilities" + ], + "description": "A provider job: where its counts come from (wai/extensions/quantum-providers.md section 8.3): tallied from one record a shot (shots), the provider's own counts (vendor_counts), or rebuilt from the probabilities it returned by largest remainders, derived and not shot records (probabilities). Results sealed before it carry neither it nor execution." + }, + "execution": { + "type": "object", + "description": "A provider job: how the device was asked to run the program (section 8.3): who states it (stated_by: client, provider or nobody); what the client sent (sent: the request's members and the settings among them); each of mitigation, twirling, decoupling, remapping and optimisation (off, on, default when the request sets nothing for it, none when the device has no such step, unknown when nobody states it); whether the gates were to run as written (verbatim); and a note.", + "required": [ + "stated_by", + "mitigation", + "twirling", + "decoupling", + "remapping", + "optimisation", + "verbatim" + ], + "properties": { + "stated_by": { + "enum": [ + "client", + "provider", + "nobody" + ] + }, + "sent": { + "type": "object", + "required": [ + "fields", + "settings" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "settings": { + "type": "object" + } + }, + "additionalProperties": false + }, + "mitigation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "twirling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "decoupling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "remapping": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "optimisation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "verbatim": { + "type": [ + "boolean", + "null" + ] + }, + "note": { + "type": "string" + } + }, + "additionalProperties": false + }, + "calibration": { + "type": [ + "string", + "null" + ], + "description": "A provider job: the calibration snapshot it ran under." + }, + "job": { + "type": "object", + "description": "A provider job: the provider's job id and its status checks." + }, + "ideal": { + "description": "A provider job: the circuit's exact distribution set beside the measured counts.", + "anyOf": [ + { + "type": "object", + "required": [ + "computed", + "total_variation_distance", + "hellinger_fidelity" + ], + "properties": { + "computed": { + "const": true + }, + "method": { + "type": "string" + }, + "total_variation_distance": { + "type": "number" + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number" + }, + "ideal_outcomes": { + "type": "integer" + }, + "note": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "computed", + "why" + ], + "properties": { + "computed": { + "const": false + }, + "why": { + "type": "string" + } + } + } + ] + }, + "cost": { + "type": "object", + "description": "A provider job: the estimate shown before it was sent, what the provider says it charged, and whether the person confirmed a run that was not free." + }, + "provenance": { + "title": "wai.quantum.provenance/1", + "description": "What a result came from, under the five categories cross-platform provenance surveys use: the circuit, the computer, the compilation, the execution and the software. A host adds it to the results it seals (the job service does, and each item of a set); a result without it reads as it always did. wai-quantum-service/docs/provenance.md maps every field to where it is and whether the receipt seals it.", + "type": "object", + "required": [ + "schema", + "circuit", + "computer", + "compilation", + "execution", + "software" + ], + "properties": { + "schema": { + "const": "wai.quantum.provenance/1" + }, + "circuit": { + "type": "object", + "description": "The program: the BLAKE3 digest of its text as given, its qubits and its gates.", + "required": [ + "program" + ], + "properties": { + "program": { + "type": "string", + "description": "BLAKE3 of the program's text, in hex." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": [ + "integer", + "null" + ] + } + } + }, + "computer": { + "type": "object", + "description": "What ran it: a classical simulator, the method and its accuracy class, a device target's hash when the job named one, and the fabric's members when the result names where its state ran.", + "required": [ + "kind", + "method" + ], + "properties": { + "kind": { + "const": "simulator" + }, + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "target": { + "type": "string", + "description": "The device target's hash; its layout, routes and noise are in the result's own target." + }, + "fabric": { + "type": "object", + "description": "The kernel and the member that ran the state, or each partition's, as the result's fabric names them.", + "properties": { + "kernel": { + "type": "string" + }, + "members": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "compilation": { + "type": "object", + "description": "Whether the job asked to be compiled; if it did, each pass in order with its check's verdict, the certificate's digest, the gate set compiled to (its basis), the level, the ε budget and the distance the result carries, and that no pass draws a random number.", + "required": [ + "asked" + ], + "properties": { + "asked": { + "type": "boolean" + }, + "passes": { + "type": [ + "array", + "null" + ], + "items": { + "type": "object", + "properties": { + "pass": { + "type": "string" + }, + "verdict": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ] + }, + "basis": { + "type": [ + "string", + "null" + ], + "description": "The gate set compiled to: clifford_t or standard." + }, + "level": { + "type": [ + "integer", + "null" + ] + }, + "epsilon": { + "type": [ + "number", + "null" + ] + }, + "distance": { + "type": [ + "number", + "null" + ] + }, + "seeded": { + "const": false + }, + "device": { + "type": "string", + "description": "A job on a device target, compiled exactly to its gates: where its layout and routes are." + }, + "status": { + "const": "not-applicable" + }, + "why": { + "type": "string" + } + } + }, + "execution": { + "type": "object", + "description": "The shots, the seed and the plan the job ran under; its identifier and times are the host's, outside the result.", + "required": [ + "plan" + ], + "properties": { + "shots": { + "type": [ + "integer", + "null" + ] + }, + "seed": { + "type": [ + "integer", + "null" + ] + }, + "plan": { + "type": "object", + "properties": { + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0 + } + } + } + } + }, + "software": { + "type": "object", + "description": "The engine's name and version, and the host's.", + "required": [ + "engine", + "host" + ], + "properties": { + "engine": { + "type": "string" + }, + "host": { + "type": "string" + } + } + } + } + }, + "mitigation": { + "title": "wai.quantum.mitigation/1", + "description": "A job's mitigation (its request's mitigate, engine::mitigate), in its result: the method and the options it ran with, its bias and variance assumptions, each observable raw and mitigated with a standard error each and the ideal value (or, for readout, the counts inverted as a quasi-distribution), the method's own details and what it spent. docs/qec.md describes each method.", + "type": "object", + "required": [ + "method", + "options", + "assumptions" + ], + "properties": { + "method": { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + "options": { + "type": "object", + "description": "The options it ran with, the defaults filled in.", + "properties": { + "method": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "factors": { + "type": "array", + "items": { + "type": "number" + } + }, + "extrapolation": { + "enum": [ + "richardson", + "linear", + "exponential" + ] + }, + "samples": { + "type": "integer" + }, + "training": { + "type": "integer" + }, + "keep": { + "type": "integer" + }, + "learn_shots": { + "type": "integer" + } + } + }, + "assumptions": { + "type": "object", + "properties": { + "bias": { + "type": "string" + }, + "variance": { + "type": "string" + } + } + }, + "noise": { + "type": "string", + "description": "How the job's noise model is read for the method." + }, + "note": { + "type": "string" + }, + "observables": { + "type": "array", + "items": { + "type": "object", + "description": "One observable: its raw value and the mitigated one, each with its standard error, and the ideal value a simulation knows.", + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "raw": { + "type": "number" + }, + "raw_stderr": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + }, + "ideal": { + "type": "number" + } + } + } + }, + "distribution": { + "type": "array", + "description": "readout: each outcome's raw share and its mitigated quasi-probability, with its standard error.", + "items": { + "type": "object", + "properties": { + "bits": { + "type": "string" + }, + "raw": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + } + } + } + }, + "details": { + "type": "object", + "description": "The method's own: the folded scales and the folding check (zne), the learned model and the amplified values (pea), the quasi-probability and the value it converges to (pec), the training fits (cdr), the purity (vd), the flip and its amplification (readout).", + "additionalProperties": true + }, + "cost": { + "type": "object", + "description": "The circuits and shots it spent beyond the job's own.", + "properties": { + "circuits": { + "type": "integer", + "minimum": 0 + }, + "shots": { + "type": "integer", + "minimum": 0 + }, + "note": { + "type": "string" + } + } + } + } + }, + "pulse": { + "type": "object", + "description": "A pulse run (method pulse, engine::pulse): what was read and its distribution, the final populations, each capture's reading, the final density matrix's digest, the schedule's length, the integrator and its step, the device and where each parameter came from, and what the receipt binds (calibration).", + "required": [ + "read", + "outcome_bits", + "populations", + "simulated_qubits", + "density_hash", + "integrator", + "device", + "calibration" + ], + "properties": { + "read": { + "type": "string", + "description": "What the distribution reads: the captures together (into the program's bits when each writes one), or the final state." + }, + "outcome_bits": { + "type": "array", + "items": { + "type": "string" + }, + "description": "What each character of an outcome is, left to right: a program bit (c[0]) or a qubit ($0)." + }, + "distribution": { + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "number" + }, + "description": "The probability of each outcome, which the counts sample; null when the captures start at different samples." + }, + "populations": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The final state read on every simulated qubit, the highest qubit first, a level above 0 read as 1." + }, + "simulated_qubits": { + "type": "array", + "items": { + "type": "integer" + } + }, + "captures": { + "type": "array", + "items": { + "type": "object", + "properties": { + "frame": { + "type": "string" + }, + "qubit": { + "type": "integer" + }, + "start": { + "type": "integer" + }, + "start_ns": { + "type": "number" + }, + "bit": { + "type": [ + "string", + "null" + ] + }, + "p1": { + "type": "number" + }, + "p2": { + "type": "number" + } + } + } + }, + "leakage": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "p2": { + "type": "number" + } + } + }, + "description": "With three levels: each qubit's final probability of level 2." + }, + "trace": { + "type": "number" + }, + "density_hash": { + "type": "string", + "description": "The BLAKE3 of the final density matrix's bits: the same on every platform." + }, + "duration": { + "type": "integer" + }, + "duration_ns": { + "type": "number" + }, + "integrator": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "order": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "substeps": { + "type": "integer" + }, + "step_ns": { + "type": "number" + }, + "steps": { + "type": "integer" + }, + "norm_max": { + "type": "number" + }, + "frame": { + "type": "string" + } + } + }, + "device": { + "type": "object", + "properties": { + "levels": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "qubits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "frequency_hz": { + "type": "number" + }, + "rabi_hz": { + "type": "number" + }, + "anharmonicity_hz": { + "type": "number" + }, + "t1_ns": { + "type": "number" + }, + "t2_ns": { + "type": "number" + }, + "from": { + "type": "object", + "additionalProperties": { + "enum": [ + "pulse", + "target", + "default", + "none" + ] + } + } + } + } + }, + "couplings": { + "type": "array" + }, + "model": { + "type": "string" + } + } + }, + "calibration": { + "type": "object", + "description": "What the receipt binds: the program's, its calibrations', the schedule's and the device's digests, and the target snapshot.", + "properties": { + "program": { + "type": "string" + }, + "calibrations": { + "type": "string" + }, + "schedule": { + "type": "string" + }, + "device": { + "type": "string" + }, + "target": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "calibration": { + "type": "object" + } + } + } + } + }, + "not_modelled": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, diff --git a/wai/wai-quantum-cli/docs/service-mcp.json b/wai/wai-quantum-cli/docs/service-mcp.json index f5abd8b29..e7e0e7381 100644 --- a/wai/wai-quantum-cli/docs/service-mcp.json +++ b/wai/wai-quantum-cli/docs/service-mcp.json @@ -4413,6 +4413,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -4548,6 +4552,7 @@ "cost", "cost_currency", "cost_unknown", + "cost_at_least", "cost_no_ceiling", "energy", "energy_unknown" @@ -4656,6 +4661,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -9071,6 +9080,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -9206,6 +9219,7 @@ "cost", "cost_currency", "cost_unknown", + "cost_at_least", "cost_no_ceiling", "energy", "energy_unknown" @@ -9314,6 +9328,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -10539,6 +10557,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -10674,6 +10696,7 @@ "cost", "cost_currency", "cost_unknown", + "cost_at_least", "cost_no_ceiling", "energy", "energy_unknown" @@ -10782,6 +10805,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -16915,6 +16942,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -17050,6 +17081,7 @@ "cost", "cost_currency", "cost_unknown", + "cost_at_least", "cost_no_ceiling", "energy", "energy_unknown" @@ -17158,6 +17190,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -21573,6 +21609,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -21708,6 +21748,7 @@ "cost", "cost_currency", "cost_unknown", + "cost_at_least", "cost_no_ceiling", "energy", "energy_unknown" @@ -21816,6 +21857,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -23041,6 +23086,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -23176,6 +23225,7 @@ "cost", "cost_currency", "cost_unknown", + "cost_at_least", "cost_no_ceiling", "energy", "energy_unknown" @@ -23284,6 +23334,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -26055,6 +26109,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -26190,6 +26248,7 @@ "cost", "cost_currency", "cost_unknown", + "cost_at_least", "cost_no_ceiling", "energy", "energy_unknown" @@ -26298,6 +26357,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -31124,6 +31187,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -31259,6 +31326,7 @@ "cost", "cost_currency", "cost_unknown", + "cost_at_least", "cost_no_ceiling", "energy", "energy_unknown" @@ -31367,6 +31435,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -35782,6 +35854,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -35917,6 +35993,7 @@ "cost", "cost_currency", "cost_unknown", + "cost_at_least", "cost_no_ceiling", "energy", "energy_unknown" @@ -36025,6 +36102,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -37250,6 +37331,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -37385,6 +37470,7 @@ "cost", "cost_currency", "cost_unknown", + "cost_at_least", "cost_no_ceiling", "energy", "energy_unknown" @@ -37493,6 +37579,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -39351,6 +39441,10 @@ "type": "object", "description": "For a provider's result, what it says of itself." }, + "planner": { + "type": "object", + "description": "For a job under a contract, what its reasoning says: the route chosen, the class wanted and given, whether the choice depends on the host, what was kept, and the shadow." + }, "key": { "type": [ "string", @@ -56313,6 +56407,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -56448,6 +56546,7 @@ "cost", "cost_currency", "cost_unknown", + "cost_at_least", "cost_no_ceiling", "energy", "energy_unknown" @@ -56556,6 +56655,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -60971,6 +61074,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -61106,6 +61213,7 @@ "cost", "cost_currency", "cost_unknown", + "cost_at_least", "cost_no_ceiling", "energy", "energy_unknown" @@ -61214,6 +61322,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -62074,6 +62186,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -62209,6 +62325,7 @@ "cost", "cost_currency", "cost_unknown", + "cost_at_least", "cost_no_ceiling", "energy", "energy_unknown" @@ -62317,6 +62434,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, diff --git a/wai/wai-quantum-cli/schemas/local-tools.v1.json b/wai/wai-quantum-cli/schemas/local-tools.v1.json index b93994584..559cb4e92 100644 --- a/wai/wai-quantum-cli/schemas/local-tools.v1.json +++ b/wai/wai-quantum-cli/schemas/local-tools.v1.json @@ -52,7 +52,7 @@ }, "planner": { "type": "object", - "description": "For a job under a contract, what its reasoning says: the route chosen, the class wanted and given, what was kept, and the shadow." + "description": "For a job under a contract, what its reasoning says: the route chosen, the class wanted and given, whether the choice depends on the host, what was kept, and the shadow." }, "recheck": { "type": "object", diff --git a/wai/wai-quantum-cli/src/main.rs b/wai/wai-quantum-cli/src/main.rs index 76d4526d5..e8daa93e0 100644 --- a/wai/wai-quantum-cli/src/main.rs +++ b/wai/wai-quantum-cli/src/main.rs @@ -1182,7 +1182,7 @@ pub(crate) fn print_planner(p: &Value) { let time = price["time"]["seconds"].as_f64().map_or_else(|| "time unknown".to_string(), |t| format!("about {t:.3e} s ({})", s(&price["time"]["basis"]))); let money = if price["money"]["free"] == true { "free".to_string() } else if let Some(a) = price["money"]["amount"].as_str() { format!("{a} {}", s(&price["money"]["currency"])) } else { "cost unknown".to_string() }; let priced = if price.is_null() { String::new() } else { format!(" — {money}, {time}") }; - let left = price["leaves_out"].as_array().filter(|a| !a.is_empty()).map(|a| format!("; leaves out {}", a.iter().map(|x| s(x)).collect::>().join(", "))).unwrap_or_default(); + let left = price["leaves_out"].as_array().filter(|a| !a.is_empty()).map(|a| format!("; leaves out {}", a.iter().map(&s).collect::>().join(", "))).unwrap_or_default(); let outcome = if let Some(c) = r["rejected"]["code"].as_str() { format!("rejected ({c}: {})", s(&r["rejected"]["why"])) } else { s(&r["outcome"]) }; println!(" {:<28} {} {}{priced}{left}", s(&r["route"]), s(&r["class"]), outcome); } diff --git a/wai/wai-quantum-cli/src/providers.rs b/wai/wai-quantum-cli/src/providers.rs index 888ad0703..cbb809d8b 100644 --- a/wai/wai-quantum-cli/src/providers.rs +++ b/wai/wai-quantum-cli/src/providers.rs @@ -925,11 +925,19 @@ mod tests { fn the_tools_say_what_they_cost_and_run_on_provider_says_it_spends_money() { let t = mcp_tools(); let names: Vec<&str> = t.iter().map(|x| x["name"].as_str().unwrap()).collect(); - assert_eq!(names, ["providers_list", "provider_estimate", "run_on_provider", "get_provider_job", "cancel_provider_job", "list_provider_jobs"]); - let run = t[2]["description"].as_str().unwrap(); - assert!(run.contains("SPEND THE PERSON'S MONEY") && run.contains("confirm_cost"), "{run}"); - assert!(t[2]["inputSchema"]["properties"]["confirm_cost"].is_object()); - assert!(t[1]["description"].as_str().unwrap().contains("Nothing is submitted and nothing is spent")); + assert_eq!(names, ["providers_list", "provider_estimate", "run_on_provider", "plan_routes", "run_routed", "get_provider_job", "cancel_provider_job", "list_provider_jobs"]); + // Each tool that can send a job says it can spend, and takes the person's word. + for i in [2, 4] { + let run = t[i]["description"].as_str().unwrap(); + assert!(run.contains("SPEND THE PERSON'S MONEY") && run.contains("confirm_cost"), "{run}"); + assert!(t[i]["inputSchema"]["properties"]["confirm_cost"].is_object()); + } + for i in [1, 3] { + assert!(t[i]["description"].as_str().unwrap().contains("Nothing is submitted and nothing is spent"), "{}", t[i]["name"]); + assert!(t[i]["inputSchema"]["properties"].get("confirm_cost").is_none(), "{}", t[i]["name"]); + } + // A routed tool weighs a contract, and requires one. + assert_eq!(t[3]["inputSchema"]["required"], json!(["qasm", "contract"])); } /// The tools against the reference provider, in this process. diff --git a/wai/wai-quantum-qpu/src/job.rs b/wai/wai-quantum-qpu/src/job.rs index 44095673c..4a0efc754 100644 --- a/wai/wai-quantum-qpu/src/job.rs +++ b/wai/wai-quantum-qpu/src/job.rs @@ -295,6 +295,10 @@ impl Plan { if let Some(u) = &e.unit { m["unit"] = json!(u); } + // The least it can come to: no ceiling is met by it. + if e.at_least { + m["at_least"] = json!(true); + } m } (None, false) => json!({ "free": false, "unknown": "the provider's estimate states no amount" }), @@ -484,8 +488,14 @@ pub fn route_with(targets: &[Target], also: Vec, request: &Value pub fn run_routed_here(routed: &Routed, request: &Value, key: &SigningKey, energy: Value) -> Result { let planner::Choice::Local(plan) = &routed.choice else { return Err(JobError::Failed("the planner chose a provider, and this runs what it chose here".into())) }; let mut result = Registry::builtins().run(request, plan).map_err(JobError::Failed)?; - planner::attach(&mut result, &routed.reasoning); - Ok(wai_quantum::engine::job::seal(request, plan, result, key, energy)) + planner::complete(&mut result, &routed.reasoning).map_err(JobError::Failed)?; + let body = wai_quantum::engine::job::seal(request, plan, result, key, energy); + // A host gives no receipt its own verifier refuses. + let own = wai_quantum::engine::job::check(&body); + if !own.valid() { + return Err(JobError::Failed(format!("no receipt is given: this host's verifier would refuse it ({})", own.reasons.join(", ")))); + } + Ok(body) } /// The provider [`route`] chose, as [`start`] sends it: refused, with the plan, @@ -573,7 +583,7 @@ fn sealed(t: &Target, request: &Value, read: &provider::Request, sealing: &Value let mut result = provider::result_stated(read, measured, &statement).map_err(|e| t.fail(e))?; // A contract job's reasoning, its shadow and what it kept (section 8.6). if let Some(reasoning) = sealing.get("planner") { - planner::seal_provider(Registry::builtins(), request, &mut result, reasoning, elapsed_ms); + planner::seal_provider(Registry::builtins(), request, &mut result, reasoning, elapsed_ms).map_err(|e| t.fail(e))?; } let body = provider::seal(request, result, key, sealing["why"].as_str().unwrap_or_default()); // A provider's word reaches the seal, and a host gives no receipt its own diff --git a/wai/wai-quantum-qpu/tests/clients.rs b/wai/wai-quantum-qpu/tests/clients.rs index cfa318a1b..f22dfe37b 100644 --- a/wai/wai-quantum-qpu/tests/clients.rs +++ b/wai/wai-quantum-qpu/tests/clients.rs @@ -723,6 +723,33 @@ fn a_built_in_kind_runs_under_a_contract_and_a_classical_method_shadows_it() { } } +/// A price the service bills by the minute is estimated at the least a task can +/// come to: under a contract's ceiling it is not known to be within it, and the +/// route says so; named with no ceiling, its cost is the person's to confirm. +#[test] +fn a_cost_estimated_at_the_least_it_can_come_to_meets_no_ceiling() { + let target = || { + let service = TasksService::new(true, false); + let t = kept(move |r: &Request| service.answer(r)); + let keys = Keys::new("AKIDEXAMPLE", Secret::new("wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"), None); + let client = CloudTasks::new(t, keys, "us-west-1", "arn:test:simulator", "bucket").unwrap().with_endpoints("https://tasks.test", "https://bucket.test"); + Target::new("tasks", Kind::CloudTasks, Box::new(client), None) + }; + let bell = "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n"; + let capped = json!({ "qasm": bell, "provider": "tasks", "shots": 100, "contract": { "max_cost": { "amount": "100", "currency": "USD" } } }); + let e = job::plan(&target(), &capped).err().unwrap().to_string(); + assert!(e.ends_with("[J071]") && e.contains("the least it can come to"), "{e}"); + // Routed with every route in view, it is listed with its price and why. + let routed = json!({ "qasm": bell, "shots": 100, "contract": { "exactness": "simulated", "providers": "allowed", "max_cost": { "amount": "100", "currency": "USD" } } }); + let e = job::route(&[target()], &routed, 1 << 30).err().unwrap().to_string(); + assert!(e.ends_with("[J071]") && e.contains("provider:tasks: at least 0.003750 USD"), "{e}"); + // Named, with no ceiling: planned, its estimate shown, and its route met. + let named = json!({ "qasm": bell, "provider": "tasks", "shots": 100, "contract": {} }); + let p = job::plan(&target(), &named).unwrap(); + let route = p.json["planner"]["routes"].as_array().unwrap().iter().find(|r| r["route"] == "provider:tasks").unwrap().clone(); + assert_eq!((route["outcome"].as_str(), route["price"]["money"]["at_least"].as_bool(), route["price"]["money"]["unit"].as_str()), (Some("chosen"), Some(true), Some("minute")), "{route}"); +} + /// Each built-in kind, through a service that follows its contract, states /// what its client sent (read from the very body it posts), where its counts /// come from, and its class by its device's provenance; and its receipt keeps diff --git a/wai/wai-quantum-service/README.md b/wai/wai-quantum-service/README.md index db996b0c9..7854da9b1 100644 --- a/wai/wai-quantum-service/README.md +++ b/wai/wai-quantum-service/README.md @@ -102,6 +102,10 @@ How the methods run: - **stabilizer**, with noise, samples by Pauli frames against one noiseless outcome of the tableau, 64 shots to a machine word. Its counts have the law of independent noisy shots. Its expectation values are estimates with standard errors, from at least 10,000 shots unless `trajectories` sets the number. Amplitude damping is not a Pauli channel and is refused. - **trajectories** treats every shot as an independent noisy trajectory in law. Shots that took the same errors share one state, so the error-free part of a circuit, and the error-free majority of the shots, run once. `histories` in the result counts the distinct error histories that ran. +### Under a contract + +A job may carry a `contract`: the class wanted, a deadline, a cost ceiling, an energy ceiling, and whether a provider may be used ([section 8.6](../extensions/quantum-providers.md) of the provider protocol). The service prices each method here for it, rejects those that cannot meet it, runs the cheapest of the rest and seals its reasoning in the receipt. A job no method here meets is refused at once, and in a dry run, with every method's reason (`J071`). The service reaches no provider: none is among its routes, whatever the contract allows, and a contract that wants a device's counts is refused. Its energy figures before a run are estimates from what it has metered, so a `max_joules` is met only by a method it has metered. A run past its contract's deadline is stopped (`J074`), and nothing is sealed. A queued job keeps the reasoning it was admitted with across a restart. A contract is one job's: a set refuses one (`J073`). + ### Programs that measure in the middle A program that measures a qubit and then acts on it, resets a qubit after its first gate, or uses `if` on measured bits runs on `statevector` or `stabilizer`. `auto` picks the stabilizer tableau when every gate is Clifford, and the state vector otherwise. diff --git a/wai/wai-quantum-service/schemas/service-tools.v1.json b/wai/wai-quantum-service/schemas/service-tools.v1.json index 245cf6f97..70ccf65f7 100644 --- a/wai/wai-quantum-service/schemas/service-tools.v1.json +++ b/wai/wai-quantum-service/schemas/service-tools.v1.json @@ -64,6 +64,10 @@ "type": "object", "description": "For a provider's result, what it says of itself." }, + "planner": { + "type": "object", + "description": "For a job under a contract, what its reasoning says: the route chosen, the class wanted and given, whether the choice depends on the host, what was kept, and the shadow." + }, "key": { "type": [ "string", diff --git a/wai/wai-quantum-service/src/jobs.rs b/wai/wai-quantum-service/src/jobs.rs index 93bc4adb9..c6cc68092 100644 --- a/wai/wai-quantum-service/src/jobs.rs +++ b/wai/wai-quantum-service/src/jobs.rs @@ -320,6 +320,11 @@ impl Job { if let Work::Set { plans, .. } = &self.work { r["set_plans"] = json!(plans); } + // A contract job's reasoning, as it was admitted: what it runs on was + // decided by it, and its result seals it. + if let Work::Planned(reasoning) = &self.work { + r["planner"] = reasoning.clone(); + } r } } @@ -492,11 +497,14 @@ impl Service { Status::Queued => { let cap = s.config.job_mib << 20; let replanned = match &job.work { - Work::One | Work::Planned(_) if planner::has_contract(&job.request) => planner::decide(wai_quantum::engine::registry::Registry::builtins(), &job.request, &planner::Host::new(cap)).and_then(|d| match d.choice { + // A contract job runs on the route its reasoning chose when it + // was admitted, and that reasoning is what its receipt seals. + Work::Planned(reasoning) => Ok((job.plan.clone(), Work::Planned(reasoning.clone()))), + Work::One if planner::has_contract(&job.request) => planner::decide(wai_quantum::engine::registry::Registry::builtins(), &job.request, &planner::Host::new(cap)).and_then(|d| match d.choice { planner::Choice::Local(p) => Ok((p, Work::Planned(d.reasoning))), _ => Err("its contract's route is not on this service".to_string()), }), - Work::One | Work::Planned(_) => crate::catalog::plan(&job.request, cap).map(|p| (p, Work::One)), + Work::One => crate::catalog::plan(&job.request, cap).map(|p| (p, Work::One)), Work::Set { items, .. } => sets::plan(items, cap).map(|plans| (sets::summary(&plans), Work::Set { items: items.clone(), plans })), }; match replanned.and_then(|(p, w)| if p.memory_bytes.div_ceil(1 << 20) > s.config.job_mib { Err(format!("it needs about {} MiB, more than one job may take here now", p.memory_bytes >> 20)) } else { Ok((p, w)) }) { @@ -561,7 +569,10 @@ impl Service { } Work::Set { items, plans } } - None => Work::One, + None => match rec.get("planner") { + Some(reasoning) if reasoning.is_object() => Work::Planned(reasoning.clone()), + _ => Work::One, + }, }; let mut result = None; if rec.get("result").is_some() { @@ -1115,8 +1126,10 @@ impl Service { r["energy"] = figure; // A contract's reasoning, and what it kept against the figure. if let Work::Planned(reasoning) = work { - planner::attach(&mut r, reasoning); + planner::complete(&mut r, reasoning)?; planner::finish(request, &mut r, None); + // The service gives no receipt its own verifier refuses. + planner::own_check(request, &r)?; } signer.seal_into(request, &mut r); let receipt = r.as_object_mut().and_then(|o| o.shift_remove("receipt")).ok_or("a result has a receipt")?; @@ -1227,8 +1240,11 @@ impl Service { None => format!("the job ran past {} s; it was stopped", self.config.job_timeout.as_secs()), }); } + // Never past the deadline by more than a step: a contract's deadline is + // held to the millisecond, not to the next look at the worker. + let step = Duration::from_millis(200).min(deadline.saturating_duration_since(Instant::now()) + Duration::from_millis(1)); if exited.is_none() { - match tokio::time::timeout(Duration::from_millis(200), child.wait()).await { + match tokio::time::timeout(step, child.wait()).await { Ok(Ok(status)) => { if let energy::Meter::Packages(p) = meter { after = p.read(); @@ -1239,7 +1255,7 @@ impl Service { Err(_) => {} } } else { - tokio::time::sleep(Duration::from_millis(200)).await; + tokio::time::sleep(step).await; } }; let elapsed_ms = began.elapsed().as_millis() as u64; @@ -1518,6 +1534,37 @@ mod tests { let _ = std::fs::remove_dir_all(&dir); } + /// A contract job queued when the service stopped keeps the reasoning it was + /// admitted with: the route it runs on, and what its receipt seals. Decided + /// again on a service that has metered nothing yet, its energy ceiling would + /// refuse it. + #[test] + fn a_contract_job_keeps_its_reasoning_across_a_restart() { + use wai_quantum::engine::{planner, registry::Registry}; + let dir = store_dir("contract"); + let req = json!({ "qasm": "OPENQASM 3.0; qubit q; h q;", "shots": 5, "contract": { "exactness": "exact", "max_joules": 10 } }); + let metered = |_: &Plan| -> Result<(f64, String), String> { Ok((0.5, "a test's figure".to_string())) }; + let d = planner::decide(Registry::builtins(), &req, &planner::Host::new(1 << 30).with_joules(&metered)).unwrap(); + let planner::Choice::Local(p) = d.choice else { panic!("{}", d.reasoning) }; + // Asked again with nothing metered, the same contract has no route. + assert!(planner::decide(Registry::builtins(), &req, &planner::Host::new(1 << 30)).unwrap_err().ends_with("[J071]")); + let id; + { + let s = Service::with_store(config(), Box::new(store::Files::open(&dir.join("store")).unwrap())); + id = s.submit_work("a", req.clone(), p.clone(), Work::Planned(d.reasoning.clone()), None).unwrap(); + } + let s = Service::open(config(), Box::new(store::Files::open(&dir.join("store")).unwrap())).unwrap(); + assert_eq!(s.get(&id).unwrap()["status"], "queued", "{}", s.get(&id).unwrap()); + { + let jobs = s.jobs.lock().unwrap(); + let j = jobs.get(&id).unwrap(); + assert!(matches!(&j.work, Work::Planned(r) if *r == d.reasoning), "{:?}", j.work); + assert_eq!(j.plan.method, p.method); + } + drop(s); + let _ = std::fs::remove_dir_all(&dir); + } + /// A job that was running when the service stopped runs again, once, /// from its stored request: queued in its order, it finishes with a /// receipt that verifies. Stopped again while it runs, it is diff --git a/wai/wai-quantum-service/src/mcp.rs b/wai/wai-quantum-service/src/mcp.rs index 694b07ec7..fdad01047 100644 --- a/wai/wai-quantum-service/src/mcp.rs +++ b/wai/wai-quantum-service/src/mcp.rs @@ -241,7 +241,10 @@ fn tool_list() -> Value { on_target["properties"].as_object_mut().map(|o| o.remove("method")); // A set: the job's fields, shared by every item, and its programs or its sweep. let mut set_props = job_props.clone(); - set_props.as_object_mut().map(|o| { o.remove("source"); o.remove("contract"); }); + if let Some(o) = set_props.as_object_mut() { + o.remove("source"); + o.remove("contract"); + } set_props["qasm"] = json!({ "type": "string", "description": "With sweep: the program, which declares the inputs the sweep gives values (`input uint n;`, `input float theta;`, `input angle phi;`)." }); set_props["programs"] = json!({ "type": "array", "minItems": 1, "maxItems": wai_quantum::engine::sets::MAX_ITEMS, "items": { "anyOf": [{ "type": "string" }, { "type": "object", "required": ["qasm"] }] }, "description": "The set's programs: each a program's text, or a job ({\"qasm\", …}) whose own fields win over the set's." }); set_props["sweep"] = json!({ "type": "object", "additionalProperties": { "type": "array", "minItems": 1, "items": { "type": "number" } }, "description": "Each input of qasm and its values: every combination runs, the names in sorted order, the first varying slowest; an integer input's values are whole numbers." }); diff --git a/wai/wai-quantum-service/tests/contract.rs b/wai/wai-quantum-service/tests/contract.rs index 94c4b7a6f..8e9e9eabd 100644 --- a/wai/wai-quantum-service/tests/contract.rs +++ b/wai/wai-quantum-service/tests/contract.rs @@ -122,7 +122,9 @@ fn a_contract_is_met_or_refused_and_the_service_never_reaches_a_provider() { } // A run past its deadline is stopped: this one's nominal time counts its state, - // and its million shots are what takes the time. + // and its million shots are what takes the time. The service looks at the + // worker again at the deadline itself, not at its next round 200 ms on, so a + // run that would end within that round is stopped all the same. let slow = json!({ "qasm": "OPENQASM 3.0;\nqubit[24] q;\nbit[24] c;\nrx(0.3) q[0];\nc = measure q;\n", "method": "statevector", "shots": 1000000, "contract": { "deadline_seconds": 0.05 } }); let (code, made) = http(port, "POST", "/v1/jobs", Some(&slow)); assert_eq!(code, 202, "{made}"); diff --git a/wai/wai-quantum/docs/job-refusals.md b/wai/wai-quantum/docs/job-refusals.md index 0514bf3cf..7e22e7191 100644 --- a/wai/wai-quantum/docs/job-refusals.md +++ b/wai/wai-quantum/docs/job-refusals.md @@ -87,7 +87,7 @@ browser engine. A test holds this page to the code's table. | `J065` | refused | An intent on a job whose noise names a registered channel: the intent checks model the built-in channels alone, so the check is refused rather than made against another model. | | `J070` | refused | A contract that does not read: not an object, a member a contract does not have, an exactness that is no class, a max_cost that is not an amount in decimals and a currency, a deadline or an energy ceiling that is not above zero, providers that is neither never nor allowed, or a job that names a provider while its contract says never. | | `J071` | refused | No route this host can see meets the contract: each route's price or reason is listed, so the contract or the job can be changed. Nothing fell back to a route the contract does not allow. | -| `J072` | refused | A method's result whose accuracy class does not meet the contract, as can only happen to a plan that is not the planner's: nothing it gave is returned. | +| `J072` | refused | A route's result whose accuracy class does not meet the class its job wants: the contract's, or under a contract that names none the class the job keeps. Nothing it gave is returned, since its receipt would not verify. | | `J073` | refused | A contract where it cannot be honoured: on a set or an item of one (each program runs under its own contract, alone), or on a build with no planner. It is refused rather than read as absent. | | `J074` | refused | A run stopped at its contract's deadline, by a host that can stop one: the estimate it was planned on was wrong here, and nothing was sealed. | | `J100` | dropped | A line of an answer that is not a statement (`name = View(...)`), a program (a fenced `qasm` block with its name), a comment or a marker: left out. | diff --git a/wai/wai-quantum/schemas/job-result.v1.json b/wai/wai-quantum/schemas/job-result.v1.json index 9145c223a..e81a514bb 100644 --- a/wai/wai-quantum/schemas/job-result.v1.json +++ b/wai/wai-quantum/schemas/job-result.v1.json @@ -1541,6 +1541,10 @@ }, "unknown": { "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." } } }, @@ -1741,6 +1745,7 @@ "cost", "cost_currency", "cost_unknown", + "cost_at_least", "cost_no_ceiling", "energy", "energy_unknown" diff --git a/wai/wai-quantum/src/engine/planner.rs b/wai/wai-quantum/src/engine/planner.rs index 8e1f72e12..301a98bc3 100644 --- a/wai/wai-quantum/src/engine/planner.rs +++ b/wai/wai-quantum/src/engine/planner.rs @@ -122,6 +122,10 @@ pub fn meets(wanted: &str, got: &str) -> bool { } } +/// The classes of the table from the most exact: a route's class is the first of +/// them that every class its method declares meets. +const LADDER: [&str; 6] = ["bit-exact", "exact", "single", "bounded", "estimate", "heuristic"]; + /// How exact a class is, for a shadow's choice among classical methods: the /// strongest first. fn strength(class: &str) -> u32 { @@ -246,7 +250,8 @@ pub struct Quote { /// not known. pub cannot: Option, /// What it costs: `{"free": true}`, `{"free": false, "amount", "currency"}` - /// with an optional `unit`, or `{"free": false, "unknown": "why"}`. + /// with an optional `unit`, and `"at_least": true` when the amount is the + /// least it can come to, or `{"free": false, "unknown": "why"}`. pub money: Value, /// How long the provider says it takes, queue included. pub seconds: Option, @@ -358,7 +363,7 @@ pub struct Considered { /// A whole number as JSON, or the double nearest it past what every reader reads /// alike: a price is sealed, and an inexact whole number invalidates a receipt. fn whole(x: u64) -> Value { - if x <= (1 << 53) - 1 { json!(x) } else { json!(x as f64) } + if x < (1 << 53) { json!(x) } else { json!(x as f64) } } fn is_gpu(method: &str) -> bool { @@ -368,7 +373,14 @@ fn is_gpu(method: &str) -> bool { /// The class a method's result has at worst, as far as the plan can say: the /// weakest it declares, or for the methods whose class the job fixes, that one. fn class_of(m: &dyn Method, r: Option<&Request>, plan: Option<&Plan>, target: bool) -> String { - let worst = || m.classes().into_iter().max_by_key(|c| strength(c)).unwrap_or_else(|| "unknown".into()); + let worst = || { + let declared = m.classes(); + match declared.as_slice() { + [] => "unknown".to_string(), + [one] => one.clone(), + many => LADDER.iter().find(|c| many.iter().all(|d| meets(c, d))).map_or_else(|| "unknown".to_string(), |c| c.to_string()), + } + }; match (m.name(), r) { ("stabilizer", Some(r)) => if r.noise.is_some() || target { "estimate".into() } else { "exact".into() }, ("stabilizer_rank", Some(r)) => if ["terms", "epsilon"].iter().any(|k| r.options.get(*k).is_some_and(|x| !x.is_null())) { "estimate".into() } else { "exact".into() }, @@ -548,6 +560,10 @@ fn gate(route: &Value, h: &Held<'_>) -> Option<&'static str> { if decimal_cmp(a, most) == Ordering::Greater { return Some("cost"); } + // The least it can come to: what it will come to is not known. + if price["money"]["at_least"] == true { + return Some("cost_at_least"); + } } (Some(_), Some(_)) => return Some("cost_currency"), _ => return Some("cost_unknown"), @@ -585,6 +601,7 @@ fn gate_why(code: &str, route: &Value, h: &Held<'_>) -> String { "cost_unknown" => format!("{}: an unknown cost does not meet a ceiling", money_said(&price["money"])), "cost_currency" => format!("{}, and the ceiling is in {}: the planner converts no currency", money_said(&price["money"]), h.contract.max_cost.as_ref().map_or("", |c| c.1.as_str())), "cost" => format!("{}, above the ceiling of {} {}", money_said(&price["money"]), h.contract.max_cost.as_ref().map_or("", |c| c.0.as_str()), h.contract.max_cost.as_ref().map_or("", |c| c.1.as_str())), + "cost_at_least" => format!("{}: the least it can come to, and what the job takes decides the rest, so it is not known to be within the ceiling of {} {}", money_said(&price["money"]), h.contract.max_cost.as_ref().map_or("", |c| c.0.as_str()), h.contract.max_cost.as_ref().map_or("", |c| c.1.as_str())), "energy_unknown" => format!("its energy is not known, so it cannot be held to the ceiling of {} J: {}", h.contract.max_joules.unwrap_or(0.0), price["energy"]["why"].as_str().unwrap_or("")), "energy" => format!("about {} J, above the ceiling of {} J", price["energy"]["joules"], h.contract.max_joules.unwrap_or(0.0)), other => other.to_string(), @@ -594,6 +611,7 @@ fn gate_why(code: &str, route: &Value, h: &Held<'_>) -> String { fn money_said(m: &Value) -> String { match (m["free"].as_bool(), m["amount"].as_str(), m["currency"].as_str(), m["unknown"].as_str()) { (Some(true), ..) => "free".to_string(), + (_, Some(a), Some(c), _) if m["at_least"] == true => format!("at least {a} {c}"), (_, Some(a), Some(c), _) => format!("{a} {c}"), (_, _, _, Some(u)) => u.to_string(), _ => "its cost is unknown".to_string(), @@ -614,8 +632,10 @@ fn cheaper(a: &Value, b: &Value) -> Ordering { _ => Ordering::Equal, }; let ms = |r: &Value| r["price"]["time"]["seconds"].as_f64().map(|s| (s * 1000.0).ceil()); + // By value: -0.0 is 0 (a JSON number has no NaN). + let by_value = |x: f64, y: f64| x.partial_cmp(&y).unwrap_or(Ordering::Equal); let time_order = match (ms(a), ms(b)) { - (Some(x), Some(y)) => x.total_cmp(&y), + (Some(x), Some(y)) => by_value(x, y), (Some(_), None) => Ordering::Less, (None, Some(_)) => Ordering::Greater, (None, None) => Ordering::Equal, @@ -625,7 +645,7 @@ fn cheaper(a: &Value, b: &Value) -> Ordering { money_order .then(time_order) .then_with(|| local(a).cmp(&local(b))) - .then_with(|| memory(a).total_cmp(&memory(b))) + .then_with(|| by_value(memory(a), memory(b))) .then_with(|| a["route"].as_str().unwrap_or("").as_bytes().cmp(b["route"].as_str().unwrap_or("").as_bytes())) } @@ -877,7 +897,8 @@ pub fn plan_and_run_in(reg: &Registry, v: &Value, host: &Host<'_>) -> Result<(Pl match d.choice { Choice::Local(p) => { let mut result = reg.run(v, &p)?; - attach(&mut result, &d.reasoning); + complete(&mut result, &d.reasoning)?; + own_check(v, &result)?; Ok((p, result)) } Choice::Provider(name) => Err(format!("this job's contract is met by the provider {name}; a host that reaches it runs it there")), @@ -891,9 +912,36 @@ pub fn contract_schema() -> Value { serde_json::from_str::(text).ok().and_then(|v| v.pointer("/properties/contract").cloned()).unwrap_or_else(|| json!({ "type": "object" })) } -/// `reasoning` in `result`. -pub fn attach(result: &mut Value, reasoning: &Value) { +/// `reasoning` in `result`, the result held first to the class the reasoning +/// wants, whether the contract named it or the job keeps what it would have had: +/// a method that gave less gives no answer ([`refusal::CLASS_BROKEN`]), since +/// its receipt would break section 8.6. +pub fn complete(result: &mut Value, reasoning: &Value) -> Result<(), String> { + if let Some(wanted) = reasoning["wanted"].as_str() { + let got = result.pointer("/accuracy/class").and_then(Value::as_str).unwrap_or(""); + let approximate = result.pointer("/accuracy/approximate") == Some(&Value::Bool(true)); + if !meets(wanted, got) || (wanted == "simulated" && approximate) { + let why = if approximate && wanted == "simulated" { "an approximate simulator's".to_string() } else { format!("{got:?}") }; + return Err(tag(refusal::CLASS_BROKEN, format!("the route {} gave a result of class {why}, and the job wants {wanted}: nothing it gave is returned", reasoning["choice"].as_str().unwrap_or("?")))); + } + } result["planner"] = reasoning.clone(); + Ok(()) +} + +/// A contract job's result held to section 8.6 before a host seals it, as its +/// verifier will hold it once sealed: a host gives no receipt its own verifier +/// would refuse. What it kept is stated as [`finish`] states it. +pub fn own_check(v: &Value, result: &Value) -> Result<(), String> { + let mut r = result.clone(); + if r.get("planner").is_some() && r["planner"].get("kept").is_none() { + finish(v, &mut r, None); + } + let broken = check(v, &r); + if broken.is_empty() { + return Ok(()); + } + Err(format!("internal: no receipt is given: this host's verifier would refuse its reasoning ({})", broken.join(", "))) } /// A result's class held to the contract once it has run: a method that gave @@ -954,7 +1002,7 @@ pub fn missed(result: &Value) -> bool { /// The seed a job's shadow samples with. pub fn shadow_seed(v: &Value) -> u64 { let seed = v.get("seed").and_then(Value::as_u64).unwrap_or(1); - (seed + SHADOW_SEED_OFFSET) % (1 << 53) + ((u128::from(seed) + u128::from(SHADOW_SEED_OFFSET)) % (1 << 53)) as u64 } /// The classical method that can reach the provider's counts within the @@ -1016,24 +1064,33 @@ fn shadow_plan(reg: &Registry, v: &Value, host: &Host<'_>, contract: &Contract, /// outcomes (section 8.6). `None` when either leaves out shots. pub fn distance(a: &Value, b: &Value, shots: u64) -> Option { let (a, b) = (a.as_object()?, b.as_object()?); + if shots == 0 { + return None; + } let mut keys: Vec<&String> = a.keys().chain(b.keys()).collect(); keys.sort_by(|x, y| x.as_bytes().cmp(y.as_bytes())); keys.dedup(); let s = shots as f64; - let (mut numerator, mut root, mut floor) = (0u64, 0.0f64, 0.0f64); + // Sums of whole numbers are exact; each product and quotient is a double's. + let (mut numerator, mut root, mut floor) = (0u128, 0.0f64, 0.0f64); for k in keys { let x = a.get(k).and_then(Value::as_u64).unwrap_or(0); let y = b.get(k).and_then(Value::as_u64).unwrap_or(0); - numerator += x.abs_diff(y); - root += ((x * y) as f64).sqrt(); - let p = (x + y) as f64 / (2.0 * s); - floor += (4.0 * p * (1.0 - p) / (std::f64::consts::PI * s)).sqrt(); + numerator += u128::from(x.abs_diff(y)); + root += ((x as f64) * (y as f64)).sqrt(); + let p = (u128::from(x) + u128::from(y)) as f64 / (2.0 * s); + let inner = 4.0 * p * (1.0 - p) / (std::f64::consts::PI * s); + if inner.is_nan() || inner < 0.0 { + return None; + } + floor += inner.sqrt(); } - let denominator = 2 * shots; + let denominator = 2 * u128::from(shots); + let whole = |x: u128| if x < (1 << 53) { json!(x as u64) } else { json!(x as f64) }; Some(json!({ "computed": true, - "numerator": numerator, - "denominator": denominator, + "numerator": whole(numerator), + "denominator": whole(denominator), "total_variation": numerator as f64 / denominator as f64, "hellinger_fidelity": root * root / (s * s), "sampling_tvd_expected": 0.5 * floor, @@ -1055,9 +1112,9 @@ pub fn shadow(reg: &Registry, reasoning: &Value, result: &Value) -> Value { Err(e) => return json!({ "ran": false, "code": "failed", "why": e }), }; let shots = result.get("shots").and_then(Value::as_u64).unwrap_or(0); - let whole_lists = result["omitted_shots"].as_u64() == Some(0) && out["omitted_shots"].as_u64() == Some(0); + let whole_lists = result["omitted_shots"].as_f64() == Some(0.0) && out["omitted_shots"].as_f64() == Some(0.0); let distance = if whole_lists { - distance(&result["counts"], &out["counts"], shots).unwrap_or_else(|| json!({ "computed": false, "why": "the counts are not of their form" })) + distance(&result["counts"], &out["counts"], shots).unwrap_or_else(|| json!({ "computed": false, "why": "the counts give no distance: no shots, or a list that is not of its form" })) } else { json!({ "computed": false, "why": "a list of counts leaves out shots, so the distance is not known from them" }) }; @@ -1080,11 +1137,13 @@ pub fn shadow(reg: &Registry, reasoning: &Value, result: &Value) -> Value { /// A provider's contract job's result made complete: the reasoning, the shadow /// and what the contract kept. What the job took, from its submission, is the -/// host's to say. -pub fn seal_provider(reg: &Registry, v: &Value, result: &mut Value, reasoning: &Value, elapsed_ms: Option) { - attach(result, reasoning); +/// host's to say. A result whose class is not what the job wants (its device +/// said another provenance when it ran) gives no answer. +pub fn seal_provider(reg: &Registry, v: &Value, result: &mut Value, reasoning: &Value, elapsed_ms: Option) -> Result<(), String> { + complete(result, reasoning)?; result["shadow"] = shadow(reg, reasoning, result); finish(v, result, elapsed_ms); + Ok(()) } // --------------------------------------------------------------------------- @@ -1113,7 +1172,7 @@ fn route_form(r: &Value) -> bool { Some(true) => true, Some(false) => m["unknown"].is_string() || (m["amount"].is_string() && m["currency"].is_string()), None => false, - }; + } && m.get("at_least").is_none_or(|x| *x == Value::Bool(true)); let time_ok = p["time"].is_object() && (p["time"]["seconds"].is_null() || p["time"]["seconds"].as_f64().is_some_and(|s| s >= 0.0)); let energy_ok = p["energy"].is_object() && (p["energy"]["joules"].is_null() || p["energy"]["joules"].is_number()); let left_ok = p["leaves_out"].as_array().is_some_and(|a| a.iter().all(|w| w.as_str().is_some_and(|w| LEFT_OUT.contains(&w)))); @@ -1255,7 +1314,8 @@ fn kept_holds(c: &Contract, p: &Value, result: &Value) -> bool { if let Some(d) = c.deadline_seconds { let e = &kept["deadline"]["elapsed_ms"]; let want = e.as_f64().map(|e| e <= d * 1000.0); - let local_e = result["method"] != "provider" && result.get("elapsed_ms").is_some_and(|x| x != e); + // A local result's own elapsed_ms, by value, and null when it has none. + let local_e = result["method"] != "provider" && result.get("elapsed_ms").and_then(Value::as_f64) != e.as_f64(); if kept["deadline"]["seconds"].as_f64() != Some(d) || !(e.is_null() || is_whole(e)) || kept["deadline"]["kept"].as_bool() != want || local_e { return false; } @@ -1282,29 +1342,44 @@ fn kept_holds(c: &Contract, p: &Value, result: &Value) -> bool { true } +/// JSON equality with numbers by value (section 8.4: a number's spelling is not +/// sealed): `4` and `4.0` are one number. +fn same(a: &Value, b: &Value) -> bool { + match (a, b) { + (Value::Number(x), Value::Number(y)) => x.as_f64() == y.as_f64(), + (Value::Array(x), Value::Array(y)) => x.len() == y.len() && x.iter().zip(y).all(|(p, q)| same(p, q)), + (Value::Object(x), Value::Object(y)) => x.len() == y.len() && x.iter().all(|(k, v)| y.get(k).is_some_and(|w| same(v, w))), + _ => a == b, + } +} + /// Whether a sealed shadow is of its form, what its plan says, and its distance /// what its counts give. fn shadow_holds(request: &Value, p: &Value, result: &Value) -> bool { let (s, plan) = (&result["shadow"], &p["shadow"]); match s["ran"].as_bool() { - Some(false) => s["code"].is_string() && s["why"].is_string() && (plan["route"].is_null().then(|| plan["code"] == s["code"]).unwrap_or(s["code"] == "failed")), + Some(false) => s["code"].is_string() && s["why"].is_string() && if plan["route"].is_null() { plan["code"] == s["code"] } else { s["code"] == "failed" }, Some(true) => { let shots = result["shots"].as_f64(); let req = &s["request"]; - let seed = request.get("seed").and_then(Value::as_u64).unwrap_or(1); - let req_ok = plan["request"] == *req + let req_ok = same(&plan["request"], req) && req["qasm"] == request["qasm"] && req["shots"].as_f64() == shots - && req["seed"].as_u64() == Some((seed + SHADOW_SEED_OFFSET) % (1 << 53)) + && req["seed"].as_u64() == Some(shadow_seed(request)) && plan["route"].as_str().and_then(|r| r.strip_prefix("method:")) == req["method"].as_str(); let m = s["counts"].as_object(); let listed: Option = m.map(|o| o.values().filter_map(Value::as_f64).sum()); let counts_ok = m.is_some() && s["omitted_shots"].as_f64().zip(listed).map(|(o, l)| o + l) == shots && is_whole(&s["distinct_outcomes"]); + // By value: an omitted_shots of 0 however it is written. + let whole_lists = result["omitted_shots"].as_f64() == Some(0.0) && s["omitted_shots"].as_f64() == Some(0.0); let distance_ok = match s["distance"]["computed"].as_bool() { - Some(false) => s["distance"]["why"].is_string(), - Some(true) => shots.and_then(|x| distance(&result["counts"], &s["counts"], x as u64)).is_some_and(|d| { - ["numerator", "denominator", "total_variation", "hellinger_fidelity", "sampling_tvd_expected"].iter().all(|k| d[*k].as_f64() == s["distance"][*k].as_f64()) - }) && result["omitted_shots"].as_u64() == Some(0) && s["omitted_shots"].as_u64() == Some(0), + Some(false) => s["distance"]["why"].is_string() && !whole_lists, + Some(true) => { + whole_lists + && shots.and_then(|x| distance(&result["counts"], &s["counts"], x as u64)).is_some_and(|d| { + ["numerator", "denominator", "total_variation", "hellinger_fidelity", "sampling_tvd_expected"].iter().all(|k| d[*k].as_f64() == s["distance"][*k].as_f64()) + }) + } None => false, }; req_ok && counts_ok && distance_ok && s["route"] == plan["route"] && s["accuracy"]["class"].is_string() && s["shots"].as_f64() == shots diff --git a/wai/wai-quantum/src/engine/planner/tests.rs b/wai/wai-quantum/src/engine/planner/tests.rs index 598454f9a..62e97ff12 100644 --- a/wai/wai-quantum/src/engine/planner/tests.rs +++ b/wai/wai-quantum/src/engine/planner/tests.rs @@ -397,6 +397,15 @@ fn a_provider_is_held_to_the_cost_ceiling_and_an_unknown_is_not_free() { assert_eq!(of(&decided(&ask(Some(("100", "USD"))), unknown.clone())).as_deref(), Some("cost_unknown")); assert_eq!(of(&decided(&ask(None), unknown)).as_deref(), Some("cost_no_ceiling")); assert_eq!(of(&decided(&ask(Some(("100", "USD"))), vec![quote("qpu", "silicon", usd("lots"), Some(1.0))])).as_deref(), Some("cost_unknown"), "an amount that is no decimal is unknown"); + // The least it can come to is not what it will: under a ceiling it is not + // known to meet, and above it, it is known not to. + let least = |a: &str| vec![quote("qpu", "silicon", json!({ "free": false, "amount": a, "currency": "USD", "unit": "minute", "at_least": true }), Some(12.0))]; + assert_eq!(of(&decided(&ask(Some(("100", "USD"))), least("0.3"))).as_deref(), Some("cost_at_least")); + assert!(route(&decided(&ask(Some(("100", "USD"))), least("0.3")).reasoning, "provider:qpu")["rejected"]["why"].as_str().unwrap().contains("at least 0.3 USD")); + assert_eq!(of(&decided(&ask(Some(("0.29", "USD"))), least("0.3"))).as_deref(), Some("cost")); + assert_eq!(of(&decided(&ask(Some(("0.3", "USD"))), least("0.3"))).as_deref(), Some("cost_at_least"), "at the ceiling, and it may come to more"); + let named_least = decided(&json!({ "qasm": BELL, "shots": 1000, "provider": "qpu", "contract": {} }), least("0.3")); + assert_eq!(named_least.reasoning["choice"], "provider:qpu", "named with no ceiling, its cost is the person's to confirm"); // Free needs no ceiling. assert_eq!(of(&decided(&ask(None), vec![quote("qpu", "silicon", json!({ "free": true }), Some(1.0))])), None); // Named by the job, its cost is the person's to confirm, as it is with no contract. @@ -666,7 +675,7 @@ fn provider_body(req: &Value, quotes: Vec, counts: Vec) -> Value { let e = provider::provider_execution(&json!({ "mitigation": "none", "twirling": "none", "decoder": "none", "decoupling": "none", "remapping": "none", "optimisation": "none", "verbatim": true })); let e = e.unwrap_or_else(|_| provider::provider_execution(&json!({ "mitigation": "none", "twirling": "none", "decoupling": "none", "remapping": "none", "optimisation": "none", "verbatim": true })).unwrap()); let mut result = provider::result_stated(&read, m, &provider::Statement::new(provider::CountsSource::Shots, e)).unwrap(); - seal_provider(reg(), req, &mut result, &d.reasoning, Some(12_000)); + seal_provider(reg(), req, &mut result, &d.reasoning, Some(12_000)).unwrap(); provider::seal(req, result, &SigningKey::from_bytes(&[9; 32]), "on lab") } @@ -772,6 +781,8 @@ fn every_rule_a_verifier_holds_a_provider_s_contract_job_to_is_broken_once_and_f (&[SHADOW], Box::new(|b| b["result"]["shadow"]["distance"]["hellinger_fidelity"] = json!(1.0))), (&[SHADOW], Box::new(|b| b["result"]["shadow"]["distance"]["sampling_tvd_expected"] = json!(0.0))), (&[SHADOW], Box::new(|b| b["result"]["shadow"]["distance"] = json!({ "computed": false }))), + // Not computed, with every shot listed on both sides: it could have been. + (&[SHADOW], Box::new(|b| b["result"]["shadow"]["distance"] = json!({ "computed": false, "why": "said so" }))), (&[SHADOW], Box::new(|b| b["result"]["shadow"]["omitted_shots"] = json!(1))), (&[SHADOW], Box::new(|b| b["result"]["shadow"]["route"] = json!("method:statevector"))), (&[SHADOW], Box::new(|b| b["result"]["shadow"]["request"]["seed"] = json!(7))), @@ -788,6 +799,9 @@ fn every_rule_a_verifier_holds_a_provider_s_contract_job_to_is_broken_once_and_f (&[PLANNER_ROUTE, PLANNER_CHOICE], Box::new(|b| at(b, "provider:qpu")["price"]["money"]["amount"] = json!("1.01"))), (&[PLANNER_ROUTE, PLANNER_CHOICE], Box::new(|b| at(b, "provider:qpu")["price"]["money"]["currency"] = json!("EUR"))), (&[PLANNER_ROUTE, PLANNER_CHOICE], Box::new(|b| at(b, "provider:qpu")["price"]["money"] = json!({ "free": false, "unknown": "not said" }))), + // The least it can come to, under the ceiling, claimed to meet it. + (&[PLANNER_ROUTE, PLANNER_CHOICE], Box::new(|b| at(b, "provider:qpu")["price"]["money"]["at_least"] = json!(true))), + (&[PLANNER_FORM], Box::new(|b| at(b, "provider:qpu")["price"]["money"]["at_least"] = json!(false))), (&[PLANNER_ROUTE, PLANNER_CHOICE], Box::new(|b| at(b, "provider:qpu")["price"]["time"]["seconds"] = json!(301.0))), (&[PLANNER_ROUTE, PLANNER_CHOICE], Box::new(|b| at(b, "provider:qpu")["price"]["time"] = json!({ "seconds": null, "why": "not said" }))), // A device's class that is not its provenance's. @@ -802,6 +816,9 @@ fn every_rule_a_verifier_holds_a_provider_s_contract_job_to_is_broken_once_and_f want.sort_unstable(); assert_eq!(reasons(&body), want, "{}", body["result"]["shadow"]); } + // An omitted_shots of 0 is 0 however it is written. + let spelt = resealed(&good, |b| b["result"]["shadow"]["omitted_shots"] = json!(0.0)); + assert_eq!(reasons(&spelt), Vec::<&str>::new()); // Charged past the ceiling, stated: valid, and it says it missed. let over = resealed(&good, |b| { b["result"]["cost"]["charged"]["amount"] = json!("1.5"); @@ -889,12 +906,99 @@ fn the_job_s_other_members_run_as_they_do_under_a_contract() { // A pulse job's bound is held the same way: its class is bounded, not exact. let pulse = "OPENQASM 3.0;\ndefcalgrammar \"openpulse\";\ncal {\n port d0;\n frame f0 = newframe(d0, 5e9, 0);\n waveform w = gaussian(0.1, 16dt, 4dt);\n}\ndefcal x $0 {\n play(f0, w);\n}\nx $0;\n"; let asked = json!({ "qasm": pulse, "method": "pulse", "contract": { "exactness": "exact" } }); - match catalog::plan(&asked, GIB) { - Ok(p) => panic!("{p:?}"), - Err(e) => assert!(e.ends_with("[J071]") || refusal::codes_in(&e).iter().any(|c| c.starts_with('J') || c.starts_with('Q')), "{e}"), - } + let e = catalog::plan(&asked, GIB).unwrap_err(); + assert!(e.ends_with("[J071]") && e.contains("its class is bounded"), "{e}"); + let c = considered(&json!({ "qasm": pulse, "method": "pulse", "contract": { "exactness": "bounded" } }), GIB); + assert_eq!((c.reasoning["choice"].as_str(), c.reasoning["routes"].as_array().map(Vec::len)), (Some("method:pulse"), Some(1)), "{}", c.reasoning); // On the fabric: a member asked for leaves only the state vector's route. let c = considered(&json!({ "qasm": BELL, "shots": 10, "fabric": "cpu", "contract": {} }), GIB); assert_eq!(c.reasoning["choice"], "method:stabilizer"); assert_eq!(code(&c.reasoning, "method:statevector_single"), Some("fabric")); } + +/// A method that declares two classes neither of which meets the other. +struct TwoWays; + +impl Method for TwoWays { + fn name(&self) -> &str { + "two_ways" + } + fn version(&self) -> &str { + "0.1.0" + } + fn classes(&self) -> Vec { + vec!["single".into(), "bounded".into()] + } + fn descriptor(&self) -> Value { + json!({ "circuits": "any", "answers": ["counts"] }) + } + fn plan(&self, job: &Job<'_>) -> Result { + let r = job.request()?; + Ok(Plan { method: "two_ways".into(), why: "a test's method".into(), memory_bytes: 1 << 20, work: 1, qubits: r.program.n_qubits, target: None }) + } + fn run(&self, job: &Job<'_>, _: &Plan, out: &mut Value) -> Result<(), String> { + let r = job.request()?; + out["accuracy"] = json!({ "class": "single" }); + let mut counts = Map::new(); + counts.insert(r.program.bitstring(|_| false), json!(r.shots)); + out["counts"] = Value::Object(counts); + Ok(()) + } +} + +/// A route's class is one every class its method declares meets: a method that +/// may give single or bounded is heuristic at worst, and a job that keeps its +/// class verifies whichever it gives. The ladder by strength said bounded, and a +/// single result then broke the receipt its host sealed. +#[test] +fn a_method_that_declares_two_classes_is_held_to_one_both_meet() { + let mut r = Registry::with_builtins(); + r.register(crate::engine::registry::Component::method(TwoWays)).unwrap(); + let req = json!({ "qasm": BELL, "shots": 10, "method": "two_ways", "contract": {} }); + let (p, result) = plan_and_run_in(&r, &req, &Host::new(GIB)).unwrap(); + assert_eq!(route(&result["planner"], "method:two_ways")["class"], "heuristic", "{}", result["planner"]); + assert_eq!(result["planner"]["wanted"], "heuristic"); + let body = job::seal(&req, &p, result, &SigningKey::from_bytes(&[3; 32]), json!({ "unmetered": "a test" })); + assert_eq!(reasons(&body), Vec::<&str>::new()); + // Asked for bounded by name, it is not known to give it. + let e = plan_and_run_in(&r, &json!({ "qasm": BELL, "shots": 10, "method": "two_ways", "contract": { "exactness": "bounded" } }), &Host::new(GIB)).unwrap_err(); + assert!(e.ends_with("[J071]") && e.contains("its class is heuristic"), "{e}"); +} + +/// A result short of what the reasoning wants gives no answer, whether the +/// contract named the class or the job kept auto's: its receipt would not verify. +#[test] +fn a_result_short_of_what_the_reasoning_wants_is_not_completed() { + let reasoning = |w: Value| json!({ "wanted": w, "choice": "method:mps" }); + let heuristic = json!({ "method": "mps", "accuracy": { "class": "heuristic" } }); + let mut r = heuristic.clone(); + let e = complete(&mut r, &reasoning(json!("exact"))).unwrap_err(); + assert!(e.ends_with("[J072]") && r.get("planner").is_none(), "{e}"); + let mut r = heuristic.clone(); + complete(&mut r, &reasoning(json!("heuristic"))).unwrap(); + assert_eq!(r["planner"]["wanted"], "heuristic"); + let mut r = heuristic; + complete(&mut r, &reasoning(Value::Null)).unwrap(); + let mut approximate = json!({ "method": "provider", "accuracy": { "class": "simulated", "approximate": true } }); + assert!(complete(&mut approximate, &json!({ "wanted": "simulated", "choice": "provider:sim" })).unwrap_err().ends_with("[J072]")); +} + +/// The distance is exact where it sums whole numbers and a double's elsewhere, +/// however many the shots: a product of two counts is never taken in a machine +/// word that wraps. +#[test] +fn the_distance_holds_at_the_largest_shots() { + let s: u64 = (1 << 53) - 1; + let a = json!({ "0": s }); + let b = json!({ "0": s - 2, "1": 2 }); + let d = distance(&a, &b, s).unwrap(); + assert_eq!(d["numerator"], 4); + assert!(d["denominator"].is_f64(), "2·S past 2^53 − 1 is written as a double: {d}"); + assert_eq!(d["denominator"].as_f64(), Some(2.0 * s as f64)); + let root = ((s as f64) * ((s - 2) as f64)).sqrt(); + assert_eq!(d["hellinger_fidelity"].as_f64(), Some(root * root / ((s as f64) * (s as f64)))); + assert_eq!(d["total_variation"].as_f64(), Some(4.0 / (2.0 * s as f64))); + // No shots, no distance; and counts past the shots leave none either. + assert!(distance(&a, &b, 0).is_none()); + assert!(distance(&json!({ "0": 10 }), &json!({ "0": 10 }), 3).is_none()); +} diff --git a/wai/wai-quantum/src/engine/pulse.rs b/wai/wai-quantum/src/engine/pulse.rs index 2a5440c00..6d1027b50 100644 --- a/wai/wai-quantum/src/engine/pulse.rs +++ b/wai/wai-quantum/src/engine/pulse.rs @@ -61,7 +61,9 @@ pub const DEFAULT_ANHARMONICITY_MHZ: f64 = -300.0; /// The most samples a schedule's view writes out in full. pub const MAX_VIEW_SAMPLES: usize = 65_536; -const KEYS: [&str; 8] = ["qasm", "method", "shots", "seed", "pulse", "target", "dry_run", "verdict"]; +// `contract` is the planner's to read (engine::planner): a pulse job under one is +// held to it like any other. +const KEYS: [&str; 9] = ["qasm", "method", "shots", "seed", "pulse", "target", "dry_run", "verdict", "contract"]; const OPTIONS: [&str; 7] = ["dt_ns", "levels", "tolerance", "substeps", "qubits", "couplings", "ports"]; const QUBIT_KEYS: [&str; 5] = ["frequency_ghz", "rabi_mhz", "anharmonicity_mhz", "t1_us", "t2_us"]; @@ -384,7 +386,7 @@ fn prepare(v: &Value) -> Result<(String, Prepared), String> { let o = v.as_object().ok_or_else(|| tag(refusal::NOT_A_JOB, "a job is a JSON object"))?; if let Some(k) = o.keys().find(|k| !KEYS.contains(&k.as_str())) { return Err(perr(format!( - "\"{k}\": a pulse run takes qasm, shots, seed, pulse and target; observables, amplitudes, noise, compile, repair, intent and mitigate belong to the circuit methods (its decay comes from T1 and T2)" + "\"{k}\": a pulse run takes qasm, shots, seed, pulse, target and a contract; observables, amplitudes, noise, compile, repair, intent and mitigate belong to the circuit methods (its decay comes from T1 and T2)" ))); } // A pulse run always states its verdict; asking for it changes nothing. diff --git a/wai/wai-quantum/src/engine/refusal.rs b/wai/wai-quantum/src/engine/refusal.rs index c811b3837..4b54cd7e2 100644 --- a/wai/wai-quantum/src/engine/refusal.rs +++ b/wai/wai-quantum/src/engine/refusal.rs @@ -121,7 +121,7 @@ table! { // A contract (engine::planner). CONTRACT_FORM = "J070", Refused, "A contract that does not read: not an object, a member a contract does not have, an exactness that is no class, a max_cost that is not an amount in decimals and a currency, a deadline or an energy ceiling that is not above zero, providers that is neither never nor allowed, or a job that names a provider while its contract says never."; NOTHING_MEETS = "J071", Refused, "No route this host can see meets the contract: each route's price or reason is listed, so the contract or the job can be changed. Nothing fell back to a route the contract does not allow."; - CLASS_BROKEN = "J072", Refused, "A method's result whose accuracy class does not meet the contract, as can only happen to a plan that is not the planner's: nothing it gave is returned."; + CLASS_BROKEN = "J072", Refused, "A route's result whose accuracy class does not meet the class its job wants: the contract's, or under a contract that names none the class the job keeps. Nothing it gave is returned, since its receipt would not verify."; CONTRACT_HERE = "J073", Refused, "A contract where it cannot be honoured: on a set or an item of one (each program runs under its own contract, alone), or on a build with no planner. It is refused rather than read as absent."; DEADLINE_PASSED = "J074", Refused, "A run stopped at its contract's deadline, by a host that can stop one: the estimate it was planned on was wrong here, and nothing was sealed."; -- 2.54.0 (Apple Git-157) From 0f1e26eef366dca0ca8ea8890cc810521d961ef6 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Fri, 6 Nov 2026 07:59:51 -0500 Subject: [PATCH 04/42] wai-quantum: the command line holds an energy ceiling to the job service's estimate --max-joules refused every route on the command line, which estimated no run's energy before it ran. The job service's estimate moves into the engine (engine::energy::estimate), one implementation over a host's own timings: a method's median rate and median power over its last three or more runs there, the planner's nominal rate where it has timed fewer, and why there is none where it has metered fewer. The service calls it and says what it said; the command line calls it over its own runs. Around each local run the command line reads the counter the engine reads (this process's own CPU energy on macOS, the processor packages' on Linux where they may be read) and keeps the run's work, time and power in quantum-timings.json beside its other files, the last 32 of each method. run, plan, the routed runs and the MCP run and plan tools hold max_joules to that estimate, labelled an estimate with what it rests on, and a method with fewer than three runs read here is refused for its energy, with why. A reading taken in the command line's own process is never complete, so it is never sealed: a result still says its energy is unmetered, and kept.energy that it is not known. An estimate under a microjoule is held to a ceiling as at most one, on the service too. The new end-to-end test fails on 83d16c50d (every route energy_unknown, J071) and passes here. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/wai-quantum-cli.yml | 6 +- .github/workflows/wai-quantum-service.yml | 1 + ...6-11-06-wai-quantum-cli-energy-estimate.md | 14 + wai/wai-quantum-cli/README.md | 2 +- wai/wai-quantum-cli/README.zh-CN.md | 2 +- wai/wai-quantum-cli/docs/llms-full.txt | 24 +- wai/wai-quantum-cli/src/estimates.rs | 260 ++++++++++++++++++ wai/wai-quantum-cli/src/main.rs | 24 +- wai/wai-quantum-cli/src/mcp.rs | 5 +- wai/wai-quantum-cli/src/providers.rs | 15 +- wai/wai-quantum-cli/tests/estimates.rs | 114 ++++++++ wai/wai-quantum-qpu/src/job.rs | 14 +- wai/wai-quantum-service/src/http.rs | 6 +- wai/wai-quantum-service/src/jobs.rs | 63 +---- wai/wai-quantum/src/engine/energy.rs | 125 +++++++++ wai/wai-quantum/src/engine/job.rs | 19 +- wai/wai-quantum/src/engine/planner.rs | 7 +- 17 files changed, 617 insertions(+), 84 deletions(-) create mode 100644 wai/changes/2026-11-06-wai-quantum-cli-energy-estimate.md create mode 100644 wai/wai-quantum-cli/src/estimates.rs create mode 100644 wai/wai-quantum-cli/tests/estimates.rs diff --git a/.github/workflows/wai-quantum-cli.yml b/.github/workflows/wai-quantum-cli.yml index 0216792d9..79004f899 100644 --- a/.github/workflows/wai-quantum-cli.yml +++ b/.github/workflows/wai-quantum-cli.yml @@ -106,7 +106,11 @@ jobs: providers::tasks::tests::a_job_reads_as_its_task \ providers::tasks::tests::a_cancelled_request_ends_its_wait_and_a_change_wakes_it \ a_contract_weighs_every_route_and_its_receipt_says_why \ - an_agent_weighs_a_contract_and_runs_on_the_route_it_chooses; do + an_agent_weighs_a_contract_and_runs_on_the_route_it_chooses \ + an_energy_ceiling_is_held_to_this_command_line_s_estimate_and_none_is_not_met \ + with_fewer_than_three_runs_read_here_no_route_meets_an_energy_ceiling \ + estimates::tests::the_timings_keep_each_method_s_last_runs_and_read_back \ + estimates::tests::three_metered_runs_give_an_estimate_and_fewer_none; do grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/test.log" || { echo "::error::$t did not run and pass"; exit 1; } done # The model harness and the views in an agent's host, each test by name. diff --git a/.github/workflows/wai-quantum-service.yml b/.github/workflows/wai-quantum-service.yml index 25f17a0da..13b72131f 100644 --- a/.github/workflows/wai-quantum-service.yml +++ b/.github/workflows/wai-quantum-service.yml @@ -106,6 +106,7 @@ jobs: engine::energy::tests::the_probe_finds_a_live_counter_s_cadence_and_refuses_a_stalled_one \ engine::energy::tests::only_top_level_package_zones_are_read_and_a_frozen_one_is_not_live \ engine::energy::tests::a_package_figure_names_its_scope_and_declares_its_edges \ + engine::energy::tests::a_host_s_estimate_rests_on_its_own_runs_and_says_whose \ qasm::tests::a_bound_parameter_reads_as_the_program_written_with_its_value; do grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/engine.log" || { echo "::error::$t did not run"; exit 1; } done diff --git a/wai/changes/2026-11-06-wai-quantum-cli-energy-estimate.md b/wai/changes/2026-11-06-wai-quantum-cli-energy-estimate.md new file mode 100644 index 000000000..b53b85a97 --- /dev/null +++ b/wai/changes/2026-11-06-wai-quantum-cli-energy-estimate.md @@ -0,0 +1,14 @@ +### wai-quantum: the command line holds an energy ceiling to the job service's estimate + +- **One estimate for every host** (`engine::energy::estimate`): a method's median rate and median power over its last + three or more runs on a host, the planner's nominal rate where it has timed fewer, and why there is none where it has + metered fewer. The job service now calls it, and its dry runs say what they said; the command line calls it too. + An estimate under a microjoule is held to a ceiling as at most one, not as unknown. +- **`--max-joules` works on the command line.** Around each run on this machine the command line reads the energy + counter the engine reads (this process's own on macOS, the processor packages' on Linux where they may be read) and + keeps the run's work, time and power in `quantum-timings.json` beside its other files, the last 32 runs of each + method, only to estimate from. `run`, `plan`, the routed runs and the MCP run and plan tools hold a contract's + `max_joules` to that estimate, labelled an estimate with what it rests on. A method with fewer than three runs read + here has none, and a route on it is refused for its energy, with why, as before. +- **Nothing is sealed that is not a reading.** A run read in its own process is never a complete reading, so a result + here still says its energy is unmetered, and a contract's `kept.energy` says it is not known. diff --git a/wai/wai-quantum-cli/README.md b/wai/wai-quantum-cli/README.md index 9164f9cc9..7f21fc37f 100644 --- a/wai/wai-quantum-cli/README.md +++ b/wai/wai-quantum-cli/README.md @@ -109,7 +109,7 @@ wai-quantum run circuit.qasm --method statevector --fabric cpu --fabric cpu --sh wai-quantum run prog.qasm --fabric a-member-elsewhere # exits 1 ``` -**Under a contract.** `--exactness CLASS`, `--deadline SECONDS`, `--max-cost 0.50:USD`, `--max-joules J` and `--allow-providers` (or `--contract` with the JSON of [the provider protocol's section 8.6](../extensions/quantum-providers.md)) say what the answer must be. The planner then prices every route it can see: each method here, at its memory and the time its work predicts, and with `--allow-providers` each of your own providers, by its own estimate and what that leaves out (each is asked, and sent nothing). It rejects every route that cannot meet the contract, runs the cheapest of the rest, and seals its reasoning in the receipt. An unknown never passes: a time nobody states does not meet a deadline, nor an unknown cost a ceiling, nor an estimate that is only the least a job can come to. Nothing falls back, from exact to approximate or between a simulator and a device, and with no route left the job is refused with every route's reason (`J071`). A contract that names no class keeps the class `auto` would give, and a device's counts are reached only by asking for `measured` (or `any`). A provider's answer carries a classical method's counts beside it, with their distance, wherever a method here can reach them in the time the contract leaves, and the receipt says why where none can. A ceiling confirms nothing: a run that is not free still takes `--yes`. `wai-quantum plan` with the same options shows every route's price or reason and sends nothing; `wai-quantum verify --recheck` prices the routes again here and runs the shadow again; a run that kept less than its contract asked is still sealed, says so, and exits 4. +**Under a contract.** `--exactness CLASS`, `--deadline SECONDS`, `--max-cost 0.50:USD`, `--max-joules J` and `--allow-providers` (or `--contract` with the JSON of [the provider protocol's section 8.6](../extensions/quantum-providers.md)) say what the answer must be. The planner then prices every route it can see: each method here, at its memory and the time its work predicts, and with `--allow-providers` each of your own providers, by its own estimate and what that leaves out (each is asked, and sent nothing). It rejects every route that cannot meet the contract, runs the cheapest of the rest, and seals its reasoning in the receipt. An unknown never passes: a time nobody states does not meet a deadline, nor an unknown cost a ceiling, nor an estimate that is only the least a job can come to. Nothing falls back, from exact to approximate or between a simulator and a device, and with no route left the job is refused with every route's reason (`J071`). A contract that names no class keeps the class `auto` would give, and a device's counts are reached only by asking for `measured` (or `any`). A provider's answer carries a classical method's counts beside it, with their distance, wherever a method here can reach them in the time the contract leaves, and the receipt says why where none can. A ceiling confirms nothing: a run that is not free still takes `--yes`. `--max-joules` is held to an estimate made before the run, the job service's: a method's median power over its last three or more runs read on this machine, over the run's estimated time. Around each run here the command line reads the energy counter the engine reads (this process's own on macOS, the processor packages' on Linux where you may read them) and keeps what it read in `~/.config/wai/quantum-timings.json` (or `$WAI_QUANTUM_TIMINGS`), only to estimate from. The reading is never sealed, since a run read in its own process is not read completely, and the estimate is labelled one. A method with fewer than three runs read here has none, and a route on it is refused for its energy, with why. `wai-quantum plan` with the same options shows every route's price or reason and sends nothing; `wai-quantum verify --recheck` prices the routes again here and runs the shadow again; a run that kept less than its contract asked is still sealed, says so, and exits 4. Each result names: diff --git a/wai/wai-quantum-cli/README.zh-CN.md b/wai/wai-quantum-cli/README.zh-CN.md index f32c931c7..9a2f8269b 100644 --- a/wai/wai-quantum-cli/README.zh-CN.md +++ b/wai/wai-quantum-cli/README.zh-CN.md @@ -112,7 +112,7 @@ wai-quantum run circuit.qasm --method statevector --fabric cpu --fabric cpu --sh wai-quantum run prog.qasm --fabric a-member-elsewhere # exits 1:别处的成员,被拒绝 ``` -**在契约之下。** `--exactness CLASS`、`--deadline SECONDS`、`--max-cost 0.50:USD`、`--max-joules J` 和 `--allow-providers`(或用 `--contract` 给出 [提供方协议第 8.6 节](../extensions/quantum-providers.md) 的 JSON)说明答案必须满足什么。规划器随后为它能看到的每条路径定价:本机的每个方法,按其内存和其工作量所预示的时间;加上 `--allow-providers` 时,还有你自己的每个提供方,按其自身的估算以及该估算未包含的内容(每个都会被询问,但不会发送任何东西)。它拒绝每条无法满足契约的路径,运行其余路径中最便宜的一条,并把它的推理封入收据。未知量从不算作满足:无人说明的时间不满足截止时间,未知的费用不满足上限,只是作业最低可能费用的估算也不满足。不会回退:既不会从精确退到近似,也不会在模拟器与设备之间互换;没有路径剩下时,作业被拒绝,并列出每条路径的原因(`J071`)。未指明类别的契约保留 `auto` 会给出的类别;只有请求 `measured`(或 `any`)才会用到设备的计数。提供方的答案旁边附有经典方法的计数及两者的距离,只要本机有方法能在契约留下的时间内得到它们;没有方法能做到时,收据会说明原因。上限不构成确认:不免费的运行仍需要 `--yes`。带相同选项的 `wai-quantum plan` 显示每条路径的价格或原因,不发送任何东西;`wai-quantum verify --recheck` 在本机重新为路径定价并重新运行影子运行;未能满足契约全部要求的运行仍会被封存,并如实说明,退出状态为 4。 +**在契约之下。** `--exactness CLASS`、`--deadline SECONDS`、`--max-cost 0.50:USD`、`--max-joules J` 和 `--allow-providers`(或用 `--contract` 给出 [提供方协议第 8.6 节](../extensions/quantum-providers.md) 的 JSON)说明答案必须满足什么。规划器随后为它能看到的每条路径定价:本机的每个方法,按其内存和其工作量所预示的时间;加上 `--allow-providers` 时,还有你自己的每个提供方,按其自身的估算以及该估算未包含的内容(每个都会被询问,但不会发送任何东西)。它拒绝每条无法满足契约的路径,运行其余路径中最便宜的一条,并把它的推理封入收据。未知量从不算作满足:无人说明的时间不满足截止时间,未知的费用不满足上限,只是作业最低可能费用的估算也不满足。不会回退:既不会从精确退到近似,也不会在模拟器与设备之间互换;没有路径剩下时,作业被拒绝,并列出每条路径的原因(`J071`)。未指明类别的契约保留 `auto` 会给出的类别;只有请求 `measured`(或 `any`)才会用到设备的计数。提供方的答案旁边附有经典方法的计数及两者的距离,只要本机有方法能在契约留下的时间内得到它们;没有方法能做到时,收据会说明原因。上限不构成确认:不免费的运行仍需要 `--yes`。`--max-joules` 依据运行前的估算来判断,即作业服务的估算:某方法在本机最近三次或更多次读取过的运行的中位功率,乘以本次运行的估算时间。命令行在本机每次运行前后读取引擎所读的能量计数器(macOS 上是本进程自身的计数器,Linux 上是你有权读取的处理器封装计数器),并把读数保存在 `~/.config/wai/quantum-timings.json`(或 `$WAI_QUANTUM_TIMINGS`)中,仅用于估算。读数从不封入收据,因为在自身进程内读取的运行读数并不完整;估算也明确标为估算。在本机读取过的运行少于三次的方法没有估算,基于它的路径会因能量未知而被拒绝,并说明原因。带相同选项的 `wai-quantum plan` 显示每条路径的价格或原因,不发送任何东西;`wai-quantum verify --recheck` 在本机重新为路径定价并重新运行影子运行;未能满足契约全部要求的运行仍会被封存,并如实说明,退出状态为 4。 每个结果都注明: diff --git a/wai/wai-quantum-cli/docs/llms-full.txt b/wai/wai-quantum-cli/docs/llms-full.txt index 20a8608e1..a8c5832b1 100644 --- a/wai/wai-quantum-cli/docs/llms-full.txt +++ b/wai/wai-quantum-cli/docs/llms-full.txt @@ -1887,9 +1887,11 @@ Options: it, and the receipt says whether it was kept (exit 4 when it was not) --max-joules - The most energy the run may take, in joules: a route whose energy is not known does not - meet it, and this command estimates none, so here every route is refused; the job service - estimates from what it has metered + The most energy the run may take, in joules, held to an estimate before it runs: a + method's median power over its last three or more runs read here, over the run's estimated + time (the job service's estimate, from this command line's own runs; never a reading of + this one, which is not sealed). A method with fewer than three runs read here has no + estimate, and a route on it is refused, with why --allow-providers Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods @@ -2073,9 +2075,11 @@ Options: it, and the receipt says whether it was kept (exit 4 when it was not) --max-joules - The most energy the run may take, in joules: a route whose energy is not known does not - meet it, and this command estimates none, so here every route is refused; the job service - estimates from what it has metered + The most energy the run may take, in joules, held to an estimate before it runs: a + method's median power over its last three or more runs read here, over the run's estimated + time (the job service's estimate, from this command line's own runs; never a reading of + this one, which is not sealed). A method with fewer than three runs read here has no + estimate, and a route on it is refused, with why --allow-providers Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods @@ -3201,9 +3205,11 @@ Options: it, and the receipt says whether it was kept (exit 4 when it was not) --max-joules - The most energy the run may take, in joules: a route whose energy is not known does not - meet it, and this command estimates none, so here every route is refused; the job service - estimates from what it has metered + The most energy the run may take, in joules, held to an estimate before it runs: a + method's median power over its last three or more runs read here, over the run's estimated + time (the job service's estimate, from this command line's own runs; never a reading of + this one, which is not sealed). A method with fewer than three runs read here has no + estimate, and a route on it is refused, with why --allow-providers Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods diff --git a/wai/wai-quantum-cli/src/estimates.rs b/wai/wai-quantum-cli/src/estimates.rs new file mode 100644 index 000000000..a17e6443a --- /dev/null +++ b/wai/wai-quantum-cli/src/estimates.rs @@ -0,0 +1,260 @@ +//! What this command line estimates a run's energy at before it runs, so that a +//! contract's `max_joules` (`--max-joules`) is held to something. +//! +//! The estimate is the engine's, the one the job service gives +//! ([`wai_quantum::engine::energy::estimate`]): a method's median power over its +//! last metered runs here, taken over the run's estimated time. The runs are +//! this command line's own. Around each run on this machine it reads the energy +//! counter the engine reads (on macOS, this process's own CPU energy; on Linux, +//! the processor packages', where this user may read them), and keeps the run's +//! work, time and power: in `$WAI_QUANTUM_TIMINGS`, or +//! `$XDG_CONFIG_HOME/wai/quantum-timings.json`, or +//! `~/.config/wai/quantum-timings.json`, the last 32 runs of each method. +//! Nothing is sent anywhere. +//! +//! A reading here is never sealed as a run's energy. A process read while it +//! runs is a lower bound by its threads' time slices still on a core, and the +//! packages count every process on them, so neither is the complete reading of +//! one job a receipt's figure is (the job service's, of a worker read once it +//! has exited). A result here still says it is unmetered. What the planner +//! holds a ceiling to is an estimate, labelled so, with what it rests on; a +//! method with fewer than three metered runs here has none, and a route on it +//! is refused for its energy, with why. + +use serde_json::{Map, Value, json}; +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; +use std::time::Instant; +use wai_quantum::engine::catalog::Plan; +use wai_quantum::engine::energy::{self, Estimate, TIMINGS, Timing}; + +/// The file's form. +pub const SCHEMA: &str = "wai.quantum.timings/1"; +/// Whose timings an estimate rests on, in its words. +const HOST: &str = "this command line"; +/// A limit on a run whose time is not known: the command line sets none, and +/// shows no estimate's time, only its energy to the planner; 0 says there is none. +const AT_MOST_S: u64 = 0; + +/// Where the timings are kept. +pub fn path() -> Option { + if let Some(p) = std::env::var_os("WAI_QUANTUM_TIMINGS").filter(|p| !p.is_empty()) { + return Some(PathBuf::from(p)); + } + let base = std::env::var_os("XDG_CONFIG_HOME").map(PathBuf::from).or_else(|| std::env::var_os("HOME").map(|h| Path::new(&h).join(".config")))?; + Some(base.join("wai").join("quantum-timings.json")) +} + +/// This command line's timings of each method here. +#[derive(Debug, Default)] +pub struct Book { + path: Option, + runs: BTreeMap>, +} + +fn timing_of(v: &Value) -> Option { + Some(Timing { + work: v["work"].as_u64()?, + elapsed_ms: v["elapsed_ms"].as_u64()?, + watts: v["watts"].as_f64().filter(|w| w.is_finite() && *w > 0.0), + }) +} + +impl Book { + /// The timings at [`path`]; none where the file is missing or not of its form. + pub fn load() -> Book { + Book::at(path()) + } + + /// The timings at `path`. + pub fn at(path: Option) -> Book { + let v = path.as_deref().and_then(|p| std::fs::read_to_string(p).ok()).and_then(|t| serde_json::from_str::(&t).ok()).filter(|v| v["schema"] == SCHEMA); + let mut runs = BTreeMap::new(); + for (method, list) in v.as_ref().and_then(|v| v["methods"].as_object()).into_iter().flatten() { + let mut kept: Vec = list.as_array().into_iter().flatten().filter_map(timing_of).collect(); + let over = kept.len().saturating_sub(TIMINGS); + kept.drain(..over); + runs.insert(method.clone(), kept); + } + Book { path, runs } + } + + /// What this command line estimates of `plan` before it runs: the engine's + /// estimate from its timings of the plan's method here. + pub fn estimate(&self, plan: &Plan) -> Estimate { + let mine = self.runs.get(&plan.method).map_or(&[][..], Vec::as_slice); + energy::estimate(plan, mine, HOST, unmetered().as_deref(), AT_MOST_S) + } + + /// The planner's view of [`Book::estimate`]: joules, or why there are none. + pub fn joules(&self, plan: &Plan) -> Result<(f64, String), String> { + self.estimate(plan).joules + } + + /// A run of `plan` here that took `elapsed_ms`, at `watts` where it was read: + /// kept, the oldest of its method dropped past [`TIMINGS`]. + pub fn record(&mut self, plan: &Plan, elapsed_ms: u64, watts: Option) { + let list = self.runs.entry(plan.method.clone()).or_default(); + list.push(Timing { work: plan.work, elapsed_ms, watts: watts.filter(|w| w.is_finite() && *w > 0.0) }); + let over = list.len().saturating_sub(TIMINGS); + list.drain(..over); + } + + /// Written back to its file, replacing it whole. + pub fn save(&self) -> Result<(), String> { + let Some(p) = &self.path else { return Ok(()) }; + let mut methods = Map::new(); + for (m, list) in &self.runs { + methods.insert(m.clone(), Value::Array(list.iter().map(|t| json!({ "work": t.work, "elapsed_ms": t.elapsed_ms, "watts": t.watts })).collect())); + } + let v = json!({ + "schema": SCHEMA, + "kept": "only on this machine; nothing is sent anywhere", + "about": "each method's last runs here, as the command line read them around each run: the basis of its energy estimates before a run, never a reading of any job", + "methods": methods, + }); + if let Some(d) = p.parent().filter(|d| !d.as_os_str().is_empty()) { + std::fs::create_dir_all(d).map_err(|e| format!("{}: {e}", d.display()))?; + } + let tmp = p.with_extension(format!("json.wai-quantum-{}", std::process::id())); + std::fs::write(&tmp, format!("{}\n", serde_json::to_string_pretty(&v).unwrap_or_default())).map_err(|e| format!("{}: {e}", tmp.display()))?; + std::fs::rename(&tmp, p).map_err(|e| { + let _ = std::fs::remove_file(&tmp); + format!("{}: {e}", p.display()) + }) + } +} + +/// Why this command line reads no energy counter here, where it reads none. +pub fn unmetered() -> Option { + if cfg!(target_os = "macos") { + return energy::own().is_none().then(|| "this process's CPU energy counter does not read here".to_string()); + } + if cfg!(target_os = "linux") { + return match energy::access_in(Path::new("/sys/class/powercap")) { + energy::Access::Readable => None, + a => Some(a.why().to_string()), + }; + } + Some("this command line reads no energy counter on this system".to_string()) +} + +/// What was read before a run. +enum Before { + Own(energy::Reading), + Packages(energy::Packages, energy::PackageSnapshot), + Nothing, +} + +/// A run being read: its start, and the counter as it stood. +pub struct Around { + began: Instant, + before: Before, +} + +impl Around { + /// The counter read now, before a run, where one reads. + pub fn begin() -> Around { + let before = if cfg!(target_os = "macos") { + energy::own().map_or(Before::Nothing, Before::Own) + } else if unmetered().is_none() { + match energy::Packages::open() { + Ok(p) => match p.read() { + Some(s) => Before::Packages(p, s), + None => Before::Nothing, + }, + Err(_) => Before::Nothing, + } + } else { + Before::Nothing + }; + Around { began: Instant::now(), before } + } + + /// The run's time, and its power where the counter was read on both sides. + pub fn end(self) -> (u64, Option) { + // This process's threads leave their cores, and their energy is counted. + if matches!(self.before, Before::Own(_)) { + std::thread::sleep(std::time::Duration::from_millis(5)); + } + let elapsed = self.began.elapsed(); + let seconds = elapsed.as_secs_f64(); + let joules = match &self.before { + Before::Own(b) => energy::own().map(|a| a.joules() - b.joules()), + Before::Packages(p, b) => p.read().and_then(|a| p.between(b, &a, 0)).map(|r| r.energy_uj as f64 / 1e6), + Before::Nothing => None, + }; + let watts = joules.filter(|j| *j > 0.0 && seconds > 0.0).map(|j| j / seconds); + (u64::try_from(elapsed.as_millis()).unwrap_or(u64::MAX), watts) + } +} + +/// `run` read around: its answer, and the power over it where the counter read +/// on both sides. +pub fn read_run(run: impl FnOnce() -> T) -> (T, Option) { + let around = Around::begin(); + let out = run(); + let (_, watts) = around.end(); + (out, watts) +} + +/// A job body run here, kept in the timings: its method and work as planned, +/// the engine's own time over it (as the job service keeps it), and `watts`. +pub fn keep(body: &Value, watts: Option) { + let (Some(method), Some(work), Some(elapsed_ms)) = (body["method"].as_str(), body.pointer("/estimate/work").and_then(Value::as_u64), body.pointer("/result/elapsed_ms").and_then(Value::as_u64)) else { return }; + let plan = Plan { method: method.to_string(), why: String::new(), memory_bytes: 0, work, qubits: 0, target: None }; + let mut book = Book::load(); + book.record(&plan, elapsed_ms, watts); + if let Err(e) = book.save() { + eprintln!("note: the timings this command line estimates from were not kept: {e}"); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn plan(method: &str, work: u64) -> Plan { + Plan { method: method.into(), why: String::new(), memory_bytes: 1, work, qubits: 2, target: None } + } + + /// A method's last runs are kept, the oldest dropped past 32, a power that is + /// no power is not one, and the file reads back as it was written. + #[test] + fn the_timings_keep_each_method_s_last_runs_and_read_back() { + let dir = std::env::temp_dir().join(format!("wai-quantum-timings-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + let file = dir.join("t.json"); + let mut b = Book::at(Some(file.clone())); + for i in 0..40 { + b.record(&plan("stabilizer", 1000 + i), 10, Some(2.0)); + } + b.record(&plan("exact", 5), 7, Some(f64::NAN)); + b.record(&plan("exact", 6), 7, Some(0.0)); + b.save().unwrap(); + let back = Book::at(Some(file)); + assert_eq!(back.runs["stabilizer"].len(), TIMINGS); + assert_eq!(back.runs["stabilizer"][0].work, 1008, "the oldest are dropped"); + assert_eq!(back.runs["exact"].iter().map(|t| t.watts).collect::>(), [None, None]); + let _ = std::fs::remove_dir_all(&dir); + } + + /// Three metered runs give an estimate, labelled one; fewer give none, with why. + #[test] + fn three_metered_runs_give_an_estimate_and_fewer_none() { + let mut b = Book::at(None); + let p = plan("stabilizer", 2_000_000); + for _ in 0..2 { + b.record(&p, 100, Some(10.0)); + } + let e = b.joules(&p).unwrap_err(); + assert!(e.contains("this command line has not yet metered three stabilizer jobs") || e.contains("does not meter"), "{e}"); + b.record(&p, 100, Some(10.0)); + // 2e6 work at the median rate 2e7 a second: 0.1 s at 10 W, whatever this + // host meters now: the estimate rests on the runs kept. + let (j, basis) = b.joules(&p).unwrap(); + assert_eq!(j, 1.0); + assert!(basis.starts_with("an estimate, never a reading") && !basis.contains("measured"), "{basis}"); + assert_eq!(b.estimate(&p).energy["energy_provenance"], "Estimator"); + } +} diff --git a/wai/wai-quantum-cli/src/main.rs b/wai/wai-quantum-cli/src/main.rs index e8daa93e0..adca884de 100644 --- a/wai/wai-quantum-cli/src/main.rs +++ b/wai/wai-quantum-cli/src/main.rs @@ -90,6 +90,7 @@ mod converge; mod dap; mod debug; mod estimate; +mod estimates; mod eval; mod discover; mod guide; @@ -568,7 +569,7 @@ struct Job { /// When the run must be done by, in seconds: a route whose time is not known does not meet it, and the receipt says whether it was kept (exit 4 when it was not) #[arg(long = "deadline", value_name = "SECONDS")] deadline: Option, - /// The most energy the run may take, in joules: a route whose energy is not known does not meet it, and this command estimates none, so here every route is refused; the job service estimates from what it has metered + /// The most energy the run may take, in joules, held to an estimate before it runs: a method's median power over its last three or more runs read here, over the run's estimated time (the job service's estimate, from this command line's own runs; never a reading of this one, which is not sealed). A method with fewer than three runs read here has no estimate, and a route on it is refused, with why #[arg(long, value_name = "JOULES")] max_joules: Option, /// Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods here: each is asked to estimate the job, and nothing is sent unless one is chosen. A device is chosen only when --exactness measured or any asks for its class. On the job service, which reaches no provider, it changes nothing @@ -938,8 +939,10 @@ fn request(job: &Job, qasm: String) -> Value { r } -/// What a result says of its energy: the command line does not meter a run. -pub(crate) const UNMETERED: &str = "the command line does not meter a run's energy"; +/// What a result says of its energy: the command line seals no reading of a +/// run (one read in its own process is never complete), and keeps what it reads +/// only to estimate later runs from (estimates). +pub(crate) const UNMETERED: &str = "the command line seals no reading of a run's energy: a run in its own process cannot be read completely, so what it reads around a run is kept only to estimate later runs from"; /// The exit status of a run that kept not all its contract asked: a deadline, a /// ceiling on energy or on cost, as the result states. Its answer is sealed. @@ -947,11 +950,20 @@ pub(crate) const CONTRACT_MISSED: i32 = 4; /// The job body `run` gives, as the service gives it: the request, the plan, /// and the result sealed with `key` ([`job::run`]). +/// A contract's `max_joules` is held to this command line's estimate of each +/// route's energy, from its own runs here (estimates); the run is read, and kept +/// to estimate from, never sealed. pub fn run_here(req: &Value, memory_gb: u64, key: &wai_quantum::ed25519_dalek::SigningKey) -> Result { if catalog::is_set(req) { return wai_quantum::engine::sets::run(req, memory_gb << 30, key, json!({ "unmetered": UNMETERED })); } - job::run(req, memory_gb << 30, key, json!({ "unmetered": UNMETERED })) + let book = estimates::Book::load(); + let joules = |p: &catalog::Plan| book.joules(p); + let (out, watts) = estimates::read_run(|| job::run_with(req, memory_gb << 30, key, json!({ "unmetered": UNMETERED }), Some(&joules))); + if let Ok(body) = &out { + estimates::keep(body, watts); + } + out } /// What is new in a circuit as a reader takes it in. @@ -1379,7 +1391,9 @@ fn main() { Command::Plan { job, json } if job.asks_a_contract() => { use wai_quantum::engine::{planner, refusal, registry::Registry}; let req = job_request(&job).unwrap_or_else(|e| die(&e)); - let c = planner::consider(Registry::builtins(), &req, &planner::Host::new(job.memory_gb << 30)).unwrap_or_else(|e| die(&e)); + let book = estimates::Book::load(); + let joules = |p: &catalog::Plan| book.joules(p); + let c = planner::consider(Registry::builtins(), &req, &planner::Host::new(job.memory_gb << 30).with_joules(&joules)).unwrap_or_else(|e| die(&e)); if json { let mut v = c.plan.as_ref().map_or_else(|| json!({}), |p| serde_json::to_value(p).unwrap_or(Value::Null)); if let Some(e) = &c.refusal { diff --git a/wai/wai-quantum-cli/src/mcp.rs b/wai/wai-quantum-cli/src/mcp.rs index d4010b45d..cbe668e01 100644 --- a/wai/wai-quantum-cli/src/mcp.rs +++ b/wai/wai-quantum-cli/src/mcp.rs @@ -597,7 +597,10 @@ fn call(name: &str, args: &Value, memory_gb: u64, key: &SigningKey, client: &Cli qasm()?; let req = with_target()?; if wai_quantum::engine::planner::has_contract(&req) { - return wai_quantum::engine::planner::plan_value(wai_quantum::engine::registry::Registry::builtins(), &req, memory_gb << 30); + let book = crate::estimates::Book::load(); + let joules = |p: &catalog::Plan| book.joules(p); + let host = wai_quantum::engine::planner::Host::new(memory_gb << 30).with_joules(&joules); + return wai_quantum::engine::planner::plan_value_on(wai_quantum::engine::registry::Registry::builtins(), &req, &host); } catalog::plan(&req, memory_gb << 30).map(|p| serde_json::to_value(p).unwrap_or(Value::Null)) } diff --git a/wai/wai-quantum-cli/src/providers.rs b/wai/wai-quantum-cli/src/providers.rs index cbb809d8b..ec0550da2 100644 --- a/wai/wai-quantum-cli/src/providers.rs +++ b/wai/wai-quantum-cli/src/providers.rs @@ -310,7 +310,7 @@ pub fn plan(job: &Job, as_json: bool) { let req = job_request(job).unwrap_or_else(|e| die(&e)); let (reg, stores) = load(); let (open, closed) = targets(®, &stores, job.memory_gb << 30); - let routed = pjob::route_with(&open, closed, &req, job.memory_gb << 30).unwrap_or_else(|e| die(&e.to_string())); + let routed = pjob::route_with(&open, closed, &req, job.memory_gb << 30, Some(&|p: &wai_quantum::engine::catalog::Plan| crate::estimates::Book::load().joules(p))).unwrap_or_else(|e| die(&e.to_string())); if as_json { println!("{}", routed.json()); } else { @@ -323,7 +323,7 @@ fn run_routed(job: &Job, out: &Output, key: &KeyArgs, args: &RunArgs) { let req = job_request(job).unwrap_or_else(|e| die(&e)); let (reg, stores) = load(); let (open, closed) = targets(®, &stores, job.memory_gb << 30); - let routed = pjob::route_with(&open, closed, &req, job.memory_gb << 30).unwrap_or_else(|e| die(&e.to_string())); + let routed = pjob::route_with(&open, closed, &req, job.memory_gb << 30, Some(&|p: &wai_quantum::engine::catalog::Plan| crate::estimates::Book::load().joules(p))).unwrap_or_else(|e| die(&e.to_string())); if args.dry_run { if out.json { println!("{}", routed.json()); @@ -334,7 +334,9 @@ fn run_routed(job: &Job, out: &Output, key: &KeyArgs, args: &RunArgs) { } let k = load_key(key); let Some(name) = routed.provider().map(str::to_string) else { - let body = pjob::run_routed_here(&routed, &req, &k.key, json!({ "unmetered": crate::UNMETERED })).unwrap_or_else(|e| die(&e.to_string())); + let (body, watts) = crate::estimates::read_run(|| pjob::run_routed_here(&routed, &req, &k.key, json!({ "unmetered": crate::UNMETERED }))); + let body = body.unwrap_or_else(|e| die(&e.to_string())); + crate::estimates::keep(&body, watts); if out.json { println!("{body}"); } else { @@ -850,12 +852,15 @@ pub fn mcp_call_with(name: &str, args: &Value, key: &SigningKey, reg: &Registry, "plan_routes" | "run_routed" => (|| { let req = mcp_routed(args)?; let (open, closed) = targets(reg, stores, crate::DEFAULT_MEMORY_GB << 30); - let routed = pjob::route_with(&open, closed, &req, crate::DEFAULT_MEMORY_GB << 30).map_err(|e| e.to_string())?; + let routed = pjob::route_with(&open, closed, &req, crate::DEFAULT_MEMORY_GB << 30, Some(&|p: &wai_quantum::engine::catalog::Plan| crate::estimates::Book::load().joules(p))).map_err(|e| e.to_string())?; if name == "plan_routes" { return Ok(routed.json()); } let Some(chosen) = routed.provider() else { - return pjob::run_routed_here(&routed, &req, key, json!({ "unmetered": crate::UNMETERED })).map_err(|e| e.to_string()); + let (body, watts) = crate::estimates::read_run(|| pjob::run_routed_here(&routed, &req, key, json!({ "unmetered": crate::UNMETERED }))); + let body = body.map_err(|e| e.to_string())?; + crate::estimates::keep(&body, watts); + return Ok(body); }; let t = open.iter().find(|t| t.name == chosen).ok_or("internal: the planner chose a provider it was not given")?; let confirmed = args.get("confirm_cost") == Some(&Value::Bool(true)); diff --git a/wai/wai-quantum-cli/tests/estimates.rs b/wai/wai-quantum-cli/tests/estimates.rs new file mode 100644 index 000000000..d9be040ce --- /dev/null +++ b/wai/wai-quantum-cli/tests/estimates.rs @@ -0,0 +1,114 @@ +//! A contract's energy ceiling on the command line, held to its estimate before a +//! run: the job service's estimate, from this command line's own runs here. A +//! method with no runs to estimate from is refused for its energy, with why, and +//! a reading is never sealed. + +use serde_json::{Value, json}; +use std::path::{Path, PathBuf}; +use std::process::{Command, Output}; + +const BELL: &str = "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n"; + +struct Home(PathBuf); + +impl Home { + fn new(name: &str) -> Home { + let dir = std::env::temp_dir().join(format!("wai-quantum-estimates-{name}-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(&dir).unwrap(); + std::fs::write(dir.join("bell.qasm"), BELL).unwrap(); + Home(dir) + } + + fn timings(&self) -> PathBuf { + self.0.join("timings.json") + } + + fn run(&self, args: &[&str]) -> Output { + Command::new(env!("CARGO_BIN_EXE_wai-quantum")) + .args(args) + .current_dir(&self.0) + .env("HOME", &self.0) + .env("XDG_CONFIG_HOME", self.0.join("config")) + .env("WAI_QUANTUM_TIMINGS", self.timings()) + .env_remove("WAI_QUANTUM_KEY") + .env_remove("WAI_QUANTUM_PROVIDERS") + .output() + .unwrap() + } +} + +impl Drop for Home { + fn drop(&mut self) { + let _ = std::fs::remove_dir_all(&self.0); + } +} + +fn route<'a>(planner: &'a Value, name: &str) -> &'a Value { + planner["routes"].as_array().unwrap().iter().find(|r| r["route"] == name).unwrap_or_else(|| panic!("no {name}: {planner}")) +} + +fn seed(path: &Path, method: &str, runs: usize) { + let one = json!({ "work": 1_000_000, "elapsed_ms": 100, "watts": 10.0 }); + let v = json!({ "schema": "wai.quantum.timings/1", "methods": { method: vec![one; runs] } }); + std::fs::write(path, v.to_string()).unwrap(); +} + +#[test] +fn an_energy_ceiling_is_held_to_this_command_line_s_estimate_and_none_is_not_met() { + let h = Home::new("ceiling"); + // Three runs of the stabilizer read here, at 10 W and ten million work units a + // second, and none of any other method. + seed(&h.timings(), "stabilizer", 3); + let out = h.run(&["run", "bell.qasm", "--shots", "100", "--exactness", "exact", "--max-joules", "1", "--demo-key", "--json"]); + assert_eq!(out.status.code(), Some(0), "{}", String::from_utf8_lossy(&out.stderr)); + let body: Value = serde_json::from_slice(&out.stdout).unwrap(); + let p = &body["result"]["planner"]; + assert_eq!(p["choice"], "method:stabilizer", "{p}"); + let energy = &route(p, "method:stabilizer")["price"]["energy"]; + let joules = energy["joules"].as_f64().unwrap_or_else(|| panic!("{energy}")); + assert!(joules > 0.0 && joules <= 1.0, "{energy}"); + let basis = energy["basis"].as_str().unwrap(); + assert!(basis.starts_with("an estimate, never a reading") && basis.contains("median power") && !basis.contains("measured"), "{basis}"); + // A method with no runs to estimate from: refused for its energy, with why. + for m in ["method:exact", "method:statevector"] { + let r = route(p, m); + assert_eq!(r["rejected"]["code"], "energy_unknown", "{r}"); + assert!(r["price"]["energy"]["joules"].is_null() && r["rejected"]["why"].as_str().unwrap().contains("meter"), "{r}"); + } + // The run's own energy is not sealed: an estimate is not a reading. + assert!(body["result"]["energy"]["unmetered"].as_str().unwrap().contains("seals no reading"), "{}", body["result"]["energy"]); + assert!(body["result"]["energy"].get("joules_micro").is_none()); + assert!(body["result"]["planner"]["kept"]["energy"]["kept"].is_null(), "{}", body["result"]["planner"]["kept"]); + std::fs::write(h.0.join("job.json"), body.to_string()).unwrap(); + let v = h.run(&["verify", "job.json", "--json"]); + assert_eq!(v.status.code(), Some(0), "{}", String::from_utf8_lossy(&v.stdout)); + // The run is kept beside the three it was estimated from. + let kept: Value = serde_json::from_str(&std::fs::read_to_string(h.timings()).unwrap()).unwrap(); + assert_eq!(kept["methods"]["stabilizer"].as_array().unwrap().len(), 4, "{kept}"); + // A ceiling below the estimate is not met, and says by how much. + let out = h.run(&["run", "bell.qasm", "--shots", "100", "--exactness", "exact", "--max-joules", "1e-12", "--demo-key"]); + assert_eq!(out.status.code(), Some(1)); + let said = String::from_utf8_lossy(&out.stderr); + assert!(said.contains("[J071]") && said.contains("method:stabilizer: about") && said.contains("above the ceiling"), "{said}"); + // The plan states the same estimate, and sends and runs nothing. + let out = h.run(&["plan", "bell.qasm", "--shots", "100", "--exactness", "exact", "--max-joules", "1", "--json"]); + assert_eq!(out.status.code(), Some(0), "{}", String::from_utf8_lossy(&out.stderr)); + let plan: Value = serde_json::from_slice(&out.stdout).unwrap(); + assert_eq!(route(&plan["planner"], "method:stabilizer")["price"]["energy"]["joules"].as_f64(), Some(joules)); +} + +#[test] +fn with_fewer_than_three_runs_read_here_no_route_meets_an_energy_ceiling() { + let h = Home::new("none"); + seed(&h.timings(), "stabilizer", 2); + let out = h.run(&["run", "bell.qasm", "--shots", "100", "--max-joules", "1000", "--demo-key"]); + assert_eq!(out.status.code(), Some(1)); + let said = String::from_utf8_lossy(&out.stderr); + assert!(said.contains("[J071]") && said.contains("method:stabilizer: its energy is not known"), "{said}"); + // Without a ceiling, the same run runs, and is kept to estimate from. + let out = h.run(&["run", "bell.qasm", "--shots", "100", "--demo-key", "--json"]); + assert_eq!(out.status.code(), Some(0), "{}", String::from_utf8_lossy(&out.stderr)); + let kept: Value = serde_json::from_str(&std::fs::read_to_string(h.timings()).unwrap()).unwrap(); + assert_eq!(kept["methods"]["stabilizer"].as_array().unwrap().len(), 3, "{kept}"); +} diff --git a/wai/wai-quantum-qpu/src/job.rs b/wai/wai-quantum-qpu/src/job.rs index 4a0efc754..1e4a4b733 100644 --- a/wai/wai-quantum-qpu/src/job.rs +++ b/wai/wai-quantum-qpu/src/job.rs @@ -455,12 +455,13 @@ impl Routed { /// cannot run the job, or does not answer, is a route with why. The refusal, when /// no route meets the contract, comes back with its reasons. pub fn route(targets: &[Target], request: &Value, job_bytes: u64) -> Result { - route_with(targets, Vec::new(), request, job_bytes) + route_with(targets, Vec::new(), request, job_bytes, None) } -/// [`route`], with `also` among the routes: the providers a host could not open, -/// each with why. -pub fn route_with(targets: &[Target], also: Vec, request: &Value, job_bytes: u64) -> Result { +/// [`route`], with `also` among the routes (the providers a host could not +/// open, each with why), and the host's estimate of a local route's energy +/// before it runs, where it has one (engine::energy::estimate). +pub fn route_with(targets: &[Target], also: Vec, request: &Value, job_bytes: u64, joules: Option<&planner::Joules<'_>>) -> Result { let mut quotes = also; let mut plans = Vec::new(); for t in targets { @@ -473,7 +474,10 @@ pub fn route_with(targets: &[Target], also: Vec, request: &Value Err(e) => quotes.push(planner::Quote::cannot(t.name.clone(), e.to_string())), } } - let host = planner::Host::new(job_bytes).with_quotes(quotes); + let mut host = planner::Host::new(job_bytes).with_quotes(quotes); + if let Some(j) = joules { + host = host.with_joules(j); + } let d = planner::decide(Registry::builtins(), request, &host).map_err(JobError::Failed)?; if let planner::Choice::Provider(name) = &d.choice && let Some((_, p)) = plans.iter_mut().find(|(n, _)| n == name) diff --git a/wai/wai-quantum-service/src/http.rs b/wai/wai-quantum-service/src/http.rs index feacca700..e74da2ce0 100644 --- a/wai/wai-quantum-service/src/http.rs +++ b/wai/wai-quantum-service/src/http.rs @@ -300,11 +300,7 @@ pub(crate) fn plan_job(app: &App, request: &Value) -> Result<(catalog::Plan, Wor /// What the service estimates a plan's energy at, from what it has metered, or /// why it estimates none. fn joules_estimate(app: &App, p: &catalog::Plan) -> Result<(f64, String), String> { - let (_, e) = app.service.estimate(p); - match e["joules_micro_estimate"].as_u64() { - Some(u) => Ok((u as f64 / 1e6, e["basis"].as_str().unwrap_or("an estimate from what this service has metered").to_string())), - None => Err(e["unestimated"].as_str().unwrap_or("this service estimates none").to_string()), - } + app.service.estimated(p).joules } /// Plans and admits `request` for `who`: the job's id, or the refusal's diff --git a/wai/wai-quantum-service/src/jobs.rs b/wai/wai-quantum-service/src/jobs.rs index c6cc68092..2d4c58306 100644 --- a/wai/wai-quantum-service/src/jobs.rs +++ b/wai/wai-quantum-service/src/jobs.rs @@ -338,17 +338,9 @@ struct Client { submissions: VecDeque, } -/// One timed job of a method: its work, the time the engine took over it, -/// and its energy figure's power where it has one, for the dry run. -#[derive(Clone, Copy, Debug)] -struct Timing { - work: u64, - elapsed_ms: u64, - watts: Option, -} - -/// The timings a method keeps, at most. -const TIMINGS: usize = 32; +// One timed job of a method, and how many a method keeps: the engine's, which +// the command line's estimates share (engine::energy::estimate). +use wai_quantum::engine::energy::{TIMINGS, Timing}; /// What the service found in its store when it started. #[derive(Clone, Copy, Debug, Default)] @@ -881,44 +873,19 @@ impl Service { /// each labelled with its basis; and, where such jobs were metered, their /// median power over the estimated time, an estimate and never a reading. pub fn estimate(&self, plan: &Plan) -> (Value, Value) { - let t = self.timings.lock().unwrap(); - let mine: Vec = t.get(&plan.method).map(|q| q.iter().copied().collect()).unwrap_or_default(); - let median = |mut v: Vec| -> Option { - v.retain(|x| x.is_finite() && *x > 0.0); - if v.len() < 3 { - return None; - } - v.sort_by(f64::total_cmp); - Some(v[v.len() / 2]) + let e = self.estimated(plan); + (e.time, e.energy) + } + + /// [`Service::estimate`], with the energy as the planner holds a contract's + /// `max_joules` to it: the engine's one estimate, from this service's timings. + pub fn estimated(&self, plan: &Plan) -> wai_quantum::engine::energy::Estimate { + let mine: Vec = self.timings.lock().unwrap().get(&plan.method).map(|q| q.iter().copied().collect()).unwrap_or_default(); + let unmetered = match crate::energy::meter() { + crate::energy::Meter::Unmetered(why) => Some(why.as_str()), + _ => None, }; - let rates: Vec = mine.iter().filter(|x| x.elapsed_ms >= 5 && x.work > 0).map(|x| x.work as f64 / (x.elapsed_ms as f64 / 1e3)).collect(); - let n = rates.len(); - let (seconds, basis) = match (median(rates), wai_quantum::engine::catalog::nominal_rate(&plan.method)) { - (Some(rate), _) => (Some(plan.work as f64 / rate), format!("the median rate of the last {n} {} jobs this service timed", plan.method)), - (None, Some(rate)) => (Some(plan.work as f64 / rate), format!("the planner's nominal rate for {} ({rate:.1e} of its work units a second); this service has not yet timed three of its jobs", plan.method)), - (None, None) => (None, format!("the work the planner counts for {} does not predict its time, and this service has not yet timed three of its jobs", plan.method)), - }; - let time = match seconds { - Some(s) => json!({ "seconds": s, "basis": basis, "note": "an estimate: the run is bounded by the job's time limit, not by this" }), - None => json!({ "seconds": null, "why": basis, "at_most": self.config.job_timeout.as_secs() }), - }; - let powers: Vec = mine.iter().filter_map(|x| x.watts).collect(); - let k = powers.len(); - let energy = match (median(powers), seconds) { - (Some(w), Some(s)) if (w * s * 1e6).round() < 1.0 => json!({ "unestimated": "the estimate is under a microjoule, below what a figure resolves" }), - (Some(w), Some(s)) => json!({ - "joules_micro_estimate": (w * s * 1e6).round() as u64, - "energy_provenance": "Estimator", - "basis": format!("the median power of the last {k} metered {} jobs here, over the estimated time", plan.method), - "note": "an estimate from past readings, never a reading of this job", - }), - _ => json!({ "unestimated": match crate::energy::meter() { - crate::energy::Meter::Unmetered(why) => format!("this host does not meter jobs ({why}), so there is nothing to estimate from"), - _ if seconds.is_none() => "no time estimate to take the power over".to_string(), - _ => format!("this service has not yet metered three {} jobs to estimate from", plan.method), - } }), - }; - (time, energy) + wai_quantum::engine::energy::estimate(plan, &mine, "this service", unmetered, self.config.job_timeout.as_secs()) } /// Drops finished jobs older than [`Config::retain`], their records, and diff --git a/wai/wai-quantum/src/engine/energy.rs b/wai/wai-quantum/src/engine/energy.rs index 0446f7ea6..b7d6ffb3d 100644 --- a/wai/wai-quantum/src/engine/energy.rs +++ b/wai/wai-quantum/src/engine/energy.rs @@ -49,6 +49,97 @@ use serde_json::{Value, json}; +// --------------------------------------------------------------------------- +// What a host estimates of a run before it runs +// --------------------------------------------------------------------------- + +/// One timed run of a method on a host: its work as the planner counts it, the +/// time the engine took over it, and the power over it where a reading gave +/// one. A host keeps these to estimate its next runs from ([`estimate`]): the +/// job service from the figures it seals, the command line from the readings +/// it takes around its own runs. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Timing { + pub work: u64, + pub elapsed_ms: u64, + /// Watts over the run, where it was read. + pub watts: Option, +} + +/// The timings a host keeps of one method, at most. +pub const TIMINGS: usize = 32; + +/// What a host estimates of a plan before it runs: its time and its energy as a +/// dry run states them, and the energy as the planner holds a contract's +/// `max_joules` to it (engine::planner). Always an estimate from past runs, +/// never a reading of this one: its provenance class is `Estimator`. +#[derive(Clone, Debug, PartialEq)] +pub struct Estimate { + pub time: Value, + pub energy: Value, + /// Joules and what they rest on, or why there are none. + pub joules: Result<(f64, String), String>, +} + +/// The middle of the positive, finite values among `v`, once there are three. +fn median(mut v: Vec) -> Option { + v.retain(|x| x.is_finite() && *x > 0.0); + if v.len() < 3 { + return None; + } + v.sort_by(f64::total_cmp); + Some(v[v.len() / 2]) +} + +/// `plan`'s time and energy before it runs, from `timed`, what `host` (`this +/// service`, `this command line`) timed of the plan's method here: its median +/// rate once three runs are timed, else the planner's nominal rate; and its +/// median power over that time once three runs were metered. `unmetered` is why +/// the host meters nothing, where it does not; `at_most_s` bounds a run whose +/// time is not known. One implementation for every host that estimates. +pub fn estimate(plan: &super::catalog::Plan, timed: &[Timing], host: &str, unmetered: Option<&str>, at_most_s: u64) -> Estimate { + let method = plan.method.as_str(); + let rates: Vec = timed.iter().filter(|x| x.elapsed_ms >= 5 && x.work > 0).map(|x| x.work as f64 / (x.elapsed_ms as f64 / 1e3)).collect(); + let n = rates.len(); + let (seconds, basis) = match (median(rates), super::catalog::nominal_rate(method)) { + (Some(rate), _) => (Some(plan.work as f64 / rate), format!("the median rate of the last {n} {method} jobs {host} timed")), + (None, Some(rate)) => (Some(plan.work as f64 / rate), format!("the planner's nominal rate for {method} ({rate:.1e} of its work units a second); {host} has not yet timed three of its jobs")), + (None, None) => (None, format!("the work the planner counts for {method} does not predict its time, and {host} has not yet timed three of its jobs")), + }; + let time = match seconds { + Some(s) => json!({ "seconds": s, "basis": basis, "note": "an estimate: the run is bounded by the job's time limit, not by this" }), + None => json!({ "seconds": null, "why": basis, "at_most": at_most_s }), + }; + let powers: Vec = timed.iter().filter_map(|x| x.watts).collect(); + let k = powers.len(); + let said = |w: f64| format!("the median power of the last {k} metered {method} jobs here ({w:.3} W), over the estimated time"); + let (energy, joules) = match (median(powers), seconds) { + (Some(w), Some(s)) if (w * s * 1e6).round() < 1.0 => ( + json!({ "unestimated": "the estimate is under a microjoule, below what a figure resolves" }), + // Under half a microjoule: at most one, and a ceiling is held to that. + Ok((1e-6, format!("an estimate, never a reading: at most a microjoule, from {}", said(w)))), + ), + (Some(w), Some(s)) => ( + json!({ + "joules_micro_estimate": (w * s * 1e6).round() as u64, + "energy_provenance": "Estimator", + "basis": said(w), + "note": "an estimate from past readings, never a reading of this job", + }), + Ok(((w * s * 1e6).round() / 1e6, format!("an estimate, never a reading: {}", said(w)))), + ), + _ => { + let why = match unmetered { + Some(why) => format!("this host does not meter jobs ({why}), so there is nothing to estimate from"), + None if seconds.is_none() => "no time estimate to take the power over".to_string(), + None => format!("{host} has not yet metered three {method} jobs to estimate from"), + }; + (json!({ "unestimated": why }), Err(why)) + } + }; + Estimate { time, energy, joules } +} + /// The least `joules_micro × relative_ppm` a hardware class may declare /// (energy-measurement §2.3): `⌈10⁶ × 0.5/√3⌉`. pub const RESOLUTION_FLOOR_UJ_PPM: u64 = 288_676; @@ -824,4 +915,38 @@ mod tests { assert!(after.energy_nj > before.energy_nj, "{before:?} {after:?}"); assert!(after.cpu_ns > before.cpu_ns && after.window_ns >= before.window_ns); } + + fn plan(method: &str, work: u64) -> super::super::catalog::Plan { + super::super::catalog::Plan { method: method.into(), why: String::new(), memory_bytes: 1, work, qubits: 2, target: None } + } + + /// One estimate for every host: its words name whose runs it rests on, three + /// metered runs give one labelled an estimate, fewer give none with why, and + /// one under a microjoule is held to a microjoule. + #[test] + fn a_host_s_estimate_rests_on_its_own_runs_and_says_whose() { + let p = plan("stabilizer", 2_000_000); + let run = |watts| Timing { work: 1_000_000, elapsed_ms: 100, watts }; + let none = estimate(&p, &[], "this command line", None, 5); + assert!(none.time["basis"].as_str().unwrap().contains("this command line has not yet timed three"), "{}", none.time); + assert_eq!(none.joules.unwrap_err(), "this command line has not yet metered three stabilizer jobs to estimate from"); + let unmetered = estimate(&p, &[run(None), run(None), run(None)], "this service", Some("no counter"), 5); + assert_eq!(unmetered.joules.unwrap_err(), "this host does not meter jobs (no counter), so there is nothing to estimate from"); + assert!(unmetered.time["basis"].as_str().unwrap().contains("this service timed"), "{}", unmetered.time); + // 2e6 work at 1e7 a second, 0.2 s at 10 W: 2 J, whatever the host meters now. + let three = estimate(&p, &[run(Some(10.0)), run(Some(10.0)), run(Some(10.0))], "this command line", Some("no counter"), 5); + assert_eq!(three.energy["joules_micro_estimate"], 2_000_000); + assert_eq!(three.energy["energy_provenance"], "Estimator"); + let (j, basis) = three.joules.unwrap(); + assert_eq!(j, 2.0); + assert!(basis.starts_with("an estimate, never a reading") && !basis.contains("measured"), "{basis}"); + // A tiny job: under half a microjoule is held to one, never to nothing. + // 1 work unit at 1e7 a second is 0.1 µs; at 0.1 W, 0.01 µJ. + let tiny = estimate(&plan("stabilizer", 1), &[run(Some(0.1)), run(Some(0.1)), run(Some(0.1))], "this service", None, 5); + assert!(tiny.energy.get("unestimated").is_some(), "{}", tiny.energy); + assert_eq!(tiny.joules.unwrap().0, 1e-6); + // A method whose time is not predicted has no energy to take over it. + let pauli = estimate(&plan("pauli", 10), &[run(Some(10.0)), run(Some(10.0))], "this service", None, 5); + assert_eq!((pauli.time["at_most"].as_u64(), pauli.joules.unwrap_err().as_str()), (Some(5), "no time estimate to take the power over")); + } } diff --git a/wai/wai-quantum/src/engine/job.rs b/wai/wai-quantum/src/engine/job.rs index 3638afc5a..c3c2029ed 100644 --- a/wai/wai-quantum/src/engine/job.rs +++ b/wai/wai-quantum/src/engine/job.rs @@ -12,7 +12,13 @@ use serde_json::{Value, json}; /// `energy` (the host's figure, or why it has none) inside the result, and /// the result sealed with `key`. pub fn run(request: &Value, job_bytes: u64, key: &SigningKey, energy: Value) -> Result { - let (plan, result) = plan_and_run(request, job_bytes)?; + run_with(request, job_bytes, key, energy, None) +} + +/// [`run`], on a host that estimates a plan's energy before it runs (`joules`, +/// engine::energy::estimate), so that a contract's `max_joules` is held to it. +pub fn run_with(request: &Value, job_bytes: u64, key: &SigningKey, energy: Value, joules: Option<&super::planner::Joules<'_>>) -> Result { + let (plan, result) = plan_and_run_with(request, job_bytes, joules)?; Ok(seal(request, &plan, result, key, energy)) } @@ -20,10 +26,19 @@ pub fn run(request: &Value, job_bytes: u64, key: &SigningKey, energy: Value) -> /// not yet sealed. A host that runs a job in a process of its own, away from /// its key, gives these back to be sealed ([`seal`]). pub fn plan_and_run(request: &Value, job_bytes: u64) -> Result<(catalog::Plan, Value), String> { + plan_and_run_with(request, job_bytes, None) +} + +/// [`plan_and_run`], with the host's energy estimate where it has one. +pub fn plan_and_run_with(request: &Value, job_bytes: u64, joules: Option<&super::planner::Joules<'_>>) -> Result<(catalog::Plan, Value), String> { exact_request(request)?; // A contract's reasoning travels with its result (engine::planner). if super::planner::has_contract(request) { - return super::planner::plan_and_run_in(super::registry::Registry::builtins(), request, &super::planner::Host::new(job_bytes)); + let mut host = super::planner::Host::new(job_bytes); + if let Some(j) = joules { + host = host.with_joules(j); + } + return super::planner::plan_and_run_in(super::registry::Registry::builtins(), request, &host); } let plan = catalog::plan(request, job_bytes)?; let result = super::run::run(request, &plan)?; diff --git a/wai/wai-quantum/src/engine/planner.rs b/wai/wai-quantum/src/engine/planner.rs index 301a98bc3..dc88806ae 100644 --- a/wai/wai-quantum/src/engine/planner.rs +++ b/wai/wai-quantum/src/engine/planner.rs @@ -883,7 +883,12 @@ pub(crate) fn plan_in(reg: &Registry, v: &Value, job_bytes: u64) -> Result Result { - let d = decide(reg, v, &Host::new(job_bytes))?; + plan_value_on(reg, v, &Host::new(job_bytes)) +} + +/// [`plan_value`] on `host`: its energy estimate, where it has one. +pub fn plan_value_on(reg: &Registry, v: &Value, host: &Host<'_>) -> Result { + let d = decide(reg, v, host)?; let Choice::Local(p) = d.choice else { return Err("internal: a provider chosen with none brought".to_string()) }; let mut o = serde_json::to_value(&p).map_err(|e| e.to_string())?; o["planner"] = d.reasoning; -- 2.54.0 (Apple Git-157) From 33c06b58307bab10dbb6c8a4802a95d5de0aecd3 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Fri, 6 Nov 2026 10:11:56 -0500 Subject: [PATCH 05/42] wai-quantum: the review's fixes to the planner under a contract (a working commit, before the corpus) Every finding of the review of #668, in the engine, both verifiers and the spec, each with a test that fails on the old rule. The corpus, the blessed tool lists and the proofs follow in the next commit. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/wai-quantum-cli.yml | 3 +- .github/workflows/wai-quantum-qpu.yml | 7 +- .github/workflows/wai-quantum-registry.yml | 11 +- ...06-wai-quantum-planner-under-a-contract.md | 42 +- wai/extensions/quantum-providers.md | 196 ++++-- wai/quantum-conformance/receipts/generate.py | 89 ++- .../receipts/jobs/cli-contract-auto.json | 2 +- .../receipts/jobs/cli-contract-bounded.json | 1 + .../jobs/cli-contract-fabric-cpu.json | 1 + .../receipts/jobs/cli-contract-local.json | 2 +- .../jobs/cli-contract-provider-priced.json | 2 +- .../receipts/jobs/cli-contract-pulse.json | 1 + .../jobs/cli-contract-routed-seed.json | 1 + .../receipts/jobs/cli-contract-routed.json | 2 +- .../receipts/jobs/cli-contract-target.json | 1 + .../jobs/scripted-contract-prx-circuits.json | 22 +- .../receipts/made.lock.json | 15 +- wai/quantum-conformance/receipts/make.sh | 16 +- .../tools/receipt_differential.py | 23 +- .../tools/receipt_verify.py | 599 ++++++++++++++---- wai/wai-quantum-cli/README.md | 2 +- wai/wai-quantum-cli/README.zh-CN.md | 2 +- .../schemas/local-tools.v1.json | 24 + wai/wai-quantum-cli/src/main.rs | 22 +- wai/wai-quantum-cli/src/mcp.rs | 4 +- wai/wai-quantum-cli/src/providers.rs | 45 +- wai/wai-quantum-cli/tests/providers.rs | 51 +- wai/wai-quantum-qpu/src/job.rs | 165 ++++- wai/wai-quantum-qpu/tests/clients.rs | 8 +- wai/wai-quantum/docs/job-refusals.md | 4 +- wai/wai-quantum/schemas/job-request.v1.json | 7 +- wai/wai-quantum/schemas/job-result.v1.json | 34 +- wai/wai-quantum/src/engine/planner.rs | 549 +++++++++++----- wai/wai-quantum/src/engine/planner/tests.rs | 288 ++++++++- wai/wai-quantum/src/engine/pulse.rs | 2 +- wai/wai-quantum/src/engine/refusal.rs | 4 +- wai/wai-quantum/src/quantum_cutrank.rs | 16 +- wai/wai-quantum/src/repro.rs | 2 +- 38 files changed, 1799 insertions(+), 466 deletions(-) create mode 100644 wai/quantum-conformance/receipts/jobs/cli-contract-bounded.json create mode 100644 wai/quantum-conformance/receipts/jobs/cli-contract-fabric-cpu.json create mode 100644 wai/quantum-conformance/receipts/jobs/cli-contract-pulse.json create mode 100644 wai/quantum-conformance/receipts/jobs/cli-contract-routed-seed.json create mode 100644 wai/quantum-conformance/receipts/jobs/cli-contract-target.json diff --git a/.github/workflows/wai-quantum-cli.yml b/.github/workflows/wai-quantum-cli.yml index 0216792d9..51e132f64 100644 --- a/.github/workflows/wai-quantum-cli.yml +++ b/.github/workflows/wai-quantum-cli.yml @@ -106,7 +106,8 @@ jobs: providers::tasks::tests::a_job_reads_as_its_task \ providers::tasks::tests::a_cancelled_request_ends_its_wait_and_a_change_wakes_it \ a_contract_weighs_every_route_and_its_receipt_says_why \ - an_agent_weighs_a_contract_and_runs_on_the_route_it_chooses; do + an_agent_weighs_a_contract_and_runs_on_the_route_it_chooses \ + tests::the_command_line_parses_as_documented; do grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/test.log" || { echo "::error::$t did not run and pass"; exit 1; } done # The model harness and the views in an agent's host, each test by name. diff --git a/.github/workflows/wai-quantum-qpu.yml b/.github/workflows/wai-quantum-qpu.yml index d9797212a..89f4ffde3 100644 --- a/.github/workflows/wai-quantum-qpu.yml +++ b/.github/workflows/wai-quantum-qpu.yml @@ -79,10 +79,10 @@ jobs: # tests never touch one but the macOS leg's own. export WAI_QUANTUM_CREDENTIALS=file cargo test --locked 2>&1 | tee "$RUNNER_TEMP/test.log" - # The library (81, the cloud-tasks client's 22 and a job under a contract's - # 5 among them), the clients against their contracts (16), and the providers + # The library (82, the cloud-tasks client's 22 and a job under a contract's + # 6 among them), the clients against their contracts (16), and the providers # end to end (12), each binary's count pinned. - for n in 81 16 12; do + for n in 82 16 12; do grep -qE "^test result: ok\. $n passed; 0 failed" "$RUNNER_TEMP/test.log" || { echo "::error::a test binary did not pass all $n of its tests"; exit 1; } done for t in curl_carries_a_request_to_a_server_and_back every_operation_over_http every_operation_over_a_local_process \ @@ -108,6 +108,7 @@ jobs: job::tests::a_contract_is_weighed_before_anything_is_sent job::tests::a_cost_ceiling_holds_the_estimate_and_is_no_confirmation \ job::tests::every_provider_is_weighed_against_the_engine_s_own_methods job::tests::a_shadow_and_its_reasoning_outlive_what_sent_the_job \ job::tests::a_deadline_it_cannot_be_held_to_is_refused_and_one_that_leaves_no_time_says_so \ + job::tests::a_job_past_its_deadline_is_cancelled_where_it_waits \ a_built_in_kind_runs_under_a_contract_and_a_classical_method_shadows_it a_cost_estimated_at_the_least_it_can_come_to_meets_no_ceiling; do grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/test.log" || { echo "::error::$t did not run and pass"; exit 1; } done diff --git a/.github/workflows/wai-quantum-registry.yml b/.github/workflows/wai-quantum-registry.yml index ed8a20cbb..269df4a80 100644 --- a/.github/workflows/wai-quantum-registry.yml +++ b/.github/workflows/wai-quantum-registry.yml @@ -110,7 +110,16 @@ jobs: engine::planner::tests::nothing_falls_back_from_exact_to_approximate \ engine::planner::tests::nothing_falls_back_between_a_simulator_and_a_device \ engine::planner::tests::every_rule_a_verifier_holds_a_local_contract_job_to_is_broken_once_and_found_alone \ - engine::planner::tests::every_rule_a_verifier_holds_a_provider_s_contract_job_to_is_broken_once_and_found_alone; do + engine::planner::tests::every_rule_a_verifier_holds_a_provider_s_contract_job_to_is_broken_once_and_found_alone \ + engine::planner::tests::a_shadow_is_a_method_s_run_of_exactly_the_job_s_program \ + engine::planner::tests::a_shadow_the_host_says_failed_is_run_again \ + engine::planner::tests::under_a_contract_a_provider_is_used_only_where_it_allows_one \ + engine::planner::tests::what_a_price_may_state_is_bounded_and_past_it_is_an_unknown \ + engine::planner::tests::a_local_route_is_free_and_kept_states_exactly_the_charge \ + engine::planner::tests::auto_is_what_the_routes_give_and_cannot_be_lowered \ + engine::planner::tests::a_device_target_s_job_names_its_method_beside_the_host_s_providers \ + engine::planner::tests::a_named_approximate_simulator_runs_under_a_contract_that_names_no_class \ + engine::planner::tests::the_sampling_bound_holds_for_sparse_and_dense_outcomes; do grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/engine.log" || { echo "::error::$t did not run"; exit 1; } done - name: The example, tested and run diff --git a/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md b/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md index ef9964191..db228e86b 100644 --- a/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md +++ b/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md @@ -3,7 +3,9 @@ - **A contract in the job request** (`contract`, [quantum-providers.md §8.6](extensions/quantum-providers.md)): the class wanted (`exactness`), a cost ceiling (`max_cost`, an amount in decimals and its currency), a deadline (`deadline_seconds`), an energy ceiling (`max_joules`) and whether a provider may be used (`providers`: `never`, the - default, or `allowed`). A job without one plans as it did, byte for byte. A contract that does not read is refused + default, or `allowed`). Under a contract a provider is used, asked for an estimate or named only where it allows one: + a provider named under one that does not is refused (`J070`). The ceiling bounds the estimate a route is chosen by, + not what is charged after. A job without a contract plans as it did, byte for byte. A contract that does not read is refused (`J070`), member by member, rather than read as absent; a set refuses one (`J073`). - **The planner** (`engine::planner`) lists every route the host can see: each method here, and each of the person's providers a host brings. It prices each with what is known: a method's memory and work as the planner counts them, its @@ -14,24 +16,38 @@ that is only the least a job can come to (`cost_at_least`), nor an energy nobody estimates. Nothing falls back, from exact to approximate or between a simulator and a device. With no route left, the job is refused with every route's reason (`J071`). A contract that names no class keeps `auto`'s pick while it meets the rest, and only a route at least - as exact may take its place. + as exact may take its place. A price states at most 10^12 seconds and an amount of at most 64 characters; past + either, the host states it unknown. Routes are ordered by money (free first, then amounts by value), then time to the + nearest millisecond, then a method here before a provider, then memory and name: a total order, the same in both + verifiers. - **The reasoning is sealed** in the result as `planner` (`wai.quantum.planner/1`): every route, its price or why it was - rejected, the choice, what is the same on every host (`stable`: a digest of what the host-independent routes cost, - pinned by a test on x86_64 and arm64), and what the contract kept against what happened (`kept`: the deadline, the - energy and the charge). Both verifiers recompute each route's outcome and the choice from what the receipt states, - and give eight new reasons (`contract_form`, `planner_form`, `planner_route`, `planner_choice`, `planner_stable`, - `planner_kept`, `contract_class`, `shadow`). The corpus gains five made receipts under a contract and thirty-six - crafted ones, and three plants prove the differential sees a route, a choice and a distance taken as they stand. + rejected, what the job names, the question it asks and each method's rank in `auto`'s order, so that `auto` is + recomputed rather than taken on the host's word, the choice, what is the same on every host (`stable`: a digest of + what the host-independent routes cost, pinned by a test on x86_64 and arm64, cut-rank's anneal now on the engine's + own exp and ln so that its plan is the same bits everywhere), and what the contract kept against what happened + (`kept`: the deadline, the energy, and the charge, which is the result's). Both verifiers recompute each route's + outcome and the choice from what the receipt states, and give nine new reasons (`contract_form`, + `contract_provider`, `planner_form`, `planner_route`, `planner_choice`, `planner_stable`, `planner_kept`, + `contract_class`, `shadow`); the differential holds them to the same choice, class, kept and shadow distance, not + only the same reasons. The corpus gains MADE_COUNT made receipts under a contract and CRAFTED_COUNT crafted ones, + each of the review's single-rule changes to the second verifier is found by them, and three plants prove the + differential sees a route, a choice and a distance taken as they stand. - **A provider's answer is shadowed.** When a provider answers a contract job, the most exact classical method that can reach the same counts within the time the contract leaves runs too, on a seed of its own, and the result carries both - with their distance (total variation exactly, as whole numbers; Hellinger fidelity; what the shots alone would - leave). Where none can, the result says which tried and why. `wai-quantum verify --recheck` prices the routes again - and runs the shadow again. + with their distance (total variation exactly, as whole numbers; Hellinger fidelity; and `sampling_tvd_bound`, a + bound on what the shots alone would leave that holds for sparse outcomes as for dense ones). A shadow is a method's + run of exactly the job's program, shots and a seed of its own, with no other member; its counts are whole and sum to + its shots. Where none can run, the result says which tried and why. `wai-quantum verify --recheck` prices the routes + again, checks `auto`, and runs the shadow again, a shadow the host says failed among them. - **Every host seals only what its verifier accepts.** A result short of the class its reasoning wants gives no answer (`J072`), and each host checks a contract job's reasoning before it seals it. A run past its contract's deadline on the - job service is stopped (`J074`). + job service is stopped, and the command line cancels a provider's job still waiting at it (`J074`). A deadline holds + a method's own run time, and a provider's from submission to its counts. - **Surfaces.** `wai-quantum run` and `plan` take `--exactness`, `--max-cost`, `--deadline`, `--max-joules`, - `--allow-providers` and `--contract`; a run that kept less than it asked exits 4. The local MCP server gains + `--allow-providers` and `--contract`; `--deadline` and `--max-joules` take a finite number above 0; a run that kept + less than it asked exits 4. A run the planner routes to a provider that is not free is confirmed by `--confirm WORD` + (`confirm` for an agent), the word its dry run gives for that route, its estimate and its program, and is refused + if any has changed; `--yes` confirms only a provider the person names. The local MCP server gains `plan_routes` and `run_routed`, which weigh the person's providers beside the methods here; the engine's run and plan tools take a contract and reach no provider. The free job service takes a contract, lists no provider among its routes, holds `max_joules` to what it has metered, and keeps a queued job's reasoning across a restart. diff --git a/wai/extensions/quantum-providers.md b/wai/extensions/quantum-providers.md index 5c53c713e..1c3e8deeb 100644 --- a/wai/extensions/quantum-providers.md +++ b/wai/extensions/quantum-providers.md @@ -640,10 +640,10 @@ it did before this section was written, byte for byte. | member | | |---|---| | `exactness` | the class wanted: a string of the table below | -| `max_cost` | the most it may cost: an object of exactly `amount`, an amount in decimals (one or more digits, optionally `.` and one or more digits), and `currency`, a string not empty | -| `deadline_seconds` | a number above 0: when it must be done by, in seconds | -| `max_joules` | a number above 0: the most energy it may take, in joules | -| `providers` | `never`, the default, or `allowed`: whether a route may be one of the person's providers. A request that names a `provider` under `never` is refused | +| `max_cost` | the most a provider's estimate of the run may come to, before it runs: an object of exactly `amount`, an amount in decimals (one or more digits, optionally `.` and one or more digits, at most 64 characters in all), and `currency`, a string not empty. It bounds the estimate, not the charge, which no one knows before the run: what was charged is stated after it, beside the ceiling (`kept.cost`) | +| `deadline_seconds` | a number above 0: when it must be done by, in seconds, as below | +| `max_joules` | a number above 0: the most energy a host's estimate of the run before it runs may come to, in joules; what it took, where the host reads it, is stated after it (`kept.energy`) | +| `providers` | `never` or `allowed`: whether a route may be one of the person's providers. `never` is the default, given or not, and a request that names a `provider` under a contract that does not allow one is refused (`J070`) | A contract of any other form is refused (`J070`). So is any other member, which read as absent would be a requirement dropped in silence. @@ -665,13 +665,26 @@ read as absent would be a requirement dropped in silence. This is a table and not a ladder: `single` states no bound, so it does not meet `bounded`, and a device's counts are in no classical class. +**What a deadline measures.** For a run of one of the engine's methods, the time +the engine took over the run itself (the result's `elapsed_ms`): not the queue, the +planning, a restart before it, the check of its intents, nor the sealing. For a +provider's run, the time from the job's submission to the moment the host first +finds it finished: the provider's queue and its run count, and a host that comes +back to a job late (one sent without waiting, collected later) counts the wait +too, so its `elapsed_ms` can only overstate. A shadow is not counted: it runs in +what the deadline leaves, or not at all. A host that can stop a run stops it at +its deadline: the job service stops its worker, and the command line cancels a +provider's job still waiting there; nothing is sealed (`J074`). + **The reasoning.** `planner` is an object of: | member | | |---|---| | `format` | `wai.quantum.planner/1` | | `routes` | every route the host could see, an array with at least one member, each route's name once | -| `auto` | the route `auto` picks for this job, or `null`: the job names a provider or a method, or `auto` picks none | +| `named` | the route the job names, or `null`: as below | +| `question` | the question the job asks, as below: `noise`, `counts`, `expectations` or `amplitudes` | +| `auto` | the route `auto` picks for this job, or `null`, as below | | `wanted`, `wanted_from` | the class the routes are held to, and where it comes from, as below | | `host` | `job_bytes`, the memory one job may take on the host, a whole number; `providers`, the names of the providers it brought, an array of strings | | `choice` | the name of the route chosen: a route of `routes` | @@ -688,6 +701,7 @@ A route, an object of: | `kind` | `local` for a method, `provider` for a provider | | `class` | a string: the class its result has at worst. A method that declares one class has that one; one that declares several has the first of `bit-exact`, `exact`, `single`, `bounded`, `estimate` and `heuristic` that each of them meets (so `single` and `bounded` together are `heuristic`). A method that can be truncated says so: `mps` is `heuristic`, though a result that was not truncated says `exact`. A provider that cannot run the job is `unknown` | | `host_dependent` | `true` or `false`: whether the route depends on the host. A provider's, a method on a GPU (`statevector_single`, `cutrank_single`) and a method the host registered are | +| `auto_rank` | on a local route: its rank in `auto`'s order for the job's `question`, a whole number, or `null` where `auto` does not try it. A built-in method's is the table's below; a registered method's is the host's word | | `price` | `null`, or an object: below | | `outcome` | `chosen`, `met` or `rejected`. Exactly one route is `chosen`, and it is `choice` | | `rejected` | exactly when `outcome` is `rejected`: `code`, one of the codes below, and `why`, a sentence | @@ -700,44 +714,83 @@ A price, an object of: | member | | |---|---| -| `money` | `free`: `true`, or `false` with `amount` and `currency` (strings, the amount as the provider gives it, with an optional `unit`), or `false` with `unknown`, a sentence. An unknown cost is not free (§7). `at_least`, absent or `true`: the amount is the least the job can come to, and what it takes decides the rest | -| `time` | `seconds`, a number of at least 0 or `null`; with a number, `basis`: `nominal`, at the engine's rate for the method's work, or `provider`, the provider's own estimate, queue included; with `null`, `why` | +| `money` | `free`: `true`, or `false` with `amount` and `currency` (strings, the amount as the provider gives it, at most 64 characters, with an optional `unit`), or `false` with `unknown`, a sentence. An unknown cost is not free (§7). A local route's is `free` `true`: only a provider's costs. `at_least`, absent or `true`: the amount is the least the job can come to, and what it takes decides the rest | +| `time` | `seconds`, a number from 0 to 10^12 or `null`; with a number, `basis`: `nominal`, at the engine's rate for the method's work, or `provider`, the provider's own estimate, queue included; with `null`, `why`. A host takes a provider's estimate past 10^12 seconds, or an amount past 64 characters, as no estimate: `null` here, `unknown` there, with why | | `memory_bytes`, `work` | what a method takes, as whole numbers, a double past 2^53 − 1, or `null` on a provider's route | | `energy` | `joules`, a number or `null`; with a number, `basis`; with `null`, `why`. No provider states a job's energy before it runs, so a provider's is `null`, and a host that estimates no job's energy states `null` for every route | | `leaves_out` | what the price leaves out, an array of: `time`, it states no time; `amount`, it states no amount; `energy`, it states no energy; `mitigation`, what the provider's own mitigation costs or does, unless a client set it off or the device has none; `decoder`, any decoder's latency; `charged`, what the provider charges may differ from what it estimates | | `program` | on a provider's route, optional: the `shots`, `native_gates`, `two_qubit_gates` and `swaps` of what would be sent, and `expected_success` when a calibration states one | +**What is named.** `named` is `provider:` the request's `provider`, where it gives +a string; else `method:` its `method`, where that is a string other than `auto`; +else, for a request that names a device `target`, the one method that target's +noise takes, a local route of `routes` (the host's word: the engine's own choice +for a target); else `null`. + +**The question** a job asks is read from its request alone: `noise` when it has a +`noise` other than `null`; else `counts` when its shots are above 0 (its `shots`, +a whole number written as one from 0 to 2^64 − 1, or, where it gives none or +another, 1024 when it gives no non-empty `observables` and no non-empty +`amplitudes`, and 0 otherwise); else `expectations` when it gives non-empty +`observables` and no non-empty `amplitudes`; else `amplitudes`. + +**What `auto` picks** is read from the routes: `null` when `named` is not `null`; +for a request whose `fabric` is neither absent, `null`, `auto` nor `cpu`, +`method:statevector` where that route's `price` is not `null`, else `null`; +otherwise the local route whose `price` is not `null` and whose `auto_rank` is +least, the first in `routes` of equal ranks, or `null` when there is none. Each +built-in method's rank, by question: + +| method | noise | counts | expectations | amplitudes | +|---|---|---|---|---| +| `exact` | | 20 | 20 | 10 | +| `statevector` | | 30 | 30 | 20 | +| `statevector_single` | | 40 | 40 | 30 | +| `stabilizer` | 20 | 10 | 10 | | +| `pauli` | | | 60 | | +| `mps` | | 60 | 70 | 70 | +| `stabilizer_rank` | | | 50 | 50 | +| `tensor_network` | | | | 60 | +| `cutrank` | | 50 | | 40 | +| `cutrank_single`, `pulse` | | | | | +| `density_matrix` | 10 | | | | +| `trajectories` | 30 | | | | + +(an empty cell is `null`). So what `auto` picks is what a verifier finds: a host +cannot lower the class a job keeps by naming a weaker route `auto`'s. Whether a +route has a price is the host's word, held to what the engine gives by +`--recheck` (below). + **What is wanted.** `wanted` is the contract's `exactness` when it gives one, with `wanted_from` `contract`. When it gives none, the job keeps what it would -have had: when the request names a `provider`, or a `method` other than `auto`, or -`routes` holds one route (a program its method reads itself, a job on a device -target), `wanted` is the class of that route, with `wanted_from` `named`; otherwise -it is the class of `auto`'s route, with `wanted_from` `auto`; and when `auto` is -`null`, both are `null`. +have had: the class of the `named` route, with `wanted_from` `named`; when `named` +is `null`, the class of `auto`'s route, with `wanted_from` `auto`; and when `auto` +is `null` too, both are `null`. `named`, `question`, each built-in method's +`auto_rank`, `auto`, `wanted` and `wanted_from` must each be what these give. **Each route's outcome.** A verifier recomputes it from the request, the route and `host.job_bytes`, by these rules in this order: the first that applies is the route's `rejected.code`, and a route to which none applies is not rejected. -1. `not_named`: the request names a `provider` and this is not `provider:` that - name; or it names none, and names a method (a `method` other than `auto`, or - the one route of `routes`) and this is not `method:` that name. -2. `fabric`: the request names neither, and its `fabric` is neither absent, `null` - nor `auto`, and it is `cpu` and this is `method:statevector_single` or +1. `not_named`: `named` is not `null`, and this is not it. +2. `fabric`: `named` is `null`, and the request's `fabric` is neither absent, + `null` nor `auto`, and it is `cpu` and this is `method:statevector_single` or `method:cutrank_single`, or it is anything else and this is not `method:statevector`. 3. `cannot`: `class` is `unknown` and `price` is `null`. 4. `class`: `wanted` is not `null` and `class` does not meet it; or `wanted` is - `simulated` and `approximate` is `true`; or `wanted` is `null` and this is a - provider's route. + `simulated`, the contract names it (`wanted_from` `contract`), and `approximate` + is `true`; or `wanted` is `null` and this is a provider's route. A contract + that names no class changes nothing a job already meets: an approximate + simulator the job names keeps its place. 5. `cannot`: `price` is `null`. 6. `memory`: `memory_bytes` is above `host.job_bytes`. -7. `providers`: this is a provider's route, the request names no `provider`, and - `contract.providers` is not `allowed`. +7. `providers`: this is a provider's route, and `contract.providers` is not + `allowed`. 8. `deadline_unknown`, `deadline`: the contract gives `deadline_seconds`, and `time.seconds` is `null`, or above it. 9. For a provider's route whose `money.free` is not `true`: `cost_no_ceiling`, the - contract gives no `max_cost` and the request names no `provider`; + contract gives no `max_cost` and this is not the `named` route; `cost_unknown`, it gives one and `money` has no `amount` that is an amount in decimals, or no `currency`; `cost_currency`, the two currencies differ; `cost`, the amount is above `max_cost.amount`; `cost_at_least`, `money.at_least` @@ -753,19 +806,27 @@ So an unknown never passes where something is asked of it, and nothing falls bac not from exact to approximate, since a less exact route does not meet `wanted`; not from a simulator to a device or the reverse, since neither's class meets the other's. A cost ceiling confirms nothing: a run that is not free still needs the -person's word for that run (§7). If no route is left, the job is refused (`J071`) -with each route's reason, and there is no result to seal. +person's word for that run (§7). Where a host chose the provider (the request names +none), that word names what the person saw: a host gives the route, its +estimate's `money` and the program and shots it would send, as a short digest, and +sends the job only when the word it is given is that digest made again at send +time; a route, an estimate or a program that changed since is not sent. A host +asks no provider anything (an estimate's request carries the compiled program) +where the contract does not allow one, or wants a class no provider's counts are +in. If no route is left, the job is refused (`J071`) with each route's reason, and +there is no result to seal. **The choice.** Of the routes these rules let through, the job runs the one this picks, and `choice` names it: 1. when the contract gives no `exactness` and `auto`'s route is let through, it stands: a contract that names no class changes nothing a job already meets; -2. otherwise the least of them in this order: `money.free` `true` before not, and - then the lesser amount; a `time.seconds` before a `null`, and then the lesser - of each `seconds` × 1000 rounded up to a whole number; `local` before - `provider`; the lesser `memory_bytes`, a `null` read as 0; and the name, by its - UTF-8 bytes. +2. otherwise the least of them in this order: `money.free` `true` first, then an + `amount` in decimals (at most 64 characters), the lesser first, then any other; + a `time.seconds` before a `null`, and then the lesser of each `seconds` × 1000 + rounded to the nearest whole number, halves up (the floor of `seconds` × 1000 + + 0.5); `local` before `provider`; the lesser `memory_bytes`, a `null` read as 0; + and the name, by its UTF-8 bytes. `choice` must also be what ran: `method:` the result's `method`, or, when that is `provider`, `provider:` its `provider.name`. @@ -787,7 +848,8 @@ sentence; `routes`, the names of the routes whose `kind` is `local` and whose then the route chosen depends on nothing of the host. **`kept`** says what the contract asked, against what happened. It holds exactly a -member for each of these the contract gives. A result that missed one is still an +member for each of these the contract gives, each of exactly the members its row +names (`max_cost` of exactly `amount` and `currency`). A result that missed one is still an answer, and it says so: a `kept` of `false` breaks no rule. A host that can stop a run stops it at its deadline (`J074`), and seals nothing. @@ -795,11 +857,11 @@ run stops it at its deadline (`J074`), and seals nothing. |---|---| | `deadline` | `seconds`, the contract's; `elapsed_ms`, a whole number or `null`: the result's `elapsed_ms` by value when its `method` is not `provider` (`null` when it has none or it is not a number), and otherwise the host's time from the job's submission to its counts; `kept`, whether `elapsed_ms` ≤ `seconds` × 1000, or `null` when `elapsed_ms` is `null` | | `energy` | `max_joules`, the contract's; `joules`, the result's `energy.joules_micro` ÷ 10^6, or `null` when it has none; `kept`, whether `joules` ≤ `max_joules`, or `null` when `joules` is `null` | -| `cost` | `max_cost`, the contract's; `charged`, the result's `cost.charged`, or `null`; `kept`: with a `charged` in the ceiling's currency and an amount in decimals, whether it is at most the ceiling; with any other `charged`, `null`; with no `charged`, `true` when the result's `cost.free` is `true` or it has none, and otherwise `null` | +| `cost` | `max_cost`, the contract's; `charged`, equal to the result's `cost.charged` (numbers by value), or `null` when it has none; `kept`: with a `charged` in the ceiling's currency and an amount in decimals, whether it is at most the ceiling; with any other `charged`, `null`; with no `charged`, `true` when the result's `cost.free` is `true` or it has none, and otherwise `null` | **The class given.** The result's `accuracy.class` meets `wanted` when `wanted` is -not `null`, and a result whose `accuracy.approximate` is `true` does not meet -`simulated`. A route whose result falls short of `wanted`, whether the contract +not `null`, and a result whose `accuracy.approximate` is `true` does not meet a +`simulated` the contract names. A route whose result falls short of `wanted`, whether the contract named it or the job keeps what it would have had, gives no answer (`J072`): a host seals no result this rule refuses. @@ -808,25 +870,35 @@ reach the same counts within the contract runs too. `planner.shadow` says which, before anything runs, and the result's `shadow` carries what it gave. A shadow can be run again by anyone; it is the one part of a provider's result that can. -`planner.shadow` is an object with `route`, the name of the method, or `null`. With -a name: `class`; `budget_seconds`, what the contract leaves it, the deadline less -the provider's own time, or 300 seconds with no deadline; `price`; and `request`, -an object of `qasm`, the request's; `shots`, the result's; `seed`, the request's -`seed` (1 when it gives none) plus 2^32, modulo 2^53, a stream of its own so that a -seeded simulator's counts are not its counts by construction; and `method`, what -follows `method:` in `route`. With `null`: `code`, `budget`, `memory` or `none`; -`why`, a sentence; and optionally `tried`, each method's own. +`planner.shadow` is an object with `route`, a method's route `method:`, or +`null`. With a route, which `routes` lists: `class`, a class of `bit-exact`, `exact`, +`single`, `bounded`, `estimate` and `heuristic`, and the one `routes` gives that route; +`budget_seconds`, what the contract leaves it: the +deadline less the chosen route's `time.seconds`, and 0 when that is more, the +deadline where it is `null`, and 300 with no deadline; `price`, a local route's +price, whose `time.seconds` is a number at most `budget_seconds`; and `request`, +an object of exactly `qasm`, the request's (a string); `shots`, the result's +(by value); `seed`, the request's `seed` (a whole number written as one, from 0 to +2^64 − 1, and 1 when it gives none or another) plus 2^32, modulo 2^53, a stream of +its own so that a seeded simulator's counts are not its counts by construction; +and `method`, what follows `method:` in `route`. No other member: a noise model or +any option would make the shadow another program. With `null`: `code`, one of +`budget`, `memory` and `none`; `why`, a sentence; and optionally `tried`, an array, +each method's own. A result's `shadow` is one of: - `ran` `false`, with `code`, a string, and `why`, a sentence: when `planner.shadow` has no `route`, `code` is its `code`; otherwise `failed`, the method's run did not - complete. The provider's answer stands, alone, and says so. -- `ran` `true`, with `route` and `request`, equal to those of `planner.shadow` - (numbers by value); - `shots`, the result's; `accuracy`, an object whose `class` is a string; `counts`, - `distinct_outcomes` and `omitted_shots`, whose `counts` and `omitted_shots` sum to - the shots; optionally `elapsed_ms`; and `distance`. + complete. The provider's answer stands, alone, and says so; `--recheck` runs the + planned shadow, and a host whose failed shadow runs there is found. +- `ran` `true`, where `planner.shadow` has a route: with `route` and `request`, + equal to those of `planner.shadow` (numbers by value); `shots`, the result's; + `accuracy`, an object whose `class` is a string that meets `planner.shadow.class`; + `counts`, each a whole number written as one from 1 to 2^53 − 1, and + `omitted_shots`, a whole number of at least 0 by value, which sum exactly to the + result's `shots` (a whole number by value); `distinct_outcomes`, a whole number + of at least 0; optionally `elapsed_ms`; and `distance`. `distance` is an object. With `computed` `false`, it has `why`, and it is `false` only when the provider's or the shadow's `omitted_shots` is not 0 (by value: `0` @@ -840,15 +912,22 @@ the provider's and the shadow's count of each outcome k in either, S the result' - `total_variation`, `numerator` ÷ `denominator`; - `hellinger_fidelity`, R·R ÷ (S·S), with R the sum, in that order, of √(a_k × b_k), each count taken as a double and the product a double's; -- `sampling_tvd_expected`, 0.5·F, with F the sum, in that order, of - √(4·p·(1 − p) ÷ (π·S)) and p = (a_k + b_k) ÷ (2·S), the sum exact and then taken - as a double: what these shots alone would leave between two samples of one - distribution, on average. +- `sampling_tvd_bound`, the lesser of 1 and 0.5·F ÷ S, with F the sum, in that + order, of m(a_k + b_k): a bound on the total variation these shots alone would + leave between two samples of one distribution, on average, for every number of + outcomes and shots. m(n) is what a fair coin's split of n leaves between its two + sides on average, E|2B − n| with B binomial (n, ½): 0 for n = 0; for n = 2j + 1 + or 2j + 2 with j < 4096, the product, from 1 and in that order, of (2i + 3) ÷ + (2i + 2) for i from 0 to j − 1; and from j = 4096, (2j + 1) × c with c = (1 − + 1 ÷ (8j) + 1 ÷ (128·j·j) + 5 ÷ (1024·j·j·j)) ÷ √(π·j), each term as written. Given + how many shots of each outcome the two lists hold together, two lists of S shots + each split them at least as tightly as the coin does, so F ÷ 2S is at least the + expected total variation. A count is a whole number written as one (no fraction, no exponent) from 0 to -2^64 − 1, and 0 when it is anything else or absent. S of 0, or a p that leaves -4·p·(1 − p) below 0, gives no distance, and a `distance` that states one then does -not hold. Each double is IEEE 754, rounded to nearest, computed in the order +2^64 − 1, and 0 when it is anything else or absent. S of 0, or counts that sum to +more than 2·S, gives no distance, and a `distance` that states one then does not +hold. Each double is IEEE 754, rounded to nearest, computed in the order written, so that every verifier gets the same bits. **Reasons.** A verifier reports each of these that applies, beside those of §8.4: @@ -856,21 +935,22 @@ written, so that every verifier gets the same bits. | reason | when | |---|---| | `contract_form` | the request's `contract` is not of its form. Of §8.6, reported alone | -| `planner_form` | a contract job's result has no `planner`, or one not of the form above: `format`, `routes` and each route's members, `auto` and `choice` each naming a route of `routes`, `host`, `why`, `stable` and `kept` an object, each present; or `wanted` and `wanted_from` are not what the request and the routes give. Or a result with no contract carries a `planner`. Reported alone of §8.6 when the contract job has none | +| `contract_provider` | the request names a `provider` and its contract's `providers` is not `allowed` | +| `planner_form` | a contract job's result has no `planner`, or one not of the form above: `format`, `routes` and each route's members (a local route's `auto_rank`, its money free, every `seconds` and amount within its bounds), `named`, `auto` and `choice` each naming a route of `routes` or `null` (`choice` a route), `question`, `host`, `why`, `stable` and `kept` an object, each present; or `named`, `question`, a built-in method's `auto_rank`, `auto`, `wanted` or `wanted_from` is not what the request and the routes give. Or a result with no contract carries a `planner`. Reported alone of §8.6, beside `contract_provider` | | `planner_route` | a route's `rejected.code` is not what the rules above give it (or it is rejected when they let it through, or not when they do not), or the route `chosen` is not one and `choice` | | `planner_choice` | `choice` is not the route the choice's rules pick from those the rules let through, whatever their `outcome` says; or it is not what ran | | `planner_stable` | `stable.routes`, `digest` or `choice` is not what the routes give | | `planner_kept` | `kept` does not hold exactly a member for each the contract gives, or any of those members is not what the table gives | | `contract_class` | the result's class does not meet `wanted` | -| `shadow` | `planner.shadow` or the result's `shadow` is missing when `choice` is a provider's, or present when it is not; or the result's `shadow` is not of its form above, its `request` is not what `planner.shadow` gives and the request and result imply, its `distance` is not what its counts give. Or a result with no contract carries a `shadow` | +| `shadow` | `planner.shadow` or the result's `shadow` is missing when `choice` is a provider's, or present when it is not; or `planner.shadow` is not of its form above (its route, class, budget, price and request), or the result's `shadow` is not of its form, its `request` is not what `planner.shadow` gives, its counts do not sum to the shots, its class does not meet the plan's, or its `distance` is not what its counts give. Or a result with no contract carries a `shadow` | A verifier also states, for a contract job, its `choice`, `wanted`, the class given, `stable.choice`, `kept`, whether its shadow ran, and its `total_variation`. A price is the host's word, as everything it says it received, sent and checked is (§8.5): what a verifier recomputes is what follows from it. A verifier that holds the engine can price the routes again and run the shadow again -(`wai-quantum verify --recheck`), which holds `digest` and the shadow's counts to -what a run here gives. +(`wai-quantum verify --recheck`), which holds `digest`, `auto` and the shadow's +counts to what a run here gives, and runs a shadow the host says failed. The free job service reaches no provider. It lists none among its routes, a contract that wants a device's class is refused there (`J071`), and a request that diff --git a/wai/quantum-conformance/receipts/generate.py b/wai/quantum-conformance/receipts/generate.py index fb0052770..6fc2701e9 100644 --- a/wai/quantum-conformance/receipts/generate.py +++ b/wai/quantum-conformance/receipts/generate.py @@ -658,13 +658,88 @@ def contract_cases(run, at, drop): add("providers-not-allowed", edited(routed, drop(("request", "contract", "providers"))), ["planner_choice", "planner_route", "request_provider"], "a provider's answer to a contract that does not allow one") add("at-least-false", edited(routed, route("provider:priced", lambda r: r["price"]["money"].update(at_least=False))), ["planner_form"], "at_least given and not true") add("at-least-claimed", edited(named, route("provider:priced", lambda r: r["price"]["money"].update(at_least=True))), ["planner_choice", "planner_route"], "a cost that is the least it can come to, under the ceiling, said to meet it") - add("charged-over", edited(named, at(R + ("cost", "charged", "amount"), "1.5")), ["planner_kept"], "charged past the ceiling, and kept said to hold") - - def over(b): + def charged_over(b): b["result"]["cost"]["charged"]["amount"] = "1.5" b["result"]["planner"]["kept"]["cost"]["charged"]["amount"] = "1.5" + add("charged-over", edited(named, charged_over), ["planner_kept"], "charged past the ceiling, and kept said to hold") + + def over(b): + charged_over(b) b["result"]["planner"]["kept"]["cost"]["kept"] = False add("charged-over-stated", edited(named, over), [], "charged past the ceiling, and said so: valid") + add("kept-charged-other", edited(named, at(P + ("kept", "cost", "charged", "amount"), "0.01")), ["planner_kept"], "kept stating a charge that is not the result's: within the ceiling, and not what was charged") + add("kept-member-extra", edited(local, at(P + ("kept", "deadline", "note"), "on time")), ["planner_kept"], "a member of kept that its table does not give") + add("kept-elapsed-other", edited(local, lambda b: b["result"]["planner"]["kept"]["deadline"].update(elapsed_ms=b["result"]["elapsed_ms"] + 1)), ["planner_kept"], "a method's time in kept that is not the run's own elapsed_ms, within the deadline all the same") + + # --- what the job names, the question it asks, and what auto picks (review: auto verifiable) + add("auto-other", edited(auto, at(P + ("auto",), "method:statevector")), ["planner_form"], "auto said to pick a route the ranks do not") + add("auto-rank-lowered", edited(auto, route("method:statevector", lambda r: r.update(auto_rank=5))), ["planner_form"], "a route's rank in auto's order lowered, so that auto would pick it") + add("auto-rank-missing", edited(auto, route("method:statevector", lambda r: r.pop("auto_rank"))), ["planner_form"], "a local route without its rank in auto's order") + add("question-other", edited(auto, at(P + ("question",), "amplitudes")), ["planner_form"], "a question the request does not ask") + add("named-other", edited(named, at(P + ("named",), None)), ["planner_form"], "a provider the request names, said to be named by nothing") + # --- a provider under a contract (review: providers default to never, J070) + add("provider-named-not-allowed", edited(named, drop(("request", "contract", "providers"))), ["contract_provider", "planner_choice", "planner_route"], "a provider named under a contract that does not allow one: never is the default") + add("named-approximate", edited(named, route("provider:priced", lambda r: r.update(approximate=True))), [], "a provider named, its simulator stated approximate, under a contract that names no class: it keeps the named route's class, and the rule against an approximate simulator holds only a class the contract names") + add("approximate-rejected", edited(routed, route("provider:priced", lambda r: (r.update(approximate=True), r["rejected"].update(code="class")))), [], "a simulator stated approximate, where the contract wants simulated: rejected for its class, before its cost is weighed") + # --- the bounds of a price (review: seconds and amounts a verifier reads whole) + add("price-seconds-past", edited(routed, route("provider:priced", lambda r: r["price"]["time"].update(seconds=1e13))), ["planner_form"], "a time past 10^12 seconds, which a host states as unknown") + add("price-amount-long", edited(routed, route("provider:priced", lambda r: r["price"]["money"].update(amount="1" * 65))), ["planner_form"], "an amount of 65 characters, which a host states as unknown") + add("local-money", edited(local, route("method:statevector", lambda r: r["price"].update(money={"free": False, "amount": "0", "currency": "USD"}))), ["planner_form"], "a method here priced in money: a local route is free") + # --- the rules' edges, each a route's code the rule gives it + sv_bytes = lambda b: b["result"]["planner"]["host"]["job_bytes"] + add("memory-at-cap", edited(local, lambda b: route("method:statevector", lambda r: r["price"].update(memory_bytes=sv_bytes(b)))(b)), ["planner_stable"], "a route that needs exactly the job's memory meets it; the digest covers memory, and is not the routes' now") + + def unknown_time(r): + r["price"]["time"] = {"seconds": None, "why": "said unknown"} + r["outcome"] = "rejected" + r["rejected"] = {"code": "deadline_unknown", "why": "its time is not known, and the contract gives a deadline"} + add("deadline-unknown", edited(local, route("method:cutrank", unknown_time)), ["planner_stable"], "a route whose time is unknown under a deadline, rejected for it; the digest covers the time, and is not the routes' now") + + def currency(b): + b["request"]["contract"]["max_cost"]["currency"] = "EUR" + add("currency-other", edited(named, currency), ["planner_choice", "planner_kept", "planner_route"], "a ceiling in another currency than the estimate's: no route meets it, and kept states another ceiling") + + def joules(b): + b["request"]["contract"]["max_joules"] = 2 + for r in b["result"]["planner"]["routes"]: + if r["price"] is not None: + r["price"]["energy"] = {"joules": 1.5, "basis": "a host's estimate"} + b["result"]["energy"] = {"joules_micro": 2000000} + b["result"]["planner"]["kept"]["energy"] = {"max_joules": 2, "joules": 2, "kept": True} + b["result"]["planner"]["stable"]["choice"] = False + add("energy-at-ceiling", edited(local, joules), [], "an energy ceiling met exactly, every route estimated within it: kept, and the choice depends on the host, whose estimate it is") + add("energy-stable-claimed", edited(local, both(joules, at(P + ("stable", "choice"), True))), ["planner_stable"], "the same, the choice said to depend on nothing of the host") + # --- the shadow, a method's run of exactly the job's program (review: steered, suppressed, unverifiable) + add("shadow-route-missing", edited(routed, drop(S + ("route",))), ["shadow"], "a shadow that names no route") + add("shadow-plan-route-missing", edited(routed, drop(P + ("shadow", "route"))), ["shadow"], "a shadow planned with no route, where null would say why") + + def provider_shadow(b): + for side in (b["result"]["planner"]["shadow"], b["result"]["shadow"]): + side["route"] = "provider:ref" + side["request"].pop("method") + add("shadow-route-provider", edited(routed, provider_shadow), ["shadow"], "a provider as its own shadow") + + def noisy(b): + for side in (b["result"]["planner"]["shadow"], b["result"]["shadow"]): + side["request"]["noise"] = {"depolarizing_2q": 0.2} + add("shadow-request-extra", edited(routed, noisy), ["shadow"], "a shadow run under a noise model the job never asked for, on both sides") + add("shadow-plan-code", edited(routed, both(at(P + ("shadow",), {"route": None, "code": "failed", "why": "said so"}), at(S, {"ran": False, "code": "failed", "why": "said so"}))), ["shadow"], "a shadow planned with a code no plan has") + add("shadow-plan-class", edited(routed, at(P + ("shadow", "class"), "heuristic")), ["shadow"], "a shadow planned at a class its route is not listed with") + add("shadow-plan-budget", edited(routed, at(P + ("shadow", "budget_seconds"), 299)), ["shadow"], "a budget that is not what the contract leaves") + add("shadow-plan-price-over", edited(routed, at(P + ("shadow", "price", "time", "seconds"), 301)), ["shadow"], "a shadow planned at a time past its budget") + + def fraction(b): + c = b["result"]["shadow"]["counts"] + k = sorted(c)[0] + c[k] = c[k] - 0.5 + c[sorted(c)[1]] += 0.5 + add("shadow-count-fraction", edited(routed, fraction), ["shadow"], "a shadow's counts that are not whole, summing to the shots all the same") + add("shadow-count-sum", edited(routed, lambda b: b["result"]["shadow"]["counts"].update({sorted(b["result"]["shadow"]["counts"])[0]: b["result"]["shadow"]["counts"][sorted(b["result"]["shadow"]["counts"])[0]] + 1})), ["shadow"], "a shadow's counts that sum to more than its shots") + add("shadow-bound-other", edited(routed, lambda b: b["result"]["shadow"]["distance"].update(sampling_tvd_bound=0.01)), ["shadow"], "a bound on the distance the shots alone leave that is not what the counts give") + + def host_failed(b): + b["result"]["shadow"] = {"ran": False, "code": "failed", "why": "the host says it failed"} + add("shadow-said-failed", edited(routed, host_failed), [], "a shadow planned and said to have failed: valid to read, and run again by --recheck") return out @@ -681,7 +756,13 @@ MADE = { "cli-contract-local.json": ("the command line under a contract: exact, a deadline and a ceiling, the cheapest route here chosen and its reasoning sealed", []), "cli-contract-auto.json": ("the command line under a contract that names no class: auto's pick kept, held to a deadline", []), "cli-contract-routed.json": ("the command line under a contract that allows the person's providers and wants a simulator's counts: the free one chosen, a classical method's counts and their distance beside its own", []), - "cli-contract-provider-priced.json": ("the command line on a provider it names, under a ceiling, confirmed with --yes: the estimate held to the ceiling, the charge to it after, and the shadow", []), + "cli-contract-provider-priced.json": ("the command line on a provider it names, allowed by its contract and under a ceiling, confirmed with --yes: the estimate held to the ceiling, the charge to it after, and the shadow", []), + "cli-contract-routed-seed.json": ("the same routed job with the seed 2^53 - 2: its shadow's seed, the request's plus 2^32, wraps at 2^53", []), + "cli-contract-any.json": ("the command line under a contract that takes any class, the person's providers allowed: a free method here and a free provider tie on money and on time to the millisecond, and the method here comes first", []), + "cli-contract-bounded.json": ("the command line under a contract that wants bounded: a single-precision route does not meet it, and the state vector is chosen", []), + "cli-contract-fabric-cpu.json": ("the command line on the CPU it asks for, under a deadline: each route that runs on an accelerator rejected for it", []), + "cli-contract-target.json": ("the command line on a device target, the person's providers allowed beside it, under a deadline: the target's method is named, and the providers are not", []), + "cli-contract-pulse.json": ("the command line, a pulse program under a contract that wants bounded and a deadline: its one route", []), "service-run.json": ("the free job service, signed with its key", []), "service-run-stabilizer.json": ("the free job service: a stabilizer job with observables", []), "scripted-sampler-v2.json": ("sampler-v2 through a service that follows its contract", []), diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-auto.json b/wai/quantum-conformance/receipts/jobs/cli-contract-auto.json index 105a3f024..c3f28a7cb 100644 --- a/wai/quantum-conformance/receipts/jobs/cli-contract-auto.json +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-auto.json @@ -1 +1 @@ -{"status":"done","method":"exact","why":"bit-exact state vector of 3 qubits; what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)","estimate":{"memory_bytes":134218112,"work":40},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[3] q;\nbit[3] c;\nh q[0];\nt q[0];\ncx q[0], q[1];\nrz(pi/8) q[2];\ncx q[1], q[2];\nc = measure q;\n","shots":500,"seed":3,"contract":{"deadline_seconds":600.0}},"result":{"method":"exact","qubits":3,"gates":5,"accuracy":{"class":"bit-exact"},"state_hash":"5f1ae3e98c0555290986daf0d573de16a34ba01d1993f13f134e0b1daf6f1ab5","counts":{"000":254,"111":246},"distinct_outcomes":2,"omitted_shots":0,"elapsed_ms":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"bit-exact","wanted_from":"auto","auto":"method:exact","host":{"job_bytes":17179869184,"providers":[]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":2e-7,"basis":"nominal"},"memory_bytes":134218112,"work":40,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"chosen"},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":268447588,"work":40,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants bit-exact"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants bit-exact"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":0.024723456,"basis":"nominal"},"memory_bytes":270794752,"work":16482304,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants bit-exact"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants bit-exact"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is estimate, and the job wants bit-exact"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants bit-exact"}}],"choice":"method:exact","why":"what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"d859d0ec175157bdd2b0e221a569afd4d2d94e347cbd550027c714ab35bdb061","choice":true},"kept":{"deadline":{"seconds":600.0,"elapsed_ms":0,"kept":true}}},"energy":{"unmetered":"the command line does not meter a run's energy"},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"7fbcec2023294f5dd41b5de98fdb25c4507b99a51b15a37ce5a91516b731d303","signature":"cf1186c4834195871fa985d73ec64adccd26ae5166da0ea9fbf579d44a6f7dd059fdad4af3aee99bda5d63328523dc1a1aed42bd3e66a22640ead9d20ea23001"}}} +{"status":"done","method":"exact","why":"bit-exact state vector of 3 qubits; what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)","estimate":{"memory_bytes":134218112,"work":40},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[3] q;\nbit[3] c;\nh q[0];\nt q[0];\ncx q[0], q[1];\nrz(pi/8) q[2];\ncx q[1], q[2];\nc = measure q;\n","shots":500,"seed":3,"contract":{"deadline_seconds":600.0}},"result":{"method":"exact","qubits":3,"gates":5,"accuracy":{"class":"bit-exact"},"state_hash":"5f1ae3e98c0555290986daf0d573de16a34ba01d1993f13f134e0b1daf6f1ab5","counts":{"000":254,"111":246},"distinct_outcomes":2,"omitted_shots":0,"elapsed_ms":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"bit-exact","wanted_from":"auto","named":null,"question":"counts","auto":"method:exact","host":{"job_bytes":17179869184,"providers":[]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"auto_rank":20,"price":{"money":{"free":true},"time":{"seconds":2e-7,"basis":"nominal"},"memory_bytes":134218112,"work":40,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"chosen"},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"auto_rank":30,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":268447588,"work":40,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"auto_rank":40,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants bit-exact"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"auto_rank":10,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants bit-exact"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"auto_rank":60,"price":{"money":{"free":true},"time":{"seconds":0.024723456,"basis":"nominal"},"memory_bytes":270794752,"work":16482304,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants bit-exact"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"auto_rank":50,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants bit-exact"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants bit-exact"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is estimate, and the job wants bit-exact"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants bit-exact"}}],"choice":"method:exact","why":"what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"d859d0ec175157bdd2b0e221a569afd4d2d94e347cbd550027c714ab35bdb061","choice":true},"kept":{"deadline":{"seconds":600.0,"elapsed_ms":0,"kept":true}}},"energy":{"unmetered":"the command line does not meter a run's energy"},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"2c198a0bb868c91815a8573f898fe692b6eefba3d6d6b924cd420e02b2a19d6f","signature":"26e1443d1d91253c1064f457f81504c833d61f54d97a4a20edc878557a1e26348667298bfb6590453eaf2a44cc9311b038697fad274dd93f1adfadb660ba8a0f"}}} diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-bounded.json b/wai/quantum-conformance/receipts/jobs/cli-contract-bounded.json new file mode 100644 index 000000000..881a8df15 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-bounded.json @@ -0,0 +1 @@ +{"status":"done","method":"statevector","why":"dense double-precision state vector of 2 qubits; the cheapest of the 1 of 13 routes that meet the contract","estimate":{"memory_bytes":268437922,"work":8},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nrx(0.3) q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":100,"seed":2,"contract":{"exactness":"bounded","deadline_seconds":60.0}},"result":{"method":"statevector","qubits":2,"gates":2,"accuracy":{"class":"exact","fusion":3},"counts":{"00":99,"11":1},"distinct_outcomes":2,"omitted_shots":0,"elapsed_ms":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"bounded","wanted_from":"contract","named":null,"question":"counts","auto":"method:statevector","host":{"job_bytes":17179869184,"providers":[]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"auto_rank":20,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"exact needs dyadic angles: the angle 0.3 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]"}},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"auto_rank":30,"price":{"money":{"free":true},"time":{"seconds":8e-9,"basis":"nominal"},"memory_bytes":268437922,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"chosen"},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"auto_rank":40,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants bounded"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"auto_rank":10,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"stabilizer needs a Clifford circuit: Rx(0.3) is not a Clifford gate"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"pauli answers expectation values only"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"auto_rank":60,"price":{"money":{"free":true},"time":{"seconds":0.005603328,"basis":"nominal"},"memory_bytes":270532608,"work":3735552,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants bounded"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"stabilizer_rank answers amplitudes and expectation values"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"tensor_network answers amplitudes only"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"auto_rank":50,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"Cx on qubits [0, 1] comes after a gate on qubit 0 that is not Clifford; cutrank takes a Clifford circuit, then one layer of one-qubit gates"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants bounded"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"density_matrix is for noisy circuits (give \"noise\")"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is estimate, and the job wants bounded"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"pulse reads its own program, and runs only when a job names it"}}],"choice":"method:statevector","why":"the cheapest of the 1 of 13 routes that meet the contract","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"7f32458b3eb3e371e44723491a3a020ebeb70d954a7d13936c61dcda9b1b19dc","choice":true},"kept":{"deadline":{"seconds":60.0,"elapsed_ms":0,"kept":true}}},"energy":{"unmetered":"the command line does not meter a run's energy"},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"a9ae845acd35e18289c0345762d2d2a0cf4c37a63e0b97305f86f6d8c70343c3","signature":"d8e40b438737df12bb78666c6353d966b201a9bc773d6343d160998c4653cd3280e9be72440f52f1e642345523aa9ec103cf8d1af6683d6431dc069a91933a02"}}} diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-fabric-cpu.json b/wai/quantum-conformance/receipts/jobs/cli-contract-fabric-cpu.json new file mode 100644 index 000000000..c9c87d775 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-fabric-cpu.json @@ -0,0 +1 @@ +{"status":"done","method":"stabilizer","why":"Clifford circuit: the stabilizer tableau of 2 qubits; what auto picks, which meets the contract: the contract names no class, so it keeps auto's (4 of 13 routes meet it)","estimate":{"memory_bytes":67115270,"work":208},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":100,"seed":2,"fabric":"cpu","contract":{"deadline_seconds":60.0}},"result":{"method":"stabilizer","qubits":2,"gates":2,"accuracy":{"class":"exact"},"counts":{"00":54,"11":46},"distinct_outcomes":2,"omitted_shots":0,"outcome_dimension":1,"elapsed_ms":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"exact","wanted_from":"auto","named":null,"question":"counts","auto":"method:stabilizer","host":{"job_bytes":17179869184,"providers":[]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"auto_rank":20,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"met"},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"auto_rank":30,"price":{"money":{"free":true},"time":{"seconds":8e-9,"basis":"nominal"},"memory_bytes":268437922,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"met"},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"auto_rank":40,"price":null,"outcome":"rejected","rejected":{"code":"fabric","why":"the job's placement on the fabric is not this route's"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"auto_rank":10,"price":{"money":{"free":true},"time":{"seconds":2.496e-8,"basis":"nominal"},"memory_bytes":67115270,"work":208,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"chosen"},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants exact"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"auto_rank":60,"price":{"money":{"free":true},"time":{"seconds":0.005603328,"basis":"nominal"},"memory_bytes":270532608,"work":3735552,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"stabilizer_rank answers amplitudes and expectation values"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"tensor_network answers amplitudes only"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"auto_rank":50,"price":{"money":{"free":true},"time":{"seconds":1.35e-7,"basis":"nominal"},"memory_bytes":268435554,"work":900,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"met"},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"fabric","why":"the job's placement on the fabric is not this route's"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"density_matrix is for noisy circuits (give \"noise\")"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is estimate, and the job wants exact"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants exact"}}],"choice":"method:stabilizer","why":"what auto picks, which meets the contract: the contract names no class, so it keeps auto's (4 of 13 routes meet it)","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"e6de7586c9980adb8036dea7dc2777ba0acdb9a0138a3ef1da70c070133771f8","choice":true},"kept":{"deadline":{"seconds":60.0,"elapsed_ms":0,"kept":true}}},"energy":{"unmetered":"the command line does not meter a run's energy"},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"369262e1f009fe7e34e4c5f81a3e46a751224bbfb4e84204952f85b046d198b8","signature":"384afecbc4152057acebc96f86b3374d81417d291f560011bbac0cbe5aa4361d33c09512c2713c48247cf7c92f4a53f6faa2376a134e138ae0c40b895f85130c"}}} diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-local.json b/wai/quantum-conformance/receipts/jobs/cli-contract-local.json index 4c0f0ef9d..fa6ac9be5 100644 --- a/wai/quantum-conformance/receipts/jobs/cli-contract-local.json +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-local.json @@ -1 +1 @@ -{"status":"done","method":"stabilizer","why":"Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract","estimate":{"memory_bytes":67172870,"work":2008},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":1000,"seed":7,"contract":{"exactness":"exact","max_cost":{"amount":"1","currency":"USD"},"deadline_seconds":60.0}},"result":{"method":"stabilizer","qubits":2,"gates":2,"accuracy":{"class":"exact"},"counts":{"11":505,"00":495},"distinct_outcomes":2,"omitted_shots":0,"outcome_dimension":1,"elapsed_ms":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"exact","wanted_from":"contract","auto":"method:stabilizer","host":{"job_bytes":17179869184,"providers":[]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"met"},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":8e-9,"basis":"nominal"},"memory_bytes":268459522,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"met"},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants exact"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":2.4096e-7,"basis":"nominal"},"memory_bytes":67172870,"work":2008,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"chosen"},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants exact"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":0.027721728,"basis":"nominal"},"memory_bytes":270532608,"work":18481152,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"stabilizer_rank answers amplitudes and expectation values"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"tensor_network answers amplitudes only"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":1.35e-6,"basis":"nominal"},"memory_bytes":268435554,"work":9000,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"met"},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants exact"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"density_matrix is for noisy circuits (give \"noise\")"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is estimate, and the job wants exact"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants exact"}}],"choice":"method:stabilizer","why":"the cheapest of the 4 of 13 routes that meet the contract","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e","choice":true},"kept":{"deadline":{"seconds":60.0,"elapsed_ms":0,"kept":true},"cost":{"max_cost":{"amount":"1","currency":"USD"},"charged":null,"kept":true}}},"energy":{"unmetered":"the command line does not meter a run's energy"},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"ef613b1d460b70a7ddc2683acc890f28f38ecde575263229b2a9f1859d2b40b5","signature":"a5c9455ca9e6073296a1eb5f1c2a1a416c6f0b3943f013a961df2fbbb543886d1625e640cfc60a9eee0427464dbf34eb4a2141e4341cc966d5fe8018da28d90c"}}} +{"status":"done","method":"stabilizer","why":"Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract","estimate":{"memory_bytes":67172870,"work":2008},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":1000,"seed":7,"contract":{"exactness":"exact","max_cost":{"amount":"1","currency":"USD"},"deadline_seconds":60.0}},"result":{"method":"stabilizer","qubits":2,"gates":2,"accuracy":{"class":"exact"},"counts":{"11":505,"00":495},"distinct_outcomes":2,"omitted_shots":0,"outcome_dimension":1,"elapsed_ms":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"exact","wanted_from":"contract","named":null,"question":"counts","auto":"method:stabilizer","host":{"job_bytes":17179869184,"providers":[]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"auto_rank":20,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"met"},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"auto_rank":30,"price":{"money":{"free":true},"time":{"seconds":8e-9,"basis":"nominal"},"memory_bytes":268459522,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"met"},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"auto_rank":40,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants exact"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"auto_rank":10,"price":{"money":{"free":true},"time":{"seconds":2.4096e-7,"basis":"nominal"},"memory_bytes":67172870,"work":2008,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"chosen"},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants exact"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"auto_rank":60,"price":{"money":{"free":true},"time":{"seconds":0.027721728,"basis":"nominal"},"memory_bytes":270532608,"work":18481152,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"stabilizer_rank answers amplitudes and expectation values"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"tensor_network answers amplitudes only"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"auto_rank":50,"price":{"money":{"free":true},"time":{"seconds":1.35e-6,"basis":"nominal"},"memory_bytes":268435554,"work":9000,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"met"},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants exact"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"density_matrix is for noisy circuits (give \"noise\")"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is estimate, and the job wants exact"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants exact"}}],"choice":"method:stabilizer","why":"the cheapest of the 4 of 13 routes that meet the contract","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e","choice":true},"kept":{"deadline":{"seconds":60.0,"elapsed_ms":0,"kept":true},"cost":{"max_cost":{"amount":"1","currency":"USD"},"charged":null,"kept":true}}},"energy":{"unmetered":"the command line does not meter a run's energy"},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"105fcdb97bff923e0420b8a5a7b5340eeab26a68b1f257fffc65b4e7a545af09","signature":"fe84735496fddb35013a8db356b40ff2ebba4fe7c5a7851208c5396ded3b9146a1ee0da323b4b8d8174891c862d52bb5aab55ad034bfce0795592a4dcfb6d205"}}} diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-provider-priced.json b/wai/quantum-conformance/receipts/jobs/cli-contract-provider-priced.json index a29847254..5219a719d 100644 --- a/wai/quantum-conformance/receipts/jobs/cli-contract-provider-priced.json +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-provider-priced.json @@ -1 +1 @@ -{"status":"done","method":"provider","why":"on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4,"contract":{"max_cost":{"amount":"1","currency":"USD"}},"provider":"priced"},"result":{"method":"provider","qubits":2,"gates":2,"accuracy":{"class":"simulated","note":"counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would"},"shots":300,"provider":{"name":"priced","kind":"process","protocol":"wai.quantum.provider/1","device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","qubits":5,"basis":"rzsxxcz","describe":"c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439"},"calibration":"reference-f2d9fe570421","compiled":{"basis":"rzsxxcz","program":"b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9","hash":"BLAKE3 of the program's OpenQASM 3 text, qasm3","qasm3":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n","native_gates":9,"two_qubit_gates":1,"swaps":0,"layout":[0,1],"final_layout":[0,1],"checked":"the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent","placement":{"chosen":"the compiler's own layout, the fewest swaps: the description states no errors"}},"job":{"id":"ref-1","polls":1},"ideal":{"computed":true,"method":"exact","total_variation_distance":0.03666666666666665,"hellinger_fidelity":0.998653743148044,"sampling_tvd_expected":0.023032943298089033,"ideal_outcomes":2,"note":"the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent"},"cost":{"free":false,"estimate":{"free":false,"amount":"0.09","currency":"USD","unit":"shot","seconds":0.0},"charged":{"amount":"0.09","currency":"USD"},"confirmed":true},"energy":{"unmetered":"the work ran at the provider; this host's meter would read only the wait"},"counts_source":"shots","execution":{"stated_by":"provider","mitigation":"none","twirling":"none","decoupling":"none","remapping":"none","optimisation":"none","verbatim":true,"note":"the reference simulates the program's gates as written, on the qubits named, and corrects nothing"},"counts":{"11":161,"00":139},"distinct_outcomes":2,"omitted_shots":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"simulated","wanted_from":"named","auto":null,"host":{"job_bytes":17179869184,"providers":["priced"]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"estimate","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"estimate","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"provider:priced","kind":"provider","provider":"priced","class":"simulated","host_dependent":true,"price":{"money":{"free":false,"amount":"0.09","currency":"USD","unit":"shot"},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder","charged"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"chosen"}],"choice":"provider:priced","why":"the route the job names, which meets its contract (1 of 14 routes)","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c","choice":false},"shadow":{"route":"method:exact","class":"bit-exact","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"budget_seconds":300.0,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]}},"kept":{"cost":{"max_cost":{"amount":"1","currency":"USD"},"charged":{"amount":"0.09","currency":"USD"},"kept":true}}},"shadow":{"ran":true,"route":"method:exact","accuracy":{"class":"bit-exact"},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"shots":300,"counts":{"00":161,"11":139},"distinct_outcomes":2,"omitted_shots":0,"distance":{"computed":true,"numerator":44,"denominator":600,"total_variation":0.07333333333333333,"hellinger_fidelity":0.9946222222222221,"sampling_tvd_expected":0.032573500793528},"elapsed_ms":0},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"05586382ac2c7005dfcbf9b65a5bbe99dbbff33b75923c119f6f4f0e46d3674f","signature":"44cf2408639ff97f6228449762f3a4ccbd481c3ad38d83eccb90d4ee4760814be58a98356cc9ef584f47598d04ffd87fa4aea88464b4c9ffac33b2ff5cdc6b08"}},"id":"pj-95909ba10d2d9f13","submitted_ms":1793951019928,"finished_ms":1793951019934} +{"status":"done","method":"provider","why":"on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4,"contract":{"max_cost":{"amount":"1","currency":"USD"},"providers":"allowed"},"provider":"priced"},"result":{"method":"provider","qubits":2,"gates":2,"accuracy":{"class":"simulated","note":"counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would"},"shots":300,"provider":{"name":"priced","kind":"process","protocol":"wai.quantum.provider/1","device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","qubits":5,"basis":"rzsxxcz","describe":"c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439"},"calibration":"reference-f2d9fe570421","compiled":{"basis":"rzsxxcz","program":"b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9","hash":"BLAKE3 of the program's OpenQASM 3 text, qasm3","qasm3":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n","native_gates":9,"two_qubit_gates":1,"swaps":0,"layout":[0,1],"final_layout":[0,1],"checked":"the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent","placement":{"chosen":"the compiler's own layout, the fewest swaps: the description states no errors"}},"job":{"id":"ref-1","polls":1},"ideal":{"computed":true,"method":"exact","total_variation_distance":0.03666666666666665,"hellinger_fidelity":0.998653743148044,"sampling_tvd_expected":0.023032943298089033,"ideal_outcomes":2,"note":"the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent"},"cost":{"free":false,"estimate":{"free":false,"amount":"0.09","currency":"USD","unit":"shot","seconds":0.0},"charged":{"amount":"0.09","currency":"USD"},"confirmed":true},"energy":{"unmetered":"the work ran at the provider; this host's meter would read only the wait"},"counts_source":"shots","execution":{"stated_by":"provider","mitigation":"none","twirling":"none","decoupling":"none","remapping":"none","optimisation":"none","verbatim":true,"note":"the reference simulates the program's gates as written, on the qubits named, and corrects nothing"},"counts":{"11":161,"00":139},"distinct_outcomes":2,"omitted_shots":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"simulated","wanted_from":"named","named":"provider:priced","question":"counts","auto":null,"host":{"job_bytes":17179869184,"providers":["priced"]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"auto_rank":20,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"auto_rank":30,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"auto_rank":40,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"estimate","host_dependent":false,"auto_rank":10,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"auto_rank":60,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"estimate","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"auto_rank":50,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"provider:priced","kind":"provider","provider":"priced","class":"simulated","host_dependent":true,"price":{"money":{"free":false,"amount":"0.09","currency":"USD","unit":"shot"},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder","charged"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"chosen"}],"choice":"provider:priced","why":"the route the job names, which meets its contract (1 of 14 routes)","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c","choice":false},"shadow":{"route":"method:exact","class":"bit-exact","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"budget_seconds":300.0,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]}},"kept":{"cost":{"max_cost":{"amount":"1","currency":"USD"},"charged":{"amount":"0.09","currency":"USD"},"kept":true}}},"shadow":{"ran":true,"route":"method:exact","accuracy":{"class":"bit-exact"},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"shots":300,"counts":{"00":161,"11":139},"distinct_outcomes":2,"omitted_shots":0,"distance":{"computed":true,"numerator":44,"denominator":600,"total_variation":0.07333333333333333,"hellinger_fidelity":0.9946222222222221,"sampling_tvd_bound":0.04602751441903442},"elapsed_ms":0},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"483113df1f4fabe90c601cc424fbecab5a3c62d886f986749078987d756d935a","signature":"aaa742d8537a113c682fabcddfcf3d4a4291cd7904f0b9337cc4b5ac2d9edd6422aa5c45f5a37ebd22ba09c3e800d5c1049d5f402be5f331ae5ba6649512be09"}},"id":"pj-316b154641049d91","submitted_ms":1793974079084,"finished_ms":1793974079087} diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-pulse.json b/wai/quantum-conformance/receipts/jobs/cli-contract-pulse.json new file mode 100644 index 000000000..f0a181c29 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-pulse.json @@ -0,0 +1 @@ +{"status":"done","method":"pulse","why":"a pulse schedule of 164 samples (82 ns) on $0 at 2 levels: 164 steps of 0.5 ns, each a series of order 12, the error within 3.512e-21 with rounding estimated at 2.840e-12; the cheapest of the 1 of 1 routes that meet the contract","estimate":{"memory_bytes":33566400,"work":55104},"request":{"qasm":"OPENQASM 3.0;\ndefcalgrammar \"openpulse\";\ncal {\n extern port d0;\n extern port a0;\n frame q0 = newframe(d0, 5.0e9, 0);\n frame c0 = newframe(a0, 5.0e9, 0);\n}\ndefcal x $0 { play(q0, drag(0.4, 64dt, 16dt, 0.2)); }\ndefcal measure $0 -> bit { return capture_v2(c0, 100dt); }\nbit c;\nx $0;\nc = measure $0;\n","shots":50,"seed":2,"method":"pulse","contract":{"exactness":"bounded","deadline_seconds":60.0}},"result":{"method":"pulse","qubits":1,"gates":2,"accuracy":{"class":"bounded","bound":2.8403945897125026e-12,"truncation_bound":3.511502073909511e-21,"rounding_estimate":2.8403945862010005e-12,"tolerance":1e-6,"norm":"trace","note":"every probability is within bound of the exact solution of the pulse model's master equation: the series' truncation proved, the rounding an estimate; the model itself (its levels, the rotating frame and the rotating-wave approximation, the envelope held for each sample) is what is solved"},"counts":{"1":46,"0":4},"distinct_outcomes":2,"omitted_shots":0,"shots":50,"diagnostics":[{"code":"Q453","outcome":"lowered","message":"a `cal` block read as OpenPulse and run here","line":3,"column":1,"length":5},{"code":"Q453","outcome":"lowered","message":"the `defcal` of x read as OpenPulse; it runs at each call","line":9,"column":1,"length":53},{"code":"Q453","outcome":"lowered","message":"the `defcal` of measure read as OpenPulse; it runs at each call","line":10,"column":1,"length":58}],"pulse":{"read":"the captures, at their one first sample, into the program's bits","outcome_bits":["c"],"distribution":{"0":0.12956041250210984,"1":0.8704395874978892},"populations":{"0":0.12956041250210984,"1":0.8704395874978892},"simulated_qubits":[0],"captures":[{"frame":"c0","qubit":0,"start":64,"start_ns":32.0,"bit":"c","p1":0.8704395874978892,"p2":0.0}],"trace":0.999999999999999,"density_hash":"09778fae666fc72fbac7b86d35f38c7a7e7fc16eb3c3799b0db32da0dc8767a4","duration":164,"duration_ns":82.0,"integrator":{"name":"taylor","order":12,"dt_ns":0.5,"substeps":1,"step_ns":0.5,"steps":164,"norm_max":0.2512047429452378,"frame":"each sample in the frame of each qubit's tone, the generator constant over it, then a diagonal phase back"},"device":{"levels":2,"dt_ns":0.5,"qubits":[{"qubit":0,"frequency_hz":5000000000.0,"rabi_hz":50000000.0,"anharmonicity_hz":-300000000.0,"from":{"frequency":"default","rabi":"default","anharmonicity":"default","t1":"none","t2":"none"}}],"couplings":[],"model":"each qubit a ladder of its levels in the frame rotating at its frequency, under the rotating-wave approximation, the envelope held for each sample; relaxation and pure dephasing from T1 and T2; static ZZ couplings"},"calibration":{"program":"f9b61296e932d2a5a5e9ab81f405f05bcf9900dacf27cbbeadf9ccaef001e0bb","calibrations":"48d81e250c5a875c58ba41229b4e2477f160e6e84f85a901dfff3fd7682b1a89","schedule":"9424e49a95d76eb70bf89923d05b5f7aca92678bd95520953373d415cc1b9267","device":"b18083ab12fd0d2f46d3d125c855119ca7f7dc0f2d73dace7d7fe5e557668b39"},"not_modelled":["the readout: a capture reads its qubit's state at its first sample, a level above 0 as 1"]},"verdict":{"schema":"wai.quantum.verdict/1","level":"executed","rank":2,"holds":null,"statement":"Executed on pulse (bounded); no intent was given, so nothing was checked against one.","parsed":{"ok":true,"diagnostics":[{"code":"Q453","outcome":"lowered","message":"a `cal` block read as OpenPulse and run here","line":3,"column":1,"length":5},{"code":"Q453","outcome":"lowered","message":"the `defcal` of x read as OpenPulse; it runs at each call","line":9,"column":1,"length":53},{"code":"Q453","outcome":"lowered","message":"the `defcal` of measure read as OpenPulse; it runs at each call","line":10,"column":1,"length":58}]},"executed":{"method":"pulse","accuracy":"bounded"},"intent":[],"critique":[],"repairs":[]},"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"bounded","wanted_from":"contract","named":"method:pulse","question":"counts","auto":null,"host":{"job_bytes":17179869184,"providers":[]},"routes":[{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":{"money":{"free":true},"time":{"seconds":0.000055104,"basis":"nominal"},"memory_bytes":33566400,"work":55104,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"chosen"}],"choice":"method:pulse","why":"the cheapest of the 1 of 1 routes that meet the contract","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:pulse"],"digest":"66699259c0f19f46979dc8a807893b52eaa894a2d6db6a3d7722004e484db32b","choice":true},"kept":{"deadline":{"seconds":60.0,"elapsed_ms":null,"kept":null}}},"energy":{"unmetered":"the command line does not meter a run's energy"},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"4ab608bd1b63101d9f156343d3c2a9c638101b2a06dde475be1f124a9a3921e0","signature":"94e0361bec90485d348c5cb786b20996149b9e78d8169db684b4f5e3efee7344efcf677d9374a9d7cc6918e8da46ad75ce45afad9bddfe4a9b031f323e0c8b0f"}}} diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-routed-seed.json b/wai/quantum-conformance/receipts/jobs/cli-contract-routed-seed.json new file mode 100644 index 000000000..f61a096bf --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-routed-seed.json @@ -0,0 +1 @@ +{"status":"done","method":"provider","why":"on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":9007199254740990,"contract":{"exactness":"simulated","providers":"allowed"}},"result":{"method":"provider","qubits":2,"gates":2,"accuracy":{"class":"simulated","note":"counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would"},"shots":300,"provider":{"name":"ref","kind":"process","protocol":"wai.quantum.provider/1","device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","qubits":5,"basis":"rzsxxcz","describe":"0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0"},"calibration":"reference-f2d9fe570421","compiled":{"basis":"rzsxxcz","program":"b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9","hash":"BLAKE3 of the program's OpenQASM 3 text, qasm3","qasm3":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n","native_gates":9,"two_qubit_gates":1,"swaps":0,"layout":[0,1],"final_layout":[0,1],"checked":"the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent","placement":{"chosen":"the compiler's own layout, the fewest swaps: the description states no errors"}},"job":{"id":"ref-1","polls":1},"ideal":{"computed":true,"method":"exact","total_variation_distance":0.013333333333333308,"hellinger_fidelity":0.9998221906060416,"sampling_tvd_expected":0.023032943298089033,"ideal_outcomes":2,"note":"the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent"},"cost":{"free":true,"estimate":{"free":true,"seconds":0.0},"charged":null,"confirmed":false},"energy":{"unmetered":"the work ran at the provider; this host's meter would read only the wait"},"counts_source":"shots","execution":{"stated_by":"provider","mitigation":"none","twirling":"none","decoupling":"none","remapping":"none","optimisation":"none","verbatim":true,"note":"the reference simulates the program's gates as written, on the qubits named, and corrects nothing"},"counts":{"11":154,"00":146},"distinct_outcomes":2,"omitted_shots":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"simulated","wanted_from":"contract","named":null,"question":"counts","auto":"method:stabilizer","host":{"job_bytes":17179869184,"providers":["ref","priced"]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"auto_rank":20,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is bit-exact, and the job wants simulated"}},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"auto_rank":30,"price":{"money":{"free":true},"time":{"seconds":8e-9,"basis":"nominal"},"memory_bytes":268442722,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"auto_rank":40,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants simulated"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"auto_rank":10,"price":{"money":{"free":true},"time":{"seconds":7.296e-8,"basis":"nominal"},"memory_bytes":67128070,"work":608,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants simulated"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"auto_rank":60,"price":{"money":{"free":true},"time":{"seconds":0.010518528000000001,"basis":"nominal"},"memory_bytes":270532608,"work":7012352,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is heuristic, and the job wants simulated"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"auto_rank":50,"price":{"money":{"free":true},"time":{"seconds":4.05e-7,"basis":"nominal"},"memory_bytes":268435554,"work":2700,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants simulated"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is estimate, and the job wants simulated"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants simulated"}},{"route":"provider:ref","kind":"provider","provider":"ref","class":"simulated","host_dependent":true,"price":{"money":{"free":true},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"chosen"},{"route":"provider:priced","kind":"provider","provider":"priced","class":"simulated","host_dependent":true,"price":{"money":{"free":false,"amount":"0.09","currency":"USD","unit":"shot"},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder","charged"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"rejected","rejected":{"code":"cost_no_ceiling","why":"0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider"}}],"choice":"provider:ref","why":"the cheapest of the 1 of 15 routes that meet the contract","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a","choice":false},"shadow":{"route":"method:exact","class":"bit-exact","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967294,"method":"exact"},"budget_seconds":300.0,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]}},"kept":{}},"shadow":{"ran":true,"route":"method:exact","accuracy":{"class":"bit-exact"},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967294,"method":"exact"},"shots":300,"counts":{"00":151,"11":149},"distinct_outcomes":2,"omitted_shots":0,"distance":{"computed":true,"numerator":10,"denominator":600,"total_variation":0.016666666666666666,"hellinger_fidelity":0.9997221944339458,"sampling_tvd_bound":0.046103716364460375},"elapsed_ms":0},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"f6073ce2965dc9ad90ddd3fcb6cbcbdfc722ebaa30cdf540517ed93b5b394d39","signature":"fd220074ac10f205ffc4d2f99571cccd5e6a839a6409ad746b592f4c3500ee448969df9bc0b7bebf1e3bf43d87511ca8b3d2b61f5060317c31bf6baaf6c1dc0b"}},"id":"pj-a1065ac85f2a95ff","submitted_ms":1793974079068,"finished_ms":1793974079071} diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-routed.json b/wai/quantum-conformance/receipts/jobs/cli-contract-routed.json index 43aa27c2f..c01511d25 100644 --- a/wai/quantum-conformance/receipts/jobs/cli-contract-routed.json +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-routed.json @@ -1 +1 @@ -{"status":"done","method":"provider","why":"on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4,"contract":{"exactness":"simulated","providers":"allowed"}},"result":{"method":"provider","qubits":2,"gates":2,"accuracy":{"class":"simulated","note":"counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would"},"shots":300,"provider":{"name":"ref","kind":"process","protocol":"wai.quantum.provider/1","device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","qubits":5,"basis":"rzsxxcz","describe":"0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0"},"calibration":"reference-f2d9fe570421","compiled":{"basis":"rzsxxcz","program":"b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9","hash":"BLAKE3 of the program's OpenQASM 3 text, qasm3","qasm3":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n","native_gates":9,"two_qubit_gates":1,"swaps":0,"layout":[0,1],"final_layout":[0,1],"checked":"the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent","placement":{"chosen":"the compiler's own layout, the fewest swaps: the description states no errors"}},"job":{"id":"ref-1","polls":1},"ideal":{"computed":true,"method":"exact","total_variation_distance":0.03666666666666665,"hellinger_fidelity":0.998653743148044,"sampling_tvd_expected":0.023032943298089033,"ideal_outcomes":2,"note":"the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent"},"cost":{"free":true,"estimate":{"free":true,"seconds":0.0},"charged":null,"confirmed":false},"energy":{"unmetered":"the work ran at the provider; this host's meter would read only the wait"},"counts_source":"shots","execution":{"stated_by":"provider","mitigation":"none","twirling":"none","decoupling":"none","remapping":"none","optimisation":"none","verbatim":true,"note":"the reference simulates the program's gates as written, on the qubits named, and corrects nothing"},"counts":{"11":161,"00":139},"distinct_outcomes":2,"omitted_shots":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"simulated","wanted_from":"contract","auto":"method:stabilizer","host":{"job_bytes":17179869184,"providers":["ref","priced"]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is bit-exact, and the job wants simulated"}},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":8e-9,"basis":"nominal"},"memory_bytes":268442722,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants simulated"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":7.296e-8,"basis":"nominal"},"memory_bytes":67128070,"work":608,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants simulated"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":0.010518528000000001,"basis":"nominal"},"memory_bytes":270532608,"work":7012352,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is heuristic, and the job wants simulated"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"price":{"money":{"free":true},"time":{"seconds":4.05e-7,"basis":"nominal"},"memory_bytes":268435554,"work":2700,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants simulated"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is estimate, and the job wants simulated"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants simulated"}},{"route":"provider:ref","kind":"provider","provider":"ref","class":"simulated","host_dependent":true,"price":{"money":{"free":true},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"chosen"},{"route":"provider:priced","kind":"provider","provider":"priced","class":"simulated","host_dependent":true,"price":{"money":{"free":false,"amount":"0.09","currency":"USD","unit":"shot"},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder","charged"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"rejected","rejected":{"code":"cost_no_ceiling","why":"0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider"}}],"choice":"provider:ref","why":"the cheapest of the 1 of 15 routes that meet the contract","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a","choice":false},"shadow":{"route":"method:exact","class":"bit-exact","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"budget_seconds":300.0,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]}},"kept":{}},"shadow":{"ran":true,"route":"method:exact","accuracy":{"class":"bit-exact"},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"shots":300,"counts":{"00":161,"11":139},"distinct_outcomes":2,"omitted_shots":0,"distance":{"computed":true,"numerator":44,"denominator":600,"total_variation":0.07333333333333333,"hellinger_fidelity":0.9946222222222221,"sampling_tvd_expected":0.032573500793528},"elapsed_ms":0},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"43a1345cab6a823054aad8325eeefac68c7a6bb8a6aedf5942d517bfbd697a26","signature":"e2c4edbd35b960bbe83427a8949916b12d0dc16978a8dd142ae10426054d54f68a9e9e0ac70c65ba4ab170134cf6dda56998f4a9ad271e9c86dc9e4115985d00"}},"id":"pj-ef8b7cfb5f9601bc","submitted_ms":1793951019912,"finished_ms":1793951019919} +{"status":"done","method":"provider","why":"on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4,"contract":{"exactness":"simulated","providers":"allowed"}},"result":{"method":"provider","qubits":2,"gates":2,"accuracy":{"class":"simulated","note":"counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would"},"shots":300,"provider":{"name":"ref","kind":"process","protocol":"wai.quantum.provider/1","device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","qubits":5,"basis":"rzsxxcz","describe":"0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0"},"calibration":"reference-f2d9fe570421","compiled":{"basis":"rzsxxcz","program":"b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9","hash":"BLAKE3 of the program's OpenQASM 3 text, qasm3","qasm3":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n","native_gates":9,"two_qubit_gates":1,"swaps":0,"layout":[0,1],"final_layout":[0,1],"checked":"the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent","placement":{"chosen":"the compiler's own layout, the fewest swaps: the description states no errors"}},"job":{"id":"ref-1","polls":1},"ideal":{"computed":true,"method":"exact","total_variation_distance":0.03666666666666665,"hellinger_fidelity":0.998653743148044,"sampling_tvd_expected":0.023032943298089033,"ideal_outcomes":2,"note":"the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent"},"cost":{"free":true,"estimate":{"free":true,"seconds":0.0},"charged":null,"confirmed":false},"energy":{"unmetered":"the work ran at the provider; this host's meter would read only the wait"},"counts_source":"shots","execution":{"stated_by":"provider","mitigation":"none","twirling":"none","decoupling":"none","remapping":"none","optimisation":"none","verbatim":true,"note":"the reference simulates the program's gates as written, on the qubits named, and corrects nothing"},"counts":{"11":161,"00":139},"distinct_outcomes":2,"omitted_shots":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"simulated","wanted_from":"contract","named":null,"question":"counts","auto":"method:stabilizer","host":{"job_bytes":17179869184,"providers":["ref","priced"]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"auto_rank":20,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is bit-exact, and the job wants simulated"}},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"auto_rank":30,"price":{"money":{"free":true},"time":{"seconds":8e-9,"basis":"nominal"},"memory_bytes":268442722,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"auto_rank":40,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants simulated"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"auto_rank":10,"price":{"money":{"free":true},"time":{"seconds":7.296e-8,"basis":"nominal"},"memory_bytes":67128070,"work":608,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants simulated"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"auto_rank":60,"price":{"money":{"free":true},"time":{"seconds":0.010518528000000001,"basis":"nominal"},"memory_bytes":270532608,"work":7012352,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is heuristic, and the job wants simulated"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"auto_rank":50,"price":{"money":{"free":true},"time":{"seconds":4.05e-7,"basis":"nominal"},"memory_bytes":268435554,"work":2700,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants simulated"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is estimate, and the job wants simulated"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants simulated"}},{"route":"provider:ref","kind":"provider","provider":"ref","class":"simulated","host_dependent":true,"price":{"money":{"free":true},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"chosen"},{"route":"provider:priced","kind":"provider","provider":"priced","class":"simulated","host_dependent":true,"price":{"money":{"free":false,"amount":"0.09","currency":"USD","unit":"shot"},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder","charged"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"rejected","rejected":{"code":"cost_no_ceiling","why":"0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider"}}],"choice":"provider:ref","why":"the cheapest of the 1 of 15 routes that meet the contract","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a","choice":false},"shadow":{"route":"method:exact","class":"bit-exact","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"budget_seconds":300.0,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]}},"kept":{}},"shadow":{"ran":true,"route":"method:exact","accuracy":{"class":"bit-exact"},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"shots":300,"counts":{"00":161,"11":139},"distinct_outcomes":2,"omitted_shots":0,"distance":{"computed":true,"numerator":44,"denominator":600,"total_variation":0.07333333333333333,"hellinger_fidelity":0.9946222222222221,"sampling_tvd_bound":0.04602751441903442},"elapsed_ms":0},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"71770ed37d2687b9f97392667c58c80a80836d6852619f0498aa1dcfec9e4996","signature":"ffe2160d7de0f0939ebb0146de12a9617976cff8049ab415f5ce85b3964cf66cdc3a3f216926f69820f2b6d9d4ebe0b206442d1e6aac5931bf27d2808671e508"}},"id":"pj-fc95adf1a5d6f2a3","submitted_ms":1793974079041,"finished_ms":1793974079044} diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-target.json b/wai/quantum-conformance/receipts/jobs/cli-contract-target.json new file mode 100644 index 000000000..dce1cb2c3 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-target.json @@ -0,0 +1 @@ +{"status":"done","method":"density_matrix","why":"density matrix of the 2 physical qubits the program touches, each gate and channel one superoperator pass, under the noise of the target synthetic-line-5 (calibration content:0b152c6f06102941): the program compiled to rzsxxcz on physical qubits [3, 4], 0 swaps, expected success 0.9563; each gate costed as the target's own, equal up to one-qubit gates; the route the job names, which meets its contract (1 of 3 routes)","estimate":{"memory_bytes":268435720,"work":400},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":50,"seed":2,"contract":{"deadline_seconds":60.0,"providers":"allowed"},"target":"synthetic-line-5"},"result":{"method":"density_matrix","qubits":2,"gates":2,"accuracy":{"class":"exact","note":"the noisy state under the target's noise model, exactly: a model of the device from its calibration snapshot: each gate's reported error as depolarising noise beside the amplitude damping and dephasing its T1, T2 and duration give, idling relaxed the same way, and each qubit's readout by its assignment errors; Markovian and gate-local, so crosstalk, leakage, coherent over-rotation and drift are not modelled; counts are seeded samples of its distribution, each bit misread by its qubit's assignment errors; expectation values are of the state before the measurement, with no readout error"},"counts":{"00":26,"11":22,"01":2},"distinct_outcomes":3,"omitted_shots":0,"ideal":{"computed":true,"total_variation_distance":0.03964591211886446,"hellinger_fidelity":0.960218501561203,"note":"the noisy distribution over the classical bits, exactly, against the circuit's ideal one by the bit-exact state vector: how far the target's noise moves the answer"},"target":{"name":"synthetic-line-5","hash":"a618b0e1c671834a0a8967524b4a7018752f50e3c11d98c1c49a687806e81701","hash_is":"BLAKE3 of the target document's RFC 8785 text","calibration":{"id":"content:0b152c6f06102941","timestamp":"2026-10-01T09:00:00+00:00"},"source":{"format":"device-properties","note":"synthetic: written for wai-quantum in the shape of the device-properties format, its numbers made up; no device's data"},"placement":{"basis":"rzsxxcz","exact":false,"layout":[3,4],"final_layout":[3,4],"swaps":0,"native_gates":9,"two_qubit_gates":1,"expected_success":0.9563103156162862,"fewest_swaps":{"layout":[0,1],"swaps":0,"expected_success":0.9491455074213893},"layouts_compared":8,"chosen":"noise-aware: of 8 layouts and their routes, the highest expected success (0.956310, against 0.949146 for the fewest swaps)","expected_success_is":"the product of each gate's success (one less its reported error, or where none is reported its relaxation over its duration) and each measured qubit's readout success (one less the mean of its assignment errors); idling is in the noise model, not in this figure","checked":"the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator","notes":["the target's gates do not hold one of the compiler's sets, so the program is compiled to rz sx x cz and each gate costed as the target's (cz as cx): the same up to one-qubit gates, which are not counted; a simulation of the device, not a program it runs as it is"]},"noise":{"model":"a model of the device from its calibration snapshot: each gate's reported error as depolarising noise beside the amplitude damping and dephasing its T1, T2 and duration give, idling relaxed the same way, and each qubit's readout by its assignment errors; Markovian and gate-local, so crosstalk, leakage, coherent over-rotation and drift are not modelled","simulated_qubits":[3,4],"duration_ns":491.0,"idle_ns":35.5,"channels":16,"one_qubit_depolarizing":{"gates":8,"mean":0.000025084801525975534},"two_qubit_depolarizing":{"gates":1,"mean":0.0029999418028110424},"readout":[{"logical":0,"physical":3,"p01":0.006877,"p10":0.03886},{"logical":1,"physical":4,"p01":0.007857,"p10":0.01804}],"notes":[]}},"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"exact","wanted_from":"named","named":"method:density_matrix","question":"counts","auto":null,"host":{"job_bytes":17179869184,"providers":["ref","priced"]},"routes":[{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":{"money":{"free":true},"time":{"seconds":7.2e-8,"basis":"nominal"},"memory_bytes":268435720,"work":400,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"chosen"},{"route":"provider:ref","kind":"provider","provider":"ref","class":"simulated","host_dependent":true,"price":{"money":{"free":true},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder"],"program":{"shots":50,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"provider:priced","kind":"provider","provider":"priced","class":"simulated","host_dependent":true,"price":{"money":{"free":false,"amount":"0.015","currency":"USD","unit":"shot"},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder","charged"],"program":{"shots":50,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}}],"choice":"method:density_matrix","why":"the route the job names, which meets its contract (1 of 3 routes)","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:density_matrix"],"digest":"16b4bfb6541720b9990c891168f637b933f09ef1134cd0bfb5165ac5d248a7e3","choice":false},"kept":{"deadline":{"seconds":60.0,"elapsed_ms":null,"kept":null}}},"energy":{"unmetered":"the command line does not meter a run's energy"},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"c60b7c322fcc2ceb37334ff4a9f4c4201bf03bb98349918e7d3cf47d097948a9","signature":"0a06f15970af18dc74d92d35d1fb7c30b956e65669f8a42a2b451c4072841afff2eaa427b322454d94c1b8fdb9b23183bb97f5bc7e17bbba34d24f54a702260f"}}} diff --git a/wai/quantum-conformance/receipts/jobs/scripted-contract-prx-circuits.json b/wai/quantum-conformance/receipts/jobs/scripted-contract-prx-circuits.json index 4c303b8ba..edb064730 100644 --- a/wai/quantum-conformance/receipts/jobs/scripted-contract-prx-circuits.json +++ b/wai/quantum-conformance/receipts/jobs/scripted-contract-prx-circuits.json @@ -8,6 +8,7 @@ "shots": 400, "seed": 5, "contract": { + "providers": "allowed", "exactness": "measured" } }, @@ -113,6 +114,8 @@ "format": "wai.quantum.planner/1", "wanted": "measured", "wanted_from": "contract", + "named": "provider:lab", + "question": "counts", "auto": null, "host": { "job_bytes": 8589934592, @@ -127,6 +130,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": null, "outcome": "rejected", "rejected": { @@ -140,6 +144,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +158,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -166,6 +172,7 @@ "method": "stabilizer", "class": "estimate", "host_dependent": false, + "auto_rank": 10, "price": null, "outcome": "rejected", "rejected": { @@ -179,6 +186,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -192,6 +200,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": null, "outcome": "rejected", "rejected": { @@ -205,6 +214,7 @@ "method": "stabilizer_rank", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -218,6 +228,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -231,6 +242,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -283,6 +298,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -405,7 +421,7 @@ "denominator": 800, "total_variation": 0.0275, "hellinger_fidelity": 0.9992431772192786, - "sampling_tvd_expected": 0.028198810450636217 + "sampling_tvd_bound": 0.039915404643269786 }, "elapsed_ms": 0 }, @@ -413,8 +429,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "1ec69219cfceace4fdadbd7ea08eea4769753ed34a7704f893e6cb6954a7981d", - "signature": "d0b09e4b2e1270cf907093c45e006e5c45f921c3a29018c4b80f5e060fb8923eeb8f0dc7b9fb565af2a1e84904a790a5d438f7c1c74f91e664947efc50341f03" + "digest": "7accadcb1d4c565d8572f2ef4140e000d100b76a3d08dd4539ab77152e55191a", + "signature": "2046d13ef4f6d65c8b3959cbdde19dd949f271f310ed164312e0f6b937b4aeba06665cd821947e49bc61b93c0162dccea80989a52f25ac9c2ed2a256d5db0903" } } } diff --git a/wai/quantum-conformance/receipts/made.lock.json b/wai/quantum-conformance/receipts/made.lock.json index 71103537c..2d0f72d6a 100644 --- a/wai/quantum-conformance/receipts/made.lock.json +++ b/wai/quantum-conformance/receipts/made.lock.json @@ -1,9 +1,14 @@ { "cli-compile.json": "1afbddc31dd54eb98a28df16b472769b5e6b12915d8cc72eb5d0093cd8c29593", - "cli-contract-auto.json": "8d44fc2fa9bf3846fa85048939cb408e395cf824a9f44236a478a2a765a28db4", - "cli-contract-local.json": "48fce7687fdf6934f415664316518fae774f95099daccaa4a9ad293fe7471fff", - "cli-contract-provider-priced.json": "a43ab21fde2040504888718de0485d5d80d94778b5500be9a8af2da0c2da7ea4", - "cli-contract-routed.json": "6e9ded06170571ce8b6b325a742f1bed371d5a1a7206aaa8f5fdbe3fc61bde36", + "cli-contract-auto.json": "6844a85707cd18e1cf9038cde4ddc0bdee8e9d861d65fd11a6340c69e416ecbf", + "cli-contract-bounded.json": "6a0d2e10c024f4ae8ffc185d800d7fd507dd30b24e0c52b4f5d01f0453298a47", + "cli-contract-fabric-cpu.json": "61ce33ef961b5f2fda544834743484debc8d687f28644fc614b82d930f96932a", + "cli-contract-local.json": "f8c3f3f2c85c85a6ed0c7da3b15e55af884fd8d06c441e13d93a5e72347cf5a7", + "cli-contract-provider-priced.json": "e2e741f626311733c3cb7f60019d2642a53d94c32a39cccb760409a5defc38ac", + "cli-contract-pulse.json": "16648cdfaeed225bdb98b5431ba1a570971d823fd531df65b79406a0508fb533", + "cli-contract-routed-seed.json": "a663c21f0c421dee1515fb7b0853ba63852cbbbbab14dbdd640b0e846164b55f", + "cli-contract-routed.json": "6ebe882a9d078095b61f501c601b24a93cae4d29f775b0bd2b74301be4736d86", + "cli-contract-target.json": "3ac678c68effba76bfb13a05e3d5e7c8fa862f2c1146dab05a7680c46b11a1a5", "cli-provider-reference-priced.json": "e569e1810da66580c9da4c4fb1185490919d03066f104de8332f99ac214a728b", "cli-provider-reference.json": "ade872d1a9e34a70f9f3928218b64b91ef2df8c21229778d79cd9cbbbb436f0c", "cli-run-mps.json": "9f8fdd7f57566b63e66e979769caae330a32fe01520d909a82f1ecba5c5a6f04", @@ -18,7 +23,7 @@ "scripted-cloud-tasks-processor-probabilities.json": "63f457f817d940d8af7e161b66aeb6b089e46c80a06c8b640b0a8ad3bd4c46cb", "scripted-cloud-tasks-processor.json": "1eb499584183085209fa4597e0f8956826f18cf29d0885e7ad9a1c55a656f66d", "scripted-cloud-tasks-simulator.json": "cc99f5d91138569f7584f913c88293a8581085ef6a38944f7425ad86591252c4", - "scripted-contract-prx-circuits.json": "7a81903f4e805d340f8cc938ad592d9ba002f6ce4ffc12fd02ef40ba8992529b", + "scripted-contract-prx-circuits.json": "61f23584bd53ee5edbebd1c9f4e7cf2a60afa6dd09c174509737cbabeb9d1f50", "scripted-native-turns-noise.json": "8a6c1bac37f1b6a856d891dbc657d91c252a40eb7a5a09ab0ec9474233425385", "scripted-native-turns.json": "9cc3b887aba07437b2a3ad6e20e7f656853c63bf8c94c21c715efdfddf95ee77", "scripted-prx-circuits.json": "d1c74db10b01a23a7b66d90356a33b8f7afc37efd7c75a5af26fbd87f99cda6b", diff --git a/wai/quantum-conformance/receipts/make.sh b/wai/quantum-conformance/receipts/make.sh index f20712024..c90d4508d 100644 --- a/wai/quantum-conformance/receipts/make.sh +++ b/wai/quantum-conformance/receipts/make.sh @@ -32,11 +32,23 @@ printf 'OPENQASM 3.0;\ninclude "stdgates.inc";\nqubit[1] q;\nrx(0.4) q[0];\n' > "$B" run bell.qasm --provider priced --shots 300 --seed 4 --yes --demo-key --json > "$OUT/cli-provider-reference-priced.json" # Jobs under a contract (section 8.6): the cheapest exact route here, under a deadline and a # ceiling; auto's class kept; every route weighed with the person's providers, the free -# simulator chosen by its class and shadowed; and a provider named, under a ceiling, confirmed. +# simulator chosen by its class and shadowed (and again with a seed whose shadow's wraps at +# 2^53); any class, where a method here and a free provider tie on money and time and the +# method comes first; a provider named and allowed, under a ceiling, confirmed; bounded, where a single- +# precision route does not meet it; the CPU asked for; a device target beside the person's +# providers; and a pulse program. +printf 'OPENQASM 3.0;\ninclude "stdgates.inc";\nqubit[2] q;\nbit[2] c;\nrx(0.3) q[0];\ncx q[0], q[1];\nc = measure q;\n' > rot.qasm +printf 'OPENQASM 3.0;\ndefcalgrammar "openpulse";\ncal {\n extern port d0;\n extern port a0;\n frame q0 = newframe(d0, 5.0e9, 0);\n frame c0 = newframe(a0, 5.0e9, 0);\n}\ndefcal x $0 { play(q0, drag(0.4, 64dt, 16dt, 0.2)); }\ndefcal measure $0 -> bit { return capture_v2(c0, 100dt); }\nbit c;\nx $0;\nc = measure $0;\n' > pulse.qasm "$B" run bell.qasm --shots 1000 --seed 7 --exactness exact --deadline 60 --max-cost 1:USD --demo-key --json > "$OUT/cli-contract-local.json" "$B" run three.qasm --shots 500 --seed 3 --deadline 600 --demo-key --json > "$OUT/cli-contract-auto.json" "$B" run bell.qasm --shots 300 --seed 4 --exactness simulated --allow-providers --demo-key --json > "$OUT/cli-contract-routed.json" -"$B" run bell.qasm --provider priced --shots 300 --seed 4 --max-cost 1:USD --yes --demo-key --json > "$OUT/cli-contract-provider-priced.json" +"$B" run bell.qasm --shots 300 --seed 9007199254740990 --exactness simulated --allow-providers --demo-key --json > "$OUT/cli-contract-routed-seed.json" +"$B" run bell.qasm --shots 100 --seed 2 --exactness any --allow-providers --deadline 60 --demo-key --json > "$OUT/cli-contract-any.json" +"$B" run bell.qasm --provider priced --allow-providers --shots 300 --seed 4 --max-cost 1:USD --yes --demo-key --json > "$OUT/cli-contract-provider-priced.json" +"$B" run rot.qasm --shots 100 --seed 2 --exactness bounded --deadline 60 --demo-key --json > "$OUT/cli-contract-bounded.json" +"$B" run bell.qasm --shots 100 --seed 2 --fabric cpu --deadline 60 --demo-key --json > "$OUT/cli-contract-fabric-cpu.json" +"$B" run bell.qasm --shots 50 --seed 2 --target synthetic-line-5 --allow-providers --deadline 60 --demo-key --json > "$OUT/cli-contract-target.json" +"$B" run pulse.qasm --method pulse --shots 50 --seed 2 --exactness bounded --deadline 60 --demo-key --json > "$OUT/cli-contract-pulse.json" "$B" submit bell.qasm --shots 200 --seed 11 --json > "$OUT/service-run.json" "$B" submit bell.qasm --shots 200 -o "Z0 Z1" --json > "$OUT/service-run-stabilizer.json" for f in "$OUT"/cli-*.json "$OUT"/service-*.json; do "$B" verify "$f" > /dev/null || { echo "make.sh: $f does not verify" >&2; exit 1; }; done diff --git a/wai/quantum-conformance/tools/receipt_differential.py b/wai/quantum-conformance/tools/receipt_differential.py index 27a77f53d..20394cd58 100644 --- a/wai/quantum-conformance/tools/receipt_differential.py +++ b/wai/quantum-conformance/tools/receipt_differential.py @@ -85,11 +85,30 @@ def run_lines(cmd, path, n): return verdicts(p.stdout, n) +def _same_number(v): + """A stated value with each number past 2^53 read as the double both verifiers + hold it as, so that one writing it whole and the other as a double agree.""" + if isinstance(v, bool) or v is None: + return v + if isinstance(v, int): + return float(v) if abs(v) > 2 ** 53 else v + if isinstance(v, dict): + return dict((k, _same_number(x)) for k, x in v.items()) + if isinstance(v, list): + return [_same_number(x) for x in v] + return v + + def said(v): - """What a verdict says that both verifiers must agree on.""" + """What a verdict says that both verifiers must agree on: its reasons, its key + and form, what it reads of a provider's result, and of a job under a contract + the choice, the class wanted and the class given, what was kept, the stable + choice, and the shadow (whether it ran and its total variation).""" p = v.get("provider") or {} c = v.get("planner") or {} - return (tuple(sorted(v.get("reasons", []))), v.get("key"), v.get("form"), p.get("form"), p.get("read_as"), p.get("counts_source"), c.get("choice"), c.get("wanted"), c.get("stable_choice"), c.get("shadow_ran")) + return (tuple(sorted(v.get("reasons", []))), v.get("key"), v.get("form"), p.get("form"), p.get("read_as"), p.get("counts_source"), + c.get("choice"), c.get("wanted"), c.get("class"), c.get("stable_choice"), _same_number(c.get("kept")), c.get("shadow_ran"), + _same_number(c.get("shadow_total_variation"))) # ----------------------------------------------------------------- one change at a time diff --git a/wai/quantum-conformance/tools/receipt_verify.py b/wai/quantum-conformance/tools/receipt_verify.py index 680dd13bc..51ccebe61 100644 --- a/wai/quantum-conformance/tools/receipt_verify.py +++ b/wai/quantum-conformance/tools/receipt_verify.py @@ -1033,9 +1033,30 @@ MEETS = { "simulated": ("simulated",), } CLASSES_WANTED = tuple(MEETS) + ("any",) +LADDER = ("bit-exact", "exact", "single", "bounded", "estimate", "heuristic") LEAVES_OUT = ("time", "amount", "energy", "mitigation", "decoder", "charged") +QUESTIONS = ("noise", "counts", "expectations", "amplitudes") _DECIMAL = re.compile(r"[0-9]+(?:\.[0-9]+)?") _GPU_METHODS = ("method:statevector_single", "method:cutrank_single") +MAX_SECONDS = 1e12 # §8.6: the most seconds a price may state +MAX_AMOUNT = 64 # §8.6: the most characters an amount may have +# §8.6: each built-in method's rank in auto's order, by question (noise, counts, +# expectations, amplitudes); None where auto does not try it for that question. +AUTO_RANKS = { + "exact": (None, 20, 20, 10), + "statevector": (None, 30, 30, 20), + "statevector_single": (None, 40, 40, 30), + "stabilizer": (20, 10, 10, None), + "pauli": (None, None, 60, None), + "mps": (None, 60, 70, 70), + "stabilizer_rank": (None, None, 50, 50), + "tensor_network": (None, None, None, 60), + "cutrank": (None, 50, None, 40), + "cutrank_single": (None, None, None, None), + "density_matrix": (10, None, None, None), + "trajectories": (30, None, None, None), + "pulse": (None, None, None, None), +} def meets(wanted, got): @@ -1044,7 +1065,16 @@ def meets(wanted, got): def _is_decimal(s): - return isinstance(s, str) and _DECIMAL.fullmatch(s) is not None + """§8.6: digits, optionally '.' and digits, at most 64 characters.""" + return isinstance(s, str) and len(s) <= MAX_AMOUNT and _DECIMAL.fullmatch(s) is not None + + +def _value_of(v): + return v.value if isinstance(v, Num) else None + + +def _same_keys(v, keys): + return isinstance(v, dict) and set(v) == set(keys) def read_contract(c): @@ -1073,8 +1103,39 @@ def read_contract(c): "providers": providers} -def _value_of(v): - return v.value if isinstance(v, Num) else None +def _seconds_ok(v): + return isinstance(v, Num) and 0 <= v.value <= MAX_SECONDS + + +def _price_form(p, local): + """§8.6: a price. A local route's money is free; seconds and amounts are bounded.""" + if not isinstance(p, dict): + return False + m = p.get("money") + if not isinstance(m, dict): + return False + if m.get("free") is False: + if local or not (isinstance(m.get("unknown"), str) or (isinstance(m.get("amount"), str) and isinstance(m.get("currency"), str))): + return False + elif m.get("free") is not True: + return False + if "at_least" in m and m["at_least"] is not True: + return False + if "amount" in m and not (isinstance(m["amount"], str) and len(m["amount"]) <= MAX_AMOUNT): + return False + t = p.get("time") + if not isinstance(t, dict) or not (t.get("seconds") is None or _seconds_ok(t["seconds"])): + return False + e = p.get("energy") + if not isinstance(e, dict) or not (e.get("joules") is None or isinstance(e["joules"], Num)): + return False + left = p.get("leaves_out") + if not isinstance(left, list) or any(w not in LEAVES_OUT for w in left): + return False + for k in ("memory_bytes", "work"): + if k not in p or not (p[k] is None or (_whole(p[k]) and p[k].value >= 0)): + return False + return True def _route_form(r): @@ -1083,8 +1144,8 @@ def _route_form(r): name, kind = r.get("route"), r.get("kind") if not isinstance(name, str): return False - method, provider = name.startswith("method:"), name.startswith("provider:") - if not ((method and len(name) > 7 and kind == "local") or (provider and len(name) > 9 and kind == "provider")): + local = name.startswith("method:") and len(name) > 7 and kind == "local" + if not (local or (name.startswith("provider:") and len(name) > 9 and kind == "provider")): return False outcome = r.get("outcome") if outcome in ("chosen", "met"): @@ -1098,32 +1159,11 @@ def _route_form(r): return False if "price" not in r: return False - p = r["price"] - if p is not None: - if not isinstance(p, dict): + if r["price"] is not None and not _price_form(r["price"], local): + return False + if local: + if "auto_rank" not in r or not (r["auto_rank"] is None or (_whole(r["auto_rank"]) and r["auto_rank"].value >= 0)): return False - m = p.get("money") - if not isinstance(m, dict): - return False - if m.get("free") is False: - if not (isinstance(m.get("unknown"), str) or (isinstance(m.get("amount"), str) and isinstance(m.get("currency"), str))): - return False - elif m.get("free") is not True: - return False - if "at_least" in m and m["at_least"] is not True: - return False - t = p.get("time") - if not isinstance(t, dict) or not (t.get("seconds") is None or (isinstance(t["seconds"], Num) and t["seconds"].value >= 0)): - return False - e = p.get("energy") - if not isinstance(e, dict) or not (e.get("joules") is None or isinstance(e["joules"], Num)): - return False - left = p.get("leaves_out") - if not isinstance(left, list) or any(w not in LEAVES_OUT for w in left): - return False - for k in ("memory_bytes", "work"): - if k not in p or not (p[k] is None or (_whole(p[k]) and p[k].value >= 0)): - return False return isinstance(r.get("class"), str) and isinstance(r.get("host_dependent"), bool) @@ -1145,7 +1185,10 @@ def _planner_form(p): names = [r["route"] for r in routes] if len(set(names)) != len(names): return False - if not (p.get("auto") is None or p["auto"] in names) or p.get("choice") not in names: + for k in ("named", "auto"): + if not (p.get(k) is None or p[k] in names): + return False + if p.get("question") not in QUESTIONS or p.get("choice") not in names: return False host = p.get("host") if not isinstance(host, dict) or not (_whole(host.get("job_bytes")) and host["job_bytes"].value >= 0): @@ -1156,38 +1199,76 @@ def _planner_form(p): return isinstance(p.get("why"), str) and isinstance(p.get("stable"), dict) and isinstance(p.get("kept"), dict) -def _named(request, routes): - """§8.6: what a request names: a provider, or a method (or the one route of routes).""" +def _request_names(request): + """§8.6: provider: for the provider a request names, else method: for a + method other than auto, else None.""" provider = request.get("provider") - provider = provider if isinstance(provider, str) else None - method = None - if provider is None: - m = request.get("method") - if isinstance(m, str) and m != "auto": - method = m - if len(routes) == 1: - name = routes[0]["route"] - method = name[len("method:"):] if name.startswith("method:") else None - return provider, method + if isinstance(provider, str): + return "provider:" + provider + m = request.get("method") + if isinstance(m, str) and m != "auto": + return "method:" + m + return None -def _gate(r, contract, request, provider, method, wanted, job_bytes): +def _question(request): + """§8.6: the question a job asks, from its request alone.""" + def listed(k): + v = request.get(k) + return isinstance(v, list) and len(v) > 0 + observables, amplitudes = listed("observables"), listed("amplitudes") + shots = request.get("shots") + if isinstance(shots, Num) and shots.literal_whole() and not shots.text.startswith("-") and int(shots.text) <= 2 ** 64 - 1: + shots = int(shots.text) + else: + shots = 1024 if not observables and not amplitudes else 0 + if request.get("noise") is not None: + return "noise" + if shots > 0: + return "counts" + if observables and not amplitudes: + return "expectations" + return "amplitudes" + + +def _fabric(request): + f = request.get("fabric") + if f is None or f == "auto": + return "free" + return "cpu" if f == "cpu" else "placed" + + +def _auto(routes, request, named): + """§8.6: the route auto picks, from the routes.""" + if named is not None: + return None + if _fabric(request) == "placed": + for r in routes: + if r["route"] == "method:statevector" and r["kind"] == "local" and r["price"] is not None: + return "method:statevector" + return None + best = None + for i, r in enumerate(routes): + if r["kind"] == "local" and r["price"] is not None and r.get("auto_rank") is not None: + key = (r["auto_rank"].value, i) + if best is None or key < best[0]: + best = (key, r["route"]) + return best[1] if best else None + + +def _gate(r, contract, request, named, wanted, from_contract, job_bytes): """§8.6's rules, in order: the first that applies, or None.""" name, price = r["route"], r["price"] is_provider = name.startswith("provider:") # 1 - if provider is not None: - if name != "provider:" + provider: - return "not_named" - elif method is not None and name != "method:" + method: + if named is not None and name != named: return "not_named" # 2 - if provider is None and method is None: - fabric = request.get("fabric") - if fabric == "cpu": - if name in _GPU_METHODS: - return "fabric" - elif fabric is not None and fabric != "auto" and name != "method:statevector": + if named is None: + fabric = _fabric(request) + if fabric == "cpu" and name in _GPU_METHODS: + return "fabric" + if fabric == "placed" and name != "method:statevector": return "fabric" cls = r["class"] # 3 @@ -1195,7 +1276,7 @@ def _gate(r, contract, request, provider, method, wanted, job_bytes): return "cannot" # 4 if wanted is not None: - if not meets(wanted, cls) or (wanted == "simulated" and r.get("approximate") is True): + if not meets(wanted, cls) or (from_contract and wanted == "simulated" and r.get("approximate") is True): return "class" elif is_provider: return "class" @@ -1207,7 +1288,7 @@ def _gate(r, contract, request, provider, method, wanted, job_bytes): if memory is not None and memory > job_bytes: return "memory" # 7 - if is_provider and provider is None and contract["providers"] != "allowed": + if is_provider and contract["providers"] != "allowed": return "providers" # 8 if contract["deadline"] is not None: @@ -1221,7 +1302,7 @@ def _gate(r, contract, request, provider, method, wanted, job_bytes): if is_provider and money.get("free") is not True: ceiling = contract["max_cost"] if ceiling is None: - if provider is None: + if named != name: return "cost_no_ceiling" else: amount, currency = money.get("amount"), money.get("currency") @@ -1244,16 +1325,19 @@ def _gate(r, contract, request, provider, method, wanted, job_bytes): def _order_key(r): - """§8.6's order: money, time to the millisecond, local first, memory, name.""" + """§8.6's order: money (free, then an amount in decimals by value, then any other), + time to the nearest millisecond (halves up; a stated one first), local first, + memory, name.""" p = r["price"] money = p["money"] if money.get("free") is True: cost = (0, fractions.Fraction(0)) + elif _is_decimal(money.get("amount")): + cost = (1, fractions.Fraction(money["amount"])) else: - amount = money.get("amount") - cost = (1, fractions.Fraction(amount) if _is_decimal(amount) else fractions.Fraction(0)) + cost = (2, fractions.Fraction(0)) seconds = _value_of(p["time"].get("seconds")) - time = (1, 0) if seconds is None else (0, math.ceil(seconds * 1000.0)) + time = (1, 0) if seconds is None else (0, math.floor(seconds * 1000.0 + 0.5)) return (cost, time, 0 if r["kind"] == "local" else 1, _value_of(p["memory_bytes"]) or 0.0, r["route"].encode("utf-8")) @@ -1284,7 +1368,8 @@ def _stable_holds(p, routes, contract): def _kept_holds(p, contract, result): - """§8.6 kept: a member for each the contract gives, each as its table says.""" + """§8.6 kept: exactly a member for each the contract gives, each of exactly its + members, each as its table says.""" kept = p["kept"] asked = (("deadline", contract["deadline"] is not None), ("energy", contract["joules"] is not None), ("cost", contract["max_cost"] is not None)) if len(kept) != sum(1 for _, a in asked if a) or any((n in kept) != a for n, a in asked): @@ -1292,7 +1377,7 @@ def _kept_holds(p, contract, result): if contract["deadline"] is not None: d = contract["deadline"] k = kept["deadline"] - if not isinstance(k, dict): + if not _same_keys(k, ("seconds", "elapsed_ms", "kept")): return False e = k.get("elapsed_ms") if not (e is None or (_whole(e) and e.value >= 0)): @@ -1305,7 +1390,7 @@ def _kept_holds(p, contract, result): if contract["joules"] is not None: j = contract["joules"] k = kept["energy"] - if not isinstance(k, dict): + if not _same_keys(k, ("max_joules", "joules", "kept")): return False micro = _value_of(_member(result, "energy", "joules_micro")) x = None if micro is None else micro / 1e6 @@ -1314,7 +1399,7 @@ def _kept_holds(p, contract, result): if contract["max_cost"] is not None: ceiling = contract["max_cost"] k = kept["cost"] - if not isinstance(k, dict): + if not _same_keys(k, ("max_cost", "charged", "kept")) or not _same_keys(k.get("max_cost"), ("amount", "currency")): return False charged = _member(result, "cost", "charged") free = _member(result, "cost", "free") @@ -1329,76 +1414,139 @@ def _kept_holds(p, contract, result): held = True else: held = None + charged_same = k.get("charged") is None if charged is None else _same(k.get("charged"), charged) if (_member(k, "max_cost", "amount") != ceiling["amount"] or _member(k, "max_cost", "currency") != ceiling["currency"] - or k.get("kept") is not held or (k.get("charged") is None) != (charged is None)): + or k.get("kept") is not held or not charged_same): return False return True def _count(v): - """§8.6: a count as a whole number written as one, from 0 to 2^64 − 1, or 0.""" + """§8.6: a count of a list, a whole number written as one from 0 to 2^64 − 1, or 0.""" if isinstance(v, Num) and v.literal_whole() and not v.text.startswith("-"): n = int(v.text) return n if n <= 2 ** 64 - 1 else 0 return 0 +def split_mad(n): + """§8.6: E|2B − n| for B binomial (n, 1/2), in doubles in the order written.""" + if n == 0: + return 0.0 + j = (n - 1) // 2 + if j < 4096: + m = 1.0 + for i in range(j): + m = m * float(2 * i + 3) / float(2 * i + 2) + return m + jj = float(j) + c = (1.0 - 1.0 / (8.0 * jj) + 1.0 / (128.0 * jj * jj) + 5.0 / (1024.0 * jj * jj * jj)) / math.sqrt(math.pi * jj) + return (2.0 * jj + 1.0) * c + + def shadow_distance(a, b, shots): """§8.6 distance: the numerator, the denominator, the total variation, the Hellinger - fidelity and what the shots alone leave, in order, or None when it cannot be taken.""" + fidelity and the sampling bound, in order, or None when it cannot be taken.""" if not (isinstance(a, dict) and isinstance(b, dict)) or shots <= 0: return None s = float(shots) - numerator, root, floor = 0, 0.0, 0.0 + numerator, root, bound, total = 0, 0.0, 0.0, 0 for k in sorted(set(a) | set(b), key=lambda k: k.encode("utf-8")): x, y = _count(a.get(k)), _count(b.get(k)) # Sums of whole numbers exact; each product and quotient a double's. numerator += abs(x - y) root += math.sqrt(float(x) * float(y)) - p = float(x + y) / (2.0 * s) - inner = 4.0 * p * (1.0 - p) / (math.pi * s) - if inner != inner or inner < 0: - return None - floor += math.sqrt(inner) + total += x + y + bound += split_mad(x + y) + if total > 2 * shots: + return None denominator = 2 * shots - return (numerator, denominator, float(numerator) / float(denominator), root * root / (s * s), 0.5 * floor) + return (numerator, denominator, float(numerator) / float(denominator), root * root / (s * s), min(1.0, 0.5 * bound / s)) -def _shadow_holds(request, p, result): - """§8.6 shadow: of its form, what its plan and the job imply, its distance its counts'.""" - s, plan = result["shadow"], p["shadow"] - if not isinstance(s, dict) or not isinstance(plan, dict): +def _whole_value(v): + """A number whose value is whole and at least 0, as a whole number (at most 2^64 − 1).""" + if isinstance(v, Num) and float(v.value).is_integer() and v.value >= 0: + return min(int(v.value), 2 ** 64 - 1) + return None + + +def _shadow_count(v): + """§8.6: a count of a shadow's list, a whole number written as one from 1 to 2^53 − 1.""" + if isinstance(v, Num) and v.literal_whole() and not v.text.startswith("-"): + n = int(v.text) + if 1 <= n <= MAX_SAFE: + return n + return None + + +def _shadow_budget(contract, provider_seconds): + d = contract["deadline"] + if d is None: + return 300.0 + if provider_seconds is None: + return d + return max(d - provider_seconds, 0.0) + + +def _shadow_plan_holds(request, contract, p, result): + """§8.6: the reasoning's shadow.""" + plan = p.get("shadow") + if not isinstance(plan, dict) or "route" not in plan: + return False + route = plan["route"] + if route is None: + return (plan.get("code") in ("budget", "memory", "none") and isinstance(plan.get("why"), str) + and ("tried" not in plan or isinstance(plan["tried"], list))) + if not (isinstance(route, str) and route.startswith("method:") and len(route) > 7): + return False + chosen = next((r for r in p["routes"] if r["route"] == p["choice"]), None) + provider_seconds = _value_of(_member(chosen, "price", "time", "seconds")) if chosen else None + budget = _shadow_budget(contract, provider_seconds) + req = plan.get("request") + price = plan.get("price") + listed = next((r for r in p["routes"] if r["route"] == route), None) + if listed is None or plan.get("class") != listed["class"]: + return False + if not (plan.get("class") in LADDER and _value_of(plan.get("budget_seconds")) == budget + and _price_form(price, True) and _value_of(_member(price, "time", "seconds")) is not None + and _value_of(price["time"]["seconds"]) <= budget): + return False + if not _same_keys(req, ("qasm", "shots", "seed", "method")): + return False + seed = request.get("seed") + seed = int(seed.text) if isinstance(seed, Num) and seed.literal_whole() and not seed.text.startswith("-") else 1 + seed = seed if seed <= 2 ** 64 - 1 else 1 + want_seed = (seed + 2 ** 32) % 2 ** 53 + given = req.get("seed") + return (_same(req.get("qasm"), request.get("qasm")) and isinstance(req.get("qasm"), str) + and _same(req.get("shots"), result.get("shots")) + and isinstance(given, Num) and given.literal_whole() and not given.text.startswith("-") and int(given.text) == want_seed + and req.get("method") == route[len("method:"):]) + + +def _shadow_holds(request, contract, p, result): + """§8.6 shadow: its plan, its form, what its plan and the job imply, its distance its + counts'.""" + s, plan = result["shadow"], p.get("shadow") + if not isinstance(s, dict) or not _shadow_plan_holds(request, contract, p, result): return False ran = s.get("ran") if ran is False: if not (isinstance(s.get("code"), str) and isinstance(s.get("why"), str)): return False return s["code"] == plan.get("code") if plan.get("route") is None else s["code"] == "failed" - if ran is not True: - return False - shots_n = result.get("shots") - shots = _value_of(shots_n) - req = s.get("request") - if not isinstance(req, dict) or not _same(plan.get("request"), req) or not _same(req.get("qasm"), request.get("qasm")): - return False - if _value_of(req.get("shots")) != shots or shots is None: - return False - seed = request.get("seed") - # The request's seed as a whole number from 0 to 2^64 − 1 written as one, else 1. - seed = int(seed.text) if isinstance(seed, Num) and seed.literal_whole() and not seed.text.startswith("-") else 1 - seed = seed if seed <= 2 ** 64 - 1 else 1 - want_seed = (seed + 2 ** 32) % 2 ** 53 - given = req.get("seed") - if not (isinstance(given, Num) and given.literal_whole() and not given.text.startswith("-") and int(given.text) == want_seed): - return False - route = plan.get("route") - if not (isinstance(route, str) and route.startswith("method:") and req.get("method") == route[len("method:"):]): + if ran is not True or plan.get("route") is None: return False + shots = _whole_value(result.get("shots")) counts = s.get("counts") - if not isinstance(counts, dict): + if not isinstance(counts, dict) or shots is None: return False - listed = sum(v.value for v in counts.values() if isinstance(v, Num)) - if _value_of(s.get("omitted_shots")) is None or _value_of(s["omitted_shots"]) + listed != shots or not (_whole(s.get("distinct_outcomes")) and s["distinct_outcomes"].value >= 0): + listed = [_shadow_count(v) for v in counts.values()] + omitted = _whole_value(s.get("omitted_shots")) + if any(n is None for n in listed) or omitted is None or sum(listed) + omitted != shots: + return False + if not (_whole(s.get("distinct_outcomes")) and s["distinct_outcomes"].value >= 0): return False d = s.get("distance") if not isinstance(d, dict): @@ -1410,16 +1558,17 @@ def _shadow_holds(request, p, result): return False elif d.get("computed") is True: if "distance-unchecked" not in PLANTS: # PLANT - # S as a whole number of at most 2^64 − 1, as §8.6 reads it. - want = shadow_distance(result.get("counts"), counts, min(max(int(shots), 0), 2 ** 64 - 1)) + want = shadow_distance(result.get("counts"), counts, shots) if want is None or theirs != 0 or ours != 0: return False - for k, v in zip(("numerator", "denominator", "total_variation", "hellinger_fidelity", "sampling_tvd_expected"), want): + for k, v in zip(("numerator", "denominator", "total_variation", "hellinger_fidelity", "sampling_tvd_bound"), want): if _value_of(d.get(k)) != float(v): return False else: return False - return (s.get("route") == route and isinstance(_member(s, "accuracy", "class"), str) and _value_of(s.get("shots")) == shots) + cls = _member(s, "accuracy", "class") + return (s.get("route") == plan["route"] and isinstance(cls, str) and meets(plan.get("class"), cls) + and _same(s.get("request"), plan.get("request")) and _same(s.get("shots"), result.get("shots"))) def check_contract(request, result, reasons): @@ -1439,27 +1588,41 @@ def check_contract(request, result, reasons): if not _planner_form(planner): reasons.add("planner_form") return + if request.get("provider") is not None and contract["providers"] != "allowed": + reasons.add("contract_provider") routes = planner["routes"] - provider, method = _named(request, routes) - # What is wanted, and where from. + # What the job names, the question it asks and what auto picks: from the request + # and the routes, never from what the reasoning says of itself. + named = _request_names(request) + if named is None and request.get("target") is not None: + stated = planner.get("named") + named = stated if isinstance(stated, str) and stated.startswith("method:") else None + question = _question(request) + ranks_ok = True + for r in routes: + if r["kind"] == "local" and r["route"][len("method:"):] in AUTO_RANKS: + want = AUTO_RANKS[r["route"][len("method:"):]][QUESTIONS.index(question)] + if _value_of(r["auto_rank"]) != want: + ranks_ok = False + auto = _auto(routes, request, named) class_of = dict((r["route"], r["class"]) for r in routes) if contract["exactness"] is not None: wanted, source = contract["exactness"], "contract" - elif provider is not None: - wanted, source = class_of.get("provider:" + provider), "named" - elif method is not None: - wanted, source = class_of.get("method:" + method), "named" - elif planner.get("auto") is not None: - wanted, source = class_of.get(planner["auto"]), "auto" + elif named is not None: + wanted, source = class_of.get(named), "named" + elif auto is not None: + wanted, source = class_of.get(auto), "auto" else: wanted, source = None, None - if planner.get("wanted") != wanted or planner["wanted_from"] != source: + if (planner.get("named") != named or planner.get("question") != question or not ranks_ok + or planner.get("auto") != auto or planner.get("wanted") != wanted or planner["wanted_from"] != source): reasons.add("planner_form") return job_bytes = planner["host"]["job_bytes"].value + from_contract = source == "contract" def gate(r): - return _gate(r, contract, request, provider, method, wanted, job_bytes) + return _gate(r, contract, request, named, wanted, from_contract, job_bytes) broken = False chosen = [r["route"] for r in routes if r["outcome"] == "chosen"] @@ -1478,7 +1641,7 @@ def check_contract(request, result, reasons): m = result.get("method") ran = "method:" + m if isinstance(m, str) else None if "choice-unchecked" not in PLANTS: # PLANT - if _picked(routes, planner.get("auto"), contract, lambda r: gate(r) is None) != planner["choice"] or ran != planner["choice"]: + if _picked(routes, auto, contract, lambda r: gate(r) is None) != planner["choice"] or ran != planner["choice"]: reasons.add("planner_choice") if not _stable_holds(planner, routes, contract): reasons.add("planner_stable") @@ -1486,10 +1649,10 @@ def check_contract(request, result, reasons): reasons.add("planner_kept") if wanted is not None: cls = _member(result, "accuracy", "class") - if not meets(wanted, cls) or (wanted == "simulated" and _member(result, "accuracy", "approximate") is True): + if not meets(wanted, cls) or (from_contract and wanted == "simulated" and _member(result, "accuracy", "approximate") is True): reasons.add("contract_class") is_provider = planner["choice"].startswith("provider:") - if is_provider != ("shadow" in result) or is_provider != ("shadow" in planner) or (is_provider and not _shadow_holds(request, planner, result)): + if is_provider != ("shadow" in result) or is_provider != ("shadow" in planner) or (is_provider and not _shadow_holds(request, contract, planner, result)): reasons.add("shadow") @@ -1758,36 +1921,45 @@ def _provider_result(**changes): _DELETE = object() -def _contract_job(**changes): - """§8.6: the provider job above, named under a contract that wants a simulator's counts, - with its reasoning and its shadow, for the self-test only: (request text, result text).""" +def _contract_job(seed=None, extra_routes=(), **changes): + """§8.6: the provider job above, named under a contract that allows it and wants a + simulator's counts, with its reasoning and its shadow, for the self-test only: + (request text, result text). Every outcome is written here, not computed.""" request = json.loads(_PROVIDER_REQUEST) - request["contract"] = {"exactness": "simulated"} + request["contract"] = {"exactness": "simulated", "providers": "allowed"} + if seed is not None: + request["seed"] = seed job_bytes = 1 << 30 facts = {"job_bytes": job_bytes, "routes": [ {"route": "method:exact", "class": "bit-exact", "seconds": None, "memory_bytes": None, "work": None}]} digest = blake3(text_of(read_json(json.dumps(facts).encode()), True).encode("utf-8")).hex() - shadow_request = {"qasm": request["qasm"], "shots": 4, "seed": 1 + 2 ** 32, "method": "exact"} + shadow_request = {"qasm": request["qasm"], "shots": 4, "seed": ((1 if seed is None else seed) + 2 ** 32) % 2 ** 53, "method": "exact"} + free_now = {"money": {"free": True}, "time": {"seconds": 1.5, "basis": "provider"}, "memory_bytes": None, + "work": None, "energy": {"joules": None, "why": "no provider states it"}, "leaves_out": ["energy"]} planner = { - "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "contract", "auto": None, - "host": {"job_bytes": job_bytes, "providers": ["lab"]}, + "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "contract", + "named": "provider:lab", "question": "counts", "auto": None, + "host": {"job_bytes": job_bytes, "providers": ["lab"] + [r["provider"] for r in extra_routes]}, "routes": [ {"route": "method:exact", "kind": "local", "method": "exact", "class": "bit-exact", "host_dependent": False, - "price": None, "outcome": "rejected", "rejected": {"code": "not_named", "why": "the job names another route"}}, + "auto_rank": 20, "price": None, "outcome": "rejected", "rejected": {"code": "not_named", "why": "the job names another route"}}, {"route": "provider:lab", "kind": "provider", "provider": "lab", "class": "simulated", "host_dependent": True, - "price": {"money": {"free": True}, "time": {"seconds": 1.5, "basis": "provider"}, "memory_bytes": None, - "work": None, "energy": {"joules": None, "why": "no provider states it"}, "leaves_out": ["energy"]}, - "outcome": "chosen"}, - ], + "price": free_now, "outcome": "chosen"}, + ] + list(extra_routes), "choice": "provider:lab", "why": "the route the job names", "stable": {"scope": "the host-independent routes", "routes": ["method:exact"], "digest": digest, "choice": False}, "kept": {}, - "shadow": {"route": "method:exact", "class": "bit-exact", "budget_seconds": 300, "price": None, "request": shadow_request}, + "shadow": {"route": "method:exact", "class": "bit-exact", "budget_seconds": 300, + "price": {"money": {"free": True}, "time": {"seconds": 0.001, "basis": "nominal"}, "memory_bytes": 1024, + "work": 8, "energy": {"joules": None, "why": "none"}, "leaves_out": []}, + "request": shadow_request}, } + # By hand: 8 shots of "1" pooled, E|2B - 8| = (3/2)(5/4)(7/6) = 2.1875; half of it over 4. + n, d, tv, hf, bound = 0, 8, 0.0, 1.0, 0.2734375 shadow = {"ran": True, "route": "method:exact", "request": shadow_request, "shots": 4, "accuracy": {"class": "bit-exact"}, "counts": {"1": 4}, "distinct_outcomes": 1, "omitted_shots": 0, - "distance": {"computed": True, "numerator": 0, "denominator": 8, "total_variation": 0.0, - "hellinger_fidelity": 1.0, "sampling_tvd_expected": 0.0}} + "distance": {"computed": True, "numerator": n, "denominator": d, "total_variation": tv, + "hellinger_fidelity": hf, "sampling_tvd_bound": bound}} result = json.loads(_provider_result()) result["planner"], result["shadow"] = planner, shadow both = {"request": request, "result": result} @@ -1804,6 +1976,45 @@ def _contract_job(**changes): return json.dumps(both["request"], separators=(",", ":")), json.dumps(both["result"], separators=(",", ":")) +def _lr(name, cls, rank, outcome, code=None, seconds=0.001, memory=1024, joules=None, host_dependent=False, priced=True): + """A local route, every member written out, for the self-test only.""" + r = {"route": "method:" + name, "kind": "local", "method": name, "class": cls, "host_dependent": host_dependent, + "auto_rank": rank, "outcome": outcome, + "price": {"money": {"free": True}, "time": {"seconds": seconds, "basis": "nominal"}, "memory_bytes": memory, + "work": 8, "energy": {"joules": joules, "basis": "a test"} if joules is not None else {"joules": None, "why": "none"}, + "leaves_out": []} if priced else None} + if code: + r["rejected"] = {"code": code, "why": "said so"} + return r + + +def _local_contract_job(contract, routes, choice, auto, stable_choice, kept, request_extra=None, energy=None, providers=()): + """§8.6: a job under a contract run on one of the engine's methods, for the self-test + only: (request text, result text). Every outcome, the choice, auto and stable.choice + are written by the caller, never computed here.""" + request = {"qasm": "OPENQASM 3.0;\nqubit[1] q;\nbit[1] c;\nx q[0];\nc = measure q;\n", "shots": 4, "contract": contract} + request.update(request_extra or {}) + job_bytes = 1 << 30 + covered = [r for r in routes if r["kind"] == "local" and r["host_dependent"] is False] + facts = {"job_bytes": job_bytes, "routes": [{"route": r["route"], "class": r["class"], + "seconds": (r["price"] or {}).get("time", {}).get("seconds"), "memory_bytes": (r["price"] or {}).get("memory_bytes"), + "work": (r["price"] or {}).get("work")} for r in covered]} + digest = blake3(text_of(read_json(json.dumps(facts).encode()), True).encode("utf-8")).hex() + wanted = contract.get("exactness") + planner = { + "format": "wai.quantum.planner/1", "wanted": wanted, "wanted_from": "contract" if wanted else None, + "named": None, "question": "counts", "auto": auto, + "host": {"job_bytes": job_bytes, "providers": list(providers)}, "routes": routes, "choice": choice, + "why": "the cheapest", "kept": kept, + "stable": {"scope": "the host-independent routes", "routes": [r["route"] for r in covered], "digest": digest, "choice": stable_choice}, + } + result = {"method": choice[len("method:"):], "qubits": 1, "gates": 1, "accuracy": {"class": "bit-exact"}, + "counts": {"1": 4}, "elapsed_ms": 3, "planner": planner, + "energy": energy if energy is not None else {"unmetered": "a test"}, + "engine": {"name": "wai-quantum", "version": "0.9.0"}, "schema": "wai.quantum.job-result/1"} + return json.dumps(request, separators=(",", ":")), json.dumps(result, separators=(",", ":")) + + def self_test(args): results = [] @@ -2103,8 +2314,11 @@ def self_test(args): PLANTS.discard(plant) # §8.6: a job under a contract, as it is and broken one way at a time. - def contract_body(**changes): - return _seal(seed, *_contract_job(**changes)) + def contract_body(job_seed=None, extra_routes=(), **changes): + return _seal(seed, *_contract_job(seed=job_seed, extra_routes=extra_routes, **changes)) + + def local_body(contract, routes, choice, auto, stable_choice, kept, **kw): + return _seal(seed, *_local_contract_job(contract, routes, choice, auto, stable_choice, kept, **kw)) contract_ok = contract_body() check("a contract job's reasoning and shadow", reasons_of(contract_ok) == []) @@ -2121,8 +2335,123 @@ def self_test(args): result__shadow__distance={"computed": False, "why": "said so"}), ["shadow"]), ("the least it can come to, on a free route", contract_body( result__planner__routes__1__price__money={"free": True, "at_least": False}), ["planner_form"]), + ("a named provider under never", contract_body(request__contract__providers="never"), + ["contract_provider", "planner_choice", "planner_route"]), + ("a shadow request with a noise model", contract_body( + result__planner__shadow__request__noise={"depolarizing_2q": 0.2}, + result__shadow__request__noise={"depolarizing_2q": 0.2}), ["shadow"]), + ("a shadow planned at a class its route is not listed with", + contract_body(result__planner__shadow__class="heuristic"), ["shadow"]), + ("a time past what a price states", contract_body(result__planner__routes__1__price__time__seconds=1e306), ["planner_form"]), ): check(name, reasons_of(raw_case) == want) + + # §8.6, rule by rule: each case is valid, and a verifier that bends the rule it + # holds to gives it a reason. Every outcome is written here by hand. + approx = {"route": "provider:approx", "kind": "provider", "provider": "approx", "class": "simulated", + "host_dependent": True, "approximate": True, "outcome": "rejected", + "rejected": {"code": "class", "why": "approximate"}, + "price": {"money": {"free": True}, "time": {"seconds": 1.0, "basis": "provider"}, "memory_bytes": None, + "work": None, "energy": {"joules": None, "why": "none"}, "leaves_out": ["energy"]}} + sim = dict(approx, provider="sim", route="provider:sim", outcome="met") + del sim["approximate"], sim["rejected"] + sim["price"] = dict(approx["price"], time={"seconds": 0.0, "basis": "provider"}) + + def base(cls_of_sv_single="class", **kw): + return [_lr("exact", "bit-exact", 20, "chosen"), _lr("statevector", "exact", 30, "met", memory=2048, **kw), + _lr("statevector_single", "single", 40, "rejected", cls_of_sv_single, host_dependent=True, priced=False), + _lr("mps", "heuristic", 60, "rejected", "class", memory=4096)] + routed = dict(request__provider=_DELETE, result__planner__named=None, result__planner__routes__0__rejected__code="class") + ceiling = {"exactness": "simulated", "providers": "allowed", "max_cost": {"amount": "1", "currency": "USD"}} + kept_free = {"cost": {"max_cost": {"amount": "1", "currency": "USD"}, "charged": None, "kept": True}} + + def provider_route(name, money, code, seconds=1.0): + return {"route": "provider:" + name, "kind": "provider", "provider": name, "class": "simulated", "host_dependent": True, + "outcome": "rejected", "rejected": {"code": code, "why": "said so"}, + "price": {"money": money, "time": {"seconds": seconds, "basis": "provider"}, "memory_bytes": None, + "work": None, "energy": {"joules": None, "why": "none"}, "leaves_out": ["energy"]}} + sim_never = provider_route("sim", {"free": True}, "providers", seconds=0.0) + for name, raw_case, want in ( + ("the least it can come to is not within a ceiling", contract_body( + extra_routes=(provider_route("least", {"free": False, "amount": "0.1", "currency": "USD", "at_least": True}, "cost_at_least"),), + request__contract=ceiling, result__planner__kept=kept_free, **routed), []), + ("a ceiling in another currency is not met", contract_body( + extra_routes=(provider_route("euro", {"free": False, "amount": "0.1", "currency": "EUR"}, "cost_currency"),), + request__contract=ceiling, result__planner__kept=kept_free, **routed), []), + ("a cost with no ceiling is not met", contract_body( + extra_routes=(provider_route("paid", {"free": False, "amount": "0.1", "currency": "USD"}, "cost_no_ceiling"),), **routed), []), + ("a charge the result does not state", contract_body( + request__contract=ceiling, result__planner__kept={"cost": dict(kept_free["cost"], charged={"amount": "0", "currency": "USD"})}, **routed), + ["planner_kept"]), + ("a planned shadow said not to have run", contract_body(result__shadow={"ran": False, "code": "none", "why": "said so"}), ["shadow"]), + ("a plan's code that no plan has", contract_body( + result__planner__shadow={"route": None, "code": "failed", "why": "said so"}, + result__shadow={"ran": False, "code": "failed", "why": "said so"}), ["shadow"]), + ("a provider under never, beside a local route", local_body({"exactness": "any"}, [ + _lr("exact", "bit-exact", 20, "chosen", seconds=0.0001), _lr("statevector", "exact", 30, "met", seconds=0.0001, memory=2048), + _lr("statevector_single", "single", 40, "rejected", "cannot", host_dependent=True, priced=False), + _lr("mps", "heuristic", 60, "met", seconds=0.0001, memory=4096), sim_never], "method:exact", "method:exact", False, {}, + providers=("sim",)), []), + ("a time not known does not meet a deadline", local_body({"exactness": "exact", "deadline_seconds": 60}, [ + _lr("exact", "bit-exact", 20, "chosen"), dict(_lr("statevector", "exact", 30, "rejected", "deadline_unknown"), + price=dict(_lr("statevector", "exact", 30, "met")["price"], time={"seconds": None, "why": "not known"})), + _lr("statevector_single", "single", 40, "rejected", "class", host_dependent=True, priced=False), + _lr("mps", "heuristic", 60, "rejected", "class", memory=4096)], "method:exact", "method:exact", True, + {"deadline": {"seconds": 60, "elapsed_ms": 3, "kept": True}}), []), + ("a deadline's time that is not the result's", local_body({"exactness": "exact", "deadline_seconds": 60}, base(), "method:exact", + "method:exact", True, {"deadline": {"seconds": 60, "elapsed_ms": 4, "kept": True}}), + ["planner_kept"]), + ("auto said to be another route", local_body({"exactness": "exact"}, base(), "method:exact", "method:statevector", True, {}), ["planner_form"]), + ("a built-in method's rank not its own", local_body({"exactness": "exact"}, [ + _lr("exact", "bit-exact", 20, "chosen"), _lr("statevector", "exact", 30, "met", memory=2048), + _lr("statevector_single", "single", 0, "rejected", "class", host_dependent=True, priced=False), + _lr("mps", "heuristic", 60, "rejected", "class", memory=4096)], "method:exact", "method:exact", True, {}), ["planner_form"]), + ("a local route that costs money", local_body({"exactness": "exact"}, [ + _lr("exact", "bit-exact", 20, "chosen"), _lr("statevector", "exact", 30, "met", memory=2048), + _lr("statevector_single", "single", 40, "rejected", "class", host_dependent=True, priced=False), + dict(_lr("mps", "heuristic", 60, "rejected", "class", memory=4096), + price=dict(_lr("mps", "heuristic", 60, "met")["price"], money={"free": False, "unknown": "a host's word"}))], + "method:exact", "method:exact", True, {}), ["planner_form"]), + ("a ceiling past 64 characters", local_body({"exactness": "exact", "max_cost": {"amount": "1" * 65, "currency": "USD"}}, base(), + "method:exact", "method:exact", True, + {"cost": {"max_cost": {"amount": "1" * 65, "currency": "USD"}, "charged": None, "kept": True}}), + ["contract_form"]), + ): + check("rule: " + name, reasons_of(raw_case) == want) + # The distance in its order, by hand: three shots of "1" against "0" twice and "1" + # once. R = sqrt(3), and R*R/(S*S) is 0.33333333333333326, where (R/S)^2 is not. + three = contract_body( + request__shots=3, result__shots=3, result__counts={"1": 3}, + result__planner__shadow__request__shots=3, result__shadow__request__shots=3, result__shadow__shots=3, + result__shadow__counts={"0": 2, "1": 1}, result__shadow__distinct_outcomes=2, + result__shadow__distance={"computed": True, "numerator": 4, "denominator": 6, "total_variation": 4 / 6, + "hellinger_fidelity": 0.33333333333333326, "sampling_tvd_bound": 0.4166666666666667}) + check("rule: the Hellinger fidelity in its order", reasons_of(three) == []) + for name, raw_case in ( + # Routed, no provider named: the approximate one is quicker, and not met. + ("an approximate simulator does not meet simulated", contract_body( + extra_routes=(approx,), request__provider=_DELETE, result__planner__named=None, + result__planner__routes__0__rejected__code="class")), + ("the shadow's seed wraps at 2^53", contract_body(job_seed=2 ** 53 - 2)), + ("single does not meet bounded", local_body({"exactness": "bounded"}, base(), "method:exact", "method:exact", True, {})), + ("a job's memory at its cap", local_body({"exactness": "exact"}, [ + _lr("exact", "bit-exact", 20, "chosen"), _lr("statevector", "exact", 30, "met", memory=1 << 30), + _lr("statevector_single", "single", 40, "rejected", "class", host_dependent=True, priced=False), + _lr("mps", "heuristic", 60, "rejected", "class", memory=4096)], "method:exact", "method:exact", True, {})), + ("a GPU's method off the CPU", local_body({"exactness": "single"}, base("fabric"), "method:exact", "method:exact", True, {}, + request_extra={"fabric": "cpu"})), + ("energy at its ceiling, and a host's estimate", local_body({"exactness": "exact", "max_joules": 2}, [ + _lr("exact", "bit-exact", 20, "chosen", joules=1.0), _lr("statevector", "exact", 30, "met", memory=2048, joules=1.0), + _lr("statevector_single", "single", 40, "rejected", "class", host_dependent=True, priced=False), + _lr("mps", "heuristic", 60, "rejected", "class", memory=4096, joules=1.0)], "method:exact", "method:exact", False, + {"energy": {"max_joules": 2, "joules": 2.0, "kept": True}}, energy={"joules_micro": 2000000})), + ("a local route before a provider's at one time", local_body({"exactness": "any", "providers": "allowed"}, [ + _lr("exact", "bit-exact", 20, "chosen", seconds=0.0001), _lr("statevector", "exact", 30, "met", seconds=0.0001, memory=2048), + _lr("statevector_single", "single", 40, "rejected", "cannot", host_dependent=True, priced=False), + _lr("mps", "heuristic", 60, "met", seconds=0.0001, memory=4096), sim], "method:exact", "method:exact", False, {}, + providers=("sim",))), + ): + check("rule: " + name, reasons_of(raw_case) == []) unnamed_route = contract_body(result__planner__routes__0__outcome="met", result__planner__routes__0__rejected=_DELETE) another_answered = contract_body(result__provider__name="other") distance_said = contract_body(result__shadow__distance__numerator=1) diff --git a/wai/wai-quantum-cli/README.md b/wai/wai-quantum-cli/README.md index 9164f9cc9..2115b0984 100644 --- a/wai/wai-quantum-cli/README.md +++ b/wai/wai-quantum-cli/README.md @@ -109,7 +109,7 @@ wai-quantum run circuit.qasm --method statevector --fabric cpu --fabric cpu --sh wai-quantum run prog.qasm --fabric a-member-elsewhere # exits 1 ``` -**Under a contract.** `--exactness CLASS`, `--deadline SECONDS`, `--max-cost 0.50:USD`, `--max-joules J` and `--allow-providers` (or `--contract` with the JSON of [the provider protocol's section 8.6](../extensions/quantum-providers.md)) say what the answer must be. The planner then prices every route it can see: each method here, at its memory and the time its work predicts, and with `--allow-providers` each of your own providers, by its own estimate and what that leaves out (each is asked, and sent nothing). It rejects every route that cannot meet the contract, runs the cheapest of the rest, and seals its reasoning in the receipt. An unknown never passes: a time nobody states does not meet a deadline, nor an unknown cost a ceiling, nor an estimate that is only the least a job can come to. Nothing falls back, from exact to approximate or between a simulator and a device, and with no route left the job is refused with every route's reason (`J071`). A contract that names no class keeps the class `auto` would give, and a device's counts are reached only by asking for `measured` (or `any`). A provider's answer carries a classical method's counts beside it, with their distance, wherever a method here can reach them in the time the contract leaves, and the receipt says why where none can. A ceiling confirms nothing: a run that is not free still takes `--yes`. `wai-quantum plan` with the same options shows every route's price or reason and sends nothing; `wai-quantum verify --recheck` prices the routes again here and runs the shadow again; a run that kept less than its contract asked is still sealed, says so, and exits 4. +**Under a contract.** `--exactness CLASS`, `--deadline SECONDS`, `--max-cost 0.50:USD`, `--max-joules J` and `--allow-providers` (or `--contract` with the JSON of [the provider protocol's section 8.6](../extensions/quantum-providers.md)) say what the answer must be. The planner then prices every route it can see: each method here, at its memory and the time its work predicts, and with `--allow-providers` each of your own providers, by its own estimate and what that leaves out (each is asked, and sent nothing). It rejects every route that cannot meet the contract, runs the cheapest of the rest, and seals its reasoning in the receipt. An unknown never passes: a time nobody states does not meet a deadline, nor an unknown cost a ceiling, nor an estimate that is only the least a job can come to. Nothing falls back, from exact to approximate or between a simulator and a device, and with no route left the job is refused with every route's reason (`J071`). A contract that names no class keeps the class `auto` would give, and a device's counts are reached only by asking for `measured` (or `any`). A provider's answer carries a classical method's counts beside it, with their distance, wherever a method here can reach them in the time the contract leaves, and the receipt says why where none can. Under a contract no provider is asked anything without `--allow-providers`, and one you name is refused without it (`J070`). A ceiling bounds the estimate a route is chosen by, not what is charged after, and confirms nothing: a run on a provider you name that is not free still takes `--yes`, and one the planner routes to a provider that is not free takes `--confirm WORD`, the word its `--dry-run` prints for that route, that estimate and that program, and is refused if any of them has changed when it would be sent. A deadline holds a method's own run time here, and a provider's from its submission to its counts; the command line cancels a provider's job still waiting at it (`J074`). `wai-quantum plan` with the same options shows every route's price or reason and sends nothing; `wai-quantum verify --recheck` prices the routes again here and runs the shadow again; a run that kept less than its contract asked is still sealed, says so, and exits 4. Each result names: diff --git a/wai/wai-quantum-cli/README.zh-CN.md b/wai/wai-quantum-cli/README.zh-CN.md index f32c931c7..9c3ee609b 100644 --- a/wai/wai-quantum-cli/README.zh-CN.md +++ b/wai/wai-quantum-cli/README.zh-CN.md @@ -112,7 +112,7 @@ wai-quantum run circuit.qasm --method statevector --fabric cpu --fabric cpu --sh wai-quantum run prog.qasm --fabric a-member-elsewhere # exits 1:别处的成员,被拒绝 ``` -**在契约之下。** `--exactness CLASS`、`--deadline SECONDS`、`--max-cost 0.50:USD`、`--max-joules J` 和 `--allow-providers`(或用 `--contract` 给出 [提供方协议第 8.6 节](../extensions/quantum-providers.md) 的 JSON)说明答案必须满足什么。规划器随后为它能看到的每条路径定价:本机的每个方法,按其内存和其工作量所预示的时间;加上 `--allow-providers` 时,还有你自己的每个提供方,按其自身的估算以及该估算未包含的内容(每个都会被询问,但不会发送任何东西)。它拒绝每条无法满足契约的路径,运行其余路径中最便宜的一条,并把它的推理封入收据。未知量从不算作满足:无人说明的时间不满足截止时间,未知的费用不满足上限,只是作业最低可能费用的估算也不满足。不会回退:既不会从精确退到近似,也不会在模拟器与设备之间互换;没有路径剩下时,作业被拒绝,并列出每条路径的原因(`J071`)。未指明类别的契约保留 `auto` 会给出的类别;只有请求 `measured`(或 `any`)才会用到设备的计数。提供方的答案旁边附有经典方法的计数及两者的距离,只要本机有方法能在契约留下的时间内得到它们;没有方法能做到时,收据会说明原因。上限不构成确认:不免费的运行仍需要 `--yes`。带相同选项的 `wai-quantum plan` 显示每条路径的价格或原因,不发送任何东西;`wai-quantum verify --recheck` 在本机重新为路径定价并重新运行影子运行;未能满足契约全部要求的运行仍会被封存,并如实说明,退出状态为 4。 +**在契约之下。** `--exactness CLASS`、`--deadline SECONDS`、`--max-cost 0.50:USD`、`--max-joules J` 和 `--allow-providers`(或用 `--contract` 给出 [提供方协议第 8.6 节](../extensions/quantum-providers.md) 的 JSON)说明答案必须满足什么。规划器随后为它能看到的每条路径定价:本机的每个方法,按其内存和其工作量所预示的时间;加上 `--allow-providers` 时,还有你自己的每个提供方,按其自身的估算以及该估算未包含的内容(每个都会被询问,但不会发送任何东西)。它拒绝每条无法满足契约的路径,运行其余路径中最便宜的一条,并把它的推理封入收据。未知量从不算作满足:无人说明的时间不满足截止时间,未知的费用不满足上限,只是作业最低可能费用的估算也不满足。不会回退:既不会从精确退到近似,也不会在模拟器与设备之间互换;没有路径剩下时,作业被拒绝,并列出每条路径的原因(`J071`)。未指明类别的契约保留 `auto` 会给出的类别;只有请求 `measured`(或 `any`)才会用到设备的计数。提供方的答案旁边附有经典方法的计数及两者的距离,只要本机有方法能在契约留下的时间内得到它们;没有方法能做到时,收据会说明原因。在契约之下,没有 `--allow-providers` 时不会询问任何提供方,你指定的提供方也会被拒绝(`J070`)。上限约束的是选择路径所依据的估算,而不是之后实际收取的费用,它也不构成确认:在你指定的提供方上运行、且不免费时,仍需要 `--yes`;规划器选到的提供方不免费时,需要 `--confirm WORD`,即它的 `--dry-run` 为该路径、该估算和该程序打印的词,发送时只要其中任何一项已有变化就会被拒绝。截止时间约束本机方法自身的运行时间,以及提供方从提交到得出计数的时间;命令行会在截止时取消仍在等待的提供方作业(`J074`)。带相同选项的 `wai-quantum plan` 显示每条路径的价格或原因,不发送任何东西;`wai-quantum verify --recheck` 在本机重新为路径定价并重新运行影子运行;未能满足契约全部要求的运行仍会被封存,并如实说明,退出状态为 4。 每个结果都注明: diff --git a/wai/wai-quantum-cli/schemas/local-tools.v1.json b/wai/wai-quantum-cli/schemas/local-tools.v1.json index 559cb4e92..47237c1c8 100644 --- a/wai/wai-quantum-cli/schemas/local-tools.v1.json +++ b/wai/wai-quantum-cli/schemas/local-tools.v1.json @@ -518,6 +518,30 @@ }, "provider_plan": { "$ref": "#/$defs/provider_estimate" + }, + "confirm": { + "type": "object", + "description": "Where the route chosen is a provider's and not free: what a person confirms it by. token is a digest of the route, its estimate's money and the program and shots it would send; a run is sent only when given that token made again at send time.", + "required": [ + "token", + "route", + "money", + "says" + ], + "properties": { + "token": { + "type": "string" + }, + "route": { + "type": "string" + }, + "money": { + "type": "object" + }, + "says": { + "type": "string" + } + } } } } diff --git a/wai/wai-quantum-cli/src/main.rs b/wai/wai-quantum-cli/src/main.rs index e8daa93e0..8d2b38ec2 100644 --- a/wai/wai-quantum-cli/src/main.rs +++ b/wai/wai-quantum-cli/src/main.rs @@ -566,10 +566,10 @@ struct Job { #[arg(long, value_name = "AMOUNT:CURRENCY", value_parser = max_cost_arg)] max_cost: Option, /// When the run must be done by, in seconds: a route whose time is not known does not meet it, and the receipt says whether it was kept (exit 4 when it was not) - #[arg(long = "deadline", value_name = "SECONDS")] + #[arg(long = "deadline", value_name = "SECONDS", value_parser = positive_arg)] deadline: Option, /// The most energy the run may take, in joules: a route whose energy is not known does not meet it, and this command estimates none, so here every route is refused; the job service estimates from what it has metered - #[arg(long, value_name = "JOULES")] + #[arg(long, value_name = "JOULES", value_parser = positive_arg)] max_joules: Option, /// Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods here: each is asked to estimate the job, and nothing is sent unless one is chosen. A device is chosen only when --exactness measured or any asks for its class. On the job service, which reaches no provider, it changes nothing #[arg(long)] @@ -587,6 +587,15 @@ impl Job { } } +/// A finite number above zero: `inf` or `NaN` would be written as no value at +/// all, and the requirement dropped in silence. +fn positive_arg(s: &str) -> Result { + match s.parse::() { + Ok(x) if x.is_finite() && x > 0.0 => Ok(x), + _ => Err(format!("give a finite number above 0, not {s}")), + } +} + /// `0.50:USD`: an amount in decimals and its currency. fn max_cost_arg(s: &str) -> Result { match s.split_once(':') { @@ -1210,7 +1219,7 @@ pub(crate) fn print_shadow(sh: &Value) { if sh["ran"] == true { let d = &sh["distance"]; let said = if d["computed"] == true { - format!("total variation {:.4} from the provider's counts (these shots alone leave about {:.4}); Hellinger fidelity {:.4}", d["total_variation"].as_f64().unwrap_or(f64::NAN), d["sampling_tvd_expected"].as_f64().unwrap_or(f64::NAN), d["hellinger_fidelity"].as_f64().unwrap_or(f64::NAN)) + format!("total variation {:.4} from the provider's counts (these shots alone leave at most about {:.4}); Hellinger fidelity {:.4}", d["total_variation"].as_f64().unwrap_or(f64::NAN), d["sampling_tvd_bound"].as_f64().unwrap_or(f64::NAN), d["hellinger_fidelity"].as_f64().unwrap_or(f64::NAN)) } else { format!("no distance: {}", s(&d["why"])) }; @@ -2076,6 +2085,13 @@ mod tests { assert!(Cli::try_parse_from(["wai-quantum", "run", "p.qasm", "--max-cost", "0.50"]).is_err(), "a ceiling has its currency"); assert!(Cli::try_parse_from(["wai-quantum", "run", "p.qasm", "--max-cost", "1e3:USD"]).is_err(), "an amount in decimals"); assert!(Cli::try_parse_from(["wai-quantum", "run", "p.qasm", "--contract", "[]"]).is_err(), "a contract is an object"); + // A ceiling or a deadline that is no finite number above zero would be + // written as nothing, and dropped in silence: refused. + for (flag, v) in [("--deadline", "inf"), ("--deadline", "0"), ("--deadline", "-1"), ("--max-joules", "NaN"), ("--max-joules", "infinity")] { + assert!(Cli::try_parse_from(["wai-quantum", "run", "p.qasm", flag, v]).is_err(), "{flag} {v}"); + } + #[cfg(feature = "providers")] + assert!(Cli::try_parse_from(["wai-quantum", "run", "p.qasm", "--confirm", "abc"]).is_err(), "a word confirms a routed run only"); #[cfg(feature = "providers")] { assert!(Cli::try_parse_from(["wai-quantum", "run", "p.qasm", "--dry-run"]).is_err(), "a dry run of what"); diff --git a/wai/wai-quantum-cli/src/mcp.rs b/wai/wai-quantum-cli/src/mcp.rs index d4010b45d..3b0aa8e6b 100644 --- a/wai/wai-quantum-cli/src/mcp.rs +++ b/wai/wai-quantum-cli/src/mcp.rs @@ -1675,13 +1675,13 @@ mod tests { let req = json!({ "qasm": bell, "shots": 50, "provider": "lab" }); hold("provider_estimate", &pjob::plan(&t, &req).unwrap().json, &mut called); // Under a contract: the provider's plan with the reasoning, a route weighed, and each of them run. - let under = json!({ "qasm": bell, "shots": 50, "provider": "lab", "contract": { "exactness": "simulated" } }); + let under = json!({ "qasm": bell, "shots": 50, "provider": "lab", "contract": { "providers": "allowed", "exactness": "simulated" } }); hold("provider_estimate", &pjob::plan(&t, &under).unwrap().json, &mut called); hold("run_on_provider", &pjob::run(&t, &under, false, &key(), wait, |_| {}).unwrap(), &mut called); let routed_to_it = json!({ "qasm": bell, "shots": 50, "contract": { "exactness": "simulated", "providers": "allowed" } }); let routed = pjob::route(std::slice::from_ref(&t), &routed_to_it, 1 << 30).unwrap(); hold("plan_routes", &routed.json(), &mut called); - let mut sent = pjob::start_routed(&t, &routed, &routed_to_it, false, &ledger).unwrap(); + let mut sent = pjob::start_routed(&t, &routed, &routed_to_it, None, &ledger).unwrap(); hold("run_routed", pjob::check(&t, &mut sent, &key(), &ledger).unwrap().job(), &mut called); let here = json!({ "qasm": bell, "shots": 50, "contract": { "exactness": "exact", "providers": "allowed" } }); let routed = pjob::route(std::slice::from_ref(&t), &here, 1 << 30).unwrap(); diff --git a/wai/wai-quantum-cli/src/providers.rs b/wai/wai-quantum-cli/src/providers.rs index cbb809d8b..aeb23781f 100644 --- a/wai/wai-quantum-cli/src/providers.rs +++ b/wai/wai-quantum-cli/src/providers.rs @@ -105,6 +105,9 @@ pub struct RunArgs { /// With --provider or --allow-providers: send the job and answer with its handle, without waiting (`wai-quantum providers collect`) #[arg(long, requires = "via_provider")] pub no_wait: bool, + /// With --allow-providers: confirm the run the planner chose when it is not free, by the word its dry run gave for that route, its estimate and its program; a route, an estimate or a program that changed since is refused. --yes confirms only a provider you name + #[arg(long, value_name = "WORD", requires = "allow_providers")] + pub confirm: Option, } #[derive(Subcommand)] @@ -314,7 +317,16 @@ pub fn plan(job: &Job, as_json: bool) { if as_json { println!("{}", routed.json()); } else { - crate::print_planner(&routed.reasoning); + print_routed(&routed); + } +} + +/// A routed plan as a reader takes it in: the planner's reasoning, and, where the +/// route chosen is not free, the word that confirms that route at that estimate. +fn print_routed(routed: &pjob::Routed) { + crate::print_planner(&routed.reasoning); + if let Some(says) = routed.json().pointer("/confirm/says").and_then(Value::as_str) { + println!("confirm {says}"); } } @@ -328,10 +340,14 @@ fn run_routed(job: &Job, out: &Output, key: &KeyArgs, args: &RunArgs) { if out.json { println!("{}", routed.json()); } else { - crate::print_planner(&routed.reasoning); + print_routed(&routed); } return; } + // A route the person was not shown is not theirs to confirm with a bare yes. + if args.yes { + die("--yes confirms a run on a provider you name (--provider); a route the planner chooses is confirmed by the word its dry run gives for it: run with --dry-run, then --confirm WORD"); + } let k = load_key(key); let Some(name) = routed.provider().map(str::to_string) else { let body = pjob::run_routed_here(&routed, &req, &k.key, json!({ "unmetered": crate::UNMETERED })).unwrap_or_else(|e| die(&e.to_string())); @@ -347,7 +363,7 @@ fn run_routed(job: &Job, out: &Output, key: &KeyArgs, args: &RunArgs) { }; let t = open.iter().find(|t| t.name == name).unwrap_or_else(|| die("internal: the planner chose a provider it was not given")); let ledger = Ledger::load_default().unwrap_or_else(|e| die(&e)); - let ticket = pjob::start_routed(t, &routed, &req, args.yes, &ledger); + let ticket = pjob::start_routed(t, &routed, &req, args.confirm.as_deref(), &ledger); follow_started(t, ticket, &ledger, &k.key, out, args, &name); } @@ -729,8 +745,8 @@ pub fn mcp_tools() -> Vec { json!({ "name": "run_routed", "title": "Run a job on the route its contract chooses (can spend the person's money)", - "description": "Runs a job on the route plan_routes chooses: a method on this machine, or one of the person's own providers. THIS CAN SPEND THE PERSON'S MONEY OR QUOTA, when the contract allows a provider and one is chosen. A cost ceiling confirms nothing: a run that is not free is refused unless confirm_cost is true, set only after the person has seen the estimate and agreed to that run. The answer is a job in the service's form, its result carrying the planner's reasoning under planner; a provider's result also carries a classical method's counts and their distance under shadow, or why no classical method could reach them. If the job has not finished within this call the answer has status running and an id, and get_provider_job collects it later. Do not run it again to find out: that is a second job, and it can be a second bill.", - "inputSchema": route_schema(json!({ "confirm_cost": { "type": "boolean", "description": "true only when the person has agreed to this run's cost. A run that is not free is refused without it, whatever the contract's ceiling." } })), + "description": "Runs a job on the route plan_routes chooses: a method on this machine, or one of the person's own providers. THIS CAN SPEND THE PERSON'S MONEY OR QUOTA, when the contract allows a provider and one is chosen. A cost ceiling confirms nothing: a run that is not free is refused unless confirm is the word plan_routes gave for that route, its estimate and its program (its confirm.token), set only after the person has seen them and agreed to that run; if the route or its estimate changed since, it is refused with the new word. The answer is a job in the service's form, its result carrying the planner's reasoning under planner; a provider's result also carries a classical method's counts and their distance under shadow, or why no classical method could reach them. If the job has not finished within this call the answer has status running and an id, and get_provider_job collects it later. Do not run it again to find out: that is a second job, and it can be a second bill.", + "inputSchema": route_schema(json!({ "confirm": { "type": "string", "description": "The word plan_routes gave (confirm.token) for the route, the estimate and the program the person agreed to. A run that is not free is refused without it, whatever the contract's ceiling, and refused if what is chosen now is not what that word names." } })), }), json!({ "name": "get_provider_job", @@ -858,10 +874,10 @@ pub fn mcp_call_with(name: &str, args: &Value, key: &SigningKey, reg: &Registry, return pjob::run_routed_here(&routed, &req, key, json!({ "unmetered": crate::UNMETERED })).map_err(|e| e.to_string()); }; let t = open.iter().find(|t| t.name == chosen).ok_or("internal: the planner chose a provider it was not given")?; - let confirmed = args.get("confirm_cost") == Some(&Value::Bool(true)); - match pjob::start_routed(t, &routed, &req, confirmed, ledger).and_then(|mut ticket| pjob::follow(t, &mut ticket, key, ledger, wait, std::thread::sleep)) { + let confirm = args.get("confirm").and_then(Value::as_str); + match pjob::start_routed(t, &routed, &req, confirm, ledger).and_then(|mut ticket| pjob::follow(t, &mut ticket, key, ledger, wait, std::thread::sleep)) { Ok(progress) => Ok(progress.job().clone()), - Err(JobError::Unconfirmed { plan, message }) => Err(format!("refused: {message}. Show the person this estimate; call again with confirm_cost: true only when they agree. The plan: {plan}")), + Err(JobError::Unconfirmed { plan, message }) => Err(format!("refused: {message}. Show the person this route and its estimate; call again with confirm set to that word only when they agree to this run. The plan: {plan}")), Err(e) => Err(e.to_string()), } })(), @@ -926,15 +942,18 @@ mod tests { let t = mcp_tools(); let names: Vec<&str> = t.iter().map(|x| x["name"].as_str().unwrap()).collect(); assert_eq!(names, ["providers_list", "provider_estimate", "run_on_provider", "plan_routes", "run_routed", "get_provider_job", "cancel_provider_job", "list_provider_jobs"]); - // Each tool that can send a job says it can spend, and takes the person's word. - for i in [2, 4] { + // Each tool that can send a job says it can spend, and takes the person's word: + // for a provider they name, that they agree; for a route the planner chose, + // the word for that route and its estimate, which no bare yes stands for. + for (i, word, kind) in [(2, "confirm_cost", "boolean"), (4, "confirm", "string")] { let run = t[i]["description"].as_str().unwrap(); - assert!(run.contains("SPEND THE PERSON'S MONEY") && run.contains("confirm_cost"), "{run}"); - assert!(t[i]["inputSchema"]["properties"]["confirm_cost"].is_object()); + assert!(run.contains("SPEND THE PERSON'S MONEY") && run.contains(word), "{run}"); + assert_eq!(t[i]["inputSchema"]["properties"][word]["type"], kind); } for i in [1, 3] { assert!(t[i]["description"].as_str().unwrap().contains("Nothing is submitted and nothing is spent"), "{}", t[i]["name"]); - assert!(t[i]["inputSchema"]["properties"].get("confirm_cost").is_none(), "{}", t[i]["name"]); + let props = &t[i]["inputSchema"]["properties"]; + assert!(props.get("confirm_cost").is_none() && props.get("confirm").is_none(), "{}", t[i]["name"]); } // A routed tool weighs a contract, and requires one. assert_eq!(t[3]["inputSchema"]["required"], json!(["qasm", "contract"])); diff --git a/wai/wai-quantum-cli/tests/providers.rs b/wai/wai-quantum-cli/tests/providers.rs index 40f1af8cc..af41e5cbd 100644 --- a/wai/wai-quantum-cli/tests/providers.rs +++ b/wai/wai-quantum-cli/tests/providers.rs @@ -334,14 +334,29 @@ fn a_contract_weighs_every_route_and_its_receipt_says_why() { let checked: Value = serde_json::from_str(&h.ok(&["verify", &saved, "--json", "--recheck"], "")).unwrap(); assert_eq!((checked["valid"].as_bool(), checked["recheck"]["shadow"]["same"].as_bool()), (Some(true), Some(true)), "{checked}"); assert_eq!(jobs(&h).len(), 1); - // Named, under a ceiling, a cost that is not free still takes the person's word. - let out = h.run(&["run", &p, "--provider", "paid", "--max-cost", "1:EUR", "--demo-key"], ""); + // Named under a contract, a provider runs only where the contract allows one. + let out = h.run(&["run", &p, "--provider", "paid", "--max-cost", "1:EUR", "--yes", "--demo-key"], ""); + assert_eq!(out.status.code(), Some(1)); + assert!(String::from_utf8_lossy(&out.stderr).contains("[J070]"), "{}", String::from_utf8_lossy(&out.stderr)); + // Allowed and under a ceiling, a cost that is not free still takes the person's word. + let out = h.run(&["run", &p, "--provider", "paid", "--allow-providers", "--max-cost", "1:EUR", "--demo-key"], ""); assert_eq!(out.status.code(), Some(3), "{}", String::from_utf8_lossy(&out.stderr)); - let out = h.run(&["run", &p, "--provider", "paid", "--max-cost", "0.1:EUR", "--yes", "--demo-key"], ""); + let out = h.run(&["run", &p, "--provider", "paid", "--allow-providers", "--max-cost", "0.1:EUR", "--yes", "--demo-key"], ""); assert_eq!(out.status.code(), Some(1)); assert!(String::from_utf8_lossy(&out.stderr).contains("above the ceiling")); - let told = h.ok(&["run", &p, "--provider", "paid", "--max-cost", "1:EUR", "--yes", "--demo-key"], ""); + let told = h.ok(&["run", &p, "--provider", "paid", "--allow-providers", "--max-cost", "1:EUR", "--yes", "--demo-key"], ""); assert!(told.contains("shadow") && told.contains("method:exact") && told.contains("kept cost: kept"), "{told}"); + // A route the planner chose is confirmed by the word its dry run gave, never by a bare yes. + let measured = ["run", &p, "--shots", "100", "--exactness", "simulated", "--allow-providers", "--max-cost", "1:EUR", "--demo-key"]; + let out = h.run(&measured.iter().copied().chain(["--yes"]).collect::>(), ""); + assert_eq!(out.status.code(), Some(1)); + assert!(String::from_utf8_lossy(&out.stderr).contains("--confirm WORD"), "{}", String::from_utf8_lossy(&out.stderr)); + // A device target's job, with the person's providers beside it and a deadline. + let target: Value = serde_json::from_str(&h.ok(&["run", &p, "--shots", "50", "--target", "synthetic-line-5", "--allow-providers", "--deadline", "60", "--demo-key", "--json"], "")).unwrap(); + assert_eq!(target["result"]["planner"]["wanted_from"], "named", "{}", target["result"]["planner"]); + let saved = file("target.json", &target.to_string()); + let checked: Value = serde_json::from_str(&h.ok(&["verify", &saved, "--json"], "")).unwrap(); + assert_eq!(checked["valid"], true, "{checked}"); } /// The same for an agent: a contract's routes, and a run on the one it chooses, @@ -362,8 +377,15 @@ fn an_agent_weighs_a_contract_and_runs_on_the_route_it_chooses() { assert_eq!(routes["structuredContent"]["provider_plan"]["estimate"]["amount"], "0.25", "{routes}"); let refused = call(&mut stdin, &mut stdout, 3, "run_routed", json!({ "qasm": BELL, "shots": 100, "contract": simulated })); assert_eq!(refused["isError"], true, "{refused}"); - assert!(refused["content"][0]["text"].as_str().unwrap().contains("confirm_cost: true"), "{refused}"); - let ran = call(&mut stdin, &mut stdout, 4, "run_routed", json!({ "qasm": BELL, "shots": 100, "contract": simulated, "confirm_cost": true })); + let word = routes["structuredContent"]["confirm"]["token"].as_str().unwrap().to_string(); + assert!(refused["content"][0]["text"].as_str().unwrap().contains(&word), "{refused}"); + // A bare yes, or a word for another route or estimate, is no confirmation. + for wrong in [json!(true), json!("0123456789abcdef")] { + let no = call(&mut stdin, &mut stdout, 11, "run_routed", json!({ "qasm": BELL, "shots": 100, "contract": simulated, "confirm": wrong, "confirm_cost": true })); + assert_eq!(no["isError"], true, "{no}"); + } + assert!(jobs(&h).is_empty(), "nothing was sent"); + let ran = call(&mut stdin, &mut stdout, 4, "run_routed", json!({ "qasm": BELL, "shots": 100, "contract": simulated, "confirm": word })); assert_eq!(ran["isError"], false, "{ran}"); let job = ran["structuredContent"].clone(); assert_eq!((job["result"]["provider"]["name"].as_str(), job["result"]["shadow"]["ran"].as_bool()), (Some("paid"), Some(true)), "{job}"); @@ -384,6 +406,23 @@ fn an_agent_weighs_a_contract_and_runs_on_the_route_it_chooses() { assert_eq!(plan["structuredContent"]["planner"]["choice"], "method:stabilizer", "{plan}"); drop(stdin); let _ = child.wait(); + // The same on the command line: its dry run gives the word, and only that word sends. + let p = h.dir.join("agent-bell.qasm"); + std::fs::write(&p, BELL).unwrap(); + let p = p.display().to_string(); + let routed = ["run", &p, "--shots", "100", "--exactness", "simulated", "--allow-providers", "--max-cost", "1:EUR", "--demo-key"]; + fn with<'a>(base: &[&'a str], more: &[&'a str]) -> Vec<&'a str> { + base.iter().chain(more).copied().collect() + } + let shown = h.ok(&with(&routed, &["--dry-run"]), ""); + assert!(shown.contains(&format!("--confirm {word}")), "{shown}"); + let sent = jobs(&h).len(); + let out = h.run(&with(&routed, &["--confirm", "0123456789abcdef"]), ""); + assert_eq!(out.status.code(), Some(3), "{}", String::from_utf8_lossy(&out.stderr)); + assert!(String::from_utf8_lossy(&out.stderr).contains("not what was confirmed"), "{}", String::from_utf8_lossy(&out.stderr)); + assert_eq!(jobs(&h).len(), sent, "a word for another route or estimate sends nothing"); + let body: Value = serde_json::from_str(&h.ok(&with(&routed, &["--confirm", &word, "--json"]), "")).unwrap(); + assert_eq!((body["result"]["provider"]["name"].as_str(), body["result"]["cost"]["confirmed"].as_bool()), (Some("paid"), Some(true)), "{body}"); } fn jobs(h: &Home) -> Vec { diff --git a/wai/wai-quantum-qpu/src/job.rs b/wai/wai-quantum-qpu/src/job.rs index 4a0efc754..2609f11d7 100644 --- a/wai/wai-quantum-qpu/src/job.rs +++ b/wai/wai-quantum-qpu/src/job.rs @@ -50,6 +50,7 @@ use std::time::Duration; use wai_quantum::ed25519_dalek::SigningKey; use wai_quantum::engine::targets::{import, layout}; use wai_quantum::engine::registry::Registry; +use wai_quantum::engine::refusal::{self, tag}; use wai_quantum::engine::{catalog, planner, provider, receipt}; use wai_quantum::quantum_fabric::sampling::Counts; use wai_quantum::quantum_toolchain::native::{NativeGate, NativeProgram}; @@ -425,7 +426,8 @@ pub struct Routed { impl Routed { /// What a dry run shows: the reasoning, the local plan when a method was - /// chosen, and the provider's own plan when one was. + /// chosen, and the provider's own plan when one was, with what a person + /// confirms it by when it is not free ([`Routed::confirmation`]). pub fn json(&self) -> Value { let mut v = json!({ "dry_run": true, "planner": self.reasoning }); match &self.choice { @@ -434,12 +436,47 @@ impl Routed { if let Some((_, p)) = self.plans.iter().find(|(n, _)| n == name) { v["provider_plan"] = p.json.clone(); } + if let Some(token) = self.confirmation() { + let money = self.chosen_route()["price"]["money"].clone(); + v["confirm"] = json!({ + "token": token, + "route": format!("provider:{name}"), + "money": money, + "says": format!("not free: {}; a ceiling confirms nothing. It runs only on the person's word for this route, this estimate and this program: --confirm {token} on the command line, confirm: \"{token}\" for an agent", self.plans.iter().find(|(n, _)| n == name).map(|(_, p)| p.confirmation()).unwrap_or_default()), + }); + } } _ => {} } v } + fn chosen_route(&self) -> &Value { + let name = self.reasoning["choice"].as_str().unwrap_or(""); + self.reasoning["routes"].as_array().and_then(|a| a.iter().find(|r| r["route"] == name)).unwrap_or(&Value::Null) + } + + /// What a person confirms a routed run that is not free by: a digest of the + /// route chosen, what its provider estimates it at (its amount, currency and + /// unit, or why that is not known) and the program and shots it would send. + /// A run is sent only with this word, made again at send time, so a route, + /// an estimate or a program that changed since the person saw it is not + /// sent. `None` for a route that is free, or one of the engine's methods. + pub fn confirmation(&self) -> Option { + let planner::Choice::Provider(name) = &self.choice else { return None }; + let (_, p) = self.plans.iter().find(|(n, _)| n == name)?; + if p.free { + return None; + } + let said = json!({ + "route": format!("provider:{name}"), + "money": self.chosen_route()["price"]["money"], + "program": compiled_json(&p.program)["program"], + "shots": p.read.shots, + }); + Some(blake3::hash(&receipt::canonical(&said)).to_hex()[..16].to_string()) + } + /// The name of the provider chosen, when one was. pub fn provider(&self) -> Option<&str> { match &self.choice { @@ -459,8 +496,13 @@ pub fn route(targets: &[Target], request: &Value, job_bytes: u64) -> Result, request: &Value, job_bytes: u64) -> Result { + let contract = planner::Contract::read(request).map_err(JobError::Failed)?; + let asks_providers = contract.as_ref().is_some_and(|c| c.providers == Some(true) && c.exactness.as_deref().is_none_or(|w| matches!(w, "measured" | "simulated" | "any"))); + let (targets, also) = if asks_providers { (targets, also) } else { (&[][..], Vec::new()) }; let mut quotes = also; let mut plans = Vec::new(); for t in targets { @@ -498,14 +540,28 @@ pub fn run_routed_here(routed: &Routed, request: &Value, key: &SigningKey, energ Ok(body) } -/// The provider [`route`] chose, as [`start`] sends it: refused, with the plan, -/// when it is not free and `confirmed` is false. -pub fn start_routed(t: &Target, routed: &Routed, request: &Value, confirmed: bool, ledger: &Ledger) -> Result { +/// The provider [`route`] chose, as [`start`] sends it. One that is not free is +/// sent only when `confirm` is the word [`Routed::confirmation`] gives now: what +/// the person saw is what is sent, at the estimate they saw. Otherwise it is +/// refused, with the plan and the word that would confirm it. +pub fn start_routed(t: &Target, routed: &Routed, request: &Value, confirm: Option<&str>, ledger: &Ledger) -> Result { let Some((_, p)) = routed.plans.iter().find(|(n, _)| *n == t.name) else { return Err(JobError::Failed(format!("the planner did not weigh {}", t.name))) }; if routed.provider() != Some(t.name.as_str()) { return Err(JobError::Failed(format!("the planner did not choose {}", t.name))); } - start_planned(t, p, request, confirmed, ledger) + if let Some(token) = routed.confirmation() + && confirm != Some(token.as_str()) + { + let seen = match confirm { + Some(_) => "the word given is not this route's at this estimate: what is chosen now, or what it costs, is not what was confirmed. ", + None => "", + }; + // The provider's plan, as a run on a provider named is refused with, and the word. + let mut plan = p.json.clone(); + plan["confirm"] = routed.json()["confirm"].clone(); + return Err(JobError::Unconfirmed { plan, message: format!("{seen}this run on {} is not free: {}; it runs only on the person's word for this route and estimate: {token}", t.name, p.confirmation()) }); + } + start_planned(t, p, request, true, ledger) } /// The dry run: the plan for `request` on `t`, with nothing submitted. @@ -697,7 +753,23 @@ fn ask(t: &Target, ticket: &mut Ticket, key: &SigningKey, ledger: &Ledger) -> Re } let id = ticket.provider_id().ok_or_else(|| JobError::Failed(format!("the record of {} has no provider's id", ticket.handle())))?.to_string(); ticket.polled(); - match t.provider.status(&id) { + let mut status = t.provider.status(&id); + // A contract's deadline, from the job's submission: past it, the job is + // cancelled, since this host can, and nothing is sealed (J074). One that + // finished first gives its result: it has been paid for. + if matches!(status, Ok(JobStatus::Pending)) + && let Some(d) = planner::deadline_ms(ticket.request()) + && ticket.elapsed_ms() as f64 > d + { + t.provider.cancel(&id).map_err(|e| t.fail(e))?; + status = t.provider.status(&id); + if !matches!(status, Ok(JobStatus::Done)) { + ticket.ended("cancelled", &t.redact(&tag(refusal::DEADLINE_PASSED, format!("cancelled at {}: it ran past its contract's deadline of {} s, and nothing was sealed", t.name, d / 1000.0)))); + ledger.put(ticket).map_err(|e| JobError::Failed(format!("the job was cancelled at its deadline, and that could not be recorded: {e}")))?; + return Ok(progress_of(ticket)); + } + } + match status { Ok(JobStatus::Pending) => return Ok(progress_of(ticket)), Ok(JobStatus::Done) => { let read = provider::read_named(ticket.request(), Some(ticket.provider())).map_err(|e| t.fail(e))?; @@ -1281,18 +1353,18 @@ mod tests { let r = Arc::new(Reference::new(Config::default()).unwrap()); let (t, ops, _) = watched(&r); // A simulator is not a device, however free. - let e = run(&t, &json!({ "qasm": BELL, "provider": "lab", "shots": 100, "contract": { "exactness": "measured" } }), false, &key, no_wait(), |_| {}).unwrap_err(); + let e = run(&t, &json!({ "qasm": BELL, "provider": "lab", "shots": 100, "contract": { "providers": "allowed", "exactness": "measured" } }), false, &key, no_wait(), |_| {}).unwrap_err(); assert!(e.to_string().ends_with("[J071]") && e.to_string().contains("simulated"), "{e}"); assert_eq!(count(&ops, "submit"), 0); // What it is, it meets. - let body = run(&t, &json!({ "qasm": BELL, "provider": "lab", "shots": 100, "seed": 3, "contract": { "exactness": "simulated" } }), false, &key, no_wait(), |_| {}).unwrap(); + let body = run(&t, &json!({ "qasm": BELL, "provider": "lab", "shots": 100, "seed": 3, "contract": { "providers": "allowed", "exactness": "simulated" } }), false, &key, no_wait(), |_| {}).unwrap(); let c = wai_quantum::engine::job::check(&body); assert!(c.valid(), "{:?}\n{}", c.reasons, body["result"]); assert_eq!(count(&ops, "submit"), 1); let p = &body["result"]["planner"]; assert_eq!((p["choice"].as_str(), p["wanted"].as_str()), (Some("provider:lab"), Some("simulated")), "{p}"); // A dry run shows it, and sends nothing. - let dry = plan(&t, &json!({ "qasm": BELL, "provider": "lab", "contract": {} })).unwrap(); + let dry = plan(&t, &json!({ "qasm": BELL, "provider": "lab", "contract": { "providers": "allowed" } })).unwrap(); assert_eq!(dry.json["planner"]["wanted_from"], "named"); assert_eq!(dry.json["planner"]["shadow"]["route"], "method:exact", "{}", dry.json["planner"]); assert_eq!(count(&ops, "submit"), 1); @@ -1311,7 +1383,7 @@ mod tests { let key = SigningKey::from_bytes(&[4; 32]); let r = priced_at("0.0003"); let (t, ops, _) = watched(&r); - let job = |most: &str| json!({ "qasm": BELL, "shots": 1000, "provider": "lab", "contract": { "max_cost": { "amount": most, "currency": "USD" } } }); + let job = |most: &str| json!({ "qasm": BELL, "shots": 1000, "provider": "lab", "contract": { "providers": "allowed", "max_cost": { "amount": most, "currency": "USD" } } }); // 1000 shots at 0.0003 is 0.3. let e = run(&t, &job("0.29"), true, &key, no_wait(), |_| {}).unwrap_err(); assert!(e.to_string().contains("above the ceiling") && e.to_string().ends_with("[J071]"), "{e}"); @@ -1329,12 +1401,12 @@ mod tests { assert_eq!(route["price"]["leaves_out"], json!(["energy", "mitigation", "decoder", "charged"]), "{route}"); assert_eq!(route["price"]["program"]["shots"], 1000); // Another currency is not this one, and an estimate that fails is unknown. - let e = run(&t, &json!({ "qasm": BELL, "provider": "lab", "contract": { "max_cost": { "amount": "100", "currency": "EUR" } } }), true, &key, no_wait(), |_| {}).unwrap_err(); + let e = run(&t, &json!({ "qasm": BELL, "provider": "lab", "contract": { "providers": "allowed", "max_cost": { "amount": "100", "currency": "EUR" } } }), true, &key, no_wait(), |_| {}).unwrap_err(); assert!(e.to_string().contains("converts no currency"), "{e}"); let quiet = Arc::new(Reference::new(Config::default()).unwrap()); let ch = Local(move |m: &Value| if m["op"] == "estimate" { json!({ "ok": false, "error": { "code": "unsupported", "message": "no estimates" } }) } else if m["op"] == "describe" { let mut d = quiet.handle(m, None); d["billing"] = json!({}); d } else { quiet.handle(m, None) }); let t = Target::new("lab", Kind::Process, Box::new(OpenProvider::new(ch)), None); - let e = plan(&t, &json!({ "qasm": BELL, "provider": "lab", "contract": { "max_cost": { "amount": "100", "currency": "USD" } } })).err().unwrap(); + let e = plan(&t, &json!({ "qasm": BELL, "provider": "lab", "contract": { "providers": "allowed", "max_cost": { "amount": "100", "currency": "USD" } } })).err().unwrap(); assert!(e.to_string().contains("does not meet a ceiling"), "{e}"); } @@ -1362,7 +1434,12 @@ mod tests { let req = json!({ "qasm": BELL, "shots": 100, "contract": { "providers": "allowed", "exactness": "exact" } }); let body = run_routed_here(&routed, &req, &key, json!({ "unmetered": "a test" })).unwrap(); assert!(wai_quantum::engine::job::check(&body).valid(), "{:?}", wai_quantum::engine::job::check(&body).reasons); - assert_eq!(body["result"]["planner"]["host"]["providers"], json!(["lab"])); + // A contract that wants a class no provider's counts are in asks no + // provider anything: an estimate's request carries the program. + assert_eq!(body["result"]["planner"]["host"]["providers"], json!([])); + assert_eq!((count(&ops, "estimate"), count(&ops, "describe")), (0, 0), "{:?}", ops.lock().unwrap()); + let never = route(&[watched(&r).0], &json!({ "qasm": BELL, "shots": 100, "contract": { "exactness": "any" } }), 1 << 30).unwrap(); + assert_eq!(never.reasoning["host"]["providers"], json!([]), "providers: never asks none"); // A device wanted: of three, the cheapest under the ceiling. let records = Records::new("routed"); let want = json!({ "qasm": BELL, "shots": 1000, "seed": 2, "contract": { "providers": "allowed", "exactness": "measured", "max_cost": { "amount": "0.5", "currency": "USD" } } }); @@ -1374,9 +1451,19 @@ mod tests { assert_eq!(routed.json()["provider_plan"]["plan"]["method"], "provider"); // Sent, and collected as any job is, by the provider the planner chose. let t = targets.iter().find(|t| t.name == "cheap").unwrap(); - assert!(matches!(start_routed(t, &routed, &want, false, &records.ledger()), Err(JobError::Unconfirmed { .. }))); - assert!(start_routed(targets.iter().find(|t| t.name == "mid").unwrap(), &routed, &want, true, &records.ledger()).is_err(), "the planner chose another"); - let mut ticket = start_routed(t, &routed, &want, true, &records.ledger()).unwrap(); + // Confirmed only by the word for this route, its estimate and its program. + let token = routed.confirmation().expect("not free"); + assert_eq!(routed.json()["confirm"]["token"], token.as_str()); + assert!(matches!(start_routed(t, &routed, &want, None, &records.ledger()), Err(JobError::Unconfirmed { .. }))); + assert!(matches!(start_routed(t, &routed, &want, Some("yes"), &records.ledger()), Err(JobError::Unconfirmed { .. })), "no bare word confirms"); + // Seen at one estimate, sent at another: refused, with the new word. + let dearer = bench(&[("dear", Some("0.001")), ("cheap", Some("0.0003")), ("mid", Some("0.0004"))]); + let rerouted = route(&dearer, &want, 1 << 30).unwrap(); + assert_eq!(rerouted.provider(), Some("cheap")); + let Err(JobError::Unconfirmed { message, .. }) = start_routed(dearer.iter().find(|t| t.name == "cheap").unwrap(), &rerouted, &want, Some(&token), &records.ledger()) else { panic!("a word for another estimate confirmed this one") }; + assert!(message.contains("not what was confirmed") && message.contains(&rerouted.confirmation().unwrap()), "{message}"); + assert!(start_routed(targets.iter().find(|t| t.name == "mid").unwrap(), &routed, &want, Some(&token), &records.ledger()).is_err(), "the planner chose another"); + let mut ticket = start_routed(t, &routed, &want, Some(&token), &records.ledger()).unwrap(); let Progress::Done(body) = check(t, &mut ticket, &key, &records.ledger()).unwrap() else { panic!("not done") }; let c = wai_quantum::engine::job::check(&body); assert!(c.valid(), "{:?}\n{}", c.reasons, body["result"]); @@ -1395,6 +1482,44 @@ mod tests { assert_eq!(routed.reasoning["choice"], "method:stabilizer"); } + /// A job still at the provider past its contract's deadline is cancelled + /// there, since this host can, and nothing is sealed (J074); a job that + /// finished first is sealed all the same, saying it missed. + #[test] + fn a_job_past_its_deadline_is_cancelled_where_it_waits() { + let records = Records::new("deadline"); + let key = SigningKey::from_bytes(&[4; 32]); + let quick = |polls: u32| { + let r = Arc::new(Reference::new(Config { polls, ..Config::default() }).unwrap()); + let ops: Asked = Arc::new(std::sync::Mutex::new(Vec::new())); + let seen = Arc::clone(&ops); + let ch = Local(move |m: &Value| { + seen.lock().unwrap().push(m["op"].as_str().unwrap_or_default().to_string()); + let mut a = r.handle(m, None); + if m["op"] == "estimate" { + a["seconds"] = json!(0); + } + a + }); + (Target::new("lab", Kind::Process, Box::new(OpenProvider::new(ch)), None), ops) + }; + let req = json!({ "qasm": BELL, "shots": 100, "provider": "lab", "contract": { "providers": "allowed", "deadline_seconds": 0.01 } }); + let (t, ops) = quick(50); + let mut ticket = start(&t, &req, false, &records.ledger()).unwrap(); + std::thread::sleep(Duration::from_millis(30)); + let Progress::Ended(job) = check(&t, &mut ticket, &key, &records.ledger()).unwrap() else { panic!("not stopped at its deadline") }; + assert_eq!(count(&ops, "cancel"), 1, "{:?}", ops.lock().unwrap()); + assert!(job["status"] == "cancelled" && job["error"].as_str().unwrap().ends_with("[J074]") && job.get("result").is_none(), "{job}"); + // Done before anyone asked after its deadline: sealed, saying it missed. + let (t, ops) = quick(0); + let mut ticket = start(&t, &req, false, &records.ledger()).unwrap(); + std::thread::sleep(Duration::from_millis(30)); + let Progress::Done(body) = check(&t, &mut ticket, &key, &records.ledger()).unwrap() else { panic!("not sealed") }; + assert_eq!(count(&ops, "cancel"), 0); + assert_eq!(body["result"]["planner"]["kept"]["deadline"]["kept"], false, "{}", body["result"]["planner"]["kept"]); + assert!(wai_quantum::engine::job::check(&body).valid(), "{:?}", wai_quantum::engine::job::check(&body).reasons); + } + /// A contract job's shadow is run where its counts are sealed, whichever /// process comes back to it; and its reasoning was kept with its record. #[test] @@ -1402,7 +1527,7 @@ mod tests { let records = Records::new("contract-record"); let key = SigningKey::from_bytes(&[4; 32]); let r = Arc::new(Reference::new(Config { polls: 2, ..Config::default() }).unwrap()); - let req = json!({ "qasm": BELL, "shots": 500, "seed": 7, "provider": "lab", "contract": { "deadline_seconds": 3600 } }); + let req = json!({ "qasm": BELL, "shots": 500, "seed": 7, "provider": "lab", "contract": { "providers": "allowed", "deadline_seconds": 3600 } }); let handle = start(&on(&r), &req, false, &records.ledger()).unwrap().handle().to_string(); let t = on(&r); let mut back = records.ledger().get(&handle).unwrap(); @@ -1437,7 +1562,7 @@ mod tests { }) }; let t = Target::new("lab", Kind::Process, Box::new(OpenProvider::new(quiet)), None); - let e = plan(&t, &json!({ "qasm": BELL, "provider": "lab", "contract": { "deadline_seconds": 3600 } })).err().unwrap(); + let e = plan(&t, &json!({ "qasm": BELL, "provider": "lab", "contract": { "providers": "allowed", "deadline_seconds": 3600 } })).err().unwrap(); assert!(e.to_string().contains("cannot be held to the deadline"), "{e}"); let late = { let r = Arc::clone(&r); @@ -1451,7 +1576,7 @@ mod tests { }; let t = Target::new("lab", Kind::Process, Box::new(OpenProvider::new(late)), None); let key = SigningKey::from_bytes(&[4; 32]); - let body = run(&t, &json!({ "qasm": BELL, "provider": "lab", "shots": 100, "contract": { "deadline_seconds": 100 } }), false, &key, no_wait(), |_| {}).unwrap(); + let body = run(&t, &json!({ "qasm": BELL, "provider": "lab", "shots": 100, "contract": { "providers": "allowed", "deadline_seconds": 100 } }), false, &key, no_wait(), |_| {}).unwrap(); let s = &body["result"]["shadow"]; assert_eq!((s["ran"].as_bool(), s["code"].as_str()), (Some(false), Some("budget")), "{s}"); assert!(wai_quantum::engine::job::check(&body).valid(), "{:?}", wai_quantum::engine::job::check(&body).reasons); diff --git a/wai/wai-quantum-qpu/tests/clients.rs b/wai/wai-quantum-qpu/tests/clients.rs index f22dfe37b..2fc10a715 100644 --- a/wai/wai-quantum-qpu/tests/clients.rs +++ b/wai/wai-quantum-qpu/tests/clients.rs @@ -696,11 +696,11 @@ fn a_built_in_kind_runs_under_a_contract_and_a_classical_method_shadows_it() { let bell = "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n"; let wait = Wait { interval: std::time::Duration::ZERO, polls: 10 }; // Its client states no price: an unknown cost does not meet a ceiling. - let capped = json!({ "qasm": bell, "provider": "lab", "shots": 400, "contract": { "max_cost": { "amount": "100", "currency": "USD" } } }); + let capped = json!({ "qasm": bell, "provider": "lab", "shots": 400, "contract": { "providers": "allowed", "max_cost": { "amount": "100", "currency": "USD" } } }); let e = job::plan(&target(), &capped).err().unwrap().to_string(); assert!(e.ends_with("[J071]") && e.contains("does not meet a ceiling"), "{e}"); // Named, with the person's confirmation for an unknown cost, it runs. - let req = json!({ "qasm": bell, "provider": "lab", "shots": 400, "seed": 5, "contract": { "exactness": "measured" } }); + let req = json!({ "qasm": bell, "provider": "lab", "shots": 400, "seed": 5, "contract": { "providers": "allowed", "exactness": "measured" } }); assert!(matches!(job::run(&target(), &req, false, &key, wait, |_| {}), Err(JobError::Unconfirmed { .. }))); let body = job::run(&target(), &req, true, &key, wait, |_| {}).unwrap(); let c = wai_quantum::engine::job::check(&body); @@ -736,7 +736,7 @@ fn a_cost_estimated_at_the_least_it_can_come_to_meets_no_ceiling() { Target::new("tasks", Kind::CloudTasks, Box::new(client), None) }; let bell = "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n"; - let capped = json!({ "qasm": bell, "provider": "tasks", "shots": 100, "contract": { "max_cost": { "amount": "100", "currency": "USD" } } }); + let capped = json!({ "qasm": bell, "provider": "tasks", "shots": 100, "contract": { "providers": "allowed", "max_cost": { "amount": "100", "currency": "USD" } } }); let e = job::plan(&target(), &capped).err().unwrap().to_string(); assert!(e.ends_with("[J071]") && e.contains("the least it can come to"), "{e}"); // Routed with every route in view, it is listed with its price and why. @@ -744,7 +744,7 @@ fn a_cost_estimated_at_the_least_it_can_come_to_meets_no_ceiling() { let e = job::route(&[target()], &routed, 1 << 30).err().unwrap().to_string(); assert!(e.ends_with("[J071]") && e.contains("provider:tasks: at least 0.003750 USD"), "{e}"); // Named, with no ceiling: planned, its estimate shown, and its route met. - let named = json!({ "qasm": bell, "provider": "tasks", "shots": 100, "contract": {} }); + let named = json!({ "qasm": bell, "provider": "tasks", "shots": 100, "contract": { "providers": "allowed" } }); let p = job::plan(&target(), &named).unwrap(); let route = p.json["planner"]["routes"].as_array().unwrap().iter().find(|r| r["route"] == "provider:tasks").unwrap().clone(); assert_eq!((route["outcome"].as_str(), route["price"]["money"]["at_least"].as_bool(), route["price"]["money"]["unit"].as_str()), (Some("chosen"), Some(true), Some("minute")), "{route}"); diff --git a/wai/wai-quantum/docs/job-refusals.md b/wai/wai-quantum/docs/job-refusals.md index 7e22e7191..ce09a56ac 100644 --- a/wai/wai-quantum/docs/job-refusals.md +++ b/wai/wai-quantum/docs/job-refusals.md @@ -85,11 +85,11 @@ browser engine. A test holds this page to the code's table. | `J063` | refused | A component the registry does not take: a name its kind holds already (a built-in's among them), a name or version that is empty or not plain text, a descriptor that is not a JSON object, a channel on other than one or two qubits, or a pass whose check states no bound. | | `J064` | refused | A registered component's answer that breaks the engine's contract: a method's result without an accuracy class it declared, or one that writes a member the engine writes (method, qubits, gates, compiled, repaired, engine, schema, components, receipt, verdict); a pass's gates on qubits the program does not have, or that do not read back; a front end's program that does not read. Nothing it gave is returned. | | `J065` | refused | An intent on a job whose noise names a registered channel: the intent checks model the built-in channels alone, so the check is refused rather than made against another model. | -| `J070` | refused | A contract that does not read: not an object, a member a contract does not have, an exactness that is no class, a max_cost that is not an amount in decimals and a currency, a deadline or an energy ceiling that is not above zero, providers that is neither never nor allowed, or a job that names a provider while its contract says never. | +| `J070` | refused | A contract that does not read: not an object, a member a contract does not have, an exactness that is no class, a max_cost that is not an amount in decimals and a currency, a deadline or an energy ceiling that is not above zero, providers that is neither never nor allowed, or a job that names a provider while its contract does not allow one (providers: never is the default). | | `J071` | refused | No route this host can see meets the contract: each route's price or reason is listed, so the contract or the job can be changed. Nothing fell back to a route the contract does not allow. | | `J072` | refused | A route's result whose accuracy class does not meet the class its job wants: the contract's, or under a contract that names none the class the job keeps. Nothing it gave is returned, since its receipt would not verify. | | `J073` | refused | A contract where it cannot be honoured: on a set or an item of one (each program runs under its own contract, alone), or on a build with no planner. It is refused rather than read as absent. | -| `J074` | refused | A run stopped at its contract's deadline, by a host that can stop one: the estimate it was planned on was wrong here, and nothing was sealed. | +| `J074` | refused | A run stopped at its contract's deadline, by a host that can stop one: the job service's worker, or a provider's job the command line cancels where it waits. The estimate it was planned on was wrong here, and nothing was sealed. | | `J100` | dropped | A line of an answer that is not a statement (`name = View(...)`), a program (a fenced `qasm` block with its name), a comment or a marker: left out. | | `J101` | dropped | A view the answer layer does not have: left out (the views are listed in the layer's specification). | | `J102` | dropped | An `@` call the engine does not have: the statement is left out. | diff --git a/wai/wai-quantum/schemas/job-request.v1.json b/wai/wai-quantum/schemas/job-request.v1.json index 4f2b9c60d..6d2dac6c6 100644 --- a/wai/wai-quantum/schemas/job-request.v1.json +++ b/wai/wai-quantum/schemas/job-request.v1.json @@ -429,7 +429,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -442,7 +442,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -467,7 +468,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", diff --git a/wai/wai-quantum/schemas/job-result.v1.json b/wai/wai-quantum/schemas/job-result.v1.json index e81a514bb..16fcb1a86 100644 --- a/wai/wai-quantum/schemas/job-result.v1.json +++ b/wai/wai-quantum/schemas/job-result.v1.json @@ -1708,6 +1708,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -1770,7 +1778,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -1791,6 +1801,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -2094,9 +2120,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" diff --git a/wai/wai-quantum/src/engine/planner.rs b/wai/wai-quantum/src/engine/planner.rs index 301a98bc3..396757607 100644 --- a/wai/wai-quantum/src/engine/planner.rs +++ b/wai/wai-quantum/src/engine/planner.rs @@ -65,7 +65,7 @@ use super::catalog::{self, Plan, Request}; use super::fabric; use super::receipt; use super::refusal::{self, tag}; -use super::registry::{Identity, Job, Kind, Method, Registry}; +use super::registry::{Identity, Job, Kind, Method, Question, Registry}; use serde_json::{Map, Value, json}; use std::cmp::Ordering; @@ -83,6 +83,17 @@ pub const SHADOW_MAX_SECONDS: f64 = 300.0; /// a seeded simulator's counts are not its counts by construction. pub const SHADOW_SEED_OFFSET: u64 = 1 << 32; +/// The most seconds a price may state (section 8.6): about 31,700 years. A +/// provider's estimate past it is not taken as a time. +pub const MAX_SECONDS: f64 = 1e12; + +/// The most characters an amount may have (section 8.6). A provider's estimate +/// past it is not taken as an amount, and a ceiling past it does not read. +pub const MAX_AMOUNT: usize = 64; + +/// The questions a job asks, by which `auto` orders the methods. +pub const QUESTIONS: [&str; 4] = ["noise", "counts", "expectations", "amplitudes"]; + /// The reasons a verifier gives (section 8.6). /// /// The request's `contract` is not of its form. @@ -102,6 +113,8 @@ pub const PLANNER_KEPT: &str = "planner_kept"; pub const CONTRACT_CLASS: &str = "contract_class"; /// A provider's contract job's shadow is missing or not what its counts give. pub const SHADOW: &str = "shadow"; +/// A request names a provider under a contract that does not allow one. +pub const CONTRACT_PROVIDER: &str = "contract_provider"; /// Whether a result of class `got` meets a contract that wants `wanted`: the /// table in section 8.6, not a ladder. A class with a stated error does not @@ -163,8 +176,12 @@ pub fn has_contract(v: &Value) -> bool { v.get("contract").is_some_and(|c| !c.is_null()) } -/// Whether `s` is an amount in decimals: digits, and optionally `.` and digits. +/// Whether `s` is an amount in decimals: digits, and optionally `.` and digits, +/// at most [`MAX_AMOUNT`] characters in all. pub fn is_decimal(s: &str) -> bool { + if s.len() > MAX_AMOUNT { + return false; + } let (whole, frac) = s.split_once('.').map_or((s, None), |(a, b)| (a, Some(b))); !whole.is_empty() && whole.bytes().all(|b| b.is_ascii_digit()) && frac.is_none_or(|f| !f.is_empty() && f.bytes().all(|b| b.is_ascii_digit())) } @@ -413,13 +430,14 @@ fn energy_of(p: &Plan, host: &Host<'_>) -> Value { } } -fn local_route(m: &dyn Method, identity: Option<&Identity>, r: Option<&Request>, plan: Option<&Plan>, host: &Host<'_>, target: bool) -> Value { +fn local_route(m: &dyn Method, identity: Option<&Identity>, r: Option<&Request>, plan: Option<&Plan>, host: &Host<'_>, target: bool, rank: Option) -> Value { let mut route = json!({ "route": format!("method:{}", m.name()), "kind": "local", "method": m.name(), "class": class_of(m, r, plan, target), "host_dependent": is_gpu(m.name()) || identity.is_some_and(|i| !i.is_builtin()), + "auto_rank": rank, "price": null, }); if let Some(p) = plan { @@ -453,12 +471,19 @@ fn provider_route(q: &Quote) -> Value { if q.approximate { route["approximate"] = json!(true); } + // What a price may state is bounded (section 8.6): past it, a provider's + // estimate is not taken as a time or an amount, and is an unknown. let time = match q.seconds { - Some(s) => json!({ "seconds": s, "basis": "provider" }), + Some(s) if (0.0..=MAX_SECONDS).contains(&s) => json!({ "seconds": s, "basis": "provider" }), + Some(s) => json!({ "seconds": null, "why": format!("the provider's estimate states {s} s, past the {MAX_SECONDS} s a price may state") }), None => json!({ "seconds": null, "why": "the provider's estimate states no time" }), }; + let mut money = q.money.clone(); + if let Some(n) = money["amount"].as_str().map(|a| a.chars().count()).filter(|n| *n > MAX_AMOUNT) { + money = json!({ "free": false, "unknown": format!("the provider's estimate states an amount of {n} characters, past the {MAX_AMOUNT} an amount may have") }); + } route["price"] = json!({ - "money": q.money, + "money": money, "time": time, "memory_bytes": null, "work": null, @@ -472,10 +497,15 @@ fn provider_route(q: &Quote) -> Value { /// What a route is held to. struct Held<'a> { contract: &'a Contract, - provider: Option<&'a str>, - method: Option<&'a str>, + /// The route the job names: the provider or the method its request names, + /// or the one method a device target's job runs on. + named: Option<&'a str>, fabric: Fab, wanted: Option<&'a str>, + /// Whether `wanted` is the class the contract names, rather than the one the + /// job keeps: only a class the contract names refuses an approximate + /// simulator a job named. + from_contract: bool, job_bytes: f64, } @@ -495,11 +525,68 @@ fn fab_of(v: &Value) -> Fab { } } -/// What a request names: a provider, or a method other than `auto`. -fn named(v: &Value) -> (Option<&str>, Option<&str>) { - let provider = v.get("provider").and_then(Value::as_str); - let method = if provider.is_some() { None } else { v.get("method").and_then(Value::as_str).filter(|m| *m != "auto") }; - (provider, method) +/// What a request itself names: `provider:` for the provider it names, +/// else `method:` for a method other than `auto`. +fn request_names(v: &Value) -> Option { + if let Some(p) = v.get("provider").and_then(Value::as_str) { + return Some(format!("provider:{p}")); + } + v.get("method").and_then(Value::as_str).filter(|m| *m != "auto").map(|m| format!("method:{m}")) +} + +/// Whether a request names a device target. +fn names_target(v: &Value) -> bool { + v.get("target").is_some_and(|t| !t.is_null()) +} + +/// The question a job asks, which orders the methods `auto` tries (section +/// 8.6): `noise` for a job with a noise model; else `counts` when it asks for +/// shots (1024 when it gives none and asks for no observable and no amplitude); +/// else `expectations` when it asks for observables and no amplitude; else +/// `amplitudes`. Read from the request alone, as any verifier reads it. +pub fn question_of(v: &Value) -> &'static str { + let listed = |k: &str| v.get(k).and_then(Value::as_array).is_some_and(|a| !a.is_empty()); + let (observables, amplitudes) = (listed("observables"), listed("amplitudes")); + let shots = v.get("shots").and_then(Value::as_u64).unwrap_or(if !observables && !amplitudes { 1024 } else { 0 }); + if v.get("noise").is_some_and(|n| !n.is_null()) { + "noise" + } else if shots > 0 { + "counts" + } else if observables && !amplitudes { + "expectations" + } else { + "amplitudes" + } +} + +fn question(q: &str) -> Question { + match q { + "noise" => Question::Noise, + "counts" => Question::Counts, + "expectations" => Question::Expectations, + _ => Question::Amplitudes, + } +} + +/// The route `auto` picks, from what the routes state (section 8.6): none for a +/// job that names a route; `method:statevector` for one placed on the fabric's +/// members, where it is priced; otherwise the priced local route of the least +/// `auto_rank`, the first listed of equal ranks. Every verifier recomputes it. +fn auto_of(routes: &[Value], request: &Value, named: Option<&str>) -> Option { + if named.is_some() { + return None; + } + if fab_of(request) == Fab::Placed { + return routes.iter().find(|r| r["route"] == "method:statevector" && r["kind"] == "local" && r["price"].is_object()).map(|_| "method:statevector".to_string()); + } + let by_value = |x: f64, y: f64| x.partial_cmp(&y).unwrap_or(Ordering::Equal); + routes + .iter() + .enumerate() + .filter(|(_, r)| r["kind"] == "local" && r["price"].is_object()) + .filter_map(|(i, r)| r["auto_rank"].as_f64().map(|k| (k, i, r))) + .min_by(|a, b| by_value(a.0, b.0).then(a.1.cmp(&b.1))) + .and_then(|(_, _, r)| r["route"].as_str().map(str::to_string)) } /// The first rule of section 8.6 a route breaks, in its order, or `None` when @@ -509,12 +596,12 @@ fn named(v: &Value) -> (Option<&str>, Option<&str>) { fn gate(route: &Value, h: &Held<'_>) -> Option<&'static str> { let name = route["route"].as_str().unwrap_or(""); let (method, provider) = (name.strip_prefix("method:"), name.strip_prefix("provider:")); - match (h.provider, h.method) { - (Some(p), _) if provider != Some(p) => return Some("not_named"), - (None, Some(m)) if method != Some(m) => return Some("not_named"), - _ => {} + if let Some(n) = h.named + && name != n + { + return Some("not_named"); } - if h.provider.is_none() && h.method.is_none() { + if h.named.is_none() { match h.fabric { Fab::Placed if method != Some("statevector") => return Some("fabric"), Fab::Cpu if method.is_some_and(is_gpu) => return Some("fabric"), @@ -527,7 +614,7 @@ fn gate(route: &Value, h: &Held<'_>) -> Option<&'static str> { return Some("cannot"); } match h.wanted { - Some(w) if !meets(w, class) || (w == "simulated" && route["approximate"] == true) => return Some("class"), + Some(w) if !meets(w, class) || (h.from_contract && w == "simulated" && route["approximate"] == true) => return Some("class"), None if provider.is_some() => return Some("class"), _ => {} } @@ -538,7 +625,7 @@ fn gate(route: &Value, h: &Held<'_>) -> Option<&'static str> { if price["memory_bytes"].as_f64().is_some_and(|m| m > h.job_bytes) { return Some("memory"); } - if provider.is_some() && h.provider.is_none() && h.contract.providers != Some(true) { + if provider.is_some() && h.contract.providers != Some(true) { return Some("providers"); } if let Some(d) = h.contract.deadline_seconds { @@ -553,7 +640,7 @@ fn gate(route: &Value, h: &Held<'_>) -> Option<&'static str> { match &h.contract.max_cost { // A provider named by the job is the person's choice, as it is with // no contract: its cost is shown, and it runs on their confirmation. - None if h.provider.is_some() => {} + None if provider.is_some_and(|_| h.named == Some(name)) => {} None => return Some("cost_no_ceiling"), Some((most, cur)) => match (amount, currency) { (Some(a), Some(c)) if c == cur => { @@ -584,24 +671,25 @@ fn gate(route: &Value, h: &Held<'_>) -> Option<&'static str> { fn gate_why(code: &str, route: &Value, h: &Held<'_>) -> String { let price = &route["price"]; let class = route["class"].as_str().unwrap_or("unknown"); + let ceiling = || h.contract.max_cost.as_ref().map_or(String::new(), |c| format!("{} {}", c.0, c.1)); match code { "not_named" => "the job names another route".to_string(), "fabric" => "the job's placement on the fabric is not this route's".to_string(), "class" => match h.wanted { Some(w) if class == "heuristic" && matches!(w, "bit-exact" | "exact" | "single" | "bounded" | "estimate") => format!("its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants {w}"), - Some(w) if w == "simulated" && route["approximate"] == true => "its provider states this simulator is approximate, and the job wants a simulator's counts that are not".to_string(), + Some(w) if w == "simulated" && route["approximate"] == true => "its provider states this simulator is approximate, and the contract wants a simulator's counts that are not".to_string(), Some(w) => format!("its class is {class}, and the job wants {w}"), None => format!("its class is {class}; the job names no class, and nothing the planner would do today gives this one: ask for measured or any, or name the provider"), }, "memory" => format!("it takes {} bytes, and a job here takes at most {}", price["memory_bytes"], h.job_bytes), - "providers" => "the contract does not allow a provider".to_string(), + "providers" => "the contract does not allow a provider: under a contract one is used only with providers: allowed".to_string(), "deadline_unknown" => format!("its time is not known, so it cannot be held to the deadline of {} s: {}", h.contract.deadline_seconds.unwrap_or(0.0), price["time"]["why"].as_str().unwrap_or("")), "deadline" => format!("about {} s, past the deadline of {} s", price["time"]["seconds"], h.contract.deadline_seconds.unwrap_or(0.0)), "cost_no_ceiling" => format!("{}: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider", money_said(&price["money"])), "cost_unknown" => format!("{}: an unknown cost does not meet a ceiling", money_said(&price["money"])), "cost_currency" => format!("{}, and the ceiling is in {}: the planner converts no currency", money_said(&price["money"]), h.contract.max_cost.as_ref().map_or("", |c| c.1.as_str())), - "cost" => format!("{}, above the ceiling of {} {}", money_said(&price["money"]), h.contract.max_cost.as_ref().map_or("", |c| c.0.as_str()), h.contract.max_cost.as_ref().map_or("", |c| c.1.as_str())), - "cost_at_least" => format!("{}: the least it can come to, and what the job takes decides the rest, so it is not known to be within the ceiling of {} {}", money_said(&price["money"]), h.contract.max_cost.as_ref().map_or("", |c| c.0.as_str()), h.contract.max_cost.as_ref().map_or("", |c| c.1.as_str())), + "cost" => format!("{}, above the ceiling of {}", money_said(&price["money"]), ceiling()), + "cost_at_least" => format!("{}: the least it can come to, and what the job takes decides the rest, so it is not known to be within the ceiling of {}", money_said(&price["money"]), ceiling()), "energy_unknown" => format!("its energy is not known, so it cannot be held to the ceiling of {} J: {}", h.contract.max_joules.unwrap_or(0.0), price["energy"]["why"].as_str().unwrap_or("")), "energy" => format!("about {} J, above the ceiling of {} J", price["energy"]["joules"], h.contract.max_joules.unwrap_or(0.0)), other => other.to_string(), @@ -618,23 +706,38 @@ fn money_said(m: &Value) -> String { } } +/// A route's money in the order: free first, then an amount in decimals by its +/// value, then any other. +fn money_rank(r: &Value) -> (u8, Option<&str>) { + let m = &r["price"]["money"]; + if m["free"] == true { + (0, None) + } else if let Some(a) = m["amount"].as_str().filter(|a| is_decimal(a)) { + (1, Some(a)) + } else { + (2, None) + } +} + +/// A time in the order: its seconds to the nearest whole millisecond, halves up. +fn millis(r: &Value) -> Option { + r["price"]["time"]["seconds"].as_f64().map(|s| (s * 1000.0 + 0.5).floor()) +} + /// Which of two routes that meet the contract is cheaper: less money (free -/// first), then less time to the millisecond (a stated time before an unknown -/// one), a local route before a provider's, less memory, and then by name, so -/// that the order is total and every verifier finds the same route. +/// first, then the lesser amount in decimals, then any other), then less time to +/// the nearest millisecond (a stated time before an unknown one), a local route +/// before a provider's, less memory, and then by name, so that the order is +/// total and every verifier finds the same route. fn cheaper(a: &Value, b: &Value) -> Ordering { - let money = |r: &Value| -> Option { if r["price"]["money"]["free"] == true { None } else { Some(r["price"]["money"]["amount"].as_str().unwrap_or("").to_string()) } }; - let money_order = match (money(a), money(b)) { - (None, None) => Ordering::Equal, - (None, Some(_)) => Ordering::Less, - (Some(_), None) => Ordering::Greater, - (Some(x), Some(y)) if is_decimal(&x) && is_decimal(&y) => decimal_cmp(&x, &y), + let ((ra, aa), (rb, ab)) = (money_rank(a), money_rank(b)); + let money_order = ra.cmp(&rb).then_with(|| match (aa, ab) { + (Some(x), Some(y)) => decimal_cmp(x, y), _ => Ordering::Equal, - }; - let ms = |r: &Value| r["price"]["time"]["seconds"].as_f64().map(|s| (s * 1000.0).ceil()); + }); // By value: -0.0 is 0 (a JSON number has no NaN). let by_value = |x: f64, y: f64| x.partial_cmp(&y).unwrap_or(Ordering::Equal); - let time_order = match (ms(a), ms(b)) { + let time_order = match (millis(a), millis(b)) { (Some(x), Some(y)) => by_value(x, y), (Some(_), None) => Ordering::Less, (None, Some(_)) => Ordering::Greater, @@ -686,13 +789,12 @@ struct Local { plans: Vec<(String, Plan)>, /// Why each route that cannot run cannot. cannot: Vec<(String, String)>, - auto: Option, - /// What the job names, when the method it runs on is fixed. - method: Option, + /// The route the job names, where it names one. + named: Option, read: Option, } -fn local_routes(reg: &Registry, v: &Value, host: &Host<'_>) -> Result { +fn local_routes(reg: &Registry, v: &Value, host: &Host<'_>, q: Question) -> Result { let identity = |m: &dyn Method| reg.identity(Kind::Method, m.name()); let job_bytes = host.job_bytes; // A program its method reads itself, and a job on a device target, have one @@ -701,9 +803,9 @@ fn local_routes(reg: &Registry, v: &Value, host: &Host<'_>) -> Result) -> Result) -> Result) -> Result) -> Result { let contract = Contract::read(v)?.ok_or_else(|| "internal: a job with no contract was brought to the planner".to_string())?; - let (provider, _) = named(v); - if provider.is_some() && contract.providers == Some(false) { - return Err(tag(refusal::CONTRACT_FORM, "the job names a provider, and its contract says providers: never")); + // Under a contract a provider is used only where the contract allows one, + // the job's own named one among them: providers: never is the default. + if v.get("provider").is_some_and(|p| !p.is_null()) && contract.providers != Some(true) { + return Err(tag(refusal::CONTRACT_FORM, "the job names a provider, and its contract does not allow one: under a contract a provider is used only with providers: allowed")); } + let provider = v.get("provider").and_then(Value::as_str); if v.get("provider").is_some_and(|p| !p.is_null()) && !provider.is_some_and(|p| host.quotes.iter().any(|q| q.name == p)) { // Refused as a job that names a provider is refused where none is reached. catalog::read_in(reg, v)?; return Err(tag(refusal::PROVIDER_HERE, "this job names a provider this host has not brought")); } + let q = question_of(v); // A job that names a provider runs on it: the methods are listed unpriced. - let mut local = if provider.is_some() { - let mut l = Local { routes: Vec::new(), plans: Vec::new(), cannot: Vec::new(), auto: None, method: None, read: None }; + let mut local = if let Some(p) = provider { + let mut l = Local { routes: Vec::new(), plans: Vec::new(), cannot: Vec::new(), named: Some(format!("provider:{p}")), read: None }; for m in reg.methods() { - l.routes.push(local_route(m, reg.identity(Kind::Method, m.name()), None, None, host, false)); + l.routes.push(local_route(m, reg.identity(Kind::Method, m.name()), None, None, host, false, m.auto_rank(question(q)))); } l } else { - local_routes(reg, v, host)? + local_routes(reg, v, host, question(q))? }; - let auto = local.auto.take(); + let named = local.named.take(); let mut routes = std::mem::take(&mut local.routes); routes.extend(host.quotes.iter().map(provider_route)); let quote_cannot = |name: &str| host.quotes.iter().find(|q| format!("provider:{}", q.name) == name).and_then(|q| q.cannot.clone()); - let method = provider.is_none().then(|| local.method.clone()).flatten(); + let auto = auto_of(&routes, v, named.as_deref()); // What the job wants: what the contract says, else what it would have had. - let named_route = provider.map(|p| format!("provider:{p}")).or_else(|| method.as_ref().map(|m| format!("method:{m}"))); let class_of_route = |name: &str| routes.iter().find(|r| r["route"] == name).and_then(|r| r["class"].as_str()).map(str::to_string); - let (wanted, wanted_from) = match (&contract.exactness, &named_route, &auto) { + let (wanted, wanted_from) = match (&contract.exactness, &named, &auto) { (Some(w), _, _) => (Some(w.clone()), Some("contract")), (None, Some(n), _) => (class_of_route(n), Some("named")), (None, None, Some(a)) => (class_of_route(a), Some("auto")), (None, None, None) => (None, None), }; let job_bytes = whole(host.job_bytes); - let fabric = if provider.is_some() { Fab::Free } else { fab_of(v) }; - let held = Held { contract: &contract, provider, method: method.as_deref(), fabric, wanted: wanted.as_deref(), job_bytes: host.job_bytes as f64 }; + let held = Held { contract: &contract, named: named.as_deref(), fabric: fab_of(v), wanted: wanted.as_deref(), from_contract: wanted_from == Some("contract"), job_bytes: host.job_bytes as f64 }; for route in &mut routes { let name = route["route"].as_str().unwrap_or("").to_string(); match gate(route, &held) { @@ -816,6 +916,8 @@ pub fn consider(reg: &Registry, v: &Value, host: &Host<'_>) -> Result Result Result { - let d = decide(reg, v, &Host::new(job_bytes))?; + plan_value_on(reg, v, &Host::new(job_bytes)) +} + +/// [`plan_value`] on `host`: its energy estimate, where it has one. +pub fn plan_value_on(reg: &Registry, v: &Value, host: &Host<'_>) -> Result { + let d = decide(reg, v, host)?; let Choice::Local(p) = d.choice else { return Err("internal: a provider chosen with none brought".to_string()) }; let mut o = serde_json::to_value(&p).map_err(|e| e.to_string())?; o["planner"] = d.reasoning; @@ -915,11 +1022,12 @@ pub fn contract_schema() -> Value { /// `reasoning` in `result`, the result held first to the class the reasoning /// wants, whether the contract named it or the job keeps what it would have had: /// a method that gave less gives no answer ([`refusal::CLASS_BROKEN`]), since -/// its receipt would break section 8.6. +/// its receipt would break section 8.6. An approximate simulator's counts fall +/// short only of a `simulated` the contract names. pub fn complete(result: &mut Value, reasoning: &Value) -> Result<(), String> { if let Some(wanted) = reasoning["wanted"].as_str() { let got = result.pointer("/accuracy/class").and_then(Value::as_str).unwrap_or(""); - let approximate = result.pointer("/accuracy/approximate") == Some(&Value::Bool(true)); + let approximate = result.pointer("/accuracy/approximate") == Some(&Value::Bool(true)) && reasoning["wanted_from"] == "contract"; if !meets(wanted, got) || (wanted == "simulated" && approximate) { let why = if approximate && wanted == "simulated" { "an approximate simulator's".to_string() } else { format!("{got:?}") }; return Err(tag(refusal::CLASS_BROKEN, format!("the route {} gave a result of class {why}, and the job wants {wanted}: nothing it gave is returned", reasoning["choice"].as_str().unwrap_or("?")))); @@ -995,6 +1103,12 @@ pub fn missed(result: &Value) -> bool { result.pointer("/planner/kept").and_then(Value::as_object).is_some_and(|k| k.values().any(|x| x["kept"] == false)) } +/// The deadline a contract job's provider run is held to, from its submission, +/// in milliseconds, where its contract gives one. +pub fn deadline_ms(v: &Value) -> Option { + Contract::read(v).ok().flatten().and_then(|c| c.deadline_seconds).map(|d| d * 1000.0) +} + // --------------------------------------------------------------------------- // The shadow // --------------------------------------------------------------------------- @@ -1005,15 +1119,22 @@ pub fn shadow_seed(v: &Value) -> u64 { ((u128::from(seed) + u128::from(SHADOW_SEED_OFFSET)) % (1 << 53)) as u64 } +/// What the contract leaves a shadow, in seconds: the deadline less the +/// provider's own time, never below 0; the deadline where the provider states +/// no time; [`SHADOW_MAX_SECONDS`] with no deadline. +fn shadow_budget(contract: &Contract, provider_seconds: Option) -> f64 { + match (contract.deadline_seconds, provider_seconds) { + (Some(d), Some(s)) => (d - s).max(0.0), + (Some(d), None) => d, + (None, _) => SHADOW_MAX_SECONDS, + } +} + /// The classical method that can reach the provider's counts within the /// contract, the most exact first and then the cheapest, or why none can: what /// the contract leaves after the provider's own time, or [`SHADOW_MAX_SECONDS`]. fn shadow_plan(reg: &Registry, v: &Value, host: &Host<'_>, contract: &Contract, provider_seconds: Option) -> Value { - let budget = match (contract.deadline_seconds, provider_seconds) { - (Some(d), Some(s)) => (d - s).max(0.0), - (Some(d), None) => d, - (None, _) => SHADOW_MAX_SECONDS, - }; + let budget = shadow_budget(contract, provider_seconds); let Ok(read) = super::provider::read_named(v, Some("shadow")) else { return json!({ "route": null, "code": "none", "why": "the job does not read as a provider job" }); }; @@ -1033,7 +1154,7 @@ fn shadow_plan(reg: &Registry, v: &Value, host: &Host<'_>, contract: &Contract, Err(e) => tried.push(json!({ "route": route, "code": "none", "why": e })), Ok(p) if p.memory_bytes > host.job_bytes => tried.push(json!({ "route": route, "code": "memory", "why": format!("it takes {} bytes, and a job here takes at most {}", p.memory_bytes, host.job_bytes) })), Ok(p) => { - let priced = local_route(m, reg.identity(Kind::Method, m.name()), Some(r), Some(&p), host, false); + let priced = local_route(m, reg.identity(Kind::Method, m.name()), Some(r), Some(&p), host, false, None); match priced["price"]["time"]["seconds"].as_f64() { Some(s) if s <= budget => candidates.push(priced), Some(s) => tried.push(json!({ "route": route, "code": "budget", "why": format!("about {s} s, and the contract leaves a shadow {budget} s") })), @@ -1059,9 +1180,17 @@ fn shadow_plan(reg: &Registry, v: &Value, host: &Host<'_>, contract: &Contract, } /// The distance between two lists of counts of the same shots, recomputable -/// from them: the total variation exactly, as whole numbers, and the Hellinger -/// fidelity and what the shots alone would leave, each in a fixed order of -/// outcomes (section 8.6). `None` when either leaves out shots. +/// from them: the total variation exactly, as whole numbers, the Hellinger +/// fidelity, and a bound on the total variation the shots alone would leave +/// between two samples of one distribution, each in a fixed order of outcomes +/// (section 8.6). `None` with no shots, or counts past them. +/// +/// The bound: given each outcome's count n in both lists together, the two +/// lists' difference on it, were both samples of one distribution, is at most +/// what a fair coin's split of n leaves on average, E|2B − n| with B binomial +/// (n, ½) ([`split_mad`]): a list of S shots exactly splits tighter. Half their +/// sum over S, and at most 1, bounds the total variation the shots alone leave, +/// for every number of outcomes and shots, sparse or dense. pub fn distance(a: &Value, b: &Value, shots: u64) -> Option { let (a, b) = (a.as_object()?, b.as_object()?); if shots == 0 { @@ -1072,18 +1201,19 @@ pub fn distance(a: &Value, b: &Value, shots: u64) -> Option { keys.dedup(); let s = shots as f64; // Sums of whole numbers are exact; each product and quotient is a double's. - let (mut numerator, mut root, mut floor) = (0u128, 0.0f64, 0.0f64); + let (mut numerator, mut root, mut bound, mut total) = (0u128, 0.0f64, 0.0f64, 0u128); for k in keys { let x = a.get(k).and_then(Value::as_u64).unwrap_or(0); let y = b.get(k).and_then(Value::as_u64).unwrap_or(0); numerator += u128::from(x.abs_diff(y)); root += ((x as f64) * (y as f64)).sqrt(); - let p = (u128::from(x) + u128::from(y)) as f64 / (2.0 * s); - let inner = 4.0 * p * (1.0 - p) / (std::f64::consts::PI * s); - if inner.is_nan() || inner < 0.0 { - return None; - } - floor += inner.sqrt(); + let n = u128::from(x) + u128::from(y); + total += n; + bound += split_mad(n); + } + // Counts past the shots are not two lists of them. + if total > 2 * u128::from(shots) { + return None; } let denominator = 2 * u128::from(shots); let whole = |x: u128| if x < (1 << 53) { json!(x as u64) } else { json!(x as f64) }; @@ -1093,10 +1223,33 @@ pub fn distance(a: &Value, b: &Value, shots: u64) -> Option { "denominator": whole(denominator), "total_variation": numerator as f64 / denominator as f64, "hellinger_fidelity": root * root / (s * s), - "sampling_tvd_expected": 0.5 * floor, + "sampling_tvd_bound": (0.5 * bound / s).min(1.0), })) } +/// E|2B − n| for B binomial (n, ½): what a fair coin's split of n leaves +/// between its two sides, on average. It is the same for n = 2j + 1 and +/// 2j + 2, and is the product of (2i + 3) ÷ (2i + 2) for i from 0 to j − 1, +/// taken in that order; from j = 4096 on, (2j + 1)·(1 − 1/8j + 1/128j² + +/// 5/1024j³) ÷ √(πj), within 3·10⁻¹⁵ of it there. Only `× ÷ + −` and `√`, in +/// IEEE 754 doubles in the order written, so every verifier gets the same bits. +pub fn split_mad(n: u128) -> f64 { + if n == 0 { + return 0.0; + } + let j = (n - 1) / 2; + if j < 4096 { + let mut m = 1.0f64; + for i in 0..j as u32 { + m = m * f64::from(2 * i + 3) / f64::from(2 * i + 2); + } + return m; + } + let jj = j as f64; + let c = (1.0 - 1.0 / (8.0 * jj) + 1.0 / (128.0 * jj * jj) + 5.0 / (1024.0 * jj * jj * jj)) / (std::f64::consts::PI * jj).sqrt(); + (2.0 * jj + 1.0) * c +} + /// A provider's result, with the shadow the reasoning planned run beside it: a /// result's `shadow`, carrying both counts' distance, or why there is none. pub fn shadow(reg: &Registry, reasoning: &Value, result: &Value) -> Value { @@ -1154,34 +1307,52 @@ fn is_whole(v: &Value) -> bool { v.as_f64().is_some_and(|x| x.fract() == 0.0 && x >= 0.0) } +/// A number of seconds a price may state: at least 0 and at most +/// [`MAX_SECONDS`]. +fn seconds_ok(v: &Value) -> bool { + v.as_f64().is_some_and(|s| (0.0..=MAX_SECONDS).contains(&s)) +} + +/// Exactly these members. +fn has_exactly(v: &Value, keys: &[&str]) -> bool { + v.as_object().is_some_and(|o| o.len() == keys.len() && keys.iter().all(|k| o.contains_key(*k))) +} + +fn price_form(p: &Value, local: bool) -> bool { + let m = &p["money"]; + let amount_ok = m.get("amount").is_none_or(|a| a.as_str().is_some_and(|a| a.chars().count() <= MAX_AMOUNT)); + let money_ok = match m["free"].as_bool() { + Some(true) => true, + // A local route's money is free: only a provider's costs. + Some(false) => !local && (m["unknown"].is_string() || (m["amount"].is_string() && m["currency"].is_string())), + None => false, + } && m.get("at_least").is_none_or(|x| *x == Value::Bool(true)) + && amount_ok; + let time_ok = p["time"].is_object() && (p["time"]["seconds"].is_null() || seconds_ok(&p["time"]["seconds"])); + let energy_ok = p["energy"].is_object() && (p["energy"]["joules"].is_null() || p["energy"]["joules"].is_number()); + let left_ok = p["leaves_out"].as_array().is_some_and(|a| a.iter().all(|w| w.as_str().is_some_and(|w| LEFT_OUT.contains(&w)))); + let counted = ["memory_bytes", "work"].iter().all(|k| p.get(*k).is_some_and(|x| x.is_null() || is_whole(x))); + money_ok && time_ok && energy_ok && left_ok && counted +} + fn route_form(r: &Value) -> bool { let Some(name) = r["route"].as_str() else { return false }; let kind = r["kind"].as_str(); - let kind_ok = (name.strip_prefix("method:").is_some_and(|m| !m.is_empty()) && kind == Some("local")) || (name.strip_prefix("provider:").is_some_and(|m| !m.is_empty()) && kind == Some("provider")); - let outcome = r["outcome"].as_str(); - let outcome_ok = match outcome { + let local = name.strip_prefix("method:").is_some_and(|m| !m.is_empty()) && kind == Some("local"); + let kind_ok = local || (name.strip_prefix("provider:").is_some_and(|m| !m.is_empty()) && kind == Some("provider")); + let outcome_ok = match r["outcome"].as_str() { Some("chosen" | "met") => r.get("rejected").is_none(), Some("rejected") => r["rejected"]["code"].is_string() && r["rejected"]["why"].is_string(), _ => false, }; let price_ok = match r.get("price") { Some(Value::Null) => true, - Some(p) if p.is_object() => { - let m = &p["money"]; - let money_ok = match m["free"].as_bool() { - Some(true) => true, - Some(false) => m["unknown"].is_string() || (m["amount"].is_string() && m["currency"].is_string()), - None => false, - } && m.get("at_least").is_none_or(|x| *x == Value::Bool(true)); - let time_ok = p["time"].is_object() && (p["time"]["seconds"].is_null() || p["time"]["seconds"].as_f64().is_some_and(|s| s >= 0.0)); - let energy_ok = p["energy"].is_object() && (p["energy"]["joules"].is_null() || p["energy"]["joules"].is_number()); - let left_ok = p["leaves_out"].as_array().is_some_and(|a| a.iter().all(|w| w.as_str().is_some_and(|w| LEFT_OUT.contains(&w)))); - let counted = ["memory_bytes", "work"].iter().all(|k| p.get(*k).is_some_and(|x| x.is_null() || is_whole(x))); - money_ok && time_ok && energy_ok && left_ok && counted - } + Some(p) if p.is_object() => price_form(p, local), _ => false, }; - kind_ok && outcome_ok && price_ok && r["class"].is_string() && r["host_dependent"].is_boolean() + // A local route states its rank in auto's order for the job's question. + let rank_ok = !local || r.get("auto_rank").is_some_and(|k| k.is_null() || is_whole(k)); + kind_ok && outcome_ok && price_ok && rank_ok && r["class"].is_string() && r["host_dependent"].is_boolean() } fn planner_form(p: &Value) -> bool { @@ -1200,6 +1371,8 @@ fn planner_form(p: &Value) -> bool { p["format"] == FORMAT && wanted_ok && from_ok + && (p["named"].is_null() || listed(&p["named"])) + && p["question"].as_str().is_some_and(|q| QUESTIONS.contains(&q)) && (p["auto"].is_null() || listed(&p["auto"])) && is_whole(&p["host"]["job_bytes"]) && p["host"]["providers"].as_array().is_some_and(|a| a.iter().all(Value::is_string)) @@ -1233,51 +1406,54 @@ pub fn check(request: &Value, result: &Value) -> Vec<&'static str> { }; let Some(p) = planner.filter(|p| planner_form(p)) else { return vec![PLANNER_FORM] }; let mut out = Vec::new(); - let routes = p["routes"].as_array().map_or(&[][..], Vec::as_slice); - let (provider, mut method) = named(request); - let class_named = |name: String| routes.iter().find(|r| r["route"] == name.as_str()).and_then(|r| r["class"].as_str()).map(str::to_string); - // A program a method reads itself, or a job on a device target, has one route. - let single = routes.len() == 1; - if single && provider.is_none() { - method = routes[0]["route"].as_str().and_then(|n| n.strip_prefix("method:")); + // Under a contract a provider is used only where it allows one. + if request.get("provider").is_some_and(|x| !x.is_null()) && contract.providers != Some(true) { + out.push(CONTRACT_PROVIDER); } - let wanted = match (&contract.exactness, provider, method, p["auto"].as_str()) { - (Some(w), ..) => Some(w.clone()), - (None, Some(n), ..) => class_named(format!("provider:{n}")), - (None, None, Some(m), _) => class_named(format!("method:{m}")), - (None, None, None, Some(a)) => class_named(a.to_string()), - (None, None, None, None) => None, + let routes = p["routes"].as_array().map_or(&[][..], Vec::as_slice); + // What the job names, the question it asks and what auto picks, each from + // the request and the routes, never from what the reasoning says of itself. + let named = match request_names(request) { + Some(n) => Some(n), + // A device target's job runs on the method its noise takes, as stated. + None if names_target(request) => p["named"].as_str().filter(|n| n.starts_with("method:")).map(str::to_string), + None => None, }; - let from = match (&contract.exactness, provider.is_some() || method.is_some(), p["auto"].is_string()) { - (Some(_), ..) => Some("contract"), - (None, true, _) => Some("named"), - (None, false, true) => Some("auto"), - (None, false, false) => None, + let q = question_of(request); + let ranks_ok = routes.iter().filter(|r| r["kind"] == "local").all(|r| { + let m = r["route"].as_str().and_then(|n| n.strip_prefix("method:")).unwrap_or(""); + Registry::builtins().method(m).is_none_or(|b| r["auto_rank"].as_f64() == b.auto_rank(question(q)).map(f64::from)) + }); + let auto = auto_of(routes, request, named.as_deref()); + let class_named = |name: &str| routes.iter().find(|r| r["route"] == name).and_then(|r| r["class"].as_str()).map(str::to_string); + let (wanted, from) = match (&contract.exactness, &named, &auto) { + (Some(w), ..) => (Some(w.clone()), Some("contract")), + (None, Some(n), _) => (class_named(n), Some("named")), + (None, None, Some(a)) => (class_named(a), Some("auto")), + (None, None, None) => (None, None), }; - if p["wanted"].as_str() != wanted.as_deref() || p["wanted_from"].as_str() != from { + if p["named"].as_str() != named.as_deref() || p["question"] != q || !ranks_ok || p["auto"].as_str() != auto.as_deref() || p["wanted"].as_str() != wanted.as_deref() || p["wanted_from"].as_str() != from { out.push(PLANNER_FORM); return out; } - let held = Held { contract: &contract, provider, method, fabric: if provider.is_some() { Fab::Free } else { fab_of(request) }, wanted: wanted.as_deref(), job_bytes: p["host"]["job_bytes"].as_f64().unwrap_or(0.0) }; + let held = Held { contract: &contract, named: named.as_deref(), fabric: fab_of(request), wanted: wanted.as_deref(), from_contract: from == Some("contract"), job_bytes: p["host"]["job_bytes"].as_f64().unwrap_or(0.0) }; let mut route_broken = false; let mut choice = None; for r in routes { - let stated = r["rejected"]["code"].as_str(); - let chosen = r["outcome"] == "chosen"; - if chosen { + if r["outcome"] == "chosen" { if choice.is_some() { route_broken = true; } choice = r["route"].as_str(); } - if stated != gate(r, &held) { + if r["rejected"]["code"].as_str() != gate(r, &held) { route_broken = true; } } if route_broken || choice != p["choice"].as_str() { out.push(PLANNER_ROUTE); } - let picked = pick(routes, p["auto"].as_str(), &held); + let picked = pick(routes, auto.as_deref(), &held); let ran = if result["method"] == "provider" { result.pointer("/provider/name").and_then(Value::as_str).map(|n| format!("provider:{n}")) } else { result["method"].as_str().map(|m| format!("method:{m}")) }; if picked.and_then(|r| r["route"].as_str()) != p["choice"].as_str() || ran.as_deref() != p["choice"].as_str() { out.push(PLANNER_CHOICE); @@ -1292,18 +1468,25 @@ pub fn check(request: &Value, result: &Value) -> Vec<&'static str> { let class = result.pointer("/accuracy/class").and_then(Value::as_str).unwrap_or(""); let approximate = result.pointer("/accuracy/approximate") == Some(&Value::Bool(true)); if let Some(w) = wanted.as_deref() - && (!meets(w, class) || (w == "simulated" && approximate)) + && (!meets(w, class) || (from == Some("contract") && w == "simulated" && approximate)) { out.push(CONTRACT_CLASS); } let is_provider = p["choice"].as_str().is_some_and(|c| c.starts_with("provider:")); - if is_provider != result.get("shadow").is_some() || is_provider != p.get("shadow").is_some() || (is_provider && !shadow_holds(request, p, result)) { + if is_provider != result.get("shadow").is_some() || is_provider != p.get("shadow").is_some() || (is_provider && !shadow_holds(request, &contract, p, result)) { out.push(SHADOW); } out } -/// Whether a sealed `kept` is what the contract and the result give. +/// A `kept` member as its table gives it: true, false, or `null` where it is not +/// known. Nothing else reads as `null`. +fn kept_is(v: &Value, want: Option) -> bool { + want.map_or(v.is_null(), |b| *v == Value::Bool(b)) +} + +/// Whether a sealed `kept` is what the contract and the result give: exactly a +/// member for each the contract gives, each of exactly its members. fn kept_holds(c: &Contract, p: &Value, result: &Value) -> bool { let kept = &p["kept"]; let Some(k) = kept.as_object() else { return false }; @@ -1316,13 +1499,13 @@ fn kept_holds(c: &Contract, p: &Value, result: &Value) -> bool { let want = e.as_f64().map(|e| e <= d * 1000.0); // A local result's own elapsed_ms, by value, and null when it has none. let local_e = result["method"] != "provider" && result.get("elapsed_ms").and_then(Value::as_f64) != e.as_f64(); - if kept["deadline"]["seconds"].as_f64() != Some(d) || !(e.is_null() || is_whole(e)) || kept["deadline"]["kept"].as_bool() != want || local_e { + if !has_exactly(&kept["deadline"], &["seconds", "elapsed_ms", "kept"]) || kept["deadline"]["seconds"].as_f64() != Some(d) || !(e.is_null() || is_whole(e)) || !kept_is(&kept["deadline"]["kept"], want) || local_e { return false; } } if let Some(j) = c.max_joules { let x = result.pointer("/energy/joules_micro").and_then(Value::as_f64).map(|u| u / 1e6); - if kept["energy"]["max_joules"].as_f64() != Some(j) || kept["energy"]["joules"].as_f64() != x || kept["energy"]["kept"].as_bool() != x.map(|x| x <= j) { + if !has_exactly(&kept["energy"], &["max_joules", "joules", "kept"]) || kept["energy"]["max_joules"].as_f64() != Some(j) || kept["energy"]["joules"].as_f64() != x || !kept_is(&kept["energy"]["kept"], x.map(|x| x <= j)) { return false; } } @@ -1335,7 +1518,11 @@ fn kept_holds(c: &Contract, p: &Value, result: &Value) -> bool { (None, false) => None, }; let sealed = &kept["cost"]; - if sealed["max_cost"]["amount"].as_str() != Some(amount.as_str()) || sealed["max_cost"]["currency"].as_str() != Some(currency.as_str()) || sealed["kept"].as_bool() != held || (sealed["charged"].is_null() != charged.is_none()) { + let charged_same = match charged { + Some(x) => same(&sealed["charged"], x), + None => sealed["charged"].is_null(), + }; + if !has_exactly(sealed, &["max_cost", "charged", "kept"]) || !has_exactly(&sealed["max_cost"], &["amount", "currency"]) || sealed["max_cost"]["amount"].as_str() != Some(amount.as_str()) || sealed["max_cost"]["currency"].as_str() != Some(currency.as_str()) || !kept_is(&sealed["kept"], held) || !charged_same { return false; } } @@ -1353,36 +1540,78 @@ fn same(a: &Value, b: &Value) -> bool { } } +/// A count of a shadow's list: a whole number written as one, from 1 to 2^53 − 1. +fn count_of(v: &Value) -> Option { + v.as_u64().filter(|n| (1..1 << 53).contains(n)) +} + +/// Whether the reasoning's `shadow` is of its form: with no route, a code of +/// `budget`, `memory` or `none`; with one, a method's route, a class, the budget +/// the contract leaves, a price within it, and a request of exactly the +/// program, the shots, the shadow's seed and the method. +fn shadow_plan_holds(request: &Value, contract: &Contract, p: &Value, result: &Value) -> bool { + let plan = &p["shadow"]; + if plan.get("route").is_none() { + return false; + } + match plan["route"].as_str() { + None => plan["route"].is_null() && plan["code"].as_str().is_some_and(|c| ["budget", "memory", "none"].contains(&c)) && plan["why"].is_string() && plan.get("tried").is_none_or(Value::is_array), + Some(route) => { + let Some(method) = route.strip_prefix("method:").filter(|m| !m.is_empty()) else { return false }; + let chosen = p["choice"].as_str().unwrap_or(""); + let budget = shadow_budget(contract, provider_seconds(&p["routes"], chosen)); + let req = &plan["request"]; + let listed = p["routes"].as_array().and_then(|a| a.iter().find(|r| r["route"].as_str() == Some(route))); + plan["class"].as_str().is_some_and(|c| LADDER.contains(&c)) + && listed.is_some_and(|r| r["class"] == plan["class"]) + && plan["budget_seconds"].as_f64() == Some(budget) + && plan["price"].is_object() + && price_form(&plan["price"], true) + && plan["price"]["time"]["seconds"].as_f64().is_some_and(|s| s <= budget) + && has_exactly(req, &["qasm", "shots", "seed", "method"]) + && req["qasm"].is_string() + && req["qasm"] == request["qasm"] + && same(&req["shots"], &result["shots"]) + && req["seed"].as_u64() == Some(shadow_seed(request)) + && req["method"].as_str() == Some(method) + } + } +} + /// Whether a sealed shadow is of its form, what its plan says, and its distance /// what its counts give. -fn shadow_holds(request: &Value, p: &Value, result: &Value) -> bool { +fn shadow_holds(request: &Value, contract: &Contract, p: &Value, result: &Value) -> bool { let (s, plan) = (&result["shadow"], &p["shadow"]); + if !shadow_plan_holds(request, contract, p, result) { + return false; + } match s["ran"].as_bool() { Some(false) => s["code"].is_string() && s["why"].is_string() && if plan["route"].is_null() { plan["code"] == s["code"] } else { s["code"] == "failed" }, Some(true) => { - let shots = result["shots"].as_f64(); - let req = &s["request"]; - let req_ok = same(&plan["request"], req) - && req["qasm"] == request["qasm"] - && req["shots"].as_f64() == shots - && req["seed"].as_u64() == Some(shadow_seed(request)) - && plan["route"].as_str().and_then(|r| r.strip_prefix("method:")) == req["method"].as_str(); - let m = s["counts"].as_object(); - let listed: Option = m.map(|o| o.values().filter_map(Value::as_f64).sum()); - let counts_ok = m.is_some() && s["omitted_shots"].as_f64().zip(listed).map(|(o, l)| o + l) == shots && is_whole(&s["distinct_outcomes"]); - // By value: an omitted_shots of 0 however it is written. + let Some(route) = plan["route"].as_str() else { return false }; + // The shots and the omitted shots by value; the counts whole, and an + // exact sum: no double between them. + let by_value = |v: &Value| v.as_f64().filter(|x| x.fract() == 0.0 && *x >= 0.0).map(|x| x as u64); + let shots = by_value(&result["shots"]); + let counts: Option> = s["counts"].as_object().and_then(|o| o.values().map(count_of).collect()); + let listed: Option = counts.map(|c| c.iter().map(|&n| u128::from(n)).sum()); + let counts_ok = match (listed, by_value(&s["omitted_shots"]), shots) { + (Some(l), Some(o), Some(n)) => l + u128::from(o) == u128::from(n), + _ => false, + } && is_whole(&s["distinct_outcomes"]); let whole_lists = result["omitted_shots"].as_f64() == Some(0.0) && s["omitted_shots"].as_f64() == Some(0.0); let distance_ok = match s["distance"]["computed"].as_bool() { Some(false) => s["distance"]["why"].is_string() && !whole_lists, Some(true) => { whole_lists - && shots.and_then(|x| distance(&result["counts"], &s["counts"], x as u64)).is_some_and(|d| { - ["numerator", "denominator", "total_variation", "hellinger_fidelity", "sampling_tvd_expected"].iter().all(|k| d[*k].as_f64() == s["distance"][*k].as_f64()) + && shots.and_then(|x| distance(&result["counts"], &s["counts"], x)).is_some_and(|d| { + ["numerator", "denominator", "total_variation", "hellinger_fidelity", "sampling_tvd_bound"].iter().all(|k| d[*k].as_f64() == s["distance"][*k].as_f64()) }) } None => false, }; - req_ok && counts_ok && distance_ok && s["route"] == plan["route"] && s["accuracy"]["class"].is_string() && s["shots"].as_f64() == shots + let class_ok = s["accuracy"]["class"].as_str().is_some_and(|c| plan["class"].as_str().is_some_and(|w| meets(w, c))); + counts_ok && distance_ok && class_ok && s["route"].as_str() == Some(route) && same(&s["request"], &plan["request"]) && same(&s["shots"], &result["shots"]) } None => false, } @@ -1406,8 +1635,10 @@ pub fn statement(result: &Value) -> Option { /// What can be run again of a sealed contract job, by this engine: the local /// routes priced again at the job's memory, held to the sealed digest, and the -/// shadow run again, held to its counts bit for bit. Nothing else is recomputed -/// here: a provider's counts cannot be, and a price the host stated is its word. +/// route `auto` picks from them, held to the sealed one; and the shadow run +/// again, held to its counts bit for bit, or, where the host says it failed, +/// run to see whether it does. Nothing else is recomputed here: a provider's +/// counts cannot be, and a price the host stated is its word. pub fn recheck(reg: &Registry, job: &Value) -> Result { let (Some(request), Some(result)) = (job.get("request"), job.get("result")) else { return Err("expected a job: {\"request\": ..., \"result\": ...}".into()); @@ -1416,29 +1647,33 @@ pub fn recheck(reg: &Registry, job: &Value) -> Result { let engine = result.pointer("/engine/version").and_then(Value::as_str); let same_engine = engine == Some(super::schema::ENGINE_VERSION); let job_bytes = p["host"]["job_bytes"].as_u64().ok_or("the reasoning names no job memory")?; - let (provider, _) = named(request); - let priced = if provider.is_some() { + let priced = if request.get("provider").is_some_and(|x| !x.is_null()) { json!({ "checked": false, "why": "the job names its provider, so no local route was priced" }) } else { let host = Host::new(job_bytes); - let mut plain = request.clone(); - // Priced as the job asks, whatever the host had beside. - if let Some(o) = plain.as_object_mut() { - o.shift_remove("provider"); - } - let local = local_routes(reg, &plain, &host)?; + let local = local_routes(reg, request, &host, question(question_of(request)))?; let digest = stable_of(&local.routes, &p["host"]["job_bytes"], None, &Contract::default())["digest"].clone(); - json!({ "checked": true, "digest": digest, "same": digest == p["stable"]["digest"] }) + let auto = auto_of(&local.routes, request, local.named.as_deref()); + let auto_same = json!(auto) == p["auto"]; + json!({ "checked": true, "digest": digest, "auto": auto, "same": digest == p["stable"]["digest"] && auto_same }) }; let s = &result["shadow"]; + let plan = &p["shadow"]; let shadow = if s.get("ran").is_none() { json!({ "checked": false, "why": "no provider answered this job, so it has no shadow" }) - } else if s["ran"] != true { - json!({ "checked": false, "why": "no shadow ran" }) - } else { + } else if s["ran"] == true { let req = &s["request"]; let run = catalog::plan_plain(reg, req, job_bytes).and_then(|pl| reg.run(req, &pl))?; json!({ "checked": true, "same": run["counts"] == s["counts"] }) + } else if s["code"] == "failed" && plan["route"].is_string() { + // The host says the shadow it planned failed: run it, and see. + let req = &plan["request"]; + match catalog::plan_plain(reg, req, job_bytes).and_then(|pl| reg.run(req, &pl)) { + Ok(_) => json!({ "checked": true, "same": false, "why": "the host says its shadow failed, and it runs here" }), + Err(e) => json!({ "checked": true, "same": true, "why": format!("it fails here too: {e}") }), + } + } else { + json!({ "checked": false, "why": "no shadow could be planned, as the reasoning says why" }) }; let holds = priced["same"] != false && shadow["same"] != false; Ok(json!({ "holds": holds, "engine": { "sealed_by": engine, "this": super::schema::ENGINE_VERSION, "same": same_engine }, "priced": priced, "shadow": shadow })) diff --git a/wai/wai-quantum/src/engine/planner/tests.rs b/wai/wai-quantum/src/engine/planner/tests.rs index 62e97ff12..b2a6892be 100644 --- a/wai/wai-quantum/src/engine/planner/tests.rs +++ b/wai/wai-quantum/src/engine/planner/tests.rs @@ -369,7 +369,10 @@ fn nothing_falls_back_between_a_simulator_and_a_device() { let e = decided(&ask(json!({ "exactness": "simulated", "providers": "allowed" })), vec![approx.clone()]); assert!(e.reasoning["routes"].as_array().unwrap().iter().any(|r| r["route"] == "provider:sim" && r["rejected"]["why"].as_str().unwrap().contains("approximate")), "{}", e.reasoning); let c = decided(&ask(json!({ "exactness": "any", "providers": "allowed" })), vec![approx.clone()]); - assert_eq!(c.reasoning["choice"], "provider:sim", "any takes every route, and this one states it takes no time"); + // A provider that says no time is not quicker than a local route that takes + // less than half a millisecond: each to the nearest millisecond, a tie, and + // the local route first. + assert_eq!(c.reasoning["choice"], "method:stabilizer", "{}", c.reasoning); // A tie to the millisecond goes to the local route. approx.seconds = Some(0.0005); let c = decided(&ask(json!({ "exactness": "any", "providers": "allowed" })), vec![approx]); @@ -404,24 +407,24 @@ fn a_provider_is_held_to_the_cost_ceiling_and_an_unknown_is_not_free() { assert!(route(&decided(&ask(Some(("100", "USD"))), least("0.3")).reasoning, "provider:qpu")["rejected"]["why"].as_str().unwrap().contains("at least 0.3 USD")); assert_eq!(of(&decided(&ask(Some(("0.29", "USD"))), least("0.3"))).as_deref(), Some("cost")); assert_eq!(of(&decided(&ask(Some(("0.3", "USD"))), least("0.3"))).as_deref(), Some("cost_at_least"), "at the ceiling, and it may come to more"); - let named_least = decided(&json!({ "qasm": BELL, "shots": 1000, "provider": "qpu", "contract": {} }), least("0.3")); + let named_least = decided(&json!({ "qasm": BELL, "shots": 1000, "provider": "qpu", "contract": { "providers": "allowed" } }), least("0.3")); assert_eq!(named_least.reasoning["choice"], "provider:qpu", "named with no ceiling, its cost is the person's to confirm"); // Free needs no ceiling. assert_eq!(of(&decided(&ask(None), vec![quote("qpu", "silicon", json!({ "free": true }), Some(1.0))])), None); // Named by the job, its cost is the person's to confirm, as it is with no contract. - let named = json!({ "qasm": BELL, "shots": 1000, "provider": "qpu", "contract": {} }); + let named = json!({ "qasm": BELL, "shots": 1000, "provider": "qpu", "contract": { "providers": "allowed" } }); let c = decided(&named, priced("0.3")); assert_eq!(c.reasoning["choice"], "provider:qpu"); assert_eq!(c.reasoning["wanted_from"], "named"); assert_eq!(c.reasoning["wanted"], "measured"); assert_eq!(code(&c.reasoning, "method:stabilizer"), Some("not_named")); // Named, a ceiling still holds, and a named device is still held to its class. - let e = decided(&json!({ "qasm": BELL, "provider": "qpu", "contract": { "max_cost": { "amount": "0.1", "currency": "USD" } } }), priced("0.3")); + let e = decided(&json!({ "qasm": BELL, "provider": "qpu", "contract": { "providers": "allowed", "max_cost": { "amount": "0.1", "currency": "USD" } } }), priced("0.3")); assert_eq!(code(&e.reasoning, "provider:qpu"), Some("cost")); - let e = decided(&json!({ "qasm": BELL, "provider": "qpu", "contract": { "exactness": "simulated" } }), priced("0.3")); + let e = decided(&json!({ "qasm": BELL, "provider": "qpu", "contract": { "providers": "allowed", "exactness": "simulated" } }), priced("0.3")); assert_eq!(code(&e.reasoning, "provider:qpu"), Some("class")); // A provider this host has not brought is refused as today. - let e = consider(reg(), &json!({ "qasm": BELL, "provider": "other", "contract": {} }), &Host::new(GIB)).unwrap_err(); + let e = consider(reg(), &json!({ "qasm": BELL, "provider": "other", "contract": { "providers": "allowed" } }), &Host::new(GIB)).unwrap_err(); assert!(e.ends_with("[J002]"), "{e}"); } @@ -659,13 +662,17 @@ fn every_rule_a_verifier_holds_a_local_contract_job_to_is_broken_once_and_found_ /// A provider's result under a contract, as a host seals it. fn provider_body(req: &Value, quotes: Vec, counts: Vec) -> Value { + provider_body_on(req, quotes, counts, "silicon", false) +} + +fn provider_body_on(req: &Value, quotes: Vec, counts: Vec, provenance: &str, approximate: bool) -> Value { let d = decide(reg(), req, &Host::new(GIB).with_quotes(quotes)).unwrap(); let Choice::Provider(name) = d.choice else { panic!("a local route was chosen: {}", d.reasoning) }; let read = provider::read_named(req, Some(&name)).unwrap(); let text = "OPENQASM 3.0;\nbit[2] c;\ncz $0, $1;\n"; let m = provider::Measured { counts, - provider: json!({ "name": name, "kind": "process", "protocol": "wai.quantum.provider/1", "device": "lab:dev", "provenance": "silicon", "qubits": 5, "basis": "rzsxxcz", "describe": "ab".repeat(32) }), + provider: json!({ "name": name, "kind": "process", "protocol": "wai.quantum.provider/1", "device": "lab:dev", "provenance": provenance, "qubits": 5, "basis": "rzsxxcz", "describe": "ab".repeat(32) }), calibration: Some("snap-1".into()), compiled: json!({ "basis": "rzsxxcz", "program": blake3::hash(text.as_bytes()).to_hex().to_string(), "qasm3": text, "native_gates": 9, "two_qubit_gates": 1, "swaps": 0, "layout": [0, 1], "final_layout": [0, 1], "checked": "checked here" }), job: json!({ "id": "j-1", "polls": 0 }), @@ -674,7 +681,7 @@ fn provider_body(req: &Value, quotes: Vec, counts: Vec) -> Value { }; let e = provider::provider_execution(&json!({ "mitigation": "none", "twirling": "none", "decoder": "none", "decoupling": "none", "remapping": "none", "optimisation": "none", "verbatim": true })); let e = e.unwrap_or_else(|_| provider::provider_execution(&json!({ "mitigation": "none", "twirling": "none", "decoupling": "none", "remapping": "none", "optimisation": "none", "verbatim": true })).unwrap()); - let mut result = provider::result_stated(&read, m, &provider::Statement::new(provider::CountsSource::Shots, e)).unwrap(); + let mut result = provider::result_stated(&read, m, &provider::Statement::new(provider::CountsSource::Shots, e).approximate(approximate)).unwrap(); seal_provider(reg(), req, &mut result, &d.reasoning, Some(12_000)).unwrap(); provider::seal(req, result, &SigningKey::from_bytes(&[9; 32]), "on lab") } @@ -779,7 +786,7 @@ fn every_rule_a_verifier_holds_a_provider_s_contract_job_to_is_broken_once_and_f (&[SHADOW], Box::new(|b| { let n = b["result"]["shadow"]["distance"]["numerator"].as_u64().unwrap(); b["result"]["shadow"]["distance"]["numerator"] = json!(n + 1); })), (&[SHADOW], Box::new(|b| b["result"]["shadow"]["distance"]["total_variation"] = json!(0.0))), (&[SHADOW], Box::new(|b| b["result"]["shadow"]["distance"]["hellinger_fidelity"] = json!(1.0))), - (&[SHADOW], Box::new(|b| b["result"]["shadow"]["distance"]["sampling_tvd_expected"] = json!(0.0))), + (&[SHADOW], Box::new(|b| b["result"]["shadow"]["distance"]["sampling_tvd_bound"] = json!(0.0))), (&[SHADOW], Box::new(|b| b["result"]["shadow"]["distance"] = json!({ "computed": false }))), // Not computed, with every shot listed on both sides: it could have been. (&[SHADOW], Box::new(|b| b["result"]["shadow"]["distance"] = json!({ "computed": false, "why": "said so" }))), @@ -802,8 +809,10 @@ fn every_rule_a_verifier_holds_a_provider_s_contract_job_to_is_broken_once_and_f // The least it can come to, under the ceiling, claimed to meet it. (&[PLANNER_ROUTE, PLANNER_CHOICE], Box::new(|b| at(b, "provider:qpu")["price"]["money"]["at_least"] = json!(true))), (&[PLANNER_FORM], Box::new(|b| at(b, "provider:qpu")["price"]["money"]["at_least"] = json!(false))), - (&[PLANNER_ROUTE, PLANNER_CHOICE], Box::new(|b| at(b, "provider:qpu")["price"]["time"]["seconds"] = json!(301.0))), - (&[PLANNER_ROUTE, PLANNER_CHOICE], Box::new(|b| at(b, "provider:qpu")["price"]["time"] = json!({ "seconds": null, "why": "not said" }))), + // The shadow's budget is what the deadline leaves after the provider's time, so + // its plan no longer says what the contract leaves it. + (&[PLANNER_ROUTE, PLANNER_CHOICE, SHADOW], Box::new(|b| at(b, "provider:qpu")["price"]["time"]["seconds"] = json!(301.0))), + (&[PLANNER_ROUTE, PLANNER_CHOICE, SHADOW], Box::new(|b| at(b, "provider:qpu")["price"]["time"] = json!({ "seconds": null, "why": "not said" }))), // A device's class that is not its provenance's. (&[CONTRACT_CLASS, "provider_class"], Box::new(|b| b["result"]["accuracy"]["class"] = json!("simulated"))), // Charged past the ceiling, and kept said to hold. @@ -979,8 +988,13 @@ fn a_result_short_of_what_the_reasoning_wants_is_not_completed() { assert_eq!(r["planner"]["wanted"], "heuristic"); let mut r = heuristic; complete(&mut r, &reasoning(Value::Null)).unwrap(); - let mut approximate = json!({ "method": "provider", "accuracy": { "class": "simulated", "approximate": true } }); - assert!(complete(&mut approximate, &json!({ "wanted": "simulated", "choice": "provider:sim" })).unwrap_err().ends_with("[J072]")); + // An approximate simulator's counts fall short of a simulator's the contract names, + // and not of the class a named simulator keeps. + let approximate = json!({ "method": "provider", "accuracy": { "class": "simulated", "approximate": true } }); + let mut r = approximate.clone(); + assert!(complete(&mut r, &json!({ "wanted": "simulated", "wanted_from": "contract", "choice": "provider:sim" })).unwrap_err().ends_with("[J072]")); + let mut r = approximate; + complete(&mut r, &json!({ "wanted": "simulated", "wanted_from": "named", "choice": "provider:sim" })).unwrap(); } /// The distance is exact where it sums whole numbers and a double's elsewhere, @@ -1002,3 +1016,251 @@ fn the_distance_holds_at_the_largest_shots() { assert!(distance(&a, &b, 0).is_none()); assert!(distance(&json!({ "0": 10 }), &json!({ "0": 10 }), 3).is_none()); } + +fn cases(good: &Value, cases: Vec<(&[&'static str], Box)>) { + for (i, (want, edit)) in cases.into_iter().enumerate() { + let body = resealed(good, edit); + let mut want = want.to_vec(); + want.sort_unstable(); + assert_eq!(reasons(&body), want, "case {i}: {}\n{}", body["result"]["shadow"], body["result"]["planner"]["shadow"]); + } +} + +/// A shadow is a classical method's run of exactly the job's program, its +/// shots and its own seed: not the provider's own counts, not a run with no +/// route planned, not one under a noise model the job never asked for, whole +/// counts that sum to the shots exactly, and a plan whose class, budget and +/// price are what the contract leaves. +#[test] +fn a_shadow_is_a_method_s_run_of_exactly_the_job_s_program() { + let req = device_contract(); + let good = provider_body(&req, vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))], vec![450, 100, 0, 450]); + assert_eq!(reasons(&good), Vec::<&str>::new()); + cases(&good, vec![ + // The provider as its own shadow, its counts at distance 0. + (&[SHADOW], Box::new(|b| { + for side in ["/result/planner/shadow", "/result/shadow"] { + let s = b.pointer_mut(side).unwrap(); + s["route"] = json!("provider:qpu"); + s["request"].as_object_mut().unwrap().shift_remove("method"); + } + let counts = b["result"]["counts"].clone(); + b["result"]["shadow"]["counts"] = counts.clone(); + b["result"]["shadow"]["distance"] = distance(&counts, &counts, 1000).unwrap(); + })), + // Run, where no route was planned. + (&[SHADOW], Box::new(|b| { + let req = b["result"]["planner"]["shadow"]["request"].clone(); + b["result"]["planner"]["shadow"] = json!({ "route": null, "code": "none", "why": "said so", "request": req }); + b["result"]["shadow"]["route"] = Value::Null; + })), + // A noise model the job never asked for, on both sides. + (&[SHADOW], Box::new(|b| { + for side in ["/result/planner/shadow/request", "/result/shadow/request"] { + b.pointer_mut(side).unwrap()["noise"] = json!({ "depolarizing_2q": 0.2 }); + } + })), + // A plan's code that no plan has, and a failure where none was planned. + (&[SHADOW], Box::new(|b| { + b["result"]["planner"]["shadow"] = json!({ "route": null, "code": "failed", "why": "said so" }); + b["result"]["shadow"] = json!({ "ran": false, "code": "failed", "why": "said so" }); + })), + (&[SHADOW], Box::new(|b| b["result"]["planner"]["shadow"]["class"] = json!("measured"))), + // A class the ladder has, and not the one its route is listed with. + (&[SHADOW], Box::new(|b| b["result"]["planner"]["shadow"]["class"] = json!("heuristic"))), + (&[SHADOW], Box::new(|b| b["result"]["planner"]["shadow"]["budget_seconds"] = json!(300.0))), + (&[SHADOW], Box::new(|b| b["result"]["planner"]["shadow"]["price"]["time"]["seconds"] = json!(289.0))), + // Counts that are not whole, or not at least 1, or sum to the shots only as doubles. + (&[SHADOW], Box::new(|b| { + let n = b["result"]["shadow"]["counts"]["00"].as_u64().unwrap(); + b["result"]["shadow"]["counts"]["00"] = json!(n as f64); + })), + (&[SHADOW], Box::new(|b| { + let n = b["result"]["shadow"]["counts"]["00"].as_u64().unwrap(); + b["result"]["shadow"]["counts"]["00"] = json!(n + 1); + b["result"]["shadow"]["counts"]["01"] = json!(-1); + })), + (&[SHADOW], Box::new(|b| { + let n = b["result"]["shadow"]["counts"]["00"].as_u64().unwrap(); + b["result"]["shadow"]["counts"]["00"] = json!(1e16); + b["result"]["shadow"]["counts"]["01"] = json!(-1e16); + b["result"]["shadow"]["counts"]["10"] = json!(n); + })), + // A class short of the plan's. + (&[SHADOW], Box::new(|b| b["result"]["shadow"]["accuracy"]["class"] = json!("heuristic"))), + ]); +} + +/// A host that says its shadow failed is held to it: run here, the shadow it +/// planned runs, and the recheck says so. +#[test] +fn a_shadow_the_host_says_failed_is_run_again() { + let req = device_contract(); + let good = provider_body(&req, vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))], vec![450, 100, 0, 450]); + let said = resealed(&good, |b| b["result"]["shadow"] = json!({ "ran": false, "code": "failed", "why": "it did not finish" })); + assert_eq!(reasons(&said), Vec::<&str>::new(), "a failure is the host's word"); + let rc = recheck(reg(), &said).unwrap(); + assert_eq!((rc["holds"].as_bool(), rc["shadow"]["same"].as_bool()), (Some(false), Some(false)), "{rc}"); +} + +/// Under a contract a provider is used only where it allows one: `never` is the +/// default, so a job that names one under any other contract is refused, and a +/// receipt that says otherwise does not verify. +#[test] +fn under_a_contract_a_provider_is_used_only_where_it_allows_one() { + let host = Host::new(GIB).with_quotes(vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))]); + for c in [json!({}), json!({ "providers": "never" }), json!({ "deadline_seconds": 60 })] { + let e = consider(reg(), &json!({ "qasm": BELL, "provider": "qpu", "contract": c }), &host).unwrap_err(); + assert_eq!(refusal::codes_in(&e), ["J070"], "{c}: {e}"); + } + let mut named = device_contract(); + named["provider"] = json!("qpu"); + let good = provider_body(&named, vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))], vec![500, 0, 0, 500]); + assert_eq!(reasons(&good), Vec::<&str>::new()); + for edit in [json!("never"), Value::Null] { + let under = resealed(&good, |b| b["request"]["contract"]["providers"] = edit.clone()); + assert_eq!(reasons(&under), vec![CONTRACT_PROVIDER, PLANNER_CHOICE, PLANNER_ROUTE], "{edit}"); + } +} + +/// What a price may state is bounded: a provider's estimate past the bounds is +/// an unknown, a receipt stating one does not verify, and a ceiling past them +/// does not read. +#[test] +fn what_a_price_may_state_is_bounded_and_past_it_is_an_unknown() { + let long = format!("0.{}1", "0".repeat(70)); + let req = json!({ "qasm": BELL, "shots": 1000, "contract": { "exactness": "measured", "providers": "allowed", "max_cost": { "amount": "1", "currency": "USD" } } }); + let c = decided(&req, vec![quote("qpu", "silicon", json!({ "free": false, "amount": long, "currency": "USD" }), Some(1e306))]); + let r = route(&c.reasoning, "provider:qpu"); + assert!(r["price"]["time"]["seconds"].is_null() && r["price"]["time"]["why"].as_str().unwrap().contains("past"), "{r}"); + assert!(r["price"]["money"]["unknown"].as_str().unwrap().contains("64"), "{r}"); + assert_eq!(code(&c.reasoning, "provider:qpu"), Some("cost_unknown")); + let good = provider_body(&device_contract(), vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))], vec![500, 0, 0, 500]); + cases(&good, vec![ + (&[PLANNER_FORM], Box::new(|b| at(b, "provider:qpu")["price"]["time"]["seconds"] = json!(1e306))), + (&[PLANNER_FORM], Box::new(|b| at(b, "provider:qpu")["price"]["money"]["amount"] = json!("1".repeat(65)))), + ]); + let e = catalog::plan(&json!({ "qasm": BELL, "contract": { "max_cost": { "amount": "1".repeat(65), "currency": "USD" } } }), GIB).unwrap_err(); + assert!(e.ends_with("[J070]"), "{e}"); +} + +/// A local route costs no money, and `kept` states exactly what the contract +/// and the result give: the charge the result states, and no other member. +#[test] +fn a_local_route_is_free_and_kept_states_exactly_the_charge() { + let local = seal_local(&json!({ "qasm": ROT, "shots": 100, "contract": { "exactness": "exact", "deadline_seconds": 30, "max_cost": { "amount": "1", "currency": "USD" } } })); + cases(&local, vec![ + (&[PLANNER_FORM], Box::new(|b| at(b, "method:statevector")["price"]["money"] = json!({ "free": false, "amount": "1", "currency": "USD" }))), + (&[PLANNER_FORM], Box::new(|b| at(b, "method:mps")["price"]["money"] = json!({ "free": false, "unknown": "a host's word" }))), + (&[PLANNER_KEPT], Box::new(|b| b["result"]["planner"]["kept"]["deadline"]["note"] = json!("x"))), + ]); + let good = provider_body(&device_contract(), vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))], vec![500, 0, 0, 500]); + cases(&good, vec![ + (&[PLANNER_KEPT], Box::new(|b| b["result"]["planner"]["kept"]["cost"]["charged"] = json!({ "amount": "0.000001", "currency": "USD" }))), + (&[PLANNER_KEPT], Box::new(|b| b["result"]["planner"]["kept"]["cost"]["extra"] = json!(true))), + // A kept that is no boolean does not read as `null`. + (&[PLANNER_KEPT], Box::new(|b| b["result"]["planner"]["kept"]["cost"]["kept"] = json!(0))), + (&[PLANNER_KEPT], Box::new(|b| { + let k = &mut b["result"]["planner"]["kept"]["deadline"]; + k["elapsed_ms"] = Value::Null; + k["kept"] = json!(0); + })), + (&[PLANNER_KEPT], Box::new(|b| b["result"]["planner"]["kept"]["cost"]["max_cost"]["note"] = json!("x"))), + ]); +} + +/// `auto` is recomputed from the routes, the question and each method's rank +/// for it: a host that says auto would pick a heuristic route, to lower the +/// class a contract that names none keeps, is found. +#[test] +fn auto_is_what_the_routes_give_and_cannot_be_lowered() { + let good = seal_local(&json!({ "qasm": ROT, "shots": 100, "contract": { "deadline_seconds": 60 } })); + assert_eq!((good["result"]["planner"]["auto"].as_str(), good["result"]["planner"]["wanted"].as_str()), (Some("method:statevector"), Some("exact"))); + assert_eq!(reasons(&good), Vec::<&str>::new()); + cases(&good, vec![ + // auto said to be mps, the class wanted heuristic, and mps run. + (&[PLANNER_FORM], Box::new(|b| { + let p = &mut b["result"]["planner"]; + p["auto"] = json!("method:mps"); + p["wanted"] = json!("heuristic"); + b["result"]["method"] = json!("mps"); + })), + (&[PLANNER_FORM], Box::new(|b| b["result"]["planner"]["question"] = json!("amplitudes"))), + (&[PLANNER_FORM], Box::new(|b| at(b, "method:mps")["auto_rank"] = json!(0))), + (&[PLANNER_FORM], Box::new(|b| b["result"]["planner"]["named"] = json!("method:statevector"))), + ]); +} + +/// A device target's job names its one method, whatever else the host brings: +/// its providers are not the job's, and the receipt verifies. +#[test] +fn a_device_target_s_job_names_its_method_beside_the_host_s_providers() { + let req = json!({ "qasm": BELL, "shots": 50, "target": "synthetic-line-5", "contract": { "providers": "allowed", "deadline_seconds": 60 } }); + let host = Host::new(GIB).with_quotes(vec![quote("qpu", "silicon", usd("0.3"), Some(1.0))]); + let (p, result) = plan_and_run_in(reg(), &req, &host).unwrap(); + let r = &result["planner"]; + assert_eq!((r["wanted_from"].as_str(), code(r, "provider:qpu")), (Some("named"), Some("not_named")), "{r}"); + let body = job::seal(&req, &p, result, &SigningKey::from_bytes(&[3; 32]), json!({ "unmetered": "a test" })); + assert_eq!(reasons(&body), Vec::<&str>::new()); +} + +/// A contract that names no class changes nothing a job already meets: an +/// approximate simulator the job names runs under a deadline alone, and only a +/// contract that names `simulated` refuses it. +#[test] +fn a_named_approximate_simulator_runs_under_a_contract_that_names_no_class() { + let mut approx = quote("sim", "simulator:a truncated network", json!({ "free": true }), Some(1.0)); + approx.approximate = true; + let req = json!({ "qasm": BELL, "shots": 1000, "seed": 7, "provider": "sim", "contract": { "providers": "allowed", "deadline_seconds": 60 } }); + let c = decided(&req, vec![approx.clone()]); + assert_eq!((c.reasoning["choice"].as_str(), c.reasoning["wanted"].as_str(), c.reasoning["wanted_from"].as_str()), (Some("provider:sim"), Some("simulated"), Some("named")), "{}", c.reasoning); + let body = provider_body_on(&req, vec![approx.clone()], vec![500, 0, 0, 500], "simulator:a truncated network", true); + assert_eq!(reasons(&body), Vec::<&str>::new()); + let mut asked = req.clone(); + asked["contract"]["exactness"] = json!("simulated"); + assert!(decided(&asked, vec![approx]).refusal.unwrap().ends_with("[J071]")); +} + +/// The sampling bound is at least the total variation two samples of one +/// distribution show on average, sparse or dense: here against seeded draws, +/// among them the case of 65,536 outcomes and 1,000 shots. +#[test] +fn the_sampling_bound_holds_for_sparse_and_dense_outcomes() { + let mut state = 0x9e37_79b9_7f4a_7c15u64; + let mut next = move || { + state = state.wrapping_add(0x9e37_79b9_7f4a_7c15); + let mut z = state; + z = (z ^ (z >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9); + z = (z ^ (z >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb); + z ^ (z >> 31) + }; + for (k, s, trials) in [(2u64, 1000u64, 200), (4, 10, 400), (16, 100, 200), (1024, 1000, 40), (65_536, 1000, 20)] { + let (mut tv, mut bound) = (0.0, 0.0); + for _ in 0..trials { + let mut sample = || { + let mut m = Map::new(); + for _ in 0..s { + let o = format!("{:017b}", next() % k); + let c = m.get(&o).and_then(Value::as_u64).unwrap_or(0); + m.insert(o, json!(c + 1)); + } + Value::Object(m) + }; + let (a, b) = (sample(), sample()); + let d = distance(&a, &b, s).unwrap(); + tv += d["total_variation"].as_f64().unwrap(); + bound += d["sampling_tvd_bound"].as_f64().unwrap(); + } + let (tv, bound) = (tv / trials as f64, bound / trials as f64); + assert!(bound >= 0.99 * tv && bound <= 1.0 && bound <= 1.5 * tv, "{k} outcomes, {s} shots: the mean total variation {tv}, the mean bound {bound}"); + } + // The split's mean deviation, against the binomial's own sum. + for n in [1u128, 2, 3, 4, 5, 10, 11, 100, 1001] { + let want: f64 = (0..=n).map(|b| (2 * b).abs_diff(n) as f64 * binomial(n, b)).sum::() / 2f64.powi(n as i32); + assert!((split_mad(n) - want).abs() <= 1e-9 * want.max(1.0), "{n}: {} {want}", split_mad(n)); + } +} + +fn binomial(n: u128, k: u128) -> f64 { + (0..k).fold(1.0, |c, i| c * (n - i) as f64 / (i + 1) as f64) +} diff --git a/wai/wai-quantum/src/engine/pulse.rs b/wai/wai-quantum/src/engine/pulse.rs index 6d1027b50..1ffb082ef 100644 --- a/wai/wai-quantum/src/engine/pulse.rs +++ b/wai/wai-quantum/src/engine/pulse.rs @@ -386,7 +386,7 @@ fn prepare(v: &Value) -> Result<(String, Prepared), String> { let o = v.as_object().ok_or_else(|| tag(refusal::NOT_A_JOB, "a job is a JSON object"))?; if let Some(k) = o.keys().find(|k| !KEYS.contains(&k.as_str())) { return Err(perr(format!( - "\"{k}\": a pulse run takes qasm, shots, seed, pulse, target and a contract; observables, amplitudes, noise, compile, repair, intent and mitigate belong to the circuit methods (its decay comes from T1 and T2)" + "\"{k}\": a pulse run takes qasm, shots, seed, pulse and target; observables, amplitudes, noise, compile, repair, intent and mitigate belong to the circuit methods (its decay comes from T1 and T2)" ))); } // A pulse run always states its verdict; asking for it changes nothing. diff --git a/wai/wai-quantum/src/engine/refusal.rs b/wai/wai-quantum/src/engine/refusal.rs index 4b54cd7e2..70336955f 100644 --- a/wai/wai-quantum/src/engine/refusal.rs +++ b/wai/wai-quantum/src/engine/refusal.rs @@ -119,11 +119,11 @@ table! { REGISTERED_INTENT = "J065", Refused, "An intent on a job whose noise names a registered channel: the intent checks model the built-in channels alone, so the check is refused rather than made against another model."; // A contract (engine::planner). - CONTRACT_FORM = "J070", Refused, "A contract that does not read: not an object, a member a contract does not have, an exactness that is no class, a max_cost that is not an amount in decimals and a currency, a deadline or an energy ceiling that is not above zero, providers that is neither never nor allowed, or a job that names a provider while its contract says never."; + CONTRACT_FORM = "J070", Refused, "A contract that does not read: not an object, a member a contract does not have, an exactness that is no class, a max_cost that is not an amount in decimals and a currency, a deadline or an energy ceiling that is not above zero, providers that is neither never nor allowed, or a job that names a provider while its contract does not allow one (providers: never is the default)."; NOTHING_MEETS = "J071", Refused, "No route this host can see meets the contract: each route's price or reason is listed, so the contract or the job can be changed. Nothing fell back to a route the contract does not allow."; CLASS_BROKEN = "J072", Refused, "A route's result whose accuracy class does not meet the class its job wants: the contract's, or under a contract that names none the class the job keeps. Nothing it gave is returned, since its receipt would not verify."; CONTRACT_HERE = "J073", Refused, "A contract where it cannot be honoured: on a set or an item of one (each program runs under its own contract, alone), or on a build with no planner. It is refused rather than read as absent."; - DEADLINE_PASSED = "J074", Refused, "A run stopped at its contract's deadline, by a host that can stop one: the estimate it was planned on was wrong here, and nothing was sealed."; + DEADLINE_PASSED = "J074", Refused, "A run stopped at its contract's deadline, by a host that can stop one: the job service's worker, or a provider's job the command line cancels where it waits. The estimate it was planned on was wrong here, and nothing was sealed."; // An answer's view statements (the answer view layer). ANSWER_PARSE = "J100", Dropped, "A line of an answer that is not a statement (`name = View(...)`), a program (a fenced `qasm` block with its name), a comment or a marker: left out."; diff --git a/wai/wai-quantum/src/quantum_cutrank.rs b/wai/wai-quantum/src/quantum_cutrank.rs index b0013f691..31500b8d2 100644 --- a/wai/wai-quantum/src/quantum_cutrank.rs +++ b/wai/wai-quantum/src/quantum_cutrank.rs @@ -93,6 +93,12 @@ pub struct ProductMeasured { steps: Vec, } +/// 2^k exactly, from the double's bits rather than a library's `exp2`, which +/// need not agree in the last place on every platform. +fn pow2(k: usize) -> f64 { + if k > 1023 { f64::INFINITY } else { f64::from_bits(((k as u64) + 1023) << 52) } +} + impl ProductMeasured { /// The state `tableau` holds with `last[q]` applied to each qubit q, to be /// summed in the qubits' own order. @@ -243,7 +249,7 @@ impl ProductMeasured { /// The work of an order: `Σ_k 2^{cut_k}`, the table entries its passes /// touch, up to a small factor. pub fn work(&self) -> f64 { - self.cuts.iter().map(|&k| (k as f64).exp2()).sum() + self.cuts.iter().map(|&k| pow2(k)).sum() } /// An order with less work, by simulated annealing from the current one: @@ -256,7 +262,7 @@ impl ProductMeasured { pub fn anneal_order(&self, moves: usize, seed: u64) -> Vec { let n = self.n; let mut s = seed; - let work = |c: &[usize]| c.iter().map(|&k| (k as f64).exp2()).sum::(); + let work = |c: &[usize]| c.iter().map(|&k| pow2(k)).sum::(); let mut order = self.order.clone(); let mut cuts = self.cuts.clone(); let mut cur = work(&cuts); @@ -284,7 +290,11 @@ impl ProductMeasured { assert_eq!(cand_cuts, self.cut_ranks_of(&cand), "the recounted cuts are the whole order's"); let c = work(&cand_cuts); // The acceptance draw only for a worse order. - if c <= cur || ((cur.log2() - c.log2()) / temp).exp() > (splitmix(&mut s) >> 11) as f64 / (1u64 << 53) as f64 { + // The same bits on every platform (crate::repro): the planner's order, + // and so a plan's memory and work, are part of what a contract job's + // stable digest pins. + let accept = || crate::repro::exp((crate::repro::ln(cur) - crate::repro::ln(c)) / std::f64::consts::LN_2 / temp); + if c <= cur || accept() > (splitmix(&mut s) >> 11) as f64 / (1u64 << 53) as f64 { order = cand; cuts = cand_cuts; cur = c; diff --git a/wai/wai-quantum/src/repro.rs b/wai/wai-quantum/src/repro.rs index 70c3ecc78..dae418c5b 100644 --- a/wai/wai-quantum/src/repro.rs +++ b/wai/wai-quantum/src/repro.rs @@ -117,7 +117,7 @@ const EXP_P: [f64; 5] = [ /// `eˣ`, bit-identical on every IEEE-754 platform: fdlibm's algorithm /// (reduction by `ln 2` in two parts, a rational approximation on /// `[−ln2/2, ln2/2]`), using only `+ − × ÷`. Within an ulp of the true value. -#[cfg(any(feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_nqs", feature = "quantum_lang"))] +#[cfg(any(feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_nqs", feature = "quantum_lang", feature = "quantum_cutrank"))] pub fn exp(x: f64) -> f64 { const LN2_HI_E: f64 = 6.931_471_803_691_238_164_90e-1; const LN2_LO_E: f64 = 1.908_214_929_270_587_700_02e-10; -- 2.54.0 (Apple Git-157) From c41929230dba24c572a1833afa9ee27c158e5a82 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Fri, 6 Nov 2026 10:53:39 -0500 Subject: [PATCH 06/42] wai-quantum: the review of the planner's contract fixed, with the corpus that holds it All seventeen findings of the review of #668, each held by a test or a corpus receipt that fails on the old rule (the commit before this one has the code). Here: the contract receipts made again with the final code, among them a seed whose shadow's wraps at 2^53, a tie between a method and a provider, a bounded contract, the CPU asked for, a device target and a pulse program; seventy-one crafted ones, new ones for every rule the review's mutants of the second verifier got past; the differential comparing what each verifier says was kept, the class and the distance as well as the reasons, which found a `kept` of 0 read as null in the reference; the provider plan test for what no provider is asked; and cut-rank's exp and ln with the feature that alone needs them. Co-Authored-By: Claude Opus 5.5 --- ...06-wai-quantum-planner-under-a-contract.md | 2 +- wai/quantum-conformance/receipts/generate.py | 4 + .../receipts/jobs/cli-contract-any.json | 1 + ...crafted-contract-approximate-rejected.json | 545 +++++++++++++++++ .../crafted-contract-at-least-claimed.json | 30 +- .../jobs/crafted-contract-at-least-false.json | 27 +- .../jobs/crafted-contract-auto-other.json | 312 ++++++++++ .../crafted-contract-auto-rank-lowered.json | 312 ++++++++++ .../crafted-contract-auto-rank-missing.json | 311 ++++++++++ .../crafted-contract-auto-rank-other.json | 312 ++++++++++ .../crafted-contract-charged-over-stated.json | 30 +- .../jobs/crafted-contract-charged-over.json | 32 +- .../jobs/crafted-contract-choice-dearer.json | 19 +- .../jobs/crafted-contract-choice-not-run.json | 19 +- .../jobs/crafted-contract-class-short.json | 19 +- .../jobs/crafted-contract-currency-other.json | 450 ++++++++++++++ .../crafted-contract-deadline-unknown.json | 347 +++++++++++ .../crafted-contract-energy-at-ceiling.json | 349 +++++++++++ ...rafted-contract-energy-stable-claimed.json | 349 +++++++++++ .../jobs/crafted-contract-form-cost-long.json | 343 +++++++++++ .../jobs/crafted-contract-form-cost.json | 19 +- .../jobs/crafted-contract-form-exactness.json | 19 +- .../jobs/crafted-contract-form-member.json | 19 +- .../crafted-contract-kept-charged-other.json | 450 ++++++++++++++ .../jobs/crafted-contract-kept-dropped.json | 19 +- .../crafted-contract-kept-elapsed-other.json | 343 +++++++++++ .../jobs/crafted-contract-kept-false.json | 19 +- .../crafted-contract-kept-member-extra.json | 344 +++++++++++ .../crafted-contract-kept-missed-stated.json | 19 +- .../jobs/crafted-contract-local-money.json | 345 +++++++++++ .../jobs/crafted-contract-memory-at-cap.json | 343 +++++++++++ .../crafted-contract-named-approximate.json | 451 ++++++++++++++ .../jobs/crafted-contract-named-other.json | 450 ++++++++++++++ .../jobs/crafted-contract-planner-format.json | 19 +- .../crafted-contract-planner-on-plain.json | 19 +- .../crafted-contract-planner-wanted-from.json | 19 +- .../jobs/crafted-contract-planner-wanted.json | 19 +- .../crafted-contract-price-amount-long.json | 544 +++++++++++++++++ .../crafted-contract-price-seconds-past.json | 544 +++++++++++++++++ ...d-contract-provider-named-not-allowed.json | 449 ++++++++++++++ .../crafted-contract-provider-not-chosen.json | 27 +- ...rafted-contract-providers-not-allowed.json | 27 +- .../jobs/crafted-contract-question-other.json | 312 ++++++++++ .../jobs/crafted-contract-route-claimed.json | 19 +- .../jobs/crafted-contract-route-code.json | 19 +- .../crafted-contract-route-price-memory.json | 19 +- .../crafted-contract-route-price-work.json | 19 +- ...afted-contract-route-provider-claimed.json | 27 +- .../crafted-contract-shadow-bound-other.json | 544 +++++++++++++++++ ...rafted-contract-shadow-count-fraction.json | 544 +++++++++++++++++ .../crafted-contract-shadow-count-short.json | 540 +++++++++++++++++ .../crafted-contract-shadow-count-sum.json | 544 +++++++++++++++++ .../jobs/crafted-contract-shadow-missing.json | 25 +- .../crafted-contract-shadow-not-computed.json | 25 +- .../crafted-contract-shadow-numerator.json | 27 +- ...crafted-contract-shadow-omitted-spelt.json | 27 +- .../crafted-contract-shadow-on-local.json | 19 +- .../crafted-contract-shadow-plan-budget.json | 544 +++++++++++++++++ .../crafted-contract-shadow-plan-class.json | 544 +++++++++++++++++ .../crafted-contract-shadow-plan-code.json | 498 ++++++++++++++++ .../crafted-contract-shadow-plan-missing.json | 27 +- ...afted-contract-shadow-plan-price-over.json | 544 +++++++++++++++++ ...ted-contract-shadow-plan-route-absent.json | 497 ++++++++++++++++ ...ed-contract-shadow-plan-route-missing.json | 543 +++++++++++++++++ ...crafted-contract-shadow-request-extra.json | 550 ++++++++++++++++++ ...crafted-contract-shadow-route-missing.json | 543 +++++++++++++++++ ...rafted-contract-shadow-route-provider.json | 542 +++++++++++++++++ .../crafted-contract-shadow-said-failed.json | 520 +++++++++++++++++ .../crafted-contract-shadow-said-none.json | 25 +- .../jobs/crafted-contract-shadow-seed.json | 27 +- .../jobs/crafted-contract-stable-choice.json | 19 +- .../jobs/crafted-contract-stable-digest.json | 19 +- .../receipts/made.lock.json | 1 + .../receipts/manifest.json | 314 +++++++++- .../tools/receipt_verify.py | 8 + wai/wai-quantum-cli/docs/llms-full.txt | 9 +- wai/wai-quantum-cli/docs/local-mcp.json | 549 ++++++++++++++--- wai/wai-quantum-cli/docs/service-mcp.json | 496 +++++++++++++--- wai/wai-quantum-cli/tests/providers.rs | 7 +- wai/wai-quantum/src/engine/planner/tests.rs | 17 + wai/wai-quantum/src/repro.rs | 22 +- 81 files changed, 17610 insertions(+), 285 deletions(-) create mode 100644 wai/quantum-conformance/receipts/jobs/cli-contract-any.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-approximate-rejected.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-auto-other.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-auto-rank-lowered.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-auto-rank-missing.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-auto-rank-other.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-currency-other.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-deadline-unknown.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-ceiling.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-energy-stable-claimed.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-form-cost-long.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-kept-charged-other.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-kept-elapsed-other.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-kept-member-extra.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-local-money.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-memory-at-cap.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-named-approximate.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-named-other.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-price-amount-long.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-price-seconds-past.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-provider-named-not-allowed.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-question-other.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-bound-other.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-fraction.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-short.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-sum.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-budget.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-class.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-code.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-price-over.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-route-absent.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-route-missing.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-request-extra.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-route-missing.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-route-provider.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-failed.json diff --git a/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md b/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md index db228e86b..5e23b7d79 100644 --- a/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md +++ b/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md @@ -29,7 +29,7 @@ outcome and the choice from what the receipt states, and give nine new reasons (`contract_form`, `contract_provider`, `planner_form`, `planner_route`, `planner_choice`, `planner_stable`, `planner_kept`, `contract_class`, `shadow`); the differential holds them to the same choice, class, kept and shadow distance, not - only the same reasons. The corpus gains MADE_COUNT made receipts under a contract and CRAFTED_COUNT crafted ones, + only the same reasons. The corpus gains eleven made receipts under a contract and seventy-one crafted ones, each of the review's single-rule changes to the second verifier is found by them, and three plants prove the differential sees a route, a choice and a distance taken as they stand. - **A provider's answer is shadowed.** When a provider answers a contract job, the most exact classical method that can diff --git a/wai/quantum-conformance/receipts/generate.py b/wai/quantum-conformance/receipts/generate.py index 6fc2701e9..f5d626878 100644 --- a/wai/quantum-conformance/receipts/generate.py +++ b/wai/quantum-conformance/receipts/generate.py @@ -608,6 +608,7 @@ def contract_cases(run, at, drop): add("form-member", edited(local, at(("request", "contract", "deadline"), 1)), ["contract_form"], "a member no contract has: read as absent, a requirement would drop in silence") add("form-exactness", edited(local, at(("request", "contract", "exactness"), "nearly")), ["contract_form"], "an exactness that is no class") add("form-cost", edited(local, at(("request", "contract", "max_cost", "amount"), "1e3")), ["contract_form"], "a ceiling's amount that is not in decimals") + add("form-cost-long", edited(local, at(("request", "contract", "max_cost", "amount"), "1" * 65)), ["contract_form"], "a ceiling's amount of 65 characters: at most 64") add("planner-missing", edited(local, drop(P)), ["planner_form"], "a contract job sealed without its reasoning") add("planner-format", edited(local, at(P + ("format",), "wai.quantum.planner/2")), ["planner_form"], "a reasoning of another format") add("planner-wanted", edited(local, at(P + ("wanted",), "heuristic")), ["planner_form"], "a class wanted that is not the contract's") @@ -674,6 +675,7 @@ def contract_cases(run, at, drop): # --- what the job names, the question it asks, and what auto picks (review: auto verifiable) add("auto-other", edited(auto, at(P + ("auto",), "method:statevector")), ["planner_form"], "auto said to pick a route the ranks do not") add("auto-rank-lowered", edited(auto, route("method:statevector", lambda r: r.update(auto_rank=5))), ["planner_form"], "a route's rank in auto's order lowered, so that auto would pick it") + add("auto-rank-other", edited(auto, route("method:mps", lambda r: r.update(auto_rank=65))), ["planner_form"], "a rank that is not the method's, on a route that does not win by it") add("auto-rank-missing", edited(auto, route("method:statevector", lambda r: r.pop("auto_rank"))), ["planner_form"], "a local route without its rank in auto's order") add("question-other", edited(auto, at(P + ("question",), "amplitudes")), ["planner_form"], "a question the request does not ask") add("named-other", edited(named, at(P + ("named",), None)), ["planner_form"], "a provider the request names, said to be named by nothing") @@ -712,6 +714,7 @@ def contract_cases(run, at, drop): # --- the shadow, a method's run of exactly the job's program (review: steered, suppressed, unverifiable) add("shadow-route-missing", edited(routed, drop(S + ("route",))), ["shadow"], "a shadow that names no route") add("shadow-plan-route-missing", edited(routed, drop(P + ("shadow", "route"))), ["shadow"], "a shadow planned with no route, where null would say why") + add("shadow-plan-route-absent", edited(routed, both(at(P + ("shadow",), {"code": "none", "why": "said none"}), at(S, {"ran": False, "code": "none", "why": "said none"}))), ["shadow"], "a plan with neither a route nor null, and a shadow said not to have run") def provider_shadow(b): for side in (b["result"]["planner"]["shadow"], b["result"]["shadow"]): @@ -735,6 +738,7 @@ def contract_cases(run, at, drop): c[sorted(c)[1]] += 0.5 add("shadow-count-fraction", edited(routed, fraction), ["shadow"], "a shadow's counts that are not whole, summing to the shots all the same") add("shadow-count-sum", edited(routed, lambda b: b["result"]["shadow"]["counts"].update({sorted(b["result"]["shadow"]["counts"])[0]: b["result"]["shadow"]["counts"][sorted(b["result"]["shadow"]["counts"])[0]] + 1})), ["shadow"], "a shadow's counts that sum to more than its shots") + add("shadow-count-short", edited(routed, both(at(S + ("omitted_shots",), 1), at(S + ("distance",), {"computed": False, "why": "a shot is omitted"}))), ["shadow"], "a shot said omitted beside counts that are all the shots: they sum to one more, and the distance, not computed, is no help") add("shadow-bound-other", edited(routed, lambda b: b["result"]["shadow"]["distance"].update(sampling_tvd_bound=0.01)), ["shadow"], "a bound on the distance the shots alone leave that is not what the counts give") def host_failed(b): diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-any.json b/wai/quantum-conformance/receipts/jobs/cli-contract-any.json new file mode 100644 index 000000000..73b484c66 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-any.json @@ -0,0 +1 @@ +{"status":"done","method":"stabilizer","why":"Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 6 of 15 routes that meet the contract","estimate":{"memory_bytes":67115270,"work":208},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":100,"seed":2,"contract":{"exactness":"any","deadline_seconds":60.0,"providers":"allowed"}},"result":{"method":"stabilizer","qubits":2,"gates":2,"accuracy":{"class":"exact"},"counts":{"00":54,"11":46},"distinct_outcomes":2,"omitted_shots":0,"outcome_dimension":1,"elapsed_ms":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"any","wanted_from":"contract","named":null,"question":"counts","auto":"method:stabilizer","host":{"job_bytes":17179869184,"providers":["ref","priced"]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"auto_rank":20,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"met"},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"auto_rank":30,"price":{"money":{"free":true},"time":{"seconds":8e-9,"basis":"nominal"},"memory_bytes":268437922,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"met"},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"auto_rank":40,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"statevector_single needs a GPU: this build has no GPU state vector"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"auto_rank":10,"price":{"money":{"free":true},"time":{"seconds":2.496e-8,"basis":"nominal"},"memory_bytes":67115270,"work":208,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"chosen"},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"pauli answers expectation values only"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"auto_rank":60,"price":{"money":{"free":true},"time":{"seconds":0.005603328,"basis":"nominal"},"memory_bytes":270532608,"work":3735552,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"met"},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"stabilizer_rank answers amplitudes and expectation values"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"tensor_network answers amplitudes only"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"auto_rank":50,"price":{"money":{"free":true},"time":{"seconds":1.35e-7,"basis":"nominal"},"memory_bytes":268435554,"work":900,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"met"},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"cutrank_single needs a GPU: this build has no GPU cut-rank table"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"density_matrix is for noisy circuits (give \"noise\")"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"trajectories is for noisy circuits (give \"noise\")"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"cannot","why":"pulse reads its own program, and runs only when a job names it"}},{"route":"provider:ref","kind":"provider","provider":"ref","class":"simulated","host_dependent":true,"price":{"money":{"free":true},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder"],"program":{"shots":100,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"met"},{"route":"provider:priced","kind":"provider","provider":"priced","class":"simulated","host_dependent":true,"price":{"money":{"free":false,"amount":"0.03","currency":"USD","unit":"shot"},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder","charged"],"program":{"shots":100,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"rejected","rejected":{"code":"cost_no_ceiling","why":"0.03 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider"}}],"choice":"method:stabilizer","why":"the cheapest of the 6 of 15 routes that meet the contract","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"e6de7586c9980adb8036dea7dc2777ba0acdb9a0138a3ef1da70c070133771f8","choice":false},"kept":{"deadline":{"seconds":60.0,"elapsed_ms":0,"kept":true}}},"energy":{"unmetered":"the command line does not meter a run's energy"},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"25467d1f1ec2e12f2c21f442c115289727fbda5e6d44bbc7d78c52c481599d24","signature":"c161c2af0b056e6fa763f56ace2cb21ef50e7d573e64200098dbb736a21c2564160701b82e79c79d4d1f15b6a2cb4a16dcbe87a90d53251efd9ac4930e955409"}}} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-approximate-rejected.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-approximate-rejected.json new file mode 100644 index 000000000..51e2627ea --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-approximate-rejected.json @@ -0,0 +1,545 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + }, + "approximate": true + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "8505d448ae9f3064944a6894d84264bc5dd76090009c74f880eb5cba7f80710f", + "signature": "741787b0d0037eb20eb5d2de281be60608910d2cc4eb00900e9c0d82409a2f8f6e55813115d9c9d4259054c1dfceb00f82f3dbe74f24d1fc1573ef6ab687b306" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-claimed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-claimed.json index 4e6bfb3ef..f65050724 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-claimed.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-claimed.json @@ -10,7 +10,8 @@ "max_cost": { "amount": "1", "currency": "USD" - } + }, + "providers": "allowed" }, "provider": "priced" }, @@ -112,6 +113,8 @@ "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "named", + "named": "provider:priced", + "question": "counts", "auto": null, "host": { "job_bytes": 17179869184, @@ -126,6 +129,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": null, "outcome": "rejected", "rejected": { @@ -139,6 +143,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": null, "outcome": "rejected", "rejected": { @@ -152,6 +157,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -165,6 +171,7 @@ "method": "stabilizer", "class": "estimate", "host_dependent": false, + "auto_rank": 10, "price": null, "outcome": "rejected", "rejected": { @@ -178,6 +185,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -191,6 +199,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": null, "outcome": "rejected", "rejected": { @@ -204,6 +213,7 @@ "method": "stabilizer_rank", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -217,6 +227,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -230,6 +241,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": null, "outcome": "rejected", "rejected": { @@ -243,6 +255,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -256,6 +269,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -269,6 +283,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -282,6 +297,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -417,7 +433,7 @@ "denominator": 600, "total_variation": 0.07333333333333333, "hellinger_fidelity": 0.9946222222222221, - "sampling_tvd_expected": 0.032573500793528 + "sampling_tvd_bound": 0.04602751441903442 }, "elapsed_ms": 0 }, @@ -425,11 +441,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "80a5efb2b9393e4ceefb4c0a3337b4a246bb9fe71604215ef1030a9ab4cbe2b4", - "signature": "2e31e43bb0ebe3d1f8b28903754604845b3ac2dc6cdc8dd78ca09ef8c96284e95d30b528b961a98b4125b216e71d8a93eba7e5bb10011a33e2b50fb3672cf20f" + "digest": "ab05e414c2fa45db84b6453b3feccfa2c7b24610b8f57d34ce9dfba33140f8a7", + "signature": "18a71d01d8ab530809628fad41835300c1167c9dc2a0659a0464753e96a8567499ddcc7df83825bbaa9cd51117738dc787d8d37209daf2061dca99ac7ec19406" } }, - "id": "pj-95909ba10d2d9f13", - "submitted_ms": 1793951019928, - "finished_ms": 1793951019934 + "id": "pj-316b154641049d91", + "submitted_ms": 1793974079084, + "finished_ms": 1793974079087 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-false.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-false.json index b0b997d06..31adc08d8 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-false.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-false.json @@ -103,6 +103,8 @@ "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -118,6 +120,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -146,6 +149,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -174,6 +178,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -187,6 +192,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -215,6 +221,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -228,6 +235,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -256,6 +264,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -269,6 +278,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -282,6 +292,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -310,6 +321,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -323,6 +335,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -336,6 +349,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -349,6 +363,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -512,7 +527,7 @@ "denominator": 600, "total_variation": 0.07333333333333333, "hellinger_fidelity": 0.9946222222222221, - "sampling_tvd_expected": 0.032573500793528 + "sampling_tvd_bound": 0.04602751441903442 }, "elapsed_ms": 0 }, @@ -520,11 +535,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "10fd84c59f77c28e172e7a50c0564f19c5c043df6c7bef32255c7de680f22e05", - "signature": "f1cef0682159106750366334bcb87d97ea25b29d3a4e4553d29cc751221406cf0260059d8cd9460b73b693b7235f33b47cbdecbdf0f653f3dec98b513d00170d" + "digest": "d18a44908d1e326f1f973e38e8baa79677d8b43a6e6503a41165ef373b8c9dc0", + "signature": "a865c48455b9443faec53460fa8e38f4bebae7b2d868fbf71c37beba7fc90a75ab31a24c4330d8c52e775c960595ce666c07e14d368db1b6ee326cf4fbc9a60d" } }, - "id": "pj-ef8b7cfb5f9601bc", - "submitted_ms": 1793951019912, - "finished_ms": 1793951019919 + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-auto-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-auto-other.json new file mode 100644 index 000000000..d5f0cad22 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-auto-other.json @@ -0,0 +1,312 @@ +{ + "status": "done", + "method": "exact", + "why": "bit-exact state vector of 3 qubits; what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)", + "estimate": { + "memory_bytes": 134218112, + "work": 40 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[3] q;\nbit[3] c;\nh q[0];\nt q[0];\ncx q[0], q[1];\nrz(pi/8) q[2];\ncx q[1], q[2];\nc = measure q;\n", + "shots": 500, + "seed": 3, + "contract": { + "deadline_seconds": 600.0 + } + }, + "result": { + "method": "exact", + "qubits": 3, + "gates": 5, + "accuracy": { + "class": "bit-exact" + }, + "state_hash": "5f1ae3e98c0555290986daf0d573de16a34ba01d1993f13f134e0b1daf6f1ab5", + "counts": { + "000": 254, + "111": 246 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "bit-exact", + "wanted_from": "auto", + "named": null, + "question": "counts", + "auto": "method:statevector", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2e-07, + "basis": "nominal" + }, + "memory_bytes": 134218112, + "work": 40, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 268447588, + "work": 40, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants bit-exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants bit-exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.024723456, + "basis": "nominal" + }, + "memory_bytes": 270794752, + "work": 16482304, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants bit-exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants bit-exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants bit-exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants bit-exact" + } + } + ], + "choice": "method:exact", + "why": "what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "d859d0ec175157bdd2b0e221a569afd4d2d94e347cbd550027c714ab35bdb061", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 600.0, + "elapsed_ms": 0, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "6397742e38ce279d22b434b5432eb585a7e6310776b7cb57bda375d95b96b002", + "signature": "926aaea5c187a5ce7755db94cc1b172bb24bff000bd8e3c32b79e58b32dcebb3866d9dcd6e31296d545de25e7e7689da9189fade243bc8d311eb6c35da969208" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-auto-rank-lowered.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-auto-rank-lowered.json new file mode 100644 index 000000000..13974762e --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-auto-rank-lowered.json @@ -0,0 +1,312 @@ +{ + "status": "done", + "method": "exact", + "why": "bit-exact state vector of 3 qubits; what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)", + "estimate": { + "memory_bytes": 134218112, + "work": 40 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[3] q;\nbit[3] c;\nh q[0];\nt q[0];\ncx q[0], q[1];\nrz(pi/8) q[2];\ncx q[1], q[2];\nc = measure q;\n", + "shots": 500, + "seed": 3, + "contract": { + "deadline_seconds": 600.0 + } + }, + "result": { + "method": "exact", + "qubits": 3, + "gates": 5, + "accuracy": { + "class": "bit-exact" + }, + "state_hash": "5f1ae3e98c0555290986daf0d573de16a34ba01d1993f13f134e0b1daf6f1ab5", + "counts": { + "000": 254, + "111": 246 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "bit-exact", + "wanted_from": "auto", + "named": null, + "question": "counts", + "auto": "method:exact", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2e-07, + "basis": "nominal" + }, + "memory_bytes": 134218112, + "work": 40, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 5, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 268447588, + "work": 40, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants bit-exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants bit-exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.024723456, + "basis": "nominal" + }, + "memory_bytes": 270794752, + "work": 16482304, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants bit-exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants bit-exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants bit-exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants bit-exact" + } + } + ], + "choice": "method:exact", + "why": "what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "d859d0ec175157bdd2b0e221a569afd4d2d94e347cbd550027c714ab35bdb061", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 600.0, + "elapsed_ms": 0, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "920a77770f5fe060634a9dbc9dd638ec61f97811f4776a6f07a0053df4d7cb1e", + "signature": "945f272d15e56164423bf4db1adc893c5db1ecca130488de74473ff59030dd150f3743a49f37612e4b309f35afd4e6296a55c58ad572771d07cb42184e4a630d" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-auto-rank-missing.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-auto-rank-missing.json new file mode 100644 index 000000000..c553d6297 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-auto-rank-missing.json @@ -0,0 +1,311 @@ +{ + "status": "done", + "method": "exact", + "why": "bit-exact state vector of 3 qubits; what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)", + "estimate": { + "memory_bytes": 134218112, + "work": 40 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[3] q;\nbit[3] c;\nh q[0];\nt q[0];\ncx q[0], q[1];\nrz(pi/8) q[2];\ncx q[1], q[2];\nc = measure q;\n", + "shots": 500, + "seed": 3, + "contract": { + "deadline_seconds": 600.0 + } + }, + "result": { + "method": "exact", + "qubits": 3, + "gates": 5, + "accuracy": { + "class": "bit-exact" + }, + "state_hash": "5f1ae3e98c0555290986daf0d573de16a34ba01d1993f13f134e0b1daf6f1ab5", + "counts": { + "000": 254, + "111": 246 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "bit-exact", + "wanted_from": "auto", + "named": null, + "question": "counts", + "auto": "method:exact", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2e-07, + "basis": "nominal" + }, + "memory_bytes": 134218112, + "work": 40, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 268447588, + "work": 40, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants bit-exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants bit-exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.024723456, + "basis": "nominal" + }, + "memory_bytes": 270794752, + "work": 16482304, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants bit-exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants bit-exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants bit-exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants bit-exact" + } + } + ], + "choice": "method:exact", + "why": "what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "d859d0ec175157bdd2b0e221a569afd4d2d94e347cbd550027c714ab35bdb061", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 600.0, + "elapsed_ms": 0, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "229928210ea46a8a118063b4ab59498bc46340f57b3382074a78e314b0de6001", + "signature": "774dffc7336ec083fe922d076d91980f2d8bb9427edc69a15d47a2d3fd187b390c5cacebe5620180964235e1347d9d8cb488cf4466d848682182da4db7a5380c" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-auto-rank-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-auto-rank-other.json new file mode 100644 index 000000000..630eff4b0 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-auto-rank-other.json @@ -0,0 +1,312 @@ +{ + "status": "done", + "method": "exact", + "why": "bit-exact state vector of 3 qubits; what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)", + "estimate": { + "memory_bytes": 134218112, + "work": 40 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[3] q;\nbit[3] c;\nh q[0];\nt q[0];\ncx q[0], q[1];\nrz(pi/8) q[2];\ncx q[1], q[2];\nc = measure q;\n", + "shots": 500, + "seed": 3, + "contract": { + "deadline_seconds": 600.0 + } + }, + "result": { + "method": "exact", + "qubits": 3, + "gates": 5, + "accuracy": { + "class": "bit-exact" + }, + "state_hash": "5f1ae3e98c0555290986daf0d573de16a34ba01d1993f13f134e0b1daf6f1ab5", + "counts": { + "000": 254, + "111": 246 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "bit-exact", + "wanted_from": "auto", + "named": null, + "question": "counts", + "auto": "method:exact", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2e-07, + "basis": "nominal" + }, + "memory_bytes": 134218112, + "work": 40, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 268447588, + "work": 40, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants bit-exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants bit-exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 65, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.024723456, + "basis": "nominal" + }, + "memory_bytes": 270794752, + "work": 16482304, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants bit-exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants bit-exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants bit-exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants bit-exact" + } + } + ], + "choice": "method:exact", + "why": "what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "d859d0ec175157bdd2b0e221a569afd4d2d94e347cbd550027c714ab35bdb061", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 600.0, + "elapsed_ms": 0, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "0d8795d6189083abac8ed6ee4a2288b72d38beb8a92d46ef2d8234320d809d03", + "signature": "e2dee694e3ffb76b40e4ca03a36e14398d8ce3cb92ad7bf7ea2e561fb483822addeb058b9769122ccfc1e52934feece756a25a6d9230d0c1438e45e775560a0d" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over-stated.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over-stated.json index f9752e15c..1274c825c 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over-stated.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over-stated.json @@ -10,7 +10,8 @@ "max_cost": { "amount": "1", "currency": "USD" - } + }, + "providers": "allowed" }, "provider": "priced" }, @@ -112,6 +113,8 @@ "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "named", + "named": "provider:priced", + "question": "counts", "auto": null, "host": { "job_bytes": 17179869184, @@ -126,6 +129,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": null, "outcome": "rejected", "rejected": { @@ -139,6 +143,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": null, "outcome": "rejected", "rejected": { @@ -152,6 +157,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -165,6 +171,7 @@ "method": "stabilizer", "class": "estimate", "host_dependent": false, + "auto_rank": 10, "price": null, "outcome": "rejected", "rejected": { @@ -178,6 +185,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -191,6 +199,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": null, "outcome": "rejected", "rejected": { @@ -204,6 +213,7 @@ "method": "stabilizer_rank", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -217,6 +227,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -230,6 +241,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": null, "outcome": "rejected", "rejected": { @@ -243,6 +255,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -256,6 +269,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -269,6 +283,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -282,6 +297,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -416,7 +432,7 @@ "denominator": 600, "total_variation": 0.07333333333333333, "hellinger_fidelity": 0.9946222222222221, - "sampling_tvd_expected": 0.032573500793528 + "sampling_tvd_bound": 0.04602751441903442 }, "elapsed_ms": 0 }, @@ -424,11 +440,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "76ad5f1e6f1fc20de95c0529d09f7fb918916bf7a2cda3573cdc1e0de0c0f071", - "signature": "ba5155d131fa1d9b3661a61128940d25d7a411a503488600c23737f4c28a8a03e1a7cae56fd1d351ff1794e2def0ebdd7fd891a7fdd4584e395bb8b1c8278e0b" + "digest": "7b8b89db3f1d38f4f14aa0e6a2a03a39cfc304edfc54dc099cb17196aaf797e8", + "signature": "6769f018dd440126a7fa92a6e7d43de59a42682f47e6d019122a763ae11e51a21a0b0ed4e15b7269aaab2993669eee95a2ba95624890799b058f55155e34360a" } }, - "id": "pj-95909ba10d2d9f13", - "submitted_ms": 1793951019928, - "finished_ms": 1793951019934 + "id": "pj-316b154641049d91", + "submitted_ms": 1793974079084, + "finished_ms": 1793974079087 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over.json index e160ba64c..04c0e1d1a 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over.json @@ -10,7 +10,8 @@ "max_cost": { "amount": "1", "currency": "USD" - } + }, + "providers": "allowed" }, "provider": "priced" }, @@ -112,6 +113,8 @@ "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "named", + "named": "provider:priced", + "question": "counts", "auto": null, "host": { "job_bytes": 17179869184, @@ -126,6 +129,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": null, "outcome": "rejected", "rejected": { @@ -139,6 +143,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": null, "outcome": "rejected", "rejected": { @@ -152,6 +157,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -165,6 +171,7 @@ "method": "stabilizer", "class": "estimate", "host_dependent": false, + "auto_rank": 10, "price": null, "outcome": "rejected", "rejected": { @@ -178,6 +185,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -191,6 +199,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": null, "outcome": "rejected", "rejected": { @@ -204,6 +213,7 @@ "method": "stabilizer_rank", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -217,6 +227,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -230,6 +241,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": null, "outcome": "rejected", "rejected": { @@ -243,6 +255,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -256,6 +269,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -269,6 +283,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -282,6 +297,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -384,7 +400,7 @@ "currency": "USD" }, "charged": { - "amount": "0.09", + "amount": "1.5", "currency": "USD" }, "kept": true @@ -416,7 +432,7 @@ "denominator": 600, "total_variation": 0.07333333333333333, "hellinger_fidelity": 0.9946222222222221, - "sampling_tvd_expected": 0.032573500793528 + "sampling_tvd_bound": 0.04602751441903442 }, "elapsed_ms": 0 }, @@ -424,11 +440,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "b98c3902ba4a67de23fd47814acea6db7556d7734d4c38d233e4ba222f5a7f71", - "signature": "0218198823c62b20b0bfb4e919b817e6385421dd0133a07eac1ab9698582cd17299c4f95e58f4127b4cd458a8d5c946232fd01a3f20108936ec0b3aa91c48f0e" + "digest": "65352c64f82ab8d8d16ef9577d758e1deb10263b52b981e82bce6255e9e95361", + "signature": "279b28b8720ddecb7986316a970ee8b50ff3cd581e99755204b3e1ff985d6f5d3a995264c9921a1e82eece6d61c562c0f5c5633919ec3ba3bccc10019fd90f06" } }, - "id": "pj-95909ba10d2d9f13", - "submitted_ms": 1793951019928, - "finished_ms": 1793951019934 + "id": "pj-316b154641049d91", + "submitted_ms": 1793974079084, + "finished_ms": 1793974079087 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-choice-dearer.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-choice-dearer.json index 0ac511cbc..db415209b 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-choice-dearer.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-choice-dearer.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -181,6 +189,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -194,6 +203,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -207,6 +217,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -231,6 +242,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -321,8 +336,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "370d0daff76feaa1ad3a817688237c50e6a3e2771237ba7230eb696c6802da13", - "signature": "8c2f4f85b6c92b49d0026db616621ea025cbaf005a22bf00ce59b9f10b6a5d93a39af0365d739d1cf3451da7a6c30ec1c032e0355308f41a6d7889939b148e03" + "digest": "22250aa4a3fa19026453970598ef47b2bf3ee334fd99848ef957c9b1917c0c91", + "signature": "24ac10d8c8c91ca434e4d7ae501fd018001b0f1985d324486fc7933225cba7fb2e132e7f4d73a249013d0b13df23f6e8164d8e2f9f32dc86ac5468053391600b" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-choice-not-run.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-choice-not-run.json index 02c8548f6..4e6c451c6 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-choice-not-run.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-choice-not-run.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -181,6 +189,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -194,6 +203,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -207,6 +217,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -231,6 +242,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -321,8 +336,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "9d73fdcb70eb6b1139081a09871f00ea1db015e897b0b0e496b92a9ce513f543", - "signature": "811f32d57a197598d5819929ef0c9226945c4ce17e7b81c12a970ca298821070e95730a5ff62dfb5e247a1d1a3ce2b538a722adf15a31bcf61dc57fc7380ac0d" + "digest": "a77dd911b3f4d938d21281f25b3c24bb86bef0942279ebcc13586a55c2fcd088", + "signature": "a56fd2981a590fe573ae93dbf8fa8397ad483ca7c936c62beb3075fd59e433b5d5b8b7bfe97526199d996932c2fd0f00c619ba09d7dabd66ac6a06441c411802" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-class-short.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-class-short.json index ca9801225..a787a3eda 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-class-short.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-class-short.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -181,6 +189,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -194,6 +203,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -207,6 +217,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -231,6 +242,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -321,8 +336,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "fcb8a0de271dcb5c79e38afbd6246f25134b1ac1052ddb7c96178df4613f463c", - "signature": "ba2606483da0f6ab63997202f05de44c823c3e93ff6ce31d77d997cf46be1e6cf07c9f4ef59605be22667844393fe7f8bdd030b9699465fc854fc19b566a8100" + "digest": "5f665f5cbac0f48cdc52e5173ca41d5e31ef846e945e6bccac21ed1567815a1e", + "signature": "ea5ad3d895c5835539c6e25fb7ee12915f093c99d1f2dc4c0ea73fc163ba42a09bb9e8e58003405f95f2eaa75c5ee6a7395b3e70a2e39ab40d74ad8507eeea0d" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-currency-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-currency-other.json new file mode 100644 index 000000000..4f40cd605 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-currency-other.json @@ -0,0 +1,450 @@ +{ + "status": "done", + "method": "provider", + "why": "on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "max_cost": { + "amount": "1", + "currency": "EUR" + }, + "providers": "allowed" + }, + "provider": "priced" + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "priced", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": false, + "estimate": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot", + "seconds": 0.0 + }, + "charged": { + "amount": "0.09", + "currency": "USD" + }, + "confirmed": true + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "named", + "named": "provider:priced", + "question": "counts", + "auto": null, + "host": { + "job_bytes": 17179869184, + "providers": [ + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "estimate", + "host_dependent": false, + "auto_rank": 10, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + } + ], + "choice": "provider:priced", + "why": "the route the job names, which meets its contract (1 of 14 routes)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": { + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": { + "amount": "0.09", + "currency": "USD" + }, + "kept": true + } + } + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "570d84bcf61e55b373c25a03553030a89db2c0ef10d74743b6b4cd98ab5559ee", + "signature": "28778cfcd50fa78ac54c2ad944d0e1d2074fc2f906b0e6014177ea8c64ace8bd860c7d334bc9c3978c8f270ca6f1e0223713004d3c79a6abc675bec4e8c81104" + } + }, + "id": "pj-316b154641049d91", + "submitted_ms": 1793974079084, + "finished_ms": 1793974079087 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-deadline-unknown.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-deadline-unknown.json new file mode 100644 index 000000000..9f748ddf6 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-deadline-unknown.json @@ -0,0 +1,347 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": null, + "why": "said unknown" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "deadline_unknown", + "why": "its time is not known, and the contract gives a deadline" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "057ee039fa3589735a188c5be6890afe3007138cbb96a8222d212ba75907a45b", + "signature": "91ac7e6c6a5fa3d70d22e798efd6c816f017039b2493f23b94a8f91cbd0dbfd6bda4013f03c3b872bb55c73121e3da6293fccb780a01629aa479c573f8a51206" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-ceiling.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-ceiling.json new file mode 100644 index 000000000..1d663e662 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-ceiling.json @@ -0,0 +1,349 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0, + "max_joules": 2 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": false + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + }, + "energy": { + "max_joules": 2, + "joules": 2, + "kept": true + } + } + }, + "energy": { + "joules_micro": 2000000 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "6860ff1e28637d9941e63089ddcb18cf620d6a50b567beb59dbdfb40db534e7f", + "signature": "2b622bb4a3535ab6dfc7ba5d4f6d06b9f3bc24a6b3b0baf87f5d602516d85e2203b47e26d0119005a558ca72d9c89dd48b996f3421f5172d35a18a7f35f57006" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-stable-claimed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-stable-claimed.json new file mode 100644 index 000000000..113dbf9fe --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-stable-claimed.json @@ -0,0 +1,349 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0, + "max_joules": 2 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + }, + "energy": { + "max_joules": 2, + "joules": 2, + "kept": true + } + } + }, + "energy": { + "joules_micro": 2000000 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "4c7d92abd363a26513749c60a7482e199d2b452c9bd05ca799178cd437dd9787", + "signature": "e671dc5ba4bdf0441a4b519820c273043b9406243a617cd85ee8fbe2f5dad522eaf43f8126cdcf2e57819f5ebf6556a865c7fe4decd18f9f37762c536e3bd20b" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-form-cost-long.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-form-cost-long.json new file mode 100644 index 000000000..f3ace4d83 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-form-cost-long.json @@ -0,0 +1,343 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "11111111111111111111111111111111111111111111111111111111111111111", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "55ee6caf6d24ba3f5f48f373cafc67c43634fb6c3186f4b468a1a9852b6db726", + "signature": "002d6f760a23262c5c830722399f7c3ed0eea130423024b1c9d58847920034d2e7a4cfc5b7f339d3ad4d854646c714a6c420934b5263333d5b5ee237afc9070c" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-form-cost.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-form-cost.json index c80eb8d87..9d20f2793 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-form-cost.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-form-cost.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -181,6 +189,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -194,6 +203,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -207,6 +217,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -231,6 +242,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -321,8 +336,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "71fae81f4fd43a8a972a1d3d7882be3eeabee5f126d71dea4e15ebf9f737eaf0", - "signature": "643a541fe275e6e2e54d816f8a2e85ec2e2a3a842e56387639610e532dd931d4d06c4fd438a4a0c9a7531568c62b0e64ec43fd67c93d07b24f2e5ba499b3180d" + "digest": "87860be8844677bbe81fc4bc5f468d3f0b887364a5a1891fa24a7d4e0d70adff", + "signature": "fcb08b3a964c6b588f9c91946b3b018ae4ad030c9d25a78fed304f7b5346ed27155f3dc59f20cab7ce3304ae6f5b972f4aaa46e417685e954d4fe795cb3d160d" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-form-exactness.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-form-exactness.json index acbc6fffa..53736a0db 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-form-exactness.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-form-exactness.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -181,6 +189,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -194,6 +203,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -207,6 +217,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -231,6 +242,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -321,8 +336,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "f6717aaa6cf2471f4f1f1fd8feb78f5c40424e2ab44c92f2d620f89db39a301f", - "signature": "f1053a342c5254e962949efba3c60a53d188fd4025a16699a8ef48b6d0baa6919a96be4f2922c6c271ea447a01d1afaaf77ab87905634f3c00d458b05d518007" + "digest": "b3f71c33c30f682fc0895319593ed53cad86dd95f0c71e2db0bdd898cd6fd09b", + "signature": "8a4253390cede8e06c4182d2adcc17aee77cc7776290c1513481db034a1519f79e51cf344954a08e6adb27dd08d0bf5347d260642bd7ee99ac335975c6104f00" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-form-member.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-form-member.json index 07d2c5d29..e1ad08180 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-form-member.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-form-member.json @@ -44,6 +44,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -56,6 +58,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -80,6 +83,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -104,6 +108,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -117,6 +122,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -141,6 +147,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -154,6 +161,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -182,6 +190,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -195,6 +204,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -208,6 +218,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -232,6 +243,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -245,6 +257,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -258,6 +271,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -271,6 +285,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -322,8 +337,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "ab091fe78b35dcd45b331b340acd7a75c3382f7a75fb987fc43a76c5666ae767", - "signature": "e24ffae02a6f4953cc43031fb6ed6696de4fd5753fd6de4b4785fef577a7a27c95ec58eff3cd2ace87aa4800c1e5fae682b139bd7a7885ae33c524d9cf9f0902" + "digest": "75b5af83ba3718bc14c58925b246ffcf8eb0d4e612c869a5c4f0bb197bbd06d5", + "signature": "12d2f38abf6b02ad41a268fc02f26ee004125f2af7af0aa0bb9b31e00ecd95e9cff728c643c25a6f14bdc9d4d580c26748779d8a0ce6fe6bd5f39675e49cb70a" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-charged-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-charged-other.json new file mode 100644 index 000000000..37ba96367 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-charged-other.json @@ -0,0 +1,450 @@ +{ + "status": "done", + "method": "provider", + "why": "on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "providers": "allowed" + }, + "provider": "priced" + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "priced", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": false, + "estimate": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot", + "seconds": 0.0 + }, + "charged": { + "amount": "0.09", + "currency": "USD" + }, + "confirmed": true + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "named", + "named": "provider:priced", + "question": "counts", + "auto": null, + "host": { + "job_bytes": 17179869184, + "providers": [ + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "estimate", + "host_dependent": false, + "auto_rank": 10, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + } + ], + "choice": "provider:priced", + "why": "the route the job names, which meets its contract (1 of 14 routes)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": { + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": { + "amount": "0.01", + "currency": "USD" + }, + "kept": true + } + } + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "a65a7bb80c70d8f076174784661aba1646195d01130a38b958103a42222fa6d4", + "signature": "d03e8cf20060933bfa4c30e867a68e46f093723ec66e91f4f266a7db2273e7d38acc12664d7796400071ab1d9c22ce819a428ce4b0381745dad53fe661557f0a" + } + }, + "id": "pj-316b154641049d91", + "submitted_ms": 1793974079084, + "finished_ms": 1793974079087 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-dropped.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-dropped.json index 08601b3e9..b6135bf40 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-dropped.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-dropped.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -181,6 +189,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -194,6 +203,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -207,6 +217,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -231,6 +242,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -313,8 +328,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "119246e24dc6542284c5ab7376d15cc307a13e98ac520cfd658fe975f852511e", - "signature": "c5fc9885ca5eee5347ae682752d2d9823952330e4a092f041e1ed67598824750ae433b75b4744b4058595d3f094505c775c46937c5f9c4d8f2289e984d207a06" + "digest": "a6f83a0d5d4d1a769ba3f1e2db4d9a6417f8c00e3585d82d441257f792f71807", + "signature": "40e7022dbadffd05aae25e5a29e2065fdaf72aed50d77678e6847eab924f0606364c4854e3b5f9d63ae2b3985f3a736c27b2d4ada03cee4a3f4a449310149d02" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-elapsed-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-elapsed-other.json new file mode 100644 index 000000000..fe683604d --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-elapsed-other.json @@ -0,0 +1,343 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 1, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "8dd8959ab32364d5e927566f4e1cf77bedc26a138a998c5f84e23317ec09bb68", + "signature": "f4974d82a25391158162bef96264451f50c94542e27df98228350d1d835d42a50109e06d2b50fd0cb04d1a355a1ceb5c92152faef8c259555443b109f21e280e" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-false.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-false.json index cf9bf6db8..248fee9d6 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-false.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-false.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -181,6 +189,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -194,6 +203,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -207,6 +217,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -231,6 +242,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -321,8 +336,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "82869a465a80472bdbd217bb2f91a32f8cd0fd97d283101155a90f0a0492e4ee", - "signature": "de3767cf310fde9c09f4ede2bc889c3f7bf4113ce869c65c4dcb009cbab710fb0aa26ea1bbb08fb895f97b62341a65887ec5d805ebbf3bd624c05ecf8c41920d" + "digest": "10370223839248edc04f691d7b95d1f1b111f44c137679a6646cdffa5d5bd035", + "signature": "2dad42ca503e3fc4b3874107fa51e2b0055aea9986e6395f93d3c6b14ade5c2ccb1b5347d29357ee693619b5c382920eeb7fcafd2da569376adf61455347520a" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-member-extra.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-member-extra.json new file mode 100644 index 000000000..1aab3cb96 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-member-extra.json @@ -0,0 +1,344 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true, + "note": "on time" + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "d5ca79f464f00ecebbba3dbe80eebe2ae26ca6d9abc35fcdf2865d0bf93d6401", + "signature": "46f56f583fefffa65d114b8470465f08f659f8a4144a5ec6a8451def1d875d56cf44db95e39826809d1a93bcf8714ef7d7b792eddd470d268fcd0a08c37ad903" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-missed-stated.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-missed-stated.json index 0289495d1..80f3c05ec 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-missed-stated.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-missed-stated.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -181,6 +189,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -194,6 +203,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -207,6 +217,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -231,6 +242,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -321,8 +336,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "ee6e449631c73ebdd4024219533f775ae5b30c5b4b0a5eccbd7d760c154fe7ea", - "signature": "777fe8b49ede42a4200e0bf1b2843434dc7aa4c0b136ff4a1c2c53da0915da3e62318747b14ce73666e8a936b70e1d0cc0f9437b29ff075a0f868fc70c34c909" + "digest": "4d5f6acd75e7da2a40a36ec202607ce18ccf2256b9593fc73f25045472e7ae76", + "signature": "ae1af272a9c200ddaf1cde1925d3eb310f04e5578bf24947b799c6469b80e41673766123025df8387962e85e722458ceb50232aac8b62803a4c4a2726976b501" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-local-money.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-local-money.json new file mode 100644 index 000000000..212a2c015 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-local-money.json @@ -0,0 +1,345 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": false, + "amount": "0", + "currency": "USD" + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "34470ed056c05a01dd3fbac948ae9e73ded8d8839f601886cc36198b01f35296", + "signature": "5427089f2905d463a4b6a510c655b7b10917bac7df07f3fb4304f0056a39b30d25a0eaff2e001da8ac1386b32086c80eb75a9833c90704411ad124649bdd050f" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-memory-at-cap.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-memory-at-cap.json new file mode 100644 index 000000000..3ddccdc42 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-memory-at-cap.json @@ -0,0 +1,343 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 17179869184, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "afdfa4976b218bf5529c2e17e42dd4a824e3227a5d053c5c01765fb1da5a7d19", + "signature": "723e21cdb1b963daccdebef8adefb59f5243c0cd7355d8589cd24798e872c3cf8b5dc868ef7ebaf119b574ea608d8d72f87f8e6cfda3c70bd80a6f7d123be80d" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-named-approximate.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-named-approximate.json new file mode 100644 index 000000000..d6dcefa3a --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-named-approximate.json @@ -0,0 +1,451 @@ +{ + "status": "done", + "method": "provider", + "why": "on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "providers": "allowed" + }, + "provider": "priced" + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "priced", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": false, + "estimate": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot", + "seconds": 0.0 + }, + "charged": { + "amount": "0.09", + "currency": "USD" + }, + "confirmed": true + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "named", + "named": "provider:priced", + "question": "counts", + "auto": null, + "host": { + "job_bytes": 17179869184, + "providers": [ + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "estimate", + "host_dependent": false, + "auto_rank": 10, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen", + "approximate": true + } + ], + "choice": "provider:priced", + "why": "the route the job names, which meets its contract (1 of 14 routes)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": { + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": { + "amount": "0.09", + "currency": "USD" + }, + "kept": true + } + } + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "6e3aaf31d04fd5ebc52dd524cf1608fb19d52269ee86927a4c79a774d4955a1d", + "signature": "761cd9075407a576ed11f3df402dbf209069f9e582f5b7b9af0dc71f8cf4674a3704ebc52e49de44d4945da7fb6d40cbd1f4dc270266bb1d722c43904f548906" + } + }, + "id": "pj-316b154641049d91", + "submitted_ms": 1793974079084, + "finished_ms": 1793974079087 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-named-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-named-other.json new file mode 100644 index 000000000..376c6bdd1 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-named-other.json @@ -0,0 +1,450 @@ +{ + "status": "done", + "method": "provider", + "why": "on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "providers": "allowed" + }, + "provider": "priced" + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "priced", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": false, + "estimate": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot", + "seconds": 0.0 + }, + "charged": { + "amount": "0.09", + "currency": "USD" + }, + "confirmed": true + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "named", + "named": null, + "question": "counts", + "auto": null, + "host": { + "job_bytes": 17179869184, + "providers": [ + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "estimate", + "host_dependent": false, + "auto_rank": 10, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + } + ], + "choice": "provider:priced", + "why": "the route the job names, which meets its contract (1 of 14 routes)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": { + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": { + "amount": "0.09", + "currency": "USD" + }, + "kept": true + } + } + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "8d8b450392d362b8e348c741bb39b5780b1dfd8f5ca56737f47e7c36870a022f", + "signature": "0696feb2aadf21e318ef609eda4933b30d90696023f184ca07f7c73dce021ca61d1394aec758f1514afddf464b03e18252d55754998c6bb964ae5cdf34d2220a" + } + }, + "id": "pj-316b154641049d91", + "submitted_ms": 1793974079084, + "finished_ms": 1793974079087 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-format.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-format.json index 1bbe04055..bb09202a4 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-format.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-format.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/2", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -181,6 +189,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -194,6 +203,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -207,6 +217,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -231,6 +242,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -321,8 +336,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "a831c3bfbcd09e0603c3ef6905c94f145ae5321efc4c42942d8dfe125b11644e", - "signature": "41886b5692e81f33d0073baf504297ca0c8f5ed88a9804a658c8588f1058fb476a3e80aa10ff46fa1c1a67c0de73d43d68e8bf2f68d6e9dfcd69c2a53361000b" + "digest": "4f13bbcc213af6a5dfc672e063f3680ea4f2f0f721e0d6c98b6675289147e723", + "signature": "0aa091dc31dcc7796db33c55afe722a035fcb15ceda1acbe7918d337c25829d766f1797c91b001122996b8a15b8df46ceaf42823431096f60204f3f2888c5608" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-on-plain.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-on-plain.json index 03c0babc2..de9fad35a 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-on-plain.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-on-plain.json @@ -54,6 +54,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -66,6 +68,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -90,6 +93,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -114,6 +118,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -127,6 +132,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -151,6 +157,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -164,6 +171,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -192,6 +200,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -205,6 +214,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -218,6 +228,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -242,6 +253,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -255,6 +267,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -268,6 +281,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -281,6 +295,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -329,8 +344,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "d039ad3c5f565d444cea86061ebdad16a38a0c3d3fd70da2327196d7fade4b07", - "signature": "62ce367bb487bd7c65ad683ff1233f95d169692050d60103ab8a61f4ac7a8d91478209fb985ec024315ada1d2af77d0b0c9a7e5caf4a732de31eb9ed51144f0b" + "digest": "cdefbe5e97db7d9b037a7aec6ddd172bcd7268b2739ca6c0677c46a3c22235f1", + "signature": "7e749e768f65aa90267ad84bd416bd1d23fa01ae04213a38010ee7318baafa60c4c88cb40e3b7a447f1435669f8a16fa1b297ed74fae281cac8c0b75e85f1005" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-wanted-from.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-wanted-from.json index f7084f9fe..61dd2057d 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-wanted-from.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-wanted-from.json @@ -38,6 +38,8 @@ "format": "wai.quantum.planner/1", "wanted": "bit-exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:exact", "host": { "job_bytes": 17179869184, @@ -50,6 +52,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -74,6 +77,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -102,6 +106,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -115,6 +120,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": null, "outcome": "rejected", "rejected": { @@ -128,6 +134,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -141,6 +148,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -169,6 +177,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -182,6 +191,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -195,6 +205,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": null, "outcome": "rejected", "rejected": { @@ -208,6 +219,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -221,6 +233,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -234,6 +247,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -247,6 +261,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -290,8 +305,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "f8f9ab0572ff3f5534db507f92d7363b351052594244dca8b8ddc51d579ba27f", - "signature": "02a26c78553fd52a9a356930229cb86daef30cf2bfdf224026acbbf83aa88130cf8126830b479fdcf5733812fdf3a6c852f9637700583920e60a8da4e7e50d03" + "digest": "7d9cda3a348962cb6acd009275760b82288d9ac4e75ff94a7956b5c2bc0b2378", + "signature": "74d566c7c7397c303cc429d9fd0de1b884fdc3f528729fe55ab7106aa83d57b063e1dbf4120dcc091fc6451d838597288444804dab8ac89630bb87242bea090a" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-wanted.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-wanted.json index f02e52b98..992671a4a 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-wanted.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-planner-wanted.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/1", "wanted": "heuristic", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -181,6 +189,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -194,6 +203,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -207,6 +217,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -231,6 +242,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -321,8 +336,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "884e03b6ed7d9f4e823cbd913ab1f9dc853c0cf4fdf37e1cf196e425bd0a3c96", - "signature": "8d92165b05fe57a7be73fc53311fdd61aaa4259e3887001f4ca75453730a1ab92e67970a48262143fc9bec0f2d4524a754ba359ae204c3b0e7d7867da28f9607" + "digest": "92cf9b69f493f54742138a83febee1a9366d765301d9f77c1cf75d8c50c61fbd", + "signature": "4959b8a99e9c11fb8c3e68a342d1e20b315b9ca9172badda54818d6dc65c1cd96c8b7211494539f25ab08ef4c752a2d13b39d7a50454b8bde9918f37b8e05f0e" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-price-amount-long.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-price-amount-long.json new file mode 100644 index 000000000..8222de6cd --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-price-amount-long.json @@ -0,0 +1,544 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "11111111111111111111111111111111111111111111111111111111111111111", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "95675d2db7469f09ea93183572f7b02549d1b6ab8fb9a73d7c00424d2867d115", + "signature": "0f1b72780bfcaf25fa169581b8a4c634d288e17f76e86ee7bbcc368476d53afd8f2b115cd8ae6f3d32321454d1ce52ddfaca6b050328aa6f41a851b93fad0c0e" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-price-seconds-past.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-price-seconds-past.json new file mode 100644 index 000000000..b38dbd4b1 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-price-seconds-past.json @@ -0,0 +1,544 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 10000000000000.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "19c76e2aeade97d303576afa32e55f3e1de7439b0a0757dd101c1a6754bc9fc9", + "signature": "30b1568f0f5e9579053b2ebf4d97f278300625d612a10e4487c5b1f8770a0599eb8729589eda4a3bf4596859f985683e7c6ffd6382f5c8c62ebea1fcde6dcd08" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-named-not-allowed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-named-not-allowed.json new file mode 100644 index 000000000..5b1ca67dd --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-named-not-allowed.json @@ -0,0 +1,449 @@ +{ + "status": "done", + "method": "provider", + "why": "on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "max_cost": { + "amount": "1", + "currency": "USD" + } + }, + "provider": "priced" + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "priced", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": false, + "estimate": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot", + "seconds": 0.0 + }, + "charged": { + "amount": "0.09", + "currency": "USD" + }, + "confirmed": true + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "named", + "named": "provider:priced", + "question": "counts", + "auto": null, + "host": { + "job_bytes": 17179869184, + "providers": [ + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "estimate", + "host_dependent": false, + "auto_rank": 10, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + } + ], + "choice": "provider:priced", + "why": "the route the job names, which meets its contract (1 of 14 routes)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": { + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": { + "amount": "0.09", + "currency": "USD" + }, + "kept": true + } + } + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "238ae4cd6d408880508a6c0083dae60bb35337226437ab6d389b092b78ff54da", + "signature": "7e209f3646e47be62fafba59a38625316775d78d65e4dc4ae750ef9d190525ec00b1205772713d0625227876e0b55c0ac230b7105bc6169d55667373ad04b201" + } + }, + "id": "pj-316b154641049d91", + "submitted_ms": 1793974079084, + "finished_ms": 1793974079087 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-not-chosen.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-not-chosen.json index 5dcfaebf7..c5da8f44d 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-not-chosen.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-not-chosen.json @@ -103,6 +103,8 @@ "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -118,6 +120,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -146,6 +149,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -174,6 +178,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -187,6 +192,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -215,6 +221,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -228,6 +235,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -256,6 +264,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -269,6 +278,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -282,6 +292,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -310,6 +321,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -323,6 +335,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -336,6 +349,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -349,6 +363,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -511,7 +526,7 @@ "denominator": 600, "total_variation": 0.07333333333333333, "hellinger_fidelity": 0.9946222222222221, - "sampling_tvd_expected": 0.032573500793528 + "sampling_tvd_bound": 0.04602751441903442 }, "elapsed_ms": 0 }, @@ -519,11 +534,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "d6dc7de2013037b505a6faa67cac125da65f771e092e231452342b00cca3fc1d", - "signature": "3cb0f49862ab18e91dd8b3917bdad3139ec2762a1c69ac719779b23f99f6d23500d70d98c78c0c8c65255e0e38d0fa25335464d26fe49b6c28787b3c69ce5a0d" + "digest": "106a024ec66679717d951e9a841a6b6f10469238811d31ff7587bf964221752a", + "signature": "26c1542acd6cb9632be2a885b34be090840761a8658df4965ea73bff805ad5af76487485445be454c365ce564af2ded296a1f3e70ac01f0e195794e8f739f701" } }, - "id": "pj-ef8b7cfb5f9601bc", - "submitted_ms": 1793951019912, - "finished_ms": 1793951019919 + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-providers-not-allowed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-providers-not-allowed.json index 4eab468ec..86c2c50c9 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-providers-not-allowed.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-providers-not-allowed.json @@ -102,6 +102,8 @@ "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -117,6 +119,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -145,6 +148,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -173,6 +177,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -186,6 +191,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -214,6 +220,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -227,6 +234,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -255,6 +263,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -268,6 +277,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -281,6 +291,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -309,6 +320,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -322,6 +334,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -335,6 +348,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -348,6 +362,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -510,7 +525,7 @@ "denominator": 600, "total_variation": 0.07333333333333333, "hellinger_fidelity": 0.9946222222222221, - "sampling_tvd_expected": 0.032573500793528 + "sampling_tvd_bound": 0.04602751441903442 }, "elapsed_ms": 0 }, @@ -518,11 +533,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "a3ced2e7936b178a2174356f0534202354e49489151e323e4e784d27db6117df", - "signature": "f920de7a55b724ea1839630afe558d81b0c2f8fbe5637ecb7306da98c0c3aac24224140f00227a82f7443bb6c703f22a1627d32e557777976cbc2ee8d3268f07" + "digest": "efcb8e61a35a909ee4ef4add3edce0131fb6c79e6a74daa72407f6932e1bba83", + "signature": "82af7c4478995abef9e4f12222f81b956c90a45a666a9b4168d11187fc22158a24d7a52eeccf2e6021e3f50c1c16e00210ed03d7d44297924dad2b0bf427600e" } }, - "id": "pj-ef8b7cfb5f9601bc", - "submitted_ms": 1793951019912, - "finished_ms": 1793951019919 + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-question-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-question-other.json new file mode 100644 index 000000000..10f35a080 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-question-other.json @@ -0,0 +1,312 @@ +{ + "status": "done", + "method": "exact", + "why": "bit-exact state vector of 3 qubits; what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)", + "estimate": { + "memory_bytes": 134218112, + "work": 40 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[3] q;\nbit[3] c;\nh q[0];\nt q[0];\ncx q[0], q[1];\nrz(pi/8) q[2];\ncx q[1], q[2];\nc = measure q;\n", + "shots": 500, + "seed": 3, + "contract": { + "deadline_seconds": 600.0 + } + }, + "result": { + "method": "exact", + "qubits": 3, + "gates": 5, + "accuracy": { + "class": "bit-exact" + }, + "state_hash": "5f1ae3e98c0555290986daf0d573de16a34ba01d1993f13f134e0b1daf6f1ab5", + "counts": { + "000": 254, + "111": 246 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "bit-exact", + "wanted_from": "auto", + "named": null, + "question": "amplitudes", + "auto": "method:exact", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2e-07, + "basis": "nominal" + }, + "memory_bytes": 134218112, + "work": 40, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 268447588, + "work": 40, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants bit-exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants bit-exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.024723456, + "basis": "nominal" + }, + "memory_bytes": 270794752, + "work": 16482304, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants bit-exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants bit-exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants bit-exact" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants bit-exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants bit-exact" + } + } + ], + "choice": "method:exact", + "why": "what auto picks, which meets the contract: the contract names no class, so it keeps auto's (1 of 13 routes meet it)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "d859d0ec175157bdd2b0e221a569afd4d2d94e347cbd550027c714ab35bdb061", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 600.0, + "elapsed_ms": 0, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "284244ed02df6c6f31e2bc4ed41553bb04d1878f6c38c14c4186941a92c76db7", + "signature": "db84d76890b160ac506199f085ceb9cd753aabea3d25395a41f07acc1155b029f66e1f835947ed1d4bca5dff1ca588b65d8c82146d90ee96c03038f42464c201" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-claimed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-claimed.json index f160e195c..014d5e0c8 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-claimed.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-claimed.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -177,6 +185,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -190,6 +199,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -203,6 +213,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -227,6 +238,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -240,6 +252,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -253,6 +266,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -266,6 +280,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -317,8 +332,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "720107c633699bc992b3830fd8c0e92a50e6ca4b87f4c0eceae955b7950ae223", - "signature": "3be5edb0f101648c0ffb79da1a674fa37241c8deee0614efda868aba617213742f51226791c5f06582da34cc2eb647ed1f58c45702d5a7e47943fe690e71e40b" + "digest": "f6695d9e18b8a7defbd23c1bbf45569fb661d8feb125c2049b55d6c803ab6238", + "signature": "35c23ba2e245b387b55540b386604d6ea485c33c44bdae1c1e2f848979287cfa83862b55170a6e49ed42facdea3496529a4bab166db5942f347b43ce70988d00" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-code.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-code.json index 55fc4b192..2b16c2d57 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-code.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-code.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -181,6 +189,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -194,6 +203,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -207,6 +217,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -231,6 +242,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -321,8 +336,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "f2d94d45853c5fc84284b2294081d6035c86869d9de36c0e3a6d1d5da234e916", - "signature": "cd22da5ca864240a12224b8dfb701814b4b2e0fac0b29cfb3850c35c7aaf194707cb94a07af57176fed8e3e60d738b6ed47f61e15e852b21e1cf5fdf0fa8f00e" + "digest": "71da1746a71c876b9b5263ebafec511337f3d864007f416b03ff443793388afe", + "signature": "cb1dca70e379cca904a26b56a401aa6a308676055e64a8de730c350df482e2f277a527205e77c76a908909e235ee6b547862ea4ec1271d98e68bd04f7c65530b" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-price-memory.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-price-memory.json index 474c29720..2580901f2 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-price-memory.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-price-memory.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -181,6 +189,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -194,6 +203,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -207,6 +217,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -231,6 +242,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -321,8 +336,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "f78c0dc9f3942eec1591f227a653caf024682a8f9bc9db8bed8758782bb190a4", - "signature": "b31ff76f9abd1fca7d0301ca92948c6f97f7362dd016579bd8e0d1415bfa6bc12c2719734d0799551a7b9edc024f49b8423fd1e4e60827744a44a0af105fb10b" + "digest": "8cf1491e17a9146e045da96684b36836c097415f58ce004da2c5367666dccc33", + "signature": "8187b36ffb9a74327eb6bd8cda5917404f8adadf468a62b36cc584ad3cd413e8909cadf661b6c5de8de6a0fb294e78f5ac4485ff21cc2691042bcddb1468760d" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-price-work.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-price-work.json index 49368bb1c..65f042b97 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-price-work.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-price-work.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -181,6 +189,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -194,6 +203,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -207,6 +217,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -231,6 +242,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -321,8 +336,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "656c7320f73afc62b7ba8b0ccbf2bfa5ae4b2cfc811d5933c78a05ec733223cf", - "signature": "e0e933b4a15a3b45dab2094749835eb24febd0bd6decdc3e33dc1d55dd564c7b05a0efbfc70804a74af54d919891d22e20212eac8b083205826a41a603c59103" + "digest": "6be0a80d6b7382e1026691f03a808ed07946d20ff850a63b7b898916309b175c", + "signature": "5489756dfcd671ad099dc88f3739bc19e0d273448092e20070b409bb12f26f23db59fbd45bd11f0ed2f6426dbe05bd8e3abb7e7eb3e17152462d5debdada410e" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provider-claimed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provider-claimed.json index 7b9b1ca43..5146700d4 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provider-claimed.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provider-claimed.json @@ -103,6 +103,8 @@ "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -118,6 +120,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -146,6 +149,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -174,6 +178,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -187,6 +192,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -215,6 +221,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -228,6 +235,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -256,6 +264,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -269,6 +278,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -282,6 +292,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -310,6 +321,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -323,6 +335,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -336,6 +349,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -349,6 +363,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -507,7 +522,7 @@ "denominator": 600, "total_variation": 0.07333333333333333, "hellinger_fidelity": 0.9946222222222221, - "sampling_tvd_expected": 0.032573500793528 + "sampling_tvd_bound": 0.04602751441903442 }, "elapsed_ms": 0 }, @@ -515,11 +530,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "722f6b1be18e58ff3fb491046e9c78bc372286f2941b152623ec680f1bb4cbf6", - "signature": "3aeaeabe49c9cfcd7d850c74733969de0d8f8fdde6633716d2949a23320e65e70dd76f957fd309a528ec4db368e20c6d0af15aafc69d7fa82ef1d0ce9b1e1501" + "digest": "90279f3317f606c223b9d0036ab8ba38543630d144bee86ac73da6946190348a", + "signature": "b0979f55f6410a2557aaacc4cd7fec407311861d761e04f6679030d759be8504252f09747c3e0b430082bdab044e79aad443d3b48fc336d6ea25fb5fa25b6c00" } }, - "id": "pj-ef8b7cfb5f9601bc", - "submitted_ms": 1793951019912, - "finished_ms": 1793951019919 + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-bound-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-bound-other.json new file mode 100644 index 000000000..ab13d4430 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-bound-other.json @@ -0,0 +1,544 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.01 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "139bebf92be7a7871cd2c87f0907a3b99185a45e454c7b703e3be932de34b512", + "signature": "411241bb7b7dcda3797437f02a7b4386954e306b33b3a1ffda7da183d3bd8a4ac6af2b8cd72409d3629d076af9ee6e8a2d4186431b61a845957ff3f109e93a06" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-fraction.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-fraction.json new file mode 100644 index 000000000..e54d29b8d --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-fraction.json @@ -0,0 +1,544 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 160.5, + "11": 139.5 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "06ded9f40cbc79002c4a5e0b38886b91ff2e0c4125d07f7887dcbd26825dc745", + "signature": "121390ef6e78d718c930f8d2ddc0ade35e88f90de72b3e904b9ec74ff6af39118c2fedaf46568daa3ab8435cba12cbb11b22920f55e207792bc44d8ee3166e0a" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-short.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-short.json new file mode 100644 index 000000000..ad5443ad0 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-short.json @@ -0,0 +1,540 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 1, + "distance": { + "computed": false, + "why": "a shot is omitted" + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "0bb468ef63f91978029f98f3a27f85c1af2fb879b6376f2624e9987e2aaaf1c9", + "signature": "61523dd3b3a93da79bca41d411e494e280293f3b73d3b12862a8d7dab30b0af19419128a10af408513e9f0925455a281de94215357b1bb19c3dcc8b1fd9fbf01" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-sum.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-sum.json new file mode 100644 index 000000000..f654dbd8c --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-sum.json @@ -0,0 +1,544 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 162, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "5a71d7b2f95d9e8177322ec62edb700e6dbbdcd6ef31589c846c4fbda66e41df", + "signature": "769872dc617089401cd5e5610b1f84548ae8db33a1078edc93e9ecce88dbdba31c7214a7230be6d2e3e7c04379ab2602ba93f9b0d3343ff8582f69f9866f3405" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-missing.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-missing.json index 4c2c908b1..a4b096f65 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-missing.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-missing.json @@ -103,6 +103,8 @@ "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -118,6 +120,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -146,6 +149,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -174,6 +178,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -187,6 +192,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -215,6 +221,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -228,6 +235,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -256,6 +264,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -269,6 +278,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -282,6 +292,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -310,6 +321,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -323,6 +335,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -336,6 +349,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -349,6 +363,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -490,11 +505,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "211b603f5d02256ed9c67ff118282180804d8612ebe90b7875b521b7cc6176f8", - "signature": "2fe2e24c206a73eca6fb008e21f81c097ce94a997829aed2a28c6cc4a587fd166b515bfa645599c052100a8baa2e12bc250d65a92bebaae90a482cccc8c1050a" + "digest": "13d9ed31dd4b470c0faa8860f4f4c7204fa57c31f15ecab5143370880e91cead", + "signature": "51c78059c14776ec04d14e98349c8155e33b304bdf747cf023211c8abcaf206bb89a963eee1369e13b0f250570d951f0337562636dc4b39178513ec001ba580f" } }, - "id": "pj-ef8b7cfb5f9601bc", - "submitted_ms": 1793951019912, - "finished_ms": 1793951019919 + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-not-computed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-not-computed.json index f0dd925da..b3355c23f 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-not-computed.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-not-computed.json @@ -103,6 +103,8 @@ "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -118,6 +120,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -146,6 +149,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -174,6 +178,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -187,6 +192,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -215,6 +221,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -228,6 +235,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -256,6 +264,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -269,6 +278,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -282,6 +292,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -310,6 +321,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -323,6 +335,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -336,6 +349,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -349,6 +363,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -515,11 +530,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "6d8d745f5fbc1b3c2e22eba7cd306fa768fbe9ba08ee9ce6473607dd6390708f", - "signature": "d94f156c26ddde59445b3cf733d768b281748d5ea308e0192a73e95b28db696f6b4fd2cc4343c67c5dc1d93f3fa35afaa0ff63d3353e23e2337eb77d1cb5b20c" + "digest": "379d167b6c8baefa93b39036b5be13abd1da2d0b6ed601b824d7ae2a0ea8cd44", + "signature": "f71eed95f50de214b1ee6daa2166d2fe0eef384b54f12dea260d7e2c20e3f41214c2a76577c5cb0259a6215149ec3b13d5eeac57ec610e4cd160f480953e8708" } }, - "id": "pj-ef8b7cfb5f9601bc", - "submitted_ms": 1793951019912, - "finished_ms": 1793951019919 + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-numerator.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-numerator.json index 2cb2ea80e..376180000 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-numerator.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-numerator.json @@ -103,6 +103,8 @@ "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -118,6 +120,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -146,6 +149,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -174,6 +178,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -187,6 +192,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -215,6 +221,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -228,6 +235,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -256,6 +264,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -269,6 +278,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -282,6 +292,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -310,6 +321,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -323,6 +335,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -336,6 +349,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -349,6 +363,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -511,7 +526,7 @@ "denominator": 600, "total_variation": 0.07333333333333333, "hellinger_fidelity": 0.9946222222222221, - "sampling_tvd_expected": 0.032573500793528 + "sampling_tvd_bound": 0.04602751441903442 }, "elapsed_ms": 0 }, @@ -519,11 +534,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "7722d0ee7dbbd9f8aaa64c11bcf3b1274468dac372b54e3b0b56b1fb893e90dc", - "signature": "738fa5783c0651d7f9c8d85efea3024367758af1cbbded44a4370dddfc3f093d23df8c4296e61bde45fb571deeb2479da1f181c1e75888fa243dcb8ed7f9750e" + "digest": "8b8c5a84ab1a5c0076b992e4929d6397cfa8ee55899bd39109277b3700cc39f3", + "signature": "7a243c18b9d1f35053dbeb1ecda4449eabbdc828cf9e413df572544439ed2c4d411b6fb5b3790fad9a97ef181ad561c421438c09a20cd52174b705d294841606" } }, - "id": "pj-ef8b7cfb5f9601bc", - "submitted_ms": 1793951019912, - "finished_ms": 1793951019919 + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-omitted-spelt.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-omitted-spelt.json index b292d78f2..b2026ea76 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-omitted-spelt.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-omitted-spelt.json @@ -103,6 +103,8 @@ "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -118,6 +120,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -146,6 +149,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -174,6 +178,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -187,6 +192,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -215,6 +221,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -228,6 +235,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -256,6 +264,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -269,6 +278,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -282,6 +292,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -310,6 +321,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -323,6 +335,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -336,6 +349,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -349,6 +363,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -511,7 +526,7 @@ "denominator": 600, "total_variation": 0.07333333333333333, "hellinger_fidelity": 0.9946222222222221, - "sampling_tvd_expected": 0.032573500793528 + "sampling_tvd_bound": 0.04602751441903442 }, "elapsed_ms": 0 }, @@ -519,11 +534,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "43a1345cab6a823054aad8325eeefac68c7a6bb8a6aedf5942d517bfbd697a26", - "signature": "e2c4edbd35b960bbe83427a8949916b12d0dc16978a8dd142ae10426054d54f68a9e9e0ac70c65ba4ab170134cf6dda56998f4a9ad271e9c86dc9e4115985d00" + "digest": "71770ed37d2687b9f97392667c58c80a80836d6852619f0498aa1dcfec9e4996", + "signature": "ffe2160d7de0f0939ebb0146de12a9617976cff8049ab415f5ce85b3964cf66cdc3a3f216926f69820f2b6d9d4ebe0b206442d1e6aac5931bf27d2808671e508" } }, - "id": "pj-ef8b7cfb5f9601bc", - "submitted_ms": 1793951019912, - "finished_ms": 1793951019919 + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-on-local.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-on-local.json index d65b33098..6b9d94a65 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-on-local.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-on-local.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -181,6 +189,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -194,6 +203,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -207,6 +217,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -231,6 +242,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -326,8 +341,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "312383afaba8a8466195d2a49f4c924694060996e544d87ab736bb659f9f0610", - "signature": "621fa3c6e86aa8c380e8becddfe6c73b4fed2f0445e508dbad06558f137e3558290146a991258bdd5a6b26d3bcafa63d26ec3250fa4ba481bed727225d07ad09" + "digest": "cf0132dbb0ef03db8cc2e383293922a4f360da9407170d3f6b80c82fcfb5feaf", + "signature": "62c27500f57bd70edabb88b6efed23d8d61c6ff6a7e7341e81138d579367187ba93ffaf17526223b90b5adb7ff707ef5cfb600fb55f6613eecdc6a6ce9f05401" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-budget.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-budget.json new file mode 100644 index 000000000..df4cd21d9 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-budget.json @@ -0,0 +1,544 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 299, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "82f19196eb1672c60150b757be1d749c84d877865130f3636646a275bbcdec4f", + "signature": "2fa03a7fb3a161d62528cf23938b754ff608314ddbbf2467e0c3c35ef17b79a1f54814e2b55f147f67b111b335739207b2b9f70fc066ceaa7206d8a7f862560c" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-class.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-class.json new file mode 100644 index 000000000..90ec91c9b --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-class.json @@ -0,0 +1,544 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "heuristic", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "496936d31fb2b0336b14d3b4d9e3cdcfcb1236707573d3f35b698b6cfa953b98", + "signature": "ee2d077e5bc1cb4d5a6aea31a46f35aafcdcdb5e1f5163afab7bab014dc48a5c3500f098abec81f51ecf5a785e35f8cac241eef8a45f7880deaf23d469ff760d" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-code.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-code.json new file mode 100644 index 000000000..03b2e6c41 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-code.json @@ -0,0 +1,498 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": null, + "code": "failed", + "why": "said so" + }, + "kept": {} + }, + "shadow": { + "ran": false, + "code": "failed", + "why": "said so" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "ab26c9537e838cbc6a9c9644e4c58d5b2ede4f59ffa6b98f907312f9b161d719", + "signature": "7b5228b3e105f8ed38f98a9d1412d64bfef5d99a6755113ca387204ab6c7f17767745240a3a6c427cc72d633106681481b7ad1b81277f8b9f7f614156d41440a" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-missing.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-missing.json index e9d453d02..84477101a 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-missing.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-missing.json @@ -103,6 +103,8 @@ "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -118,6 +120,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -146,6 +149,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -174,6 +178,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -187,6 +192,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -215,6 +221,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -228,6 +235,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -256,6 +264,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -269,6 +278,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -282,6 +292,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -310,6 +321,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -323,6 +335,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -336,6 +349,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -349,6 +363,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -484,7 +499,7 @@ "denominator": 600, "total_variation": 0.07333333333333333, "hellinger_fidelity": 0.9946222222222221, - "sampling_tvd_expected": 0.032573500793528 + "sampling_tvd_bound": 0.04602751441903442 }, "elapsed_ms": 0 }, @@ -492,11 +507,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "d563171591a0c70640883efedd6bbe698b25aaa291555e1b05a440644e96f0a2", - "signature": "321f9cde669ff900364826058dc920860ce0d87ae80538a03453dfac77cb80aa808f69aa894134c3855fc0cb9ae7e8219455ec00fa3adeb02d0dc4d07f8e2e05" + "digest": "99ee8071a7053f185308369d7c2d3053fb48be1810bae3620b9db18309da112a", + "signature": "186f1fa8390f69975387fc83797ee1963ad245d24ea675414138677d06935f15af6c6542732d04deb6178229799e3bb23436b6fcea985cf5d2cb6e87e6d5b905" } }, - "id": "pj-ef8b7cfb5f9601bc", - "submitted_ms": 1793951019912, - "finished_ms": 1793951019919 + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-price-over.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-price-over.json new file mode 100644 index 000000000..72c998a1c --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-price-over.json @@ -0,0 +1,544 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 301, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "cdb68c5f54a38f3cda0086b77cd3a17bd34d386478bc76e6eb31baab8f8444da", + "signature": "b863211c9e7458ec68c9fcf394bb164c94cb0b03633f3b2fa23fe3ad94737c329b4e27eb1bb54a84dcdda341b87d1f91cc4bb3393ea17743ae9e38d9a6e72903" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-route-absent.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-route-absent.json new file mode 100644 index 000000000..e4da858ec --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-route-absent.json @@ -0,0 +1,497 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "code": "none", + "why": "said none" + }, + "kept": {} + }, + "shadow": { + "ran": false, + "code": "none", + "why": "said none" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "374eae4f0b7be3a9abf7d6b273f986b3836d5f81b3a0093ffe393b8759afd315", + "signature": "60c49731de91da7900db1c82c0428391866e50d63a0dbdd05a18a5baf17c072e7007657c522d77812c66a2639df213dc4b44bca5782e2577d7f50f8d2e4fc907" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-route-missing.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-route-missing.json new file mode 100644 index 000000000..6bf9b0ee3 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-route-missing.json @@ -0,0 +1,543 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "20bf264048dfc3730c5005b0f19dd228b7e47b1cbb8c24f963d233472eff5433", + "signature": "d4e6431979ef31a25be0ca0abfbbabb923da30b3f2cc5d06b1b4693b124d169da0a250b0df1d745e253ddccc2d90ee006514aa4160425d005e1fbeba79c6bb02" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-request-extra.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-request-extra.json new file mode 100644 index 000000000..5eac71ba8 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-request-extra.json @@ -0,0 +1,550 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact", + "noise": { + "depolarizing_2q": 0.2 + } + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact", + "noise": { + "depolarizing_2q": 0.2 + } + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "9780bf1d6ba03584d20f5dbd238710bd569290fbb350d0c9fb5bb429f90cd92b", + "signature": "c1c439c39fea7343ce0ea8fa3d004c33cca34caa82431adc0292acde520f72f8b5e91852664986c49e42e95b3e391a62fef5a1f354a3846680fc00125bc0c00f" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-route-missing.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-route-missing.json new file mode 100644 index 000000000..394b253fb --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-route-missing.json @@ -0,0 +1,543 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "f444295186577e690c802c357da08d2f36288ce28bf5bf816092d08b5aa90731", + "signature": "b2485daa7cb1ff6fdedaa0ca71c61d9cb01a9b2248e97c67fb69157ba1d49a75d6b30e19884db85f55fcf69c2ec78c12fa625d61f0bd282d159d07d733095a03" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-route-provider.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-route-provider.json new file mode 100644 index 000000000..85bc1ce98 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-route-provider.json @@ -0,0 +1,542 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "provider:ref", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300 + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "provider:ref", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300 + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "8237aa60f386c5de8997854a2dafa89473da27c795e662b9e3e03353fdc988cf", + "signature": "c3b623c0b6013d644db0d1b4eacf368373e7a75f50e7d9a771933d22d1c2ff0f38a3ea8b69668e671e3009022a8a37f4b91745e41598e562546d0fb7d4c71208" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-failed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-failed.json new file mode 100644 index 000000000..22113ce14 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-failed.json @@ -0,0 +1,520 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": false, + "code": "failed", + "why": "the host says it failed" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "d4acbe130f23abff038dafdd2badadb3b55a0a508ee15cf2db1066dc24c97358", + "signature": "e6dcf4695c5e903911ba37897aa518690059b4b0bb166a24d50bd0466f99baa8fe86e3c457f5b49fd85d513ffefe94f3e44514d1d2afac31854628c4f6b56300" + } + }, + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-none.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-none.json index 9f7c007b6..bdd823869 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-none.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-none.json @@ -103,6 +103,8 @@ "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -118,6 +120,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -146,6 +149,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -174,6 +178,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -187,6 +192,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -215,6 +221,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -228,6 +235,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -256,6 +264,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -269,6 +278,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -282,6 +292,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -310,6 +321,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -323,6 +335,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -336,6 +349,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -349,6 +363,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -495,11 +510,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "b9535112e12c8dba74cbe248f0895cbed527ebf801fb2d8bc8c6bd4706e9cf81", - "signature": "aebd1b19a617395ebb6277c540860d0d72be04dbdd24c6c986aa5eac34fee93455e1f5588119e8aa7f5734729b2109306aadc9d922bcc5ae64f07083e320200d" + "digest": "db1833bba02f01d09ad14e8199dede5bf1387ab7c14f3ebecad33649b36c56d5", + "signature": "bcbcbd47d2cb90720e376de4dd53526f65ab41c060e2bdc07d44d5adbe5e5ed364cf5a42e41de7d316403548ecf7d33a22a4bb9cc6a1fa55985eb6e141b22207" } }, - "id": "pj-ef8b7cfb5f9601bc", - "submitted_ms": 1793951019912, - "finished_ms": 1793951019919 + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-seed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-seed.json index 2f01abe46..75cb2f582 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-seed.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-seed.json @@ -103,6 +103,8 @@ "format": "wai.quantum.planner/1", "wanted": "simulated", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -118,6 +120,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -146,6 +149,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -174,6 +178,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -187,6 +192,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -215,6 +221,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -228,6 +235,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -256,6 +264,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -269,6 +278,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -282,6 +292,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -310,6 +321,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -323,6 +335,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -336,6 +349,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -349,6 +363,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -511,7 +526,7 @@ "denominator": 600, "total_variation": 0.07333333333333333, "hellinger_fidelity": 0.9946222222222221, - "sampling_tvd_expected": 0.032573500793528 + "sampling_tvd_bound": 0.04602751441903442 }, "elapsed_ms": 0 }, @@ -519,11 +534,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "8d51d7db31462977aae7bc2369bd9e79327f7d694c5964b5b61380ecb11a2911", - "signature": "1b93b284f9336df24ced3bf08880cd21edcd2e732f8dcb600dd5be49f497006e04afb07aa7e7b3e2df0683046a32dfbe76dfb8fff0b6e6aa0b6e35da2c517e0f" + "digest": "d38df36251cec0073639413fcdc0d980a9ff855c264147735acc771e1c9c01d9", + "signature": "d58f23d423b717248aa8ec599e3b50554214ffa7d5d6958af6ce56da4defe68bfd604c2ffce733a6da7bbcf3169acb11ee72cb8e1ab6a730130b90b6c75c4e01" } }, - "id": "pj-ef8b7cfb5f9601bc", - "submitted_ms": 1793951019912, - "finished_ms": 1793951019919 + "id": "pj-fc95adf1a5d6f2a3", + "submitted_ms": 1793974079041, + "finished_ms": 1793974079044 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-stable-choice.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-stable-choice.json index a045aa5f4..1ca6c0736 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-stable-choice.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-stable-choice.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -181,6 +189,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -194,6 +203,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -207,6 +217,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -231,6 +242,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -321,8 +336,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "bf0e784f75354b4deb8a2eaf3fba0e03df5e352ea4865a3ee812c40cf0409201", - "signature": "31972adecacb1645a11305284c4bdaffa39d2d6b38479608065c99059e5123435a15a43a6c36aa15851b8efda0686746393a5022340586cce25bd3f2ad9c8c0c" + "digest": "27d48e6f95f8e1f6410b97f3bc261718f2d25039c8bb06bb10b07dc7a73da472", + "signature": "ca040d0f1a083911779b78a943317f0abc8b2b004348493100581aa05094185fa55c6f5452c87f4807571a1aa16890dfc721aedc8f7f0afde7a11ea917a45408" } } } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-stable-digest.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-stable-digest.json index 3eded6575..f41ace051 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-stable-digest.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-stable-digest.json @@ -43,6 +43,8 @@ "format": "wai.quantum.planner/1", "wanted": "exact", "wanted_from": "contract", + "named": null, + "question": "counts", "auto": "method:stabilizer", "host": { "job_bytes": 17179869184, @@ -55,6 +57,7 @@ "method": "exact", "class": "bit-exact", "host_dependent": false, + "auto_rank": 20, "price": { "money": { "free": true @@ -79,6 +82,7 @@ "method": "statevector", "class": "exact", "host_dependent": false, + "auto_rank": 30, "price": { "money": { "free": true @@ -103,6 +107,7 @@ "method": "statevector_single", "class": "single", "host_dependent": true, + "auto_rank": 40, "price": null, "outcome": "rejected", "rejected": { @@ -116,6 +121,7 @@ "method": "stabilizer", "class": "exact", "host_dependent": false, + "auto_rank": 10, "price": { "money": { "free": true @@ -140,6 +146,7 @@ "method": "pauli", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -153,6 +160,7 @@ "method": "mps", "class": "heuristic", "host_dependent": false, + "auto_rank": 60, "price": { "money": { "free": true @@ -181,6 +189,7 @@ "method": "stabilizer_rank", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -194,6 +203,7 @@ "method": "tensor_network", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -207,6 +217,7 @@ "method": "cutrank", "class": "exact", "host_dependent": false, + "auto_rank": 50, "price": { "money": { "free": true @@ -231,6 +242,7 @@ "method": "cutrank_single", "class": "single", "host_dependent": true, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -244,6 +256,7 @@ "method": "density_matrix", "class": "exact", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -257,6 +270,7 @@ "method": "trajectories", "class": "estimate", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -270,6 +284,7 @@ "method": "pulse", "class": "bounded", "host_dependent": false, + "auto_rank": null, "price": null, "outcome": "rejected", "rejected": { @@ -321,8 +336,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "0bf2e99293ac7a30c14a42859bff04f66284a9842e830875d07e99a7e4ae7eea", - "signature": "552cf92128cf9c50b5090d2bfabb0c3cd40e3ce3c4774297d7f162842d39f676e2701a09adf03cea0da9a76ff153189f6429be1a524f66d0c11a83f47267f205" + "digest": "ff5a62adad1da042c06a3765383a7e0d71238f44f2337a61d5d017ef58c097a9", + "signature": "991dd5b2ffc95a1cdcfad1439e891989eb3945d5f0fbd0a507a3c3b9e4f20e419187847634b4f9386dde61ecb4c42ddc9f18de66bc922d0d3a4453b559c4ff0d" } } } diff --git a/wai/quantum-conformance/receipts/made.lock.json b/wai/quantum-conformance/receipts/made.lock.json index 2d0f72d6a..bfb2263b5 100644 --- a/wai/quantum-conformance/receipts/made.lock.json +++ b/wai/quantum-conformance/receipts/made.lock.json @@ -1,5 +1,6 @@ { "cli-compile.json": "1afbddc31dd54eb98a28df16b472769b5e6b12915d8cc72eb5d0093cd8c29593", + "cli-contract-any.json": "f94b7119043951dc6b30be599cd3a6b3d34c897f04531b3cd70d0abb145735a1", "cli-contract-auto.json": "6844a85707cd18e1cf9038cde4ddc0bdee8e9d861d65fd11a6340c69e416ecbf", "cli-contract-bounded.json": "6a0d2e10c024f4ae8ffc185d800d7fd507dd30b24e0c52b4f5d01f0453298a47", "cli-contract-fabric-cpu.json": "61ce33ef961b5f2fda544834743484debc8d687f28644fc614b82d930f96932a", diff --git a/wai/quantum-conformance/receipts/manifest.json b/wai/quantum-conformance/receipts/manifest.json index e6409dab0..c4168c785 100644 --- a/wai/quantum-conformance/receipts/manifest.json +++ b/wai/quantum-conformance/receipts/manifest.json @@ -7,12 +7,30 @@ "made_by": "made", "what": "the command line: a compile, its certificate and its receipt" }, + { + "file": "jobs/cli-contract-any.json", + "reasons": [], + "made_by": "made", + "what": "the command line under a contract that takes any class, the person's providers allowed: a free method here and a free provider tie on money and on time to the millisecond, and the method here comes first" + }, { "file": "jobs/cli-contract-auto.json", "reasons": [], "made_by": "made", "what": "the command line under a contract that names no class: auto's pick kept, held to a deadline" }, + { + "file": "jobs/cli-contract-bounded.json", + "reasons": [], + "made_by": "made", + "what": "the command line under a contract that wants bounded: a single-precision route does not meet it, and the state vector is chosen" + }, + { + "file": "jobs/cli-contract-fabric-cpu.json", + "reasons": [], + "made_by": "made", + "what": "the command line on the CPU it asks for, under a deadline: each route that runs on an accelerator rejected for it" + }, { "file": "jobs/cli-contract-local.json", "reasons": [], @@ -23,7 +41,19 @@ "file": "jobs/cli-contract-provider-priced.json", "reasons": [], "made_by": "made", - "what": "the command line on a provider it names, under a ceiling, confirmed with --yes: the estimate held to the ceiling, the charge to it after, and the shadow" + "what": "the command line on a provider it names, allowed by its contract and under a ceiling, confirmed with --yes: the estimate held to the ceiling, the charge to it after, and the shadow" + }, + { + "file": "jobs/cli-contract-pulse.json", + "reasons": [], + "made_by": "made", + "what": "the command line, a pulse program under a contract that wants bounded and a deadline: its one route" + }, + { + "file": "jobs/cli-contract-routed-seed.json", + "reasons": [], + "made_by": "made", + "what": "the same routed job with the seed 2^53 - 2: its shadow's seed, the request's plus 2^32, wraps at 2^53" }, { "file": "jobs/cli-contract-routed.json", @@ -31,6 +61,12 @@ "made_by": "made", "what": "the command line under a contract that allows the person's providers and wants a simulator's counts: the free one chosen, a classical method's counts and their distance beside its own" }, + { + "file": "jobs/cli-contract-target.json", + "reasons": [], + "made_by": "made", + "what": "the command line on a device target, the person's providers allowed beside it, under a deadline: the target's method is named, and the providers are not" + }, { "file": "jobs/cli-provider-reference-priced.json", "reasons": [], @@ -1045,6 +1081,14 @@ "made_by": "crafted", "what": "a ceiling's amount that is not in decimals" }, + { + "file": "jobs/crafted-contract-form-cost-long.json", + "reasons": [ + "contract_form" + ], + "made_by": "crafted", + "what": "a ceiling's amount of 65 characters: at most 64" + }, { "file": "jobs/crafted-contract-planner-missing.json", "reasons": [ @@ -1307,6 +1351,274 @@ "reasons": [], "made_by": "crafted", "what": "charged past the ceiling, and said so: valid" + }, + { + "file": "jobs/crafted-contract-kept-charged-other.json", + "reasons": [ + "planner_kept" + ], + "made_by": "crafted", + "what": "kept stating a charge that is not the result's: within the ceiling, and not what was charged" + }, + { + "file": "jobs/crafted-contract-kept-member-extra.json", + "reasons": [ + "planner_kept" + ], + "made_by": "crafted", + "what": "a member of kept that its table does not give" + }, + { + "file": "jobs/crafted-contract-kept-elapsed-other.json", + "reasons": [ + "planner_kept" + ], + "made_by": "crafted", + "what": "a method's time in kept that is not the run's own elapsed_ms, within the deadline all the same" + }, + { + "file": "jobs/crafted-contract-auto-other.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "auto said to pick a route the ranks do not" + }, + { + "file": "jobs/crafted-contract-auto-rank-lowered.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "a route's rank in auto's order lowered, so that auto would pick it" + }, + { + "file": "jobs/crafted-contract-auto-rank-other.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "a rank that is not the method's, on a route that does not win by it" + }, + { + "file": "jobs/crafted-contract-auto-rank-missing.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "a local route without its rank in auto's order" + }, + { + "file": "jobs/crafted-contract-question-other.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "a question the request does not ask" + }, + { + "file": "jobs/crafted-contract-named-other.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "a provider the request names, said to be named by nothing" + }, + { + "file": "jobs/crafted-contract-provider-named-not-allowed.json", + "reasons": [ + "contract_provider", + "planner_choice", + "planner_route" + ], + "made_by": "crafted", + "what": "a provider named under a contract that does not allow one: never is the default" + }, + { + "file": "jobs/crafted-contract-named-approximate.json", + "reasons": [], + "made_by": "crafted", + "what": "a provider named, its simulator stated approximate, under a contract that names no class: it keeps the named route's class, and the rule against an approximate simulator holds only a class the contract names" + }, + { + "file": "jobs/crafted-contract-approximate-rejected.json", + "reasons": [], + "made_by": "crafted", + "what": "a simulator stated approximate, where the contract wants simulated: rejected for its class, before its cost is weighed" + }, + { + "file": "jobs/crafted-contract-price-seconds-past.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "a time past 10^12 seconds, which a host states as unknown" + }, + { + "file": "jobs/crafted-contract-price-amount-long.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "an amount of 65 characters, which a host states as unknown" + }, + { + "file": "jobs/crafted-contract-local-money.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "a method here priced in money: a local route is free" + }, + { + "file": "jobs/crafted-contract-memory-at-cap.json", + "reasons": [ + "planner_stable" + ], + "made_by": "crafted", + "what": "a route that needs exactly the job's memory meets it; the digest covers memory, and is not the routes' now" + }, + { + "file": "jobs/crafted-contract-deadline-unknown.json", + "reasons": [ + "planner_stable" + ], + "made_by": "crafted", + "what": "a route whose time is unknown under a deadline, rejected for it; the digest covers the time, and is not the routes' now" + }, + { + "file": "jobs/crafted-contract-currency-other.json", + "reasons": [ + "planner_choice", + "planner_kept", + "planner_route" + ], + "made_by": "crafted", + "what": "a ceiling in another currency than the estimate's: no route meets it, and kept states another ceiling" + }, + { + "file": "jobs/crafted-contract-energy-at-ceiling.json", + "reasons": [], + "made_by": "crafted", + "what": "an energy ceiling met exactly, every route estimated within it: kept, and the choice depends on the host, whose estimate it is" + }, + { + "file": "jobs/crafted-contract-energy-stable-claimed.json", + "reasons": [ + "planner_stable" + ], + "made_by": "crafted", + "what": "the same, the choice said to depend on nothing of the host" + }, + { + "file": "jobs/crafted-contract-shadow-route-missing.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a shadow that names no route" + }, + { + "file": "jobs/crafted-contract-shadow-plan-route-missing.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a shadow planned with no route, where null would say why" + }, + { + "file": "jobs/crafted-contract-shadow-plan-route-absent.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a plan with neither a route nor null, and a shadow said not to have run" + }, + { + "file": "jobs/crafted-contract-shadow-route-provider.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a provider as its own shadow" + }, + { + "file": "jobs/crafted-contract-shadow-request-extra.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a shadow run under a noise model the job never asked for, on both sides" + }, + { + "file": "jobs/crafted-contract-shadow-plan-code.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a shadow planned with a code no plan has" + }, + { + "file": "jobs/crafted-contract-shadow-plan-class.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a shadow planned at a class its route is not listed with" + }, + { + "file": "jobs/crafted-contract-shadow-plan-budget.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a budget that is not what the contract leaves" + }, + { + "file": "jobs/crafted-contract-shadow-plan-price-over.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a shadow planned at a time past its budget" + }, + { + "file": "jobs/crafted-contract-shadow-count-fraction.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a shadow's counts that are not whole, summing to the shots all the same" + }, + { + "file": "jobs/crafted-contract-shadow-count-sum.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a shadow's counts that sum to more than its shots" + }, + { + "file": "jobs/crafted-contract-shadow-count-short.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a shot said omitted beside counts that are all the shots: they sum to one more, and the distance, not computed, is no help" + }, + { + "file": "jobs/crafted-contract-shadow-bound-other.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a bound on the distance the shots alone leave that is not what the counts give" + }, + { + "file": "jobs/crafted-contract-shadow-said-failed.json", + "reasons": [], + "made_by": "crafted", + "what": "a shadow planned and said to have failed: valid to read, and run again by --recheck" } ] } diff --git a/wai/quantum-conformance/tools/receipt_verify.py b/wai/quantum-conformance/tools/receipt_verify.py index 51ccebe61..a47c1e524 100644 --- a/wai/quantum-conformance/tools/receipt_verify.py +++ b/wai/quantum-conformance/tools/receipt_verify.py @@ -2340,6 +2340,11 @@ def self_test(args): ("a shadow request with a noise model", contract_body( result__planner__shadow__request__noise={"depolarizing_2q": 0.2}, result__shadow__request__noise={"depolarizing_2q": 0.2}), ["shadow"]), + # By hand: "1" 4 and 1 times, 5 pooled, E|2B - 5| = 1.875; half of it over 4. + ("a shadow's counts short of its shots, the distance what they give", contract_body( + result__shadow__counts={"1": 1}, + result__shadow__distance={"computed": True, "numerator": 3, "denominator": 8, "total_variation": 0.375, + "hellinger_fidelity": 0.25, "sampling_tvd_bound": 0.234375}), ["shadow"]), ("a shadow planned at a class its route is not listed with", contract_body(result__planner__shadow__class="heuristic"), ["shadow"]), ("a time past what a price states", contract_body(result__planner__routes__1__price__time__seconds=1e306), ["planner_form"]), @@ -2445,6 +2450,9 @@ def self_test(args): _lr("statevector_single", "single", 40, "rejected", "class", host_dependent=True, priced=False), _lr("mps", "heuristic", 60, "rejected", "class", memory=4096, joules=1.0)], "method:exact", "method:exact", False, {"energy": {"max_joules": 2, "joules": 2.0, "kept": True}}, energy={"joules_micro": 2000000})), + ("an approximate simulator named, under a contract that names no class", contract_body( + request__contract={"providers": "allowed"}, result__planner__wanted_from="named", + result__planner__routes__1__approximate=True)), ("a local route before a provider's at one time", local_body({"exactness": "any", "providers": "allowed"}, [ _lr("exact", "bit-exact", 20, "chosen", seconds=0.0001), _lr("statevector", "exact", 30, "met", seconds=0.0001, memory=2048), _lr("statevector_single", "single", 40, "rejected", "cannot", host_dependent=True, priced=False), diff --git a/wai/wai-quantum-cli/docs/llms-full.txt b/wai/wai-quantum-cli/docs/llms-full.txt index 20a8608e1..ba4b8fa84 100644 --- a/wai/wai-quantum-cli/docs/llms-full.txt +++ b/wai/wai-quantum-cli/docs/llms-full.txt @@ -618,7 +618,7 @@ Parameters: ### `run_routed`: Run a job on the route its contract chooses (can spend the person's money) -Runs a job on the route plan_routes chooses: a method on this machine, or one of the person's own providers. THIS CAN SPEND THE PERSON'S MONEY OR QUOTA, when the contract allows a provider and one is chosen. A cost ceiling confirms nothing: a run that is not free is refused unless confirm_cost is true, set only after the person has seen the estimate and agreed to that run. The answer is a job in the service's form, its result carrying the planner's reasoning under planner; a provider's result also carries a classical method's counts and their distance under shadow, or why no classical method could reach them. If the job has not finished within this call the answer has status running and an id, and get_provider_job collects it later. Do not run it again to find out: that is a second job, and it can be a second bill. +Runs a job on the route plan_routes chooses: a method on this machine, or one of the person's own providers. THIS CAN SPEND THE PERSON'S MONEY OR QUOTA, when the contract allows a provider and one is chosen. A cost ceiling confirms nothing: a run that is not free is refused unless confirm is the word plan_routes gave for that route, its estimate and its program (its confirm.token), set only after the person has seen them and agreed to that run; if the route or its estimate changed since, it is refused with the new word. The answer is a job in the service's form, its result carrying the planner's reasoning under planner; a provider's result also carries a classical method's counts and their distance under shadow, or why no classical method could reach them. If the job has not finished within this call the answer has status running and an id, and get_provider_job collects it later. Do not run it again to find out: that is a second job, and it can be a second bill. Parameters: - `qasm` (string, required): The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why. @@ -627,7 +627,7 @@ Parameters: - `seed` (integer): A seed. - `observables` (array): Pauli observables: a provider's job answers counts, so a method here answers these. - `contract` (any, required): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). -- `confirm_cost` (boolean): true only when the person has agreed to this run's cost. A run that is not free is refused without it, whatever the contract's ceiling. +- `confirm` (string): The word plan_routes gave (confirm.token) for the route, the estimate and the program the person agreed to. A run that is not free is refused without it, whatever the contract's ceiling, and refused if what is chosen now is not what that word names. ### `get_provider_job`: Ask after a job on a provider @@ -1934,6 +1934,11 @@ Options: With --provider or --allow-providers: send the job and answer with its handle, without waiting (`wai-quantum providers collect`) + --confirm + With --allow-providers: confirm the run the planner chose when it is not free, by the word + its dry run gave for that route, its estimate and its program; a route, an estimate or a + program that changed since is refused. --yes confirms only a provider you name + -h, --help Print help diff --git a/wai/wai-quantum-cli/docs/local-mcp.json b/wai/wai-quantum-cli/docs/local-mcp.json index 727f0a218..2dc22ffb0 100644 --- a/wai/wai-quantum-cli/docs/local-mcp.json +++ b/wai/wai-quantum-cli/docs/local-mcp.json @@ -556,7 +556,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -569,7 +569,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -594,7 +595,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -1444,7 +1445,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -1457,7 +1458,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -1482,7 +1484,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -4268,7 +4270,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -4289,6 +4293,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -4362,6 +4382,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -5068,9 +5096,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -6113,7 +6143,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -6126,7 +6156,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -6151,7 +6182,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -8935,7 +8966,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -8956,6 +8989,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -9029,6 +9078,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -9735,9 +9792,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -11167,7 +11226,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -11180,7 +11239,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -11205,7 +11265,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -11312,7 +11372,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -11333,6 +11395,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -11406,6 +11484,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -33302,7 +33388,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -33315,7 +33401,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -33340,7 +33427,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -34193,7 +34280,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -34206,7 +34293,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -34231,7 +34319,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -37017,7 +37105,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -37038,6 +37128,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -37111,6 +37217,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -37817,9 +37931,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -38862,7 +38978,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -38875,7 +38991,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -38900,7 +39017,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -41684,7 +41801,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -41705,6 +41824,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -41778,6 +41913,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -42484,9 +42627,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -54933,7 +55078,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -54946,7 +55091,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -54971,7 +55117,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -55039,7 +55185,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -55060,6 +55208,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -55133,6 +55297,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -55760,7 +55932,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -55773,7 +55945,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -55798,7 +55971,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -56655,7 +56828,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -56668,7 +56841,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -56693,7 +56867,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -59479,7 +59653,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -59500,6 +59676,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -59573,6 +59765,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -60279,9 +60479,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -61324,7 +61526,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -61337,7 +61539,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -61362,7 +61565,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -64146,7 +64349,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -64167,6 +64372,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -64240,6 +64461,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -64946,9 +65175,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -65153,7 +65384,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -65166,7 +65397,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -65191,7 +65423,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -65230,7 +65462,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -65251,6 +65485,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -65324,6 +65574,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -65934,7 +66192,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -65955,6 +66215,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -66028,6 +66304,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -66601,7 +66885,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -66622,6 +66908,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -66695,6 +66997,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -67215,6 +67525,30 @@ } } } + }, + "confirm": { + "type": "object", + "description": "Where the route chosen is a provider's and not free: what a person confirms it by. token is a digest of the route, its estimate's money and the program and shots it would send; a run is sent only when given that token made again at send time.", + "required": [ + "token", + "route", + "money", + "says" + ], + "properties": { + "token": { + "type": "string" + }, + "route": { + "type": "string" + }, + "money": { + "type": "object" + }, + "says": { + "type": "string" + } + } } } }, @@ -67267,7 +67601,7 @@ { "name": "run_routed", "title": "Run a job on the route its contract chooses (can spend the person's money)", - "description": "Runs a job on the route plan_routes chooses: a method on this machine, or one of the person's own providers. THIS CAN SPEND THE PERSON'S MONEY OR QUOTA, when the contract allows a provider and one is chosen. A cost ceiling confirms nothing: a run that is not free is refused unless confirm_cost is true, set only after the person has seen the estimate and agreed to that run. The answer is a job in the service's form, its result carrying the planner's reasoning under planner; a provider's result also carries a classical method's counts and their distance under shadow, or why no classical method could reach them. If the job has not finished within this call the answer has status running and an id, and get_provider_job collects it later. Do not run it again to find out: that is a second job, and it can be a second bill.", + "description": "Runs a job on the route plan_routes chooses: a method on this machine, or one of the person's own providers. THIS CAN SPEND THE PERSON'S MONEY OR QUOTA, when the contract allows a provider and one is chosen. A cost ceiling confirms nothing: a run that is not free is refused unless confirm is the word plan_routes gave for that route, its estimate and its program (its confirm.token), set only after the person has seen them and agreed to that run; if the route or its estimate changed since, it is refused with the new word. The answer is a job in the service's form, its result carrying the planner's reasoning under planner; a provider's result also carries a classical method's counts and their distance under shadow, or why no classical method could reach them. If the job has not finished within this call the answer has status running and an id, and get_provider_job collects it later. Do not run it again to find out: that is a second job, and it can be a second bill.", "inputSchema": { "type": "object", "required": [ @@ -67327,7 +67661,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -67340,7 +67674,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -67365,7 +67700,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -67374,9 +67709,9 @@ } } }, - "confirm_cost": { - "type": "boolean", - "description": "true only when the person has agreed to this run's cost. A run that is not free is refused without it, whatever the contract's ceiling." + "confirm": { + "type": "string", + "description": "The word plan_routes gave (confirm.token) for the route, the estimate and the program the person agreed to. A run that is not free is refused without it, whatever the contract's ceiling, and refused if what is chosen now is not what that word names." } } }, @@ -68219,7 +68554,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -68232,7 +68567,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -68257,7 +68593,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -71043,7 +71379,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -71064,6 +71402,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -71137,6 +71491,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -71843,9 +72205,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -72888,7 +73252,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -72901,7 +73265,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -72926,7 +73291,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -75710,7 +76075,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -75731,6 +76098,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -75804,6 +76187,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -76510,9 +76901,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" diff --git a/wai/wai-quantum-cli/docs/service-mcp.json b/wai/wai-quantum-cli/docs/service-mcp.json index e7e0e7381..3ad61d2aa 100644 --- a/wai/wai-quantum-cli/docs/service-mcp.json +++ b/wai/wai-quantum-cli/docs/service-mcp.json @@ -554,7 +554,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -567,7 +567,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -592,7 +593,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -1460,7 +1461,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -1473,7 +1474,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -1498,7 +1500,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -4284,7 +4286,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -4305,6 +4309,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -4378,6 +4398,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -5084,9 +5112,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -6129,7 +6159,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -6142,7 +6172,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -6167,7 +6198,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -8951,7 +8982,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -8972,6 +9005,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -9045,6 +9094,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -9751,9 +9808,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -10428,7 +10487,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -10449,6 +10510,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -10522,6 +10599,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -13989,7 +14074,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -14002,7 +14087,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -14027,7 +14113,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -16813,7 +16899,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -16834,6 +16922,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -16907,6 +17011,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -17613,9 +17725,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -18658,7 +18772,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -18671,7 +18785,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -18696,7 +18811,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -21480,7 +21595,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -21501,6 +21618,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -21574,6 +21707,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -22280,9 +22421,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -22957,7 +23100,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -22978,6 +23123,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -23051,6 +23212,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -25709,7 +25878,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -25722,7 +25891,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -25747,7 +25917,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -25980,7 +26150,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -26001,6 +26173,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -26074,6 +26262,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -28234,7 +28430,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -28247,7 +28443,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -28272,7 +28469,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -31058,7 +31255,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -31079,6 +31278,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -31152,6 +31367,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -31858,9 +32081,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -32903,7 +33128,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -32916,7 +33141,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -32941,7 +33167,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -35725,7 +35951,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -35746,6 +35974,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -35819,6 +36063,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -36525,9 +36777,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -37202,7 +37456,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -37223,6 +37479,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -37296,6 +37568,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -52103,7 +52383,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -52116,7 +52396,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -52141,7 +52422,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -53454,7 +53735,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -53467,7 +53748,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -53492,7 +53774,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -56278,7 +56560,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -56299,6 +56583,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -56372,6 +56672,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -57078,9 +57386,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -58123,7 +58433,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -58136,7 +58446,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -58161,7 +58472,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", @@ -60945,7 +61256,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -60966,6 +61279,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -61039,6 +61368,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -61745,9 +62082,11 @@ "hellinger_fidelity": { "type": "number" }, - "sampling_tvd_expected": { + "sampling_tvd_bound": { "type": "number", - "minimum": 0 + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -62057,7 +62396,9 @@ "routes", "choice", "why", - "stable" + "stable", + "named", + "question" ], "properties": { "format": { @@ -62078,6 +62419,22 @@ null ] }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + }, "auto": { "type": [ "string", @@ -62151,6 +62508,14 @@ "type": "boolean", "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + }, "price": { "anyOf": [ { @@ -63601,7 +63966,7 @@ ] }, "max_cost": { - "description": "The most it may cost. A route with an unknown cost, or priced in another currency, does not meet it: nothing is converted.", + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", "type": [ "object", "null" @@ -63614,7 +63979,8 @@ "properties": { "amount": { "type": "string", - "description": "An amount in decimals: digits, and optionally a point and digits." + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 }, "currency": { "type": "string", @@ -63639,7 +64005,7 @@ "exclusiveMinimum": 0 }, "providers": { - "description": "Whether a route may be one of the person's providers. never is the default, and a host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's confirmation for that run.", + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", "enum": [ "never", "allowed", diff --git a/wai/wai-quantum-cli/tests/providers.rs b/wai/wai-quantum-cli/tests/providers.rs index af41e5cbd..abafcde7b 100644 --- a/wai/wai-quantum-cli/tests/providers.rs +++ b/wai/wai-quantum-cli/tests/providers.rs @@ -318,9 +318,12 @@ fn a_contract_weighs_every_route_and_its_receipt_says_why() { assert_eq!(out.status.code(), Some(1)); let v: Value = serde_json::from_slice(&out.stdout).unwrap(); assert_eq!((v["refused"]["code"].as_str(), v["planner"]["choice"].as_str()), (Some("J071"), None), "{v}"); - // Weighed against the person's providers: exact is here. - let routed = h.ok(&["plan", &p, "--shots", "100", "--exactness", "exact", "--allow-providers"], ""); + // Weighed against the person's providers, for a class they can give; for one + // none can give, none is asked, since an estimate's request carries the program. + let routed = h.ok(&["plan", &p, "--shots", "100", "--exactness", "simulated", "--allow-providers"], ""); assert!(routed.contains("provider:free-lab") && routed.contains("provider:paid"), "{routed}"); + let here = h.ok(&["plan", &p, "--shots", "100", "--exactness", "exact", "--allow-providers"], ""); + assert!(here.contains("method:stabilizer") && !here.contains("provider:"), "{here}"); assert!(jobs(&h).is_empty(), "a plan sends nothing"); let body: Value = serde_json::from_str(&h.ok(&["run", &p, "--shots", "100", "--exactness", "exact", "--allow-providers", "--demo-key", "--json"], "")).unwrap(); assert_eq!(body["result"]["method"], "stabilizer"); diff --git a/wai/wai-quantum/src/engine/planner/tests.rs b/wai/wai-quantum/src/engine/planner/tests.rs index b2a6892be..2c97bf936 100644 --- a/wai/wai-quantum/src/engine/planner/tests.rs +++ b/wai/wai-quantum/src/engine/planner/tests.rs @@ -1060,6 +1060,11 @@ fn a_shadow_is_a_method_s_run_of_exactly_the_job_s_program() { b.pointer_mut(side).unwrap()["noise"] = json!({ "depolarizing_2q": 0.2 }); } })), + // A plan that names no route at all, null or otherwise, and why none ran. + (&[SHADOW], Box::new(|b| { + b["result"]["planner"]["shadow"] = json!({ "code": "none", "why": "said so" }); + b["result"]["shadow"] = json!({ "ran": false, "code": "none", "why": "said so" }); + })), // A plan's code that no plan has, and a failure where none was planned. (&[SHADOW], Box::new(|b| { b["result"]["planner"]["shadow"] = json!({ "route": null, "code": "failed", "why": "said so" }); @@ -1070,6 +1075,13 @@ fn a_shadow_is_a_method_s_run_of_exactly_the_job_s_program() { (&[SHADOW], Box::new(|b| b["result"]["planner"]["shadow"]["class"] = json!("heuristic"))), (&[SHADOW], Box::new(|b| b["result"]["planner"]["shadow"]["budget_seconds"] = json!(300.0))), (&[SHADOW], Box::new(|b| b["result"]["planner"]["shadow"]["price"]["time"]["seconds"] = json!(289.0))), + // Counts a shot short of the shots, their distance what they give. + (&[SHADOW], Box::new(|b| { + let n = b["result"]["shadow"]["counts"]["00"].as_u64().unwrap(); + b["result"]["shadow"]["counts"]["00"] = json!(n - 1); + let (counts, shadow) = (b["result"]["counts"].clone(), b["result"]["shadow"]["counts"].clone()); + b["result"]["shadow"]["distance"] = distance(&counts, &shadow, 1000).unwrap(); + })), // Counts that are not whole, or not at least 1, or sum to the shots only as doubles. (&[SHADOW], Box::new(|b| { let n = b["result"]["shadow"]["counts"]["00"].as_u64().unwrap(); @@ -1188,6 +1200,11 @@ fn auto_is_what_the_routes_give_and_cannot_be_lowered() { (&[PLANNER_FORM], Box::new(|b| b["result"]["planner"]["question"] = json!("amplitudes"))), (&[PLANNER_FORM], Box::new(|b| at(b, "method:mps")["auto_rank"] = json!(0))), (&[PLANNER_FORM], Box::new(|b| b["result"]["planner"]["named"] = json!("method:statevector"))), + // auto said to be another route of the same class: the class wanted is as it + // was, and what the routes give is not what is sealed. + (&[PLANNER_FORM], Box::new(|b| b["result"]["planner"]["auto"] = json!("method:cutrank"))), + // A rank that is not the method's, on a route that does not win by it. + (&[PLANNER_FORM], Box::new(|b| at(b, "method:mps")["auto_rank"] = json!(65))), ]); } diff --git a/wai/wai-quantum/src/repro.rs b/wai/wai-quantum/src/repro.rs index dae418c5b..6cb6596f8 100644 --- a/wai/wai-quantum/src/repro.rs +++ b/wai/wai-quantum/src/repro.rs @@ -40,28 +40,28 @@ pub use trig::sin_cos; // Natural logarithm // --------------------------------------------------------------------------- -#[cfg(any(feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] +#[cfg(any(feature = "quantum_cutrank", feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] const LN2_HI: f64 = 6.931_471_803_691_238_164_90e-1; -#[cfg(any(feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] +#[cfg(any(feature = "quantum_cutrank", feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] const LN2_LO: f64 = 1.908_214_929_270_587_700_02e-10; -#[cfg(any(feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] +#[cfg(any(feature = "quantum_cutrank", feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] const LG1: f64 = 6.666_666_666_666_735_130e-1; -#[cfg(any(feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] +#[cfg(any(feature = "quantum_cutrank", feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] const LG2: f64 = 3.999_999_999_940_941_908e-1; -#[cfg(any(feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] +#[cfg(any(feature = "quantum_cutrank", feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] const LG3: f64 = 2.857_142_874_366_239_149e-1; -#[cfg(any(feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] +#[cfg(any(feature = "quantum_cutrank", feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] const LG4: f64 = 2.222_219_843_214_978_396e-1; -#[cfg(any(feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] +#[cfg(any(feature = "quantum_cutrank", feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] const LG5: f64 = 1.818_357_216_161_805_012e-1; -#[cfg(any(feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] +#[cfg(any(feature = "quantum_cutrank", feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] const LG6: f64 = 1.531_383_769_920_937_332e-1; -#[cfg(any(feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] +#[cfg(any(feature = "quantum_cutrank", feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] const LG7: f64 = 1.479_819_860_511_658_591e-1; /// The natural logarithm, within an ulp of the true value: `−∞` at zero, NaN /// below it. -#[cfg(any(feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] +#[cfg(any(feature = "quantum_cutrank", feature = "quantum_vml", feature = "quantum_kernel", feature = "quantum_resource", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_dmrg", feature = "quantum_noisy", feature = "quantum_tableau", feature = "quantum_lang"))] pub fn ln(x: f64) -> f64 { let mut bits = x.to_bits(); let mut hx = (bits >> 32) as u32; @@ -105,7 +105,7 @@ pub fn ln(x: f64) -> f64 { // Exponential // --------------------------------------------------------------------------- -#[cfg(any(feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_nqs", feature = "quantum_lang"))] +#[cfg(any(feature = "quantum_cutrank", feature = "quantum_frame", feature = "quantum_tn", feature = "quantum_gbs", feature = "quantum_arch", feature = "quantum_qio", feature = "quantum_nqs", feature = "quantum_lang"))] const EXP_P: [f64; 5] = [ 1.666_666_666_666_660_190_37e-1, -2.777_777_777_701_559_338_42e-3, -- 2.54.0 (Apple Git-157) From 4e36e0456c1f881ae63ca965c5037fedc0e2da9f Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Fri, 6 Nov 2026 13:46:10 -0500 Subject: [PATCH 07/42] wai-quantum: an energy ceiling is held only to an upper bound, the corpus and the tool lists with it The corpus's crafted receipts for energy at_least (under the ceiling, over it, claimed to meet it, given false, on no figure), and the tool lists and the agent docs blessed again for price.energy's bound, its basis and its estimate. Co-Authored-By: Claude Opus 5.5 --- ...fted-contract-energy-at-least-claimed.json | 350 +++++++++++ ...rafted-contract-energy-at-least-false.json | 350 +++++++++++ ...fted-contract-energy-at-least-on-null.json | 354 +++++++++++ ...crafted-contract-energy-at-least-over.json | 354 +++++++++++ .../crafted-contract-energy-at-least.json | 354 +++++++++++ .../receipts/manifest.json | 36 ++ wai/wai-quantum-cli/docs/llms-full.txt | 29 +- wai/wai-quantum-cli/docs/llms.txt | 2 +- wai/wai-quantum-cli/docs/local-mcp.json | 563 ++++++++++++++++-- wai/wai-quantum-cli/docs/service-mcp.json | 557 +++++++++++++++-- 10 files changed, 2827 insertions(+), 122 deletions(-) create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least-claimed.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least-false.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least-on-null.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least-over.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least.json diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least-claimed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least-claimed.json new file mode 100644 index 000000000..0d9a54d31 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least-claimed.json @@ -0,0 +1,350 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0, + "max_joules": 2 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "what was read leaves out a device", + "at_least": true + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": false + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + }, + "energy": { + "max_joules": 2, + "joules": 2, + "kept": true + } + } + }, + "energy": { + "joules_micro": 2000000 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "a19fedac16a2bd6cfc99f34db03240d672c6124ba41b33a13c78b8f2d519fdd1", + "signature": "0a9875244fb8a5a0570f00b201442a18a4d81d28196d45773628d04dad1d9e3917fd48f06508ee6365a525d64a7cbddcc3d8784b88a98a68e9945474220d220c" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least-false.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least-false.json new file mode 100644 index 000000000..11ca0bcde --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least-false.json @@ -0,0 +1,350 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0, + "max_joules": 2 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "what was read leaves out a device", + "at_least": false + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": false + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + }, + "energy": { + "max_joules": 2, + "joules": 2, + "kept": true + } + } + }, + "energy": { + "joules_micro": 2000000 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "90b043103c701407dd87dbf721d5a8717dfaeb6db2ac97d9821f14bbafbe8ea7", + "signature": "c3b93eb2f1e707b35ba6afc03a9d97946912209e5a86ab28ebe72171648ee9b9488d1385809e5e8bbb557863fcbd29f728b5b2ca2c6d14df872c1ecf26939100" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least-on-null.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least-on-null.json new file mode 100644 index 000000000..b07e18c63 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least-on-null.json @@ -0,0 +1,354 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0, + "max_joules": 2 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "basis": "what was read leaves out a device", + "at_least": true + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "energy_unknown", + "why": "said so" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": false + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + }, + "energy": { + "max_joules": 2, + "joules": 2, + "kept": true + } + } + }, + "energy": { + "joules_micro": 2000000 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "a821ea3d7e90fe5ee12ba58f36f5e3e44a264dcfcb17e3e90a83ebaf41b8b867", + "signature": "09a4eb65d8e2c199a9d626c96a4dd93eb48335164ba10fcb193652672a6795f5f0c46cadaaefab9b7213c73e063e0ed6b92828b35076c4d237d0b808bc7ea90d" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least-over.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least-over.json new file mode 100644 index 000000000..01f12be01 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least-over.json @@ -0,0 +1,354 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0, + "max_joules": 2 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": 3, + "basis": "what was read leaves out a device", + "at_least": true + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "energy", + "why": "said so" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": false + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + }, + "energy": { + "max_joules": 2, + "joules": 2, + "kept": true + } + } + }, + "energy": { + "joules_micro": 2000000 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "ae4617f1b1a182fd5d1771bf6bee7dc089c58c67fd4ee4ad19d42d3b0a3cc053", + "signature": "83552992d5d89399b8e542b05bc8b84c162fb958d46906626c2f174f863d1ea8b89360f1e3a1ead2286c27ea2fda6f23b527598006dbadb387dfc853f0e8a107" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least.json new file mode 100644 index 000000000..1d52b8024 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-at-least.json @@ -0,0 +1,354 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0, + "max_joules": 2 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "what was read leaves out a device", + "at_least": true + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "energy_at_least", + "why": "said so" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": 1.5, + "basis": "a host's estimate" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": false + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + }, + "energy": { + "max_joules": 2, + "joules": 2, + "kept": true + } + } + }, + "energy": { + "joules_micro": 2000000 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "f4e4e755001f177ea7fabfa630c6a9a2317b753e145cc6381493c45a1d8e358d", + "signature": "9fc7a7f2f46081bdc21e112745fd1027e1366b295a124d04acde512067ed40dc68d2257f902dad1bb363e6bada44572ab5bc3cb1134e5f578a004591a2619701" + } + } +} diff --git a/wai/quantum-conformance/receipts/manifest.json b/wai/quantum-conformance/receipts/manifest.json index c4168c785..0173ac8d3 100644 --- a/wai/quantum-conformance/receipts/manifest.json +++ b/wai/quantum-conformance/receipts/manifest.json @@ -1510,6 +1510,42 @@ "made_by": "crafted", "what": "the same, the choice said to depend on nothing of the host" }, + { + "file": "jobs/crafted-contract-energy-at-least.json", + "reasons": [], + "made_by": "crafted", + "what": "the least a run takes, under the ceiling: what a host reads leaves out a device, nothing bounds the run, and it meets no ceiling" + }, + { + "file": "jobs/crafted-contract-energy-at-least-over.json", + "reasons": [], + "made_by": "crafted", + "what": "the least a run takes, past the ceiling: it is over it, whatever else it takes" + }, + { + "file": "jobs/crafted-contract-energy-at-least-claimed.json", + "reasons": [ + "planner_route" + ], + "made_by": "crafted", + "what": "the least a run takes, said to meet the ceiling" + }, + { + "file": "jobs/crafted-contract-energy-at-least-false.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "at_least on an energy given and not true" + }, + { + "file": "jobs/crafted-contract-energy-at-least-on-null.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "at_least on an energy that states no figure" + }, { "file": "jobs/crafted-contract-shadow-route-missing.json", "reasons": [ diff --git a/wai/wai-quantum-cli/docs/llms-full.txt b/wai/wai-quantum-cli/docs/llms-full.txt index a6575252f..18e297c3a 100644 --- a/wai/wai-quantum-cli/docs/llms-full.txt +++ b/wai/wai-quantum-cli/docs/llms-full.txt @@ -28,7 +28,7 @@ Generated by `wai-quantum docs llms` from the tool lists both MCP servers serve, ## Receipts -Every result carries an Ed25519 signature over the BLAKE3 digest of the RFC 8785 canonical text of the request and of the result without its receipt. The job service signs with the key `GET /v1` publishes; the command line signs with the user's own key (`wai-quantum key` prints its did:key). `wai-quantum verify` checks either offline, and a result still verifies after any JSON reader has carried it. A receipt shows that the key signed this request and this result, and anyone can rerun the request to compare; it does not show who holds the key, nor that the physics is right. A result's `energy` is the CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or `unmetered` with the reason (the command line does not meter a run). +Every result carries an Ed25519 signature over the BLAKE3 digest of the RFC 8785 canonical text of the request and of the result without its receipt. The job service signs with the key `GET /v1` publishes; the command line signs with the user's own key (`wai-quantum key` prints its did:key). `wai-quantum verify` checks either offline, and a result still verifies after any JSON reader has carried it. A receipt shows that the key signed this request and this result, and anyone can rerun the request to compare; it does not show who holds the key, nor that the physics is right. A result's `energy` is the CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or `unmetered` with the reason (the command line seals no reading of a run: it reads some runs only to bound later ones). ## Versions and stability @@ -1887,11 +1887,10 @@ Options: it, and the receipt says whether it was kept (exit 4 when it was not) --max-joules - The most energy the run may take, in joules, held to an estimate before it runs: a - method's median power over its last three or more runs read here, over the run's estimated - time (the job service's estimate, from this command line's own runs; never a reading of - this one, which is not sealed). A method with fewer than three runs read here has no - estimate, and a route on it is refused, with why + The most energy the run may take, in joules, held before it runs to an upper bound from + this command line's own readings here: the highest power of the method's last three or + more runs read over the longest of their times, scaled up by the work, never an estimate. + A route with no bound does not meet it, and says why; a reading is never sealed --allow-providers Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods @@ -2080,11 +2079,10 @@ Options: it, and the receipt says whether it was kept (exit 4 when it was not) --max-joules - The most energy the run may take, in joules, held to an estimate before it runs: a - method's median power over its last three or more runs read here, over the run's estimated - time (the job service's estimate, from this command line's own runs; never a reading of - this one, which is not sealed). A method with fewer than three runs read here has no - estimate, and a route on it is refused, with why + The most energy the run may take, in joules, held before it runs to an upper bound from + this command line's own readings here: the highest power of the method's last three or + more runs read over the longest of their times, scaled up by the work, never an estimate. + A route with no bound does not meet it, and says why; a reading is never sealed --allow-providers Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods @@ -3210,11 +3208,10 @@ Options: it, and the receipt says whether it was kept (exit 4 when it was not) --max-joules - The most energy the run may take, in joules, held to an estimate before it runs: a - method's median power over its last three or more runs read here, over the run's estimated - time (the job service's estimate, from this command line's own runs; never a reading of - this one, which is not sealed). A method with fewer than three runs read here has no - estimate, and a route on it is refused, with why + The most energy the run may take, in joules, held before it runs to an upper bound from + this command line's own readings here: the highest power of the method's last three or + more runs read over the longest of their times, scaled up by the work, never an estimate. + A route with no bound does not meet it, and says why; a reading is never sealed --allow-providers Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods diff --git a/wai/wai-quantum-cli/docs/llms.txt b/wai/wai-quantum-cli/docs/llms.txt index 2994557bc..d58cbf25a 100644 --- a/wai/wai-quantum-cli/docs/llms.txt +++ b/wai/wai-quantum-cli/docs/llms.txt @@ -28,7 +28,7 @@ Generated by `wai-quantum docs llms` from the tool lists both MCP servers serve, ## Receipts -Every result carries an Ed25519 signature over the BLAKE3 digest of the RFC 8785 canonical text of the request and of the result without its receipt. The job service signs with the key `GET /v1` publishes; the command line signs with the user's own key (`wai-quantum key` prints its did:key). `wai-quantum verify` checks either offline, and a result still verifies after any JSON reader has carried it. A receipt shows that the key signed this request and this result, and anyone can rerun the request to compare; it does not show who holds the key, nor that the physics is right. A result's `energy` is the CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or `unmetered` with the reason (the command line does not meter a run). +Every result carries an Ed25519 signature over the BLAKE3 digest of the RFC 8785 canonical text of the request and of the result without its receipt. The job service signs with the key `GET /v1` publishes; the command line signs with the user's own key (`wai-quantum key` prints its did:key). `wai-quantum verify` checks either offline, and a result still verifies after any JSON reader has carried it. A receipt shows that the key signed this request and this result, and anyone can rerun the request to compare; it does not show who holds the key, nor that the physics is right. A result's `energy` is the CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or `unmetered` with the reason (the command line seals no reading of a run: it reads some runs only to bound later ones). ## Versions and stability diff --git a/wai/wai-quantum-cli/docs/local-mcp.json b/wai/wai-quantum-cli/docs/local-mcp.json index 2dc22ffb0..142e59533 100644 --- a/wai/wai-quantum-cli/docs/local-mcp.json +++ b/wai/wai-quantum-cli/docs/local-mcp.json @@ -587,7 +587,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -1476,7 +1476,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -4481,7 +4481,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -4567,7 +4584,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -4729,7 +4747,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -6174,7 +6209,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -9177,7 +9212,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -9263,7 +9315,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -9425,7 +9478,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -11257,7 +11327,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -11583,7 +11653,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -11669,7 +11756,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -11831,7 +11919,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -33419,7 +33524,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -34311,7 +34416,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -37316,7 +37421,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -37402,7 +37524,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -37564,7 +37687,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -39009,7 +39149,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -42012,7 +42152,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -42098,7 +42255,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -42260,7 +42418,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -55109,7 +55284,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -55396,7 +55571,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -55482,7 +55674,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -55644,7 +55837,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -55963,7 +56173,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -56859,7 +57069,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -59864,7 +60074,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -59950,7 +60177,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -60112,7 +60340,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -61557,7 +61802,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -64560,7 +64805,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -64646,7 +64908,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -64808,7 +65071,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -65415,7 +65695,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -65673,7 +65953,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -65759,7 +66056,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -65921,7 +66219,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -66403,7 +66718,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -66489,7 +66821,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -66651,7 +66984,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -67096,7 +67446,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -67182,7 +67549,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -67344,7 +67712,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -67692,7 +68077,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -68585,7 +68970,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -71590,7 +71975,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -71676,7 +72078,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -71838,7 +72241,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -73283,7 +73703,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -76286,7 +76706,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -76372,7 +76809,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -76534,7 +76972,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" diff --git a/wai/wai-quantum-cli/docs/service-mcp.json b/wai/wai-quantum-cli/docs/service-mcp.json index 3ad61d2aa..6c1112906 100644 --- a/wai/wai-quantum-cli/docs/service-mcp.json +++ b/wai/wai-quantum-cli/docs/service-mcp.json @@ -585,7 +585,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -1492,7 +1492,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -4497,7 +4497,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -4583,7 +4600,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -4745,7 +4763,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -6190,7 +6225,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -9193,7 +9228,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -9279,7 +9331,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -9441,7 +9494,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -10698,7 +10768,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -10784,7 +10871,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -10946,7 +11034,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -14105,7 +14210,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -17110,7 +17215,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -17196,7 +17318,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -17358,7 +17481,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -18803,7 +18943,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -21806,7 +21946,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -21892,7 +22049,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -22054,7 +22212,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -23311,7 +23486,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -23397,7 +23589,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -23559,7 +23752,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -25909,7 +26119,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -26361,7 +26571,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -26447,7 +26674,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -26609,7 +26837,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -28461,7 +28706,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -31466,7 +31711,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -31552,7 +31814,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -31714,7 +31977,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -33159,7 +33439,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -36162,7 +36442,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -36248,7 +36545,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -36410,7 +36708,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -37667,7 +37982,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -37753,7 +38085,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -37915,7 +38248,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -52414,7 +52764,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -53766,7 +54116,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -56771,7 +57121,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -56857,7 +57224,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -57019,7 +57387,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -58464,7 +58849,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -61467,7 +61852,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -61553,7 +61955,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -61715,7 +62118,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -62607,7 +63027,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -62693,7 +63130,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -62855,7 +63293,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -63997,7 +64452,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" -- 2.54.0 (Apple Git-157) From c41c279e592fcd3a4624b24c90e1bf9371174d19 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Fri, 6 Nov 2026 14:36:51 -0500 Subject: [PATCH 08/42] wai-quantum: the contract test on cloud-tasks at #660's test endpoint; the tool lists blessed again Co-Authored-By: Claude Opus 5.5 --- wai/wai-quantum-cli/docs/llms-full.txt | 157 +- wai/wai-quantum-cli/docs/local-mcp.json | 19022 +++++++++++++++++++- wai/wai-quantum-cli/docs/service-mcp.json | 118 +- wai/wai-quantum-qpu/tests/clients.rs | 2 +- 4 files changed, 19224 insertions(+), 75 deletions(-) diff --git a/wai/wai-quantum-cli/docs/llms-full.txt b/wai/wai-quantum-cli/docs/llms-full.txt index b6a117fa0..1f350d963 100644 --- a/wai/wai-quantum-cli/docs/llms-full.txt +++ b/wai/wai-quantum-cli/docs/llms-full.txt @@ -43,7 +43,7 @@ Runs on this machine, signed with the user's key; nothing leaves the machine. ### `run_quantum_circuit`: Run a quantum program here -Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more. +Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `contract` (the class wanted, a deadline) and the planner prices every method here, runs the cheapest that meets it, seals its reasoning under `planner`, and refuses (J071) rather than fall back to less; this tool reaches no provider, and plan_routes and run_routed do. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more. Parameters: - `source` (object): The program in another format, in place of qasm: read to the job's qasm before the job is read (a module that does not read is refused with the reader's code, Q700 to Q721), the request keeping its source. @@ -64,10 +64,11 @@ Parameters: - `mitigate` (any): Mitigate the job's expectation values (or, for readout, its counts) under its own noise: zne (the whole program folded U(U†U)^k and extrapolated), pea (the noise learned as a sparse Pauli–Lindblad model and amplified), pec (the learned channels inverted and sampled), cdr (a line fitted over near-Clifford training circuits), vd (two copies), readout (the counts' flips inverted). Needs noise and observables (shots for readout), at most 8 qubits. The result's `mitigation` gives raw and mitigated values with standard errors, the ideal value (known because this is a simulation), the method's bias and variance assumptions and its cost. A method's name, or an object. - `pulse` (object): A pulse run's options (method "pulse"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0. - `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050). +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). ### `plan_quantum_circuit`: Plan a quantum program -The method a program would run on and why, the memory and work it would take, without running it. +The method a program would run on and why, the memory and work it would take, without running it. With a contract, every route's price or reason for rejection under planner, or the refusal (J071) when no route meets it. Parameters: - `source` (object): The program in another format, in place of qasm: read to the job's qasm before the job is read (a module that does not read is refused with the reader's code, Q700 to Q721), the request keeping its source. @@ -88,6 +89,7 @@ Parameters: - `mitigate` (any): Mitigate the job's expectation values (or, for readout, its counts) under its own noise: zne (the whole program folded U(U†U)^k and extrapolated), pea (the noise learned as a sparse Pauli–Lindblad model and amplified), pec (the learned channels inverted and sampled), cdr (a line fitted over near-Clifford training circuits), vd (two copies), readout (the counts' flips inverted). Needs noise and observables (shots for readout), at most 8 qubits. The result's `mitigation` gives raw and mitigated values with standard errors, the ideal value (known because this is a simulation), the method's bias and variance assumptions and its cost. A method's name, or an object. - `pulse` (object): A pulse run's options (method "pulse"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0. - `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050). +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). ### `lint_qasm`: Check an OpenQASM program @@ -224,10 +226,11 @@ Parameters: ### `verify_quantum_result`: Check a result's receipt -Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and every rule of its form holds (`reasons` names what does not), and which key signed it. +Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and every rule of its form holds (`reasons` names what does not), and which key signed it; for a job under a contract, every route's outcome and the choice recomputed from what it states, and with recheck its routes priced again and its shadow run again. Parameters: - `job` (any, required): The job's text as it was given (preferred: read as the protocol reads it, so a member named twice or a number past what a parsed job keeps is seen), or the job: {"request": ..., "result": ...}, the result carrying its receipt. +- `recheck` (boolean): For a job under a contract: its routes priced again at the job's memory, held to the digest it sealed, and its shadow run again, held to its counts bit for bit. ### `discover_evaluate`: Judge a generator against a workbench specification @@ -440,6 +443,7 @@ Parameters: - `mitigate` (any): Mitigate the job's expectation values (or, for readout, its counts) under its own noise: zne (the whole program folded U(U†U)^k and extrapolated), pea (the noise learned as a sparse Pauli–Lindblad model and amplified), pec (the learned channels inverted and sampled), cdr (a line fitted over near-Clifford training circuits), vd (two copies), readout (the counts' flips inverted). Needs noise and observables (shots for readout), at most 8 qubits. The result's `mitigation` gives raw and mitigated values with standard errors, the ideal value (known because this is a simulation), the method's bias and variance assumptions and its cost. A method's name, or an object. - `pulse` (object): A pulse run's options (method "pulse"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0. - `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050). +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). ### `qec_code`: Show an error-correcting code and certify its distance @@ -585,6 +589,7 @@ Parameters: - `inputs` (object): A generator's inputs' values, as {"n": 5}. - `shots` (integer): Shots (default 1024). - `seed` (integer): A seed, for a provider that is a seeded simulator; a device ignores it. +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). ### `run_on_provider`: Run on a provider (can spend the person's money) @@ -596,8 +601,34 @@ Parameters: - `inputs` (object): A generator's inputs' values, as {"n": 5}. - `shots` (integer): Shots (default 1024). - `seed` (integer): A seed, for a provider that is a seeded simulator; a device ignores it. +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). - `confirm_cost` (boolean): true only when the person has agreed to this run's cost. A run that is not free is refused without it. +### `plan_routes`: Weigh a contract against every route + +Every route a job could take under its contract: the methods on this machine and each of the person's own providers, each with its price or why it was rejected, what a provider's estimate leaves out, and the route the planner would choose: the cheapest that meets the contract, or the refusal (J071) with every route's reason. Each provider is asked to describe its device and estimate the job. Nothing is submitted and nothing is spent. A device is chosen only when exactness asks for measured or any. + +Parameters: +- `qasm` (string, required): The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why. +- `inputs` (object): A generator's inputs' values, as {"n": 5}. +- `shots` (integer): Shots (default 1024). +- `seed` (integer): A seed. +- `observables` (array): Pauli observables: a provider's job answers counts, so a method here answers these. +- `contract` (any, required): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). + +### `run_routed`: Run a job on the route its contract chooses (can spend the person's money) + +Runs a job on the route plan_routes chooses: a method on this machine, or one of the person's own providers. THIS CAN SPEND THE PERSON'S MONEY OR QUOTA, when the contract allows a provider and one is chosen. A cost ceiling confirms nothing: a run that is not free is refused unless confirm is the word plan_routes gave for that route, its estimate and its program (its confirm.token), set only after the person has seen them and agreed to that run; if the route or its estimate changed since, it is refused with the new word. The answer is a job in the service's form, its result carrying the planner's reasoning under planner; a provider's result also carries a classical method's counts and their distance under shadow, or why no classical method could reach them. If the job has not finished within this call the answer has status running and an id, and get_provider_job collects it later. Do not run it again to find out: that is a second job, and it can be a second bill. + +Parameters: +- `qasm` (string, required): The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why. +- `inputs` (object): A generator's inputs' values, as {"n": 5}. +- `shots` (integer): Shots (default 1024). +- `seed` (integer): A seed. +- `observables` (array): Pauli observables: a provider's job answers counts, so a method here answers these. +- `contract` (any, required): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). +- `confirm` (string): The word plan_routes gave (confirm.token) for the route, the estimate and the program the person agreed to. A run that is not free is refused without it, whatever the contract's ceiling, and refused if what is chosen now is not what that word names. + ### `get_provider_job`: Ask after a job on a provider Where a job on one of the person's providers stands, by the id run_on_provider gave: still running, or finished, with its counts then sealed in a receipt, or ended, with why. Asking spends nothing and can be repeated; a finished job gives the same answer every time. It asks once and does not wait, so ask again later rather than in a loop: a device's queue can take hours or days. @@ -642,6 +673,7 @@ Parameters: - `pulse` (object): A pulse run's options (method "pulse"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0. - `source` (object): The program in another format, in place of qasm: read to the job's qasm before the job is read (a module that does not read is refused with the reader's code, Q700 to Q721), the request keeping its source. - `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read; a parameter left without one is refused (J050). In a sweep, the parameters it fixes. +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). - `idempotency_key` (string): A key of your making that names this run, so that a call sent again is not a second job: the same key with the same arguments answers with the job it names, for as long as the job is kept, rather than running another; the same key with other arguments is refused (J034). Make it unguessable (a UUID). A job the service interrupted is run again under its key. Without a key, every call is a new job. ### `run_quantum_set`: Run a set of quantum programs, or one over a grid @@ -693,6 +725,7 @@ Parameters: - `programs` (array): The set's programs: each a program's text, or a job ({"qasm", …}) whose own fields win over the set's. - `sweep` (object): Each input of qasm and its values: every combination runs, the names in sorted order, the first varying slowest; an integer input's values are whole numbers. - `source` (object): The program in another format, in place of qasm: read to the job's qasm before the job is read (a module that does not read is refused with the reader's code, Q700 to Q721), the request keeping its source. +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). ### `get_quantum_job`: Read a quantum job @@ -826,7 +859,7 @@ Parameters: - `observables` (array): Pauli strings to take expectation values of, e.g. ["Z0", "Z0 Z1", "X2 Y3"]. Qubits count from 0. - `amplitudes` (array): Basis states to give amplitudes of: one character per qubit, qubit n-1 first, e.g. "0011". - `noise` (object): Optional noise, each a probability: depolarizing_1q, depolarizing_2q, amplitude_damping, dephasing (after each gate on its qubits), readout (each measured bit). -- `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read; a parameter left without one is refused (J050). In a sweep, the parameters it fixes. +- `contract` (any): What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073). - `seed` (integer): Sampling seed (default 1); the same job and seed give the same counts. - `options` (object): Advanced, per method: max_bond (mps), threshold and max_terms (pauli), fusion (statevector), trajectories. - `compile` (object): Compile the program first (as compile_qasm does) and run the compiled circuit: with basis clifford_t it runs bit-exact, and the result's `compiled` states its distance from the program. @@ -837,6 +870,7 @@ Parameters: - `mitigate` (any): Mitigate the job's expectation values (or, for readout, its counts) under its own noise: zne (the whole program folded U(U†U)^k and extrapolated), pea (the noise learned as a sparse Pauli–Lindblad model and amplified), pec (the learned channels inverted and sampled), cdr (a line fitted over near-Clifford training circuits), vd (two copies), readout (the counts' flips inverted). Needs noise and observables (shots for readout), at most 8 qubits. The result's `mitigation` gives raw and mitigated values with standard errors, the ideal value (known because this is a simulation), the method's bias and variance assumptions and its cost. A method's name, or an object. - `pulse` (object): A pulse run's options (method "pulse"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0. - `source` (object): The program in another format, in place of qasm: read to the job's qasm before the job is read (a module that does not read is refused with the reader's code, Q700 to Q721), the request keeping its source. +- `params` (object): A value for each of the program's parameters (input float theta;, input angle phi;), as {"theta": 0.3}: bound exactly before the program is read; a parameter left without one is refused (J050). In a sweep, the parameters it fixes. - `idempotency_key` (string): A key of your making that names this run, so that a call sent again is not a second job: the same key with the same arguments answers with the job it names, for as long as the job is kept, rather than running another; the same key with other arguments is refused (J034). Make it unguessable (a UUID). A job the service interrupted is run again under its key. Without a key, every call is a new job. ### `quantum_circuit_examples`: Ready-to-run quantum examples @@ -1837,6 +1871,37 @@ Options: them. A member certified bit-exact gives the CPU's answers; a placement this host cannot honour is refused (J013) + --exactness + The class the answer must be of: bit-exact, exact, single, bounded, estimate, heuristic; + measured (a processor's counts), simulated (a provider's simulator's), or any. Under a + contract (this, --max-cost, --deadline, --max-joules or --allow-providers) the planner + prices every route it can see, runs the cheapest that meets it, and seals its reasoning in + the receipt; with nothing to meet it, it refuses with each route's reason (J071), and + nothing falls back. Without a class the job keeps the class auto would give + + --max-cost + The most the run may cost, as 0.50:USD: a route with an unknown cost, or priced in another + currency, does not meet it. It confirms nothing: a run that is not free still takes --yes + + --deadline + When the run must be done by, in seconds: a route whose time is not known does not meet + it, and the receipt says whether it was kept (exit 4 when it was not) + + --max-joules + The most energy the run may take, in joules: a route whose energy is not known does not + meet it, and this command estimates none, so here every route is refused; the job service + estimates from what it has metered + + --allow-providers + Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods + here: each is asked to estimate the job, and nothing is sent unless one is chosen. A + device is chosen only when --exactness measured or any asks for its class. On the job + service, which reaches no provider, it changes nothing + + --contract + The contract itself, as JSON or a file of it: exactness, max_cost, deadline_seconds, + max_joules and providers; the options above are set over it + --json Print the job as the service returns it: request, plan, result and receipt @@ -1858,16 +1923,22 @@ Options: simulator --dry-run - With --provider: the plan (the exact compile to the device's gates and its check by - simulation) and the provider's estimate; nothing is submitted + With --provider or --allow-providers: the plan (the exact compile to the device's gates + and its check by simulation) and the provider's estimate, or every route's price or + reason; nothing is submitted --yes - With --provider: confirm a run that is not free, or whose cost is unknown; without it such - a run is refused (exit 3) + With --provider or --allow-providers: confirm a run that is not free, or whose cost is + unknown; without it such a run is refused (exit 3). A cost ceiling is no confirmation --no-wait - With --provider: send the job and answer with its handle, without waiting (`wai-quantum - providers collect`) + With --provider or --allow-providers: send the job and answer with its handle, without + waiting (`wai-quantum providers collect`) + + --confirm + With --allow-providers: confirm the run the planner chose when it is not free, by the word + its dry run gave for that route, its estimate and its program; a route, an estimate or a + program that changed since is refused. --yes confirms only a provider you name -h, --help Print help @@ -1991,6 +2062,37 @@ Options: them. A member certified bit-exact gives the CPU's answers; a placement this host cannot honour is refused (J013) + --exactness + The class the answer must be of: bit-exact, exact, single, bounded, estimate, heuristic; + measured (a processor's counts), simulated (a provider's simulator's), or any. Under a + contract (this, --max-cost, --deadline, --max-joules or --allow-providers) the planner + prices every route it can see, runs the cheapest that meets it, and seals its reasoning in + the receipt; with nothing to meet it, it refuses with each route's reason (J071), and + nothing falls back. Without a class the job keeps the class auto would give + + --max-cost + The most the run may cost, as 0.50:USD: a route with an unknown cost, or priced in another + currency, does not meet it. It confirms nothing: a run that is not free still takes --yes + + --deadline + When the run must be done by, in seconds: a route whose time is not known does not meet + it, and the receipt says whether it was kept (exit 4 when it was not) + + --max-joules + The most energy the run may take, in joules: a route whose energy is not known does not + meet it, and this command estimates none, so here every route is refused; the job service + estimates from what it has metered + + --allow-providers + Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods + here: each is asked to estimate the job, and nothing is sent unless one is chosen. A + device is chosen only when --exactness measured or any asks for its class. On the job + service, which reaches no provider, it changes nothing + + --contract + The contract itself, as JSON or a file of it: exactness, max_cost, deadline_seconds, + max_joules and providers; the options above are set over it + --json Print the plan as JSON @@ -3088,6 +3190,37 @@ Options: them. A member certified bit-exact gives the CPU's answers; a placement this host cannot honour is refused (J013) + --exactness + The class the answer must be of: bit-exact, exact, single, bounded, estimate, heuristic; + measured (a processor's counts), simulated (a provider's simulator's), or any. Under a + contract (this, --max-cost, --deadline, --max-joules or --allow-providers) the planner + prices every route it can see, runs the cheapest that meets it, and seals its reasoning in + the receipt; with nothing to meet it, it refuses with each route's reason (J071), and + nothing falls back. Without a class the job keeps the class auto would give + + --max-cost + The most the run may cost, as 0.50:USD: a route with an unknown cost, or priced in another + currency, does not meet it. It confirms nothing: a run that is not free still takes --yes + + --deadline + When the run must be done by, in seconds: a route whose time is not known does not meet + it, and the receipt says whether it was kept (exit 4 when it was not) + + --max-joules + The most energy the run may take, in joules: a route whose energy is not known does not + meet it, and this command estimates none, so here every route is refused; the job service + estimates from what it has metered + + --allow-providers + Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods + here: each is asked to estimate the job, and nothing is sent unless one is chosen. A + device is chosen only when --exactness measured or any asks for its class. On the job + service, which reaches no provider, it changes nothing + + --contract + The contract itself, as JSON or a file of it: exactness, max_cost, deadline_seconds, + max_joules and providers; the options above are set over it + --json Print the job as the service returns it: request, plan, result and receipt @@ -3592,6 +3725,10 @@ Options: One job a line, each judged as a job's receipt, one JSON verdict a line; the status is 1 when any is not valid + --recheck + For a job under a contract, also run again what can be: its routes priced again at the + job's memory, held to the digest it sealed, and its shadow, held to its counts bit for bit + -h, --help Print help diff --git a/wai/wai-quantum-cli/docs/local-mcp.json b/wai/wai-quantum-cli/docs/local-mcp.json index bf7618243..8d63f6bf6 100644 --- a/wai/wai-quantum-cli/docs/local-mcp.json +++ b/wai/wai-quantum-cli/docs/local-mcp.json @@ -4,7 +4,7 @@ { "name": "run_quantum_circuit", "title": "Run a quantum program here", - "description": "Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more.", + "description": "Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `contract` (the class wanted, a deadline) and the planner prices every method here, runs the cheapest that meets it, seals its reasoning under `planner`, and refuses (J071) rather than fall back to less; this tool reaches no provider, and plan_routes and run_routed do. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more.", "inputSchema": { "type": "object", "anyOf": [ @@ -531,6 +531,78 @@ "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -1348,6 +1420,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -4113,6 +4257,867 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -5113,6 +6118,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -7876,6 +8953,867 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -8736,7 +10674,7 @@ { "name": "plan_quantum_circuit", "title": "Plan a quantum program", - "description": "The method a program would run on and why, the memory and work it would take, without running it.", + "description": "The method a program would run on and why, the memory and work it would take, without running it. With a contract, every route's price or reason for rejection under planner, or the refusal (J071) when no route meets it.", "inputSchema": { "type": "object", "anyOf": [ @@ -9263,17 +11201,89 @@ "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, "outputSchema": { "$id": "wai-quantum://schemas/plan_quantum_circuit/1", "type": "object", - "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it.", + "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it. A job with a contract carries the planner's reasoning.", "anyOf": [ { "title": "wai.quantum.plan/1", - "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it.", + "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it. A job with a contract carries the planner's reasoning.", "type": "object", "required": [ "method", @@ -9350,6 +11360,657 @@ } } }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, "verdict": { "title": "wai.quantum.verdict/1", "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", @@ -21365,7 +24026,7 @@ { "name": "verify_quantum_result", "title": "Check a result's receipt", - "description": "Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and every rule of its form holds (`reasons` names what does not), and which key signed it.", + "description": "Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and every rule of its form holds (`reasons` names what does not), and which key signed it; for a job under a contract, every route's outcome and the choice recomputed from what it states, and with recheck its routes priced again and its shadow run again.", "inputSchema": { "type": "object", "required": [ @@ -21378,6 +24039,10 @@ "string" ], "description": "The job's text as it was given (preferred: read as the protocol reads it, so a member named twice or a number past what a parsed job keeps is seen), or the job: {\"request\": ..., \"result\": ...}, the result carrying its receipt." + }, + "recheck": { + "type": "boolean", + "description": "For a job under a contract: its routes priced again at the job's memory, held to the digest it sealed, and its shadow run again, held to its counts bit for bit." } } }, @@ -21431,6 +24096,28 @@ "null" ], "description": "That key as a did:key." + }, + "planner": { + "type": "object", + "description": "For a job under a contract, what its reasoning says: the route chosen, the class wanted and given, whether the choice depends on the host, what was kept, and the shadow." + }, + "recheck": { + "type": "object", + "description": "With recheck: whether the routes priced again and the shadow run again are what the job sealed.", + "properties": { + "holds": { + "type": "boolean" + }, + "engine": { + "type": "object" + }, + "priced": { + "type": "object" + }, + "shadow": { + "type": "object" + } + } } } }, @@ -30692,6 +33379,78 @@ "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } }, "required": [ @@ -31512,6 +34271,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -34277,6 +37108,867 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -35277,6 +38969,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -38040,6 +41804,867 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -50444,6 +55069,78 @@ "type": "integer", "minimum": 0, "description": "A seed, for a provider that is a seeded simulator; a device ignores it." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -50491,6 +55188,657 @@ "confirm": { "type": "string", "description": "What the person reads before confirming a run that is not free." + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } } } }, @@ -50576,6 +55924,78 @@ "minimum": 0, "description": "A seed, for a provider that is a seeded simulator; a device ignores it." }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } + }, "confirm_cost": { "type": "boolean", "description": "true only when the person has agreed to this run's cost. A run that is not free is refused without it." @@ -51399,6 +56819,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -54164,6 +59656,867 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -55164,6 +61517,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -57927,6 +64352,12593 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + }, + "error": { + "type": "string" + }, + "code": { + "type": "string", + "description": "A failed item's refusal code (engine::refusal)." + }, + "path": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The item's leaf's sibling digests up to the root, in hex." + } + } + } + } + } + } + ] + }, + "error": { + "type": "string", + "description": "Why a job failed, or why it was interrupted." + }, + "interruptions": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "The job service: each time it stopped while the job ran, in milliseconds since 1970. A job that was running when the service stopped is queued again, once, to run from its stored request." + }, + "submitted_ms": { + "type": "integer", + "description": "The job service: when it was submitted, in milliseconds since 1970." + }, + "started_ms": { + "type": "integer" + }, + "finished_ms": { + "type": "integer" + }, + "peak_rss_bytes": { + "type": "integer", + "description": "The job service: the most memory the job's process held." + }, + "digests": { + "type": "object", + "description": "The job service: the BLAKE3 digests its store keeps the job's objects under (the request, each program, the result and the receipt).", + "properties": { + "algorithm": { + "const": "blake3" + }, + "request": { + "type": [ + "string", + "null" + ] + }, + "programs": { + "type": "array", + "items": { + "type": "string" + } + }, + "result": { + "type": "string" + }, + "receipt": { + "type": "string" + } + } + } + } + }, + { + "type": "object", + "description": "A refusal as data: the message, every code in it (the last is the code), its outcome and meaning as the code's table gives them. A host that refuses for its own reasons gives the error alone.", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + } + ] + } + }, + { + "name": "plan_routes", + "title": "Weigh a contract against every route", + "description": "Every route a job could take under its contract: the methods on this machine and each of the person's own providers, each with its price or why it was rejected, what a provider's estimate leaves out, and the route the planner would choose: the cheapest that meets the contract, or the refusal (J071) with every route's reason. Each provider is asked to describe its device and estimate the job. Nothing is submitted and nothing is spent. A device is chosen only when exactness asks for measured or any.", + "inputSchema": { + "type": "object", + "required": [ + "qasm", + "contract" + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why." + }, + "inputs": { + "type": "object", + "additionalProperties": { + "type": "integer" + }, + "description": "A generator's inputs' values, as {\"n\": 5}." + }, + "shots": { + "type": "integer", + "minimum": 1, + "description": "Shots (default 1024)." + }, + "seed": { + "type": "integer", + "minimum": 0, + "description": "A seed." + }, + "observables": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Pauli observables: a provider's job answers counts, so a method here answers these." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } + } + } + }, + "outputSchema": { + "$id": "wai-quantum://schemas/plan_routes/1", + "type": "object", + "description": "Every route a job could take under its contract, each with its price or why it was rejected, and the route chosen: nothing submitted, nothing spent.", + "anyOf": [ + { + "type": "object", + "description": "Every route a job could take under its contract, each with its price or why it was rejected, and the route chosen: nothing submitted, nothing spent.", + "required": [ + "dry_run", + "planner" + ], + "properties": { + "dry_run": { + "const": true + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "plan": { + "title": "wai.quantum.plan/1", + "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it. A job with a contract carries the planner's reasoning.", + "type": "object", + "required": [ + "method", + "why", + "memory_bytes", + "work", + "qubits" + ], + "properties": { + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0 + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "target": { + "type": "object", + "description": "A run on a device target: which target (its hash, as its receipt binds it), its calibration snapshot, where the program was placed and why, and the noise derived from the target.", + "required": [ + "name", + "hash" + ], + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "hash_is": { + "type": "string" + }, + "calibration": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "source": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "note": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "description": "The native gate set, the layout and routes chosen, the swaps, the expected success beside the fewest-swaps layout's, and the check of the compiled program." + }, + "noise": { + "type": "object", + "description": "The noise model derived from the target's calibration: its channels, durations and idling, and each qubit's readout." + } + } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + } + } + }, + "provider_plan": { + "type": "object", + "description": "The dry run of a job on a provider: nothing submitted, nothing spent.", + "required": [ + "dry_run", + "provider", + "plan", + "estimate", + "free", + "confirm" + ], + "properties": { + "dry_run": { + "const": true + }, + "provider": { + "type": "object" + }, + "calibration": { + "type": [ + "string", + "null" + ] + }, + "billing": { + "type": "object" + }, + "plan": { + "type": "object" + }, + "estimate": { + "type": "object" + }, + "free": { + "type": "boolean" + }, + "confirm": { + "type": "string", + "description": "What the person reads before confirming a run that is not free." + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + } + } + }, + "confirm": { + "type": "object", + "description": "Where the route chosen is a provider's and not free: what a person confirms it by. token is a digest of the route, its estimate's money and the program and shots it would send; a run is sent only when given that token made again at send time.", + "required": [ + "token", + "route", + "money", + "says" + ], + "properties": { + "token": { + "type": "string" + }, + "route": { + "type": "string" + }, + "money": { + "type": "object" + }, + "says": { + "type": "string" + } + } + } + } + }, + { + "type": "object", + "description": "A refusal as data: the message, every code in it (the last is the code), its outcome and meaning as the code's table gives them. A host that refuses for its own reasons gives the error alone.", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + } + ] + } + }, + { + "name": "run_routed", + "title": "Run a job on the route its contract chooses (can spend the person's money)", + "description": "Runs a job on the route plan_routes chooses: a method on this machine, or one of the person's own providers. THIS CAN SPEND THE PERSON'S MONEY OR QUOTA, when the contract allows a provider and one is chosen. A cost ceiling confirms nothing: a run that is not free is refused unless confirm is the word plan_routes gave for that route, its estimate and its program (its confirm.token), set only after the person has seen them and agreed to that run; if the route or its estimate changed since, it is refused with the new word. The answer is a job in the service's form, its result carrying the planner's reasoning under planner; a provider's result also carries a classical method's counts and their distance under shadow, or why no classical method could reach them. If the job has not finished within this call the answer has status running and an id, and get_provider_job collects it later. Do not run it again to find out: that is a second job, and it can be a second bill.", + "inputSchema": { + "type": "object", + "required": [ + "qasm", + "contract" + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why." + }, + "inputs": { + "type": "object", + "additionalProperties": { + "type": "integer" + }, + "description": "A generator's inputs' values, as {\"n\": 5}." + }, + "shots": { + "type": "integer", + "minimum": 1, + "description": "Shots (default 1024)." + }, + "seed": { + "type": "integer", + "minimum": 0, + "description": "A seed." + }, + "observables": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Pauli observables: a provider's job answers counts, so a method here answers these." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } + }, + "confirm": { + "type": "string", + "description": "The word plan_routes gave (confirm.token) for the route, the estimate and the program the person agreed to. A run that is not free is refused without it, whatever the contract's ceiling, and refused if what is chosen now is not what that word names." + } + } + }, + "outputSchema": { + "$id": "wai-quantum://schemas/run_routed/1", + "type": "object", + "description": "A job as a host returns it: its status, the method its plan chose and why, the request as submitted, and, once it is done, the result with its receipt: a job's result, or for a set (a request with programs or a sweep, its method set) the set's result. The command line's run --json, the local MCP server's run_quantum_circuit and a run on the person's own provider give a finished job; the job service also gives its id and times, and a job still queued or running, or failed with its error. A job's receipt verifies from this document alone: request and result.", + "anyOf": [ + { + "title": "wai.quantum.job/1", + "description": "A job as a host returns it: its status, the method its plan chose and why, the request as submitted, and, once it is done, the result with its receipt: a job's result, or for a set (a request with programs or a sweep, its method set) the set's result. The command line's run --json, the local MCP server's run_quantum_circuit and a run on the person's own provider give a finished job; the job service also gives its id and times, and a job still queued or running, or failed with its error. A job's receipt verifies from this document alone: request and result.", + "type": "object", + "required": [ + "status", + "request" + ], + "properties": { + "id": { + "type": "string", + "description": "The job service's id for the job." + }, + "status": { + "enum": [ + "queued", + "running", + "done", + "failed", + "cancelled", + "interrupted" + ], + "description": "interrupted: the job service stopped while the job ran, after it had run it again once from its request, so it has no result; error says so." + }, + "method": { + "type": "string", + "description": "The method the plan chose; set for a set." + }, + "why": { + "type": "string", + "description": "Why the plan chose the method." + }, + "estimate": { + "type": "object", + "description": "What the plan admitted the job with.", + "required": [ + "memory_bytes", + "work" + ], + "properties": { + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0, + "description": "In the method's own unit." + } + } + }, + "request": { + "title": "wai.quantum.job-request/1", + "description": "A job as a client submits it: a program and what is asked of it, or a set: many programs (programs), or one over a grid of its inputs (sweep), run as one job. The command line, both MCP servers, the job service, the desktop app and the Studio read it alike, and a receipt seals it as it was given. A member the engine does not read is ignored, and sealed with the rest.", + "type": "object", + "anyOf": [ + { + "required": [ + "qasm" + ] + }, + { + "required": [ + "programs" + ] + }, + { + "required": [ + "source" + ] + } + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, in OpenQASM 3 or the OpenQASM 2 forms in common use." + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "description": "The program in another format, in place of qasm (engine::formats::expand): read to the job's qasm before the job is read, the request keeping its source.", + "properties": { + "format": { + "enum": [ + "qasm", + "qir", + "jeff" + ] + }, + "program": { + "type": "string", + "description": "The program's text (OpenQASM, QIR)." + }, + "program_base64": { + "type": "string", + "description": "The program's bytes as base64 (jeff)." + } + } + }, + "shots": { + "type": "integer", + "minimum": 0, + "maximum": 1000000, + "description": "Measurement shots; 1024 when no observables or amplitudes are asked for, otherwise 0." + }, + "seed": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991, + "description": "The sampling seed (1 when not given): the same job and seed give the same counts." + }, + "method": { + "type": "string", + "description": "auto (the default: the strongest method the program admits), or a method by its name as the methods list names it; pulse runs a pulse program (OpenPulse calibrations) under the pulse options." + }, + "observables": { + "type": "array", + "maxItems": 256, + "description": "Pauli observables to take the expectation values of.", + "items": { + "anyOf": [ + { + "type": "string", + "description": "A Pauli string, as \"Z0 Z1\"; qubits count from 0." + }, + { + "type": "object", + "required": [ + "pauli" + ], + "properties": { + "pauli": { + "type": "string", + "description": "A Pauli string, as \"X3\"." + }, + "coeff": { + "type": "number", + "description": "Its coefficient (1 when not given)." + } + } + } + ] + } + }, + "amplitudes": { + "type": "array", + "maxItems": 64, + "description": "Basis states whose amplitudes to return: one 0 or 1 per qubit, qubit n-1 first.", + "items": { + "type": "string" + } + }, + "noise": { + "type": "object", + "description": "A noise model, each channel a probability. A channel not listed here is refused.", + "additionalProperties": false, + "properties": { + "depolarizing_1q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "depolarizing_2q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "amplitude_damping": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "dephasing": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "readout": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + } + }, + "options": { + "type": "object", + "description": "Options of the method that runs the job, as the methods list names them (max_bond, cutoff, fusion, trajectories, threshold, max_weight, ladder, max_terms, path_restarts), and memory_gb." + }, + "compile": { + "type": "object", + "description": "What a compile is asked for, each optional: the most the output may differ from the program (epsilon, in the operator norm up to a global phase), the level (0 lowers and approximates; 1 also rewrites and folds phases; 2 also resynthesises), the basis, the gate set it writes the program in (clifford_t: every rotation off the multiples of π/4 a Clifford+T word; standard: nothing approximated), whether to give the circuit after each pass (stages), and the twirl and dd passes, last (twirl, with its seed; dd, with its sequence).", + "properties": { + "epsilon": { + "type": "number", + "exclusiveMinimum": 0 + }, + "level": { + "type": "integer", + "minimum": 0, + "maximum": 2 + }, + "basis": { + "enum": [ + "clifford_t", + "standard" + ] + }, + "stages": { + "type": "boolean" + }, + "twirl": { + "description": "Twirl each two-qubit Clifford gate with Paulis drawn from a seeded stream: true (seed 1), or {\"seed\": N}. One seed is one instance, checked to be the same circuit.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "required": [ + "seed" + ], + "properties": { + "seed": { + "type": "integer", + "minimum": 0 + } + } + } + ] + }, + "dd": { + "description": "Dynamical decoupling in each window where a qubit idles long enough: xx or xy4 (or {\"sequence\": …}), checked to change nothing without noise.", + "anyOf": [ + { + "enum": [ + "xx", + "xy4" + ] + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "sequence": { + "enum": [ + "xx", + "xy4" + ] + } + } + } + ] + } + } + }, + "intent": { + "description": "What the program must do, checked with the run: one intent or a list. The result's verdict says how far it was checked.", + "anyOf": [ + { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + } + ] + }, + "verdict": { + "type": "boolean", + "description": "true: the result carries a verdict even with no intent." + }, + "target": { + "description": "A device target: a built-in target's name, or a target document. The program is compiled to it, placed and simulated under its noise; noise may not be given beside it.", + "anyOf": [ + { + "type": "string" + }, + { + "title": "wai.quantum.target/1", + "description": "A device target: its qubits, the pairs it couples, its native gates with their errors and durations, and the calibration snapshot they come from. A value not known is left out, never written as zero. Every field but format, name, source, qubits, gates and coupling is optional, and a field the format does not name is refused, so a misspelt one never reads as absent. Its canonical text is its RFC 8785 form, and the BLAKE3 of that text, the target's hash, names the snapshot in a receipt.", + "type": "object", + "required": [ + "format", + "name", + "source", + "qubits", + "gates", + "coupling" + ], + "additionalProperties": false, + "properties": { + "format": { + "const": "wai.quantum.target/1" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "additionalProperties": false, + "properties": { + "format": { + "type": "string", + "description": "The format the target was read from (wai-quantum targets import --help lists them)." + }, + "note": { + "type": "string", + "maxLength": 400 + } + } + }, + "calibration": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "maxLength": 400, + "description": "The calibration snapshot's id, as the source names it, or a content id of the snapshot read." + }, + "timestamp": { + "type": "string", + "maxLength": 400, + "description": "When the snapshot was taken, as the source writes it." + } + } + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2048, + "description": "Every qubit, in order.", + "items": { + "type": "object", + "required": [ + "qubit" + ], + "additionalProperties": false, + "properties": { + "qubit": { + "type": "integer", + "minimum": 0, + "description": "Its index: its place in the list." + }, + "label": { + "type": "string", + "description": "The source's own name for it, when that is not its index." + }, + "t1_us": { + "type": "number", + "minimum": 0, + "description": "T1, microseconds." + }, + "t2_us": { + "type": "number", + "minimum": 0, + "description": "T2 (the echo or Ramsey time the source reports), microseconds." + }, + "frequency_ghz": { + "type": "number", + "minimum": 0, + "description": "Its frequency, gigahertz." + }, + "readout": { + "type": "object", + "required": [ + "p01", + "p10" + ], + "additionalProperties": false, + "properties": { + "p01": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 1 | holds 0)." + }, + "p10": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 0 | holds 1)." + } + } + }, + "measure_ns": { + "type": "number", + "minimum": 0, + "description": "The measurement's duration, nanoseconds." + } + } + } + }, + "gates": { + "type": "array", + "maxItems": 262144, + "description": "Each native gate where the device runs it, sorted by gate then qubits.", + "items": { + "type": "object", + "required": [ + "gate", + "qubits" + ], + "additionalProperties": false, + "properties": { + "gate": { + "type": "string", + "pattern": "^[a-z0-9_]{1,40}$" + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + }, + "error": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "The average gate infidelity." + }, + "duration_ns": { + "type": "number", + "minimum": 0, + "description": "Nanoseconds." + } + } + } + }, + "coupling": { + "type": "array", + "description": "The pairs a two-qubit gate may act on, each once, the lower qubit first, sorted.", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + ] + }, + "fabric": { + "description": "Where the statevector method's state runs: auto (the default: on a member only where the committed measurements show it faster than this host's CPU for the job's size and fusion width, otherwise on the CPU), cpu, accelerator (the first accelerator member certified bit-exact here that holds the state, falling back to the next if it fails during the run), a member's id or key (wai-quantum fabric lists them), or a list of members, a power of two of them, the state split by its top qubits into one partition on each (cpu is a member, and a member may be named more than once). A member certified bit-exact gives the CPU's bits. A placement this host cannot honour is refused (J013), never made elsewhere.", + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "array", + "minItems": 2, + "maxItems": 64, + "items": { + "type": "string", + "minLength": 1 + } + } + ] + }, + "repair": { + "description": "Repair the program first on its flagged lines: true, or the choices.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "max_iterations": { + "type": "integer", + "minimum": 1 + }, + "dyadic_bits": { + "type": "integer", + "minimum": 1, + "maximum": 32 + }, + "sizes": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + } + } + } + ] + }, + "history": { + "type": "object", + "description": "The program's history's account of the version the job runs: its digest, and the gates and lines in each hand. The receipt binds it; a history recomputes and checks it." + }, + "provider": { + "type": "string", + "description": "The person's own provider to run on, by the name their registry gives it. Only a host that holds their credentials runs such a job; every other host refuses it." + }, + "programs": { + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "type": "string", + "description": "A program's text." + }, + { + "type": "object", + "required": [ + "qasm" + ], + "description": "A job of its own, read as a job request is (no programs or sweep in it); each item of the set's result holds its request in full." + } + ] + }, + "description": "A set (engine::sets): the programs to run as one job, each a program's text or a job of its own; the request's other fields apply to every item that does not set them itself." + }, + "sweep": { + "type": "object", + "additionalProperties": { + "type": "array", + "minItems": 1, + "items": { + "type": "number" + } + }, + "description": "A set over the request's own qasm: values for each of the program's inputs (integer, float or angle), every combination run, the names in sorted order and the first varying slowest." + }, + "params": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "A value for each of the program's parameters (`input float theta;`, `input angle phi;`), bound exactly before the program is read: it runs as if each were written as a `const` at that double. A parameter left without a value is refused (Q114, J050). In a sweep, the parameters it fixes, each bound at every point." + }, + "dry_run": { + "type": "boolean", + "description": "With true: what the host would do with the job or set, running nothing." + }, + "mitigate": { + "description": "Mitigate the job's expectation values (or, for readout, its counts) under its noise (engine::mitigate): zne, pea, pec, cdr, vd or readout, or {\"method\", …} with its options. The result's mitigation gives each value raw and mitigated.", + "anyOf": [ + { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + { + "type": "object", + "required": [ + "method" + ] + } + ] + }, + "pulse": { + "type": "object", + "description": "A pulse run's options (method \"pulse\"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0.", + "additionalProperties": false, + "properties": { + "dt_ns": { + "type": "number", + "exclusiveMinimum": 0, + "maximum": 1000, + "description": "The sample period, ns (default 0.5)." + }, + "levels": { + "type": "integer", + "enum": [ + 2, + 3 + ], + "description": "Levels kept per qubit (default 2; 3 shows leakage)." + }, + "tolerance": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1, + "description": "The most the stated error may be (default 1e-6): a run whose bound and rounding estimate pass it is refused, naming the steps that would meet it." + }, + "substeps": { + "type": "integer", + "minimum": 1, + "maximum": 4096, + "description": "Steps per sample (default: chosen so each step times the generator's norm is at most 0.5)." + }, + "qubits": { + "type": "object", + "description": "Each qubit's parameters by its index, over the target's and the defaults.", + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "frequency_ghz": { + "type": "number", + "description": "Its frequency, GHz." + }, + "rabi_mhz": { + "type": "number", + "description": "Its Rabi frequency at full amplitude, MHz." + }, + "anharmonicity_mhz": { + "type": "number", + "description": "Its anharmonicity, MHz." + }, + "t1_us": { + "type": "number", + "description": "Its relaxation time, µs." + }, + "t2_us": { + "type": "number", + "description": "Its coherence time, µs (at most 2·T1)." + } + } + } + }, + "couplings": { + "type": "array", + "description": "Static ZZ couplings.", + "items": { + "type": "object", + "required": [ + "qubits", + "zz_khz" + ], + "additionalProperties": false, + "properties": { + "qubits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + }, + "minItems": 2, + "maxItems": 2 + }, + "zz_khz": { + "type": "number", + "description": "The coupling's rate, kHz." + } + } + } + }, + "ports": { + "type": "object", + "description": "Ports by name: what each is for and the qubit it reaches.", + "additionalProperties": { + "type": "object", + "required": [ + "kind", + "qubit" + ], + "additionalProperties": false, + "properties": { + "kind": { + "enum": [ + "drive", + "measure", + "acquire" + ] + }, + "qubit": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } + } + } + }, + "result": { + "anyOf": [ + { + "title": "wai.quantum.job-result/1", + "description": "A job's result as the engine gives it, on every host: what was asked of the program, computed by the method its plan chose, with that method's accuracy class. The receipt seals the result without its receipt member, beside the request. A result names the engine that made it and this schema (engine and schema); results made before results carried them have neither and follow this schema all the same.", + "type": "object", + "required": [ + "method", + "qubits", + "gates", + "accuracy" + ], + "properties": { + "engine": { + "type": "object", + "description": "The engine that made the result: the wai-quantum crate's name and version.", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "const": "wai-quantum" + }, + "version": { + "type": "string", + "description": "Its semantic version, as MAJOR.MINOR.PATCH." + } + } + }, + "schema": { + "const": "wai.quantum.job-result/1", + "description": "The schema the result follows." + }, + "components": { + "type": "array", + "description": "The identity of every component that made the result, when a registered one took part (engine::registry): its program's format, the passes its compile ran, the noise channels it names, its method; each registered one marked so. Sealed by the receipt with the rest.", + "items": { + "type": "object", + "description": "One component that made the result (engine::registry): its kind, name and version, the BLAKE3 digest of its descriptor, and whether it is built in. A result carries these only when a registered component took part; one made by built-ins alone names them as it always has (its method, its compile's passes, its noise's channels and the engine's version), the digests of that version listed by the components list.", + "required": [ + "kind", + "name", + "version", + "digest", + "origin" + ], + "properties": { + "kind": { + "enum": [ + "method", + "pass", + "channel", + "front_end" + ] + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "digest": { + "type": "string", + "pattern": "^[0-9a-f]{64}$", + "description": "BLAKE3 of the component's descriptor in its canonical JSON (engine::registry::digest_of)." + }, + "origin": { + "enum": [ + "built-in", + "registered" + ], + "description": "built-in: the engine's own; registered: a host's own, added in its process, not part of the engine." + }, + "certified": { + "const": false, + "description": "Beside a registered component: the engine does not certify it." + } + } + } + }, + "method": { + "type": "string", + "description": "The method that ran the job (provider for a run on the person's own provider)." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": "integer", + "minimum": 0 + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "state_hash": { + "type": "string", + "description": "The bit-exact method's statevector hash (BLAKE3, hex): the same on every machine." + }, + "counts": { + "type": "object", + "description": "Outcomes and their counts, keyed by the program's classical bits, the highest bit first. At most 65536 outcomes are listed; omitted_shots holds the rest.", + "additionalProperties": { + "type": "integer", + "minimum": 0 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "outcome_dimension": { + "type": "integer", + "minimum": 0, + "description": "The stabilizer method: the dimension of the measured outcomes' affine space." + }, + "shots": { + "type": "integer", + "minimum": 0, + "description": "The shots, where the method names them in the result (trajectories, provider)." + }, + "expectations": { + "type": "array", + "items": { + "type": "object", + "required": [ + "observable", + "coeff", + "value" + ], + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "value": { + "type": "number", + "description": "The coefficient times the expectation value." + }, + "stderr": { + "type": "number", + "description": "The standard error, for an estimate." + }, + "bound": { + "type": "number", + "description": "A bound on |exact − value|: rigorous for the bounded class; with confidence beside it, holding with that probability." + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + }, + "max_terms": { + "type": "integer" + }, + "ladder": { + "type": "array", + "description": "The value at thresholds a decade apart, the asked one last.", + "items": { + "type": "object", + "required": [ + "threshold", + "value", + "bound" + ], + "properties": { + "threshold": { + "type": "number" + }, + "value": { + "type": "number" + }, + "bound": { + "type": "number" + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + } + } + } + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds, for a bound that holds with a stated probability (stabilizer_rank's sampled mode)." + } + } + } + }, + "amplitudes": { + "type": "array", + "items": { + "type": "object", + "required": [ + "bits", + "re", + "im" + ], + "properties": { + "bits": { + "type": "string", + "description": "One 0 or 1 per qubit, qubit n-1 first." + }, + "re": { + "type": "number" + }, + "im": { + "type": "number" + }, + "bound": { + "type": "number", + "minimum": 0, + "description": "A bound on |exact − value| of the amplitude, holding with the probability confidence states (stabilizer_rank's sampled mode)." + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds." + } + } + } + }, + "global_phase": { + "type": "string", + "description": "Why the amplitudes' global phase is not fixed, when it is not." + }, + "warning": { + "type": "string" + }, + "contraction_flops": { + "type": "number", + "description": "The tensor network's contraction cost." + }, + "dynamic": { + "type": "object", + "description": "A program that measures in the middle, resets or branches on a measured bit: how it ran.", + "properties": { + "measurements_and_resets": { + "type": "integer", + "minimum": 0 + }, + "branches_run": { + "type": "integer", + "minimum": 0 + }, + "states_at_once": { + "type": "integer", + "minimum": 0 + }, + "branches_weighed": { + "type": "integer", + "minimum": 0 + } + } + }, + "outputs": { + "type": "array", + "description": "The program's output declarations: each its name and type, and its value, or the places of its bits in each outcome.", + "items": { + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "bits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + } + }, + "value": { + "description": "A number, a boolean, a bit string, a duration's text, {\"re\", \"im\"}, or an array of them." + } + } + } + }, + "timing": { + "type": "object", + "description": "A program that states durations (delay, box, stretch) the method does not apply: said so, with the reader's code.", + "required": [ + "applied", + "why" + ], + "properties": { + "applied": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "diagnostics": { + "type": "array", + "description": "The reader's warnings and notes on the program, each with its code.", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "compiled": { + "description": "How the program was compiled before it ran: on the person's own provider, to the device's gates; or, asked with compile, to a basis within a budget. Either way, basis is the gate set it was compiled to.", + "anyOf": [ + { + "type": "object", + "description": "A provider job: the program sent, compiled exactly to the device's own gates: its basis (the device's gate set), its OpenQASM 3 text (qasm3) and that text's BLAKE3 (program), its counts of gates and swaps, its layouts, and the check it passed before it was sent. Results sealed before qasm3 carry the hash alone.", + "required": [ + "basis", + "program" + ], + "properties": { + "basis": { + "type": "string" + }, + "program": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "qasm3": { + "type": "string", + "description": "The program sent, as OpenQASM 3, $i being index i of the coupling map the provider described; program is the BLAKE3 of its UTF-8 bytes." + }, + "qubit_names": { + "type": "object", + "additionalProperties": { + "type": "string", + "minLength": 1 + }, + "description": "The device's own name for each index the program uses, as it was when the job was sent, where a client sends it under those names." + }, + "native_gates": { + "type": "integer" + }, + "two_qubit_gates": { + "type": "integer" + }, + "swaps": { + "type": "integer" + }, + "layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "final_layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "checked": { + "type": "string" + }, + "placement": { + "type": "object", + "description": "Where the program was placed on the device's qubits, and why." + } + } + }, + { + "type": "object", + "description": "A job asked to compile its program first: what ran is the compiled circuit, within distance of the program in the operator norm up to a global phase.", + "required": [ + "basis", + "verdict" + ], + "properties": { + "basis": { + "enum": [ + "clifford_t", + "standard" + ], + "description": "The gate set the program was compiled to." + }, + "level": { + "type": "integer", + "minimum": 0 + }, + "epsilon": { + "type": "number", + "description": "The budget asked for." + }, + "distance": { + "type": [ + "number", + "null" + ], + "description": "The bound the passes' distances add to." + }, + "verdict": { + "type": "string" + }, + "source": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "output": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ], + "description": "The BLAKE3 of the compile certificate's RFC 8785 text, in hex." + }, + "note": { + "type": "string" + } + } + } + ] + }, + "verdict": { + "title": "wai.quantum.verdict/1", + "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", + "type": "object", + "required": [ + "schema", + "level", + "rank", + "holds", + "statement", + "parsed", + "executed", + "intent", + "critique", + "repairs" + ], + "properties": { + "schema": { + "const": "wai.quantum.verdict/1" + }, + "level": { + "enum": [ + "refused", + "parsed", + "executed", + "evidence", + "proof" + ] + }, + "rank": { + "type": "integer", + "minimum": 0, + "maximum": 4, + "description": "The level's place on the ladder, from 0 (refused) to 4 (proof)." + }, + "holds": { + "type": [ + "boolean", + "null" + ] + }, + "statement": { + "type": "string", + "description": "The level in one plain line." + }, + "parsed": { + "type": "object", + "description": "Whether the reader took the program, and its warnings and notes with their codes, or its refusal.", + "required": [ + "ok" + ], + "properties": { + "ok": { + "type": "boolean" + }, + "diagnostics": { + "type": "array", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + }, + "text": { + "type": "string", + "description": "The refusal as the reader wrote it, with its line and code." + } + } + }, + "executed": { + "type": [ + "object", + "null" + ], + "description": "The method that ran and its accuracy class, and the distance a compile put between the program and what ran.", + "properties": { + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "compiled_distance": { + "type": [ + "number", + "null" + ] + } + } + }, + "intent": { + "type": "array", + "items": { + "type": "object", + "description": "One intent's check: what it asked, whether it held, how strong the check was and how it was made.", + "required": [ + "kind", + "outcome", + "strength", + "how" + ], + "properties": { + "kind": { + "enum": [ + "distribution", + "equivalent", + "prepares", + "sampled", + "compiled" + ] + }, + "outcome": { + "enum": [ + "holds", + "fails", + "unchecked" + ] + }, + "strength": { + "enum": [ + "proof", + "evidence", + "none" + ] + }, + "how": { + "type": "string" + }, + "why": { + "type": "string" + }, + "distance": { + "type": "number" + }, + "tolerance": { + "type": "number" + }, + "outcomes": { + "type": "integer", + "description": "The outcomes the distribution holds, or the samples' distinct outcomes." + }, + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The program's distribution, when its outcomes are few enough to list." + }, + "largest_gaps": { + "type": "array", + "items": { + "type": "object", + "properties": { + "outcome": { + "type": "string" + }, + "program": { + "type": "number" + }, + "intent": { + "type": "number" + } + } + } + }, + "global_phase": { + "type": [ + "number", + "null" + ] + }, + "method": { + "type": "string", + "description": "A sampled intent: the method the samples were run by." + }, + "seed": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "alpha": { + "type": "number" + }, + "fit": { + "type": "object", + "description": "A sampled intent: the test, its statistic, degrees of freedom and p-value, the level, and whether it rejected.", + "properties": { + "test": { + "type": "string" + }, + "statistic": { + "type": "number" + }, + "dof": { + "type": "integer" + }, + "p_value": { + "type": "number" + }, + "alpha": { + "type": "number" + }, + "shots": { + "type": "integer" + }, + "rejected": { + "type": "boolean" + }, + "smallest_expected": { + "type": [ + "number", + "null" + ] + }, + "impossible": { + "type": [ + "integer", + "array", + "boolean" + ] + }, + "note": { + "type": "string" + } + } + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "name": { + "type": "string" + }, + "note": { + "type": "string" + } + } + } + }, + "critique": { + "type": "array", + "description": "The program's smells, each with its lines.", + "items": { + "type": "object" + } + }, + "repairs": { + "type": "array", + "description": "Each edit a repair made, with the code it answered and the lines it changed.", + "items": { + "type": "object" + } + }, + "refusal": { + "type": "object", + "description": "For a refused job: its message and its codes.", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + }, + "sealed": { + "type": "boolean" + } + } + }, + "target": { + "type": "object", + "description": "A run on a device target: which target (its hash, as its receipt binds it), its calibration snapshot, where the program was placed and why, and the noise derived from the target.", + "required": [ + "name", + "hash" + ], + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "hash_is": { + "type": "string" + }, + "calibration": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "source": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "note": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "description": "The native gate set, the layout and routes chosen, the swaps, the expected success beside the fewest-swaps layout's, and the check of the compiled program." + }, + "noise": { + "type": "object", + "description": "The noise model derived from the target's calibration: its channels, durations and idling, and each qubit's readout." + } + } + }, + "fabric": { + "type": "object", + "description": "Where the state vector, or the pauli method's sum of terms, ran: the kernel, the placement the job asked for, the member that ran it (or each partition's), each with its certificate, and the energy. Present when the job asked for a placement, or when auto placed the state on a member by measurement (`auto`); a job auto leaves on the CPU names nothing; the receipt seals it with the rest of the result. Every member placed is certified bit-exact, so the answers are the CPU's, byte for byte.", + "required": [ + "kernel", + "asked", + "parity", + "energy" + ], + "properties": { + "kernel": { + "type": "string" + }, + "asked": { + "description": "The placement the job asked for, as it gave it.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "partitions": { + "type": "array", + "description": "Each partition's member, by the value of the state's top qubits: partition i holds the amplitudes whose top bits read i.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "partition_qubits": { + "type": "integer", + "minimum": 0 + }, + "local_qubits": { + "type": "integer", + "minimum": 0 + }, + "segments": { + "type": "integer", + "minimum": 0, + "description": "Runs of gates the partitions took in turn, between exchanges." + }, + "exchanges": { + "type": "integer", + "minimum": 0, + "description": "Partition qubits exchanged with local ones through the host's copy of the state." + }, + "fell_back_from": { + "type": "array", + "description": "An accelerator request whose member failed during the run: each member that failed, in turn, with how; the member named above ran the job.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "auto": { + "type": "object", + "description": "Why auto placed the state where it ran: the rule (a member is placed only where the committed measurements show it faster than this host's CPU for the job's size and fusion width) and the measured row it rests on, with the host, the day and the load it was measured under. Present only when auto placed a state on a member.", + "required": [ + "rule", + "host", + "fusion", + "from_qubits", + "to_qubits" + ], + "properties": { + "rule": { + "type": "string" + }, + "host": { + "type": "string", + "description": "The host's processor as the measurements name it (cpu--)." + }, + "measured": { + "type": "string", + "description": "The day the host was measured (UTC)." + }, + "about": { + "type": "string" + }, + "load": { + "type": "string" + }, + "discovery_ms": { + "type": "number", + "description": "What discovering and certifying the host's members took, once per process, as measured." + }, + "fusion": { + "type": "integer", + "minimum": 1 + }, + "from_qubits": { + "type": "integer", + "minimum": 0 + }, + "to_qubits": { + "type": "integer", + "minimum": 0 + }, + "min_launches": { + "type": "integer", + "minimum": 0 + }, + "basis": { + "type": "object", + "description": "The measured row the job is judged by: the largest measured size at or below its own, the launches of its plan, the runs of each, and the spread of the CPU's and the member's times in milliseconds.", + "required": [ + "qubits", + "launches", + "runs", + "cpu_ms", + "member_ms" + ], + "properties": { + "qubits": { + "type": "integer", + "minimum": 0 + }, + "launches": { + "type": "integer", + "minimum": 0 + }, + "runs": { + "type": "integer", + "minimum": 0 + }, + "cpu_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + }, + "member_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + } + } + } + } + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "why": { + "type": "string" + } + } + }, + "repaired": { + "type": "object", + "description": "A job asked to repair its program first: the program that ran, each repair, and what needs a person.", + "properties": { + "qasm": { + "type": "string" + }, + "repairs": { + "type": "array", + "items": { + "type": "object", + "required": [ + "code", + "by", + "edits" + ], + "properties": { + "code": { + "type": "string" + }, + "rule": { + "type": "string" + }, + "by": { + "enum": [ + "engine", + "proposal" + ] + }, + "flagged": { + "type": "array", + "items": { + "type": "integer" + } + }, + "edits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "line": { + "type": "integer" + }, + "before": { + "type": [ + "string", + "null" + ] + }, + "after": { + "type": [ + "string", + "null" + ] + } + } + } + } + } + } + }, + "needs_person": { + "type": "array", + "items": { + "type": "object" + } + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0, + "description": "Wall time of the run, where the host has a clock (not in a browser tab)." + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "receipt": { + "anyOf": [ + { + "title": "wai.quantum.receipt/2", + "description": "A result's receipt: an Ed25519 signature, by the key it names, over digest = BLAKE3(\"wai:quantum-service-receipt\\x02\" ‖ len ‖ request ‖ len ‖ result), each of request and result in its RFC 8785 canonical text (the result without its receipt member), each length 8 bytes big-endian. Whatever members the request and the result hold are sealed, the result's engine and schema among them. The first receipts (no canon member, $defs/first) sealed their writer's compact text under the domain ending \\x01; they still verify. wai/extensions/quantum-providers.md section 8.2 states the seal in full, and section 8.4 what a verifier checks.", + "type": "object", + "required": [ + "alg", + "canon", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "canon": { + "const": "rfc8785", + "description": "The canonical form the digest is taken over." + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The signing key, 32 bytes in lower-case hex." + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The digest signed, 32 bytes in lower-case hex." + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$", + "description": "The signature, 64 bytes in lower-case hex." + } + } + }, + { + "description": "The first form, before canon: the digest is over the compact text its writer wrote of each, members in the document's order (section 8.2 of wai/extensions/quantum-providers.md), under the domain ending \\x01. Never written now; still verified.", + "type": "object", + "required": [ + "alg", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$" + } + } + } + ] + }, + "provider": { + "type": "object", + "description": "A provider job: the provider's name, kind and protocol, the device, its provenance, and the hash of its description." + }, + "counts_source": { + "enum": [ + "shots", + "vendor_counts", + "probabilities" + ], + "description": "A provider job: where its counts come from (wai/extensions/quantum-providers.md section 8.3): tallied from one record a shot (shots), the provider's own counts (vendor_counts), or rebuilt from the probabilities it returned by largest remainders, derived and not shot records (probabilities). Results sealed before it carry neither it nor execution." + }, + "execution": { + "type": "object", + "description": "A provider job: how the device was asked to run the program (section 8.3): who states it (stated_by: client, provider or nobody); what the client sent (sent: the request's members and the settings among them); each of mitigation, twirling, decoupling, remapping and optimisation (off, on, default when the request sets nothing for it, none when the device has no such step, unknown when nobody states it); whether the gates were to run as written (verbatim); and a note.", + "required": [ + "stated_by", + "mitigation", + "twirling", + "decoupling", + "remapping", + "optimisation", + "verbatim" + ], + "properties": { + "stated_by": { + "enum": [ + "client", + "provider", + "nobody" + ] + }, + "sent": { + "type": "object", + "required": [ + "fields", + "settings" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "settings": { + "type": "object" + } + }, + "additionalProperties": false + }, + "mitigation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "twirling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "decoupling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "remapping": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "optimisation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "verbatim": { + "type": [ + "boolean", + "null" + ] + }, + "note": { + "type": "string" + } + }, + "additionalProperties": false + }, + "calibration": { + "type": [ + "string", + "null" + ], + "description": "A provider job: the calibration snapshot it ran under." + }, + "job": { + "type": "object", + "description": "A provider job: the provider's job id and its status checks." + }, + "ideal": { + "description": "A provider job: the circuit's exact distribution set beside the measured counts.", + "anyOf": [ + { + "type": "object", + "required": [ + "computed", + "total_variation_distance", + "hellinger_fidelity" + ], + "properties": { + "computed": { + "const": true + }, + "method": { + "type": "string" + }, + "total_variation_distance": { + "type": "number" + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number" + }, + "ideal_outcomes": { + "type": "integer" + }, + "note": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "computed", + "why" + ], + "properties": { + "computed": { + "const": false + }, + "why": { + "type": "string" + } + } + } + ] + }, + "cost": { + "type": "object", + "description": "A provider job: the estimate shown before it was sent, what the provider says it charged, and whether the person confirmed a run that was not free." + }, + "provenance": { + "title": "wai.quantum.provenance/1", + "description": "What a result came from, under the five categories cross-platform provenance surveys use: the circuit, the computer, the compilation, the execution and the software. A host adds it to the results it seals (the job service does, and each item of a set); a result without it reads as it always did. wai-quantum-service/docs/provenance.md maps every field to where it is and whether the receipt seals it.", + "type": "object", + "required": [ + "schema", + "circuit", + "computer", + "compilation", + "execution", + "software" + ], + "properties": { + "schema": { + "const": "wai.quantum.provenance/1" + }, + "circuit": { + "type": "object", + "description": "The program: the BLAKE3 digest of its text as given, its qubits and its gates.", + "required": [ + "program" + ], + "properties": { + "program": { + "type": "string", + "description": "BLAKE3 of the program's text, in hex." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": [ + "integer", + "null" + ] + } + } + }, + "computer": { + "type": "object", + "description": "What ran it: a classical simulator, the method and its accuracy class, a device target's hash when the job named one, and the fabric's members when the result names where its state ran.", + "required": [ + "kind", + "method" + ], + "properties": { + "kind": { + "const": "simulator" + }, + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "target": { + "type": "string", + "description": "The device target's hash; its layout, routes and noise are in the result's own target." + }, + "fabric": { + "type": "object", + "description": "The kernel and the member that ran the state, or each partition's, as the result's fabric names them.", + "properties": { + "kernel": { + "type": "string" + }, + "members": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "compilation": { + "type": "object", + "description": "Whether the job asked to be compiled; if it did, each pass in order with its check's verdict, the certificate's digest, the gate set compiled to (its basis), the level, the ε budget and the distance the result carries, and that no pass draws a random number.", + "required": [ + "asked" + ], + "properties": { + "asked": { + "type": "boolean" + }, + "passes": { + "type": [ + "array", + "null" + ], + "items": { + "type": "object", + "properties": { + "pass": { + "type": "string" + }, + "verdict": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ] + }, + "basis": { + "type": [ + "string", + "null" + ], + "description": "The gate set compiled to: clifford_t or standard." + }, + "level": { + "type": [ + "integer", + "null" + ] + }, + "epsilon": { + "type": [ + "number", + "null" + ] + }, + "distance": { + "type": [ + "number", + "null" + ] + }, + "seeded": { + "const": false + }, + "device": { + "type": "string", + "description": "A job on a device target, compiled exactly to its gates: where its layout and routes are." + }, + "status": { + "const": "not-applicable" + }, + "why": { + "type": "string" + } + } + }, + "execution": { + "type": "object", + "description": "The shots, the seed and the plan the job ran under; its identifier and times are the host's, outside the result.", + "required": [ + "plan" + ], + "properties": { + "shots": { + "type": [ + "integer", + "null" + ] + }, + "seed": { + "type": [ + "integer", + "null" + ] + }, + "plan": { + "type": "object", + "properties": { + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0 + } + } + } + } + }, + "software": { + "type": "object", + "description": "The engine's name and version, and the host's.", + "required": [ + "engine", + "host" + ], + "properties": { + "engine": { + "type": "string" + }, + "host": { + "type": "string" + } + } + } + } + }, + "mitigation": { + "title": "wai.quantum.mitigation/1", + "description": "A job's mitigation (its request's mitigate, engine::mitigate), in its result: the method and the options it ran with, its bias and variance assumptions, each observable raw and mitigated with a standard error each and the ideal value (or, for readout, the counts inverted as a quasi-distribution), the method's own details and what it spent. docs/qec.md describes each method.", + "type": "object", + "required": [ + "method", + "options", + "assumptions" + ], + "properties": { + "method": { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + "options": { + "type": "object", + "description": "The options it ran with, the defaults filled in.", + "properties": { + "method": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "factors": { + "type": "array", + "items": { + "type": "number" + } + }, + "extrapolation": { + "enum": [ + "richardson", + "linear", + "exponential" + ] + }, + "samples": { + "type": "integer" + }, + "training": { + "type": "integer" + }, + "keep": { + "type": "integer" + }, + "learn_shots": { + "type": "integer" + } + } + }, + "assumptions": { + "type": "object", + "properties": { + "bias": { + "type": "string" + }, + "variance": { + "type": "string" + } + } + }, + "noise": { + "type": "string", + "description": "How the job's noise model is read for the method." + }, + "note": { + "type": "string" + }, + "observables": { + "type": "array", + "items": { + "type": "object", + "description": "One observable: its raw value and the mitigated one, each with its standard error, and the ideal value a simulation knows.", + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "raw": { + "type": "number" + }, + "raw_stderr": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + }, + "ideal": { + "type": "number" + } + } + } + }, + "distribution": { + "type": "array", + "description": "readout: each outcome's raw share and its mitigated quasi-probability, with its standard error.", + "items": { + "type": "object", + "properties": { + "bits": { + "type": "string" + }, + "raw": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + } + } + } + }, + "details": { + "type": "object", + "description": "The method's own: the folded scales and the folding check (zne), the learned model and the amplified values (pea), the quasi-probability and the value it converges to (pec), the training fits (cdr), the purity (vd), the flip and its amplification (readout).", + "additionalProperties": true + }, + "cost": { + "type": "object", + "description": "The circuits and shots it spent beyond the job's own.", + "properties": { + "circuits": { + "type": "integer", + "minimum": 0 + }, + "shots": { + "type": "integer", + "minimum": 0 + }, + "note": { + "type": "string" + } + } + } + } + }, + "pulse": { + "type": "object", + "description": "A pulse run (method pulse, engine::pulse): what was read and its distribution, the final populations, each capture's reading, the final density matrix's digest, the schedule's length, the integrator and its step, the device and where each parameter came from, and what the receipt binds (calibration).", + "required": [ + "read", + "outcome_bits", + "populations", + "simulated_qubits", + "density_hash", + "integrator", + "device", + "calibration" + ], + "properties": { + "read": { + "type": "string", + "description": "What the distribution reads: the captures together (into the program's bits when each writes one), or the final state." + }, + "outcome_bits": { + "type": "array", + "items": { + "type": "string" + }, + "description": "What each character of an outcome is, left to right: a program bit (c[0]) or a qubit ($0)." + }, + "distribution": { + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "number" + }, + "description": "The probability of each outcome, which the counts sample; null when the captures start at different samples." + }, + "populations": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The final state read on every simulated qubit, the highest qubit first, a level above 0 read as 1." + }, + "simulated_qubits": { + "type": "array", + "items": { + "type": "integer" + } + }, + "captures": { + "type": "array", + "items": { + "type": "object", + "properties": { + "frame": { + "type": "string" + }, + "qubit": { + "type": "integer" + }, + "start": { + "type": "integer" + }, + "start_ns": { + "type": "number" + }, + "bit": { + "type": [ + "string", + "null" + ] + }, + "p1": { + "type": "number" + }, + "p2": { + "type": "number" + } + } + } + }, + "leakage": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "p2": { + "type": "number" + } + } + }, + "description": "With three levels: each qubit's final probability of level 2." + }, + "trace": { + "type": "number" + }, + "density_hash": { + "type": "string", + "description": "The BLAKE3 of the final density matrix's bits: the same on every platform." + }, + "duration": { + "type": "integer" + }, + "duration_ns": { + "type": "number" + }, + "integrator": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "order": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "substeps": { + "type": "integer" + }, + "step_ns": { + "type": "number" + }, + "steps": { + "type": "integer" + }, + "norm_max": { + "type": "number" + }, + "frame": { + "type": "string" + } + } + }, + "device": { + "type": "object", + "properties": { + "levels": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "qubits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "frequency_hz": { + "type": "number" + }, + "rabi_hz": { + "type": "number" + }, + "anharmonicity_hz": { + "type": "number" + }, + "t1_ns": { + "type": "number" + }, + "t2_ns": { + "type": "number" + }, + "from": { + "type": "object", + "additionalProperties": { + "enum": [ + "pulse", + "target", + "default", + "none" + ] + } + } + } + } + }, + "couplings": { + "type": "array" + }, + "model": { + "type": "string" + } + } + }, + "calibration": { + "type": "object", + "description": "What the receipt binds: the program's, its calibrations', the schedule's and the device's digests, and the target snapshot.", + "properties": { + "program": { + "type": "string" + }, + "calibrations": { + "type": "string" + }, + "schedule": { + "type": "string" + }, + "device": { + "type": "string" + }, + "target": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "calibration": { + "type": "object" + } + } + } + } + }, + "not_modelled": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + }, + { + "title": "wai.quantum.set/1", + "description": "A set's result: many programs, or one program over a grid of its inputs, run as one job (engine::sets). Its head holds the count, how many items finished and failed, the Merkle root over the items' leaves, the set's energy and time; the set's receipt seals the set's request and its head. Each item is a plain job with its own receipt, its index, its point in a sweep, and its path to the root, so it is shown sealed by the set alone. A result names the engine that made it and this schema (engine and schema).", + "type": "object", + "required": [ + "format", + "count", + "done", + "failed", + "root", + "items" + ], + "properties": { + "engine": { + "type": "object", + "description": "The engine that made the result: the wai-quantum crate's name and version.", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "const": "wai-quantum" + }, + "version": { + "type": "string" + } + } + }, + "schema": { + "const": "wai.quantum.set/1" + }, + "format": { + "const": "wai.quantum.set/1" + }, + "count": { + "type": "integer", + "minimum": 1 + }, + "done": { + "type": "integer", + "minimum": 0 + }, + "failed": { + "type": "integer", + "minimum": 0 + }, + "root": { + "type": "string", + "description": "The Merkle root of the items' leaves, in hex (domains moq-jwp:merkle-leaf and moq-jwp:merkle-node, version 1)." + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "receipt": { + "title": "wai.quantum.receipt/2", + "description": "A result's receipt: an Ed25519 signature, by the key it names, over digest = BLAKE3(\"wai:quantum-service-receipt\\x02\" ‖ len ‖ request ‖ len ‖ result), each of request and result in its RFC 8785 canonical text (the result without its receipt member), each length 8 bytes big-endian. Whatever members the request and the result hold are sealed, the result's engine and schema among them. The first receipts (no canon member, $defs/first) sealed their writer's compact text under the domain ending \\x01; they still verify. wai/extensions/quantum-providers.md section 8.2 states the seal in full, and section 8.4 what a verifier checks.", + "type": "object", + "required": [ + "alg", + "canon", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "canon": { + "const": "rfc8785", + "description": "The canonical form the digest is taken over." + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The signing key, 32 bytes in lower-case hex." + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The digest signed, 32 bytes in lower-case hex." + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$", + "description": "The signature, 64 bytes in lower-case hex." + } + } + }, + "items": { + "type": "array", + "items": { + "type": "object", + "description": "One item: its index, its point in a sweep, its request (a plain job, complete in itself), and its result with its own receipt, or why it failed; and its path to the set's root.", + "required": [ + "index", + "request", + "status", + "path" + ], + "properties": { + "index": { + "type": "integer", + "minimum": 0 + }, + "point": { + "type": "object", + "description": "A sweep's item: the value of each input it was run at." + }, + "status": { + "enum": [ + "done", + "failed" + ] + }, + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "request": { + "title": "wai.quantum.job-request/1", + "description": "A job as a client submits it: a program and what is asked of it, or a set: many programs (programs), or one over a grid of its inputs (sweep), run as one job. The command line, both MCP servers, the job service, the desktop app and the Studio read it alike, and a receipt seals it as it was given. A member the engine does not read is ignored, and sealed with the rest.", + "type": "object", + "anyOf": [ + { + "required": [ + "qasm" + ] + }, + { + "required": [ + "programs" + ] + }, + { + "required": [ + "source" + ] + } + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, in OpenQASM 3 or the OpenQASM 2 forms in common use." + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "description": "The program in another format, in place of qasm (engine::formats::expand): read to the job's qasm before the job is read, the request keeping its source.", + "properties": { + "format": { + "enum": [ + "qasm", + "qir", + "jeff" + ] + }, + "program": { + "type": "string", + "description": "The program's text (OpenQASM, QIR)." + }, + "program_base64": { + "type": "string", + "description": "The program's bytes as base64 (jeff)." + } + } + }, + "shots": { + "type": "integer", + "minimum": 0, + "maximum": 1000000, + "description": "Measurement shots; 1024 when no observables or amplitudes are asked for, otherwise 0." + }, + "seed": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991, + "description": "The sampling seed (1 when not given): the same job and seed give the same counts." + }, + "method": { + "type": "string", + "description": "auto (the default: the strongest method the program admits), or a method by its name as the methods list names it; pulse runs a pulse program (OpenPulse calibrations) under the pulse options." + }, + "observables": { + "type": "array", + "maxItems": 256, + "description": "Pauli observables to take the expectation values of.", + "items": { + "anyOf": [ + { + "type": "string", + "description": "A Pauli string, as \"Z0 Z1\"; qubits count from 0." + }, + { + "type": "object", + "required": [ + "pauli" + ], + "properties": { + "pauli": { + "type": "string", + "description": "A Pauli string, as \"X3\"." + }, + "coeff": { + "type": "number", + "description": "Its coefficient (1 when not given)." + } + } + } + ] + } + }, + "amplitudes": { + "type": "array", + "maxItems": 64, + "description": "Basis states whose amplitudes to return: one 0 or 1 per qubit, qubit n-1 first.", + "items": { + "type": "string" + } + }, + "noise": { + "type": "object", + "description": "A noise model, each channel a probability. A channel not listed here is refused.", + "additionalProperties": false, + "properties": { + "depolarizing_1q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "depolarizing_2q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "amplitude_damping": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "dephasing": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "readout": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + } + }, + "options": { + "type": "object", + "description": "Options of the method that runs the job, as the methods list names them (max_bond, cutoff, fusion, trajectories, threshold, max_weight, ladder, max_terms, path_restarts), and memory_gb." + }, + "compile": { + "type": "object", + "description": "What a compile is asked for, each optional: the most the output may differ from the program (epsilon, in the operator norm up to a global phase), the level (0 lowers and approximates; 1 also rewrites and folds phases; 2 also resynthesises), the basis, the gate set it writes the program in (clifford_t: every rotation off the multiples of π/4 a Clifford+T word; standard: nothing approximated), whether to give the circuit after each pass (stages), and the twirl and dd passes, last (twirl, with its seed; dd, with its sequence).", + "properties": { + "epsilon": { + "type": "number", + "exclusiveMinimum": 0 + }, + "level": { + "type": "integer", + "minimum": 0, + "maximum": 2 + }, + "basis": { + "enum": [ + "clifford_t", + "standard" + ] + }, + "stages": { + "type": "boolean" + }, + "twirl": { + "description": "Twirl each two-qubit Clifford gate with Paulis drawn from a seeded stream: true (seed 1), or {\"seed\": N}. One seed is one instance, checked to be the same circuit.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "required": [ + "seed" + ], + "properties": { + "seed": { + "type": "integer", + "minimum": 0 + } + } + } + ] + }, + "dd": { + "description": "Dynamical decoupling in each window where a qubit idles long enough: xx or xy4 (or {\"sequence\": …}), checked to change nothing without noise.", + "anyOf": [ + { + "enum": [ + "xx", + "xy4" + ] + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "sequence": { + "enum": [ + "xx", + "xy4" + ] + } + } + } + ] + } + } + }, + "intent": { + "description": "What the program must do, checked with the run: one intent or a list. The result's verdict says how far it was checked.", + "anyOf": [ + { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + } + ] + }, + "verdict": { + "type": "boolean", + "description": "true: the result carries a verdict even with no intent." + }, + "target": { + "description": "A device target: a built-in target's name, or a target document. The program is compiled to it, placed and simulated under its noise; noise may not be given beside it.", + "anyOf": [ + { + "type": "string" + }, + { + "title": "wai.quantum.target/1", + "description": "A device target: its qubits, the pairs it couples, its native gates with their errors and durations, and the calibration snapshot they come from. A value not known is left out, never written as zero. Every field but format, name, source, qubits, gates and coupling is optional, and a field the format does not name is refused, so a misspelt one never reads as absent. Its canonical text is its RFC 8785 form, and the BLAKE3 of that text, the target's hash, names the snapshot in a receipt.", + "type": "object", + "required": [ + "format", + "name", + "source", + "qubits", + "gates", + "coupling" + ], + "additionalProperties": false, + "properties": { + "format": { + "const": "wai.quantum.target/1" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "additionalProperties": false, + "properties": { + "format": { + "type": "string", + "description": "The format the target was read from (wai-quantum targets import --help lists them)." + }, + "note": { + "type": "string", + "maxLength": 400 + } + } + }, + "calibration": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "maxLength": 400, + "description": "The calibration snapshot's id, as the source names it, or a content id of the snapshot read." + }, + "timestamp": { + "type": "string", + "maxLength": 400, + "description": "When the snapshot was taken, as the source writes it." + } + } + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2048, + "description": "Every qubit, in order.", + "items": { + "type": "object", + "required": [ + "qubit" + ], + "additionalProperties": false, + "properties": { + "qubit": { + "type": "integer", + "minimum": 0, + "description": "Its index: its place in the list." + }, + "label": { + "type": "string", + "description": "The source's own name for it, when that is not its index." + }, + "t1_us": { + "type": "number", + "minimum": 0, + "description": "T1, microseconds." + }, + "t2_us": { + "type": "number", + "minimum": 0, + "description": "T2 (the echo or Ramsey time the source reports), microseconds." + }, + "frequency_ghz": { + "type": "number", + "minimum": 0, + "description": "Its frequency, gigahertz." + }, + "readout": { + "type": "object", + "required": [ + "p01", + "p10" + ], + "additionalProperties": false, + "properties": { + "p01": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 1 | holds 0)." + }, + "p10": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 0 | holds 1)." + } + } + }, + "measure_ns": { + "type": "number", + "minimum": 0, + "description": "The measurement's duration, nanoseconds." + } + } + } + }, + "gates": { + "type": "array", + "maxItems": 262144, + "description": "Each native gate where the device runs it, sorted by gate then qubits.", + "items": { + "type": "object", + "required": [ + "gate", + "qubits" + ], + "additionalProperties": false, + "properties": { + "gate": { + "type": "string", + "pattern": "^[a-z0-9_]{1,40}$" + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + }, + "error": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "The average gate infidelity." + }, + "duration_ns": { + "type": "number", + "minimum": 0, + "description": "Nanoseconds." + } + } + } + }, + "coupling": { + "type": "array", + "description": "The pairs a two-qubit gate may act on, each once, the lower qubit first, sorted.", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + ] + }, + "fabric": { + "description": "Where the statevector method's state runs: auto (the default: on a member only where the committed measurements show it faster than this host's CPU for the job's size and fusion width, otherwise on the CPU), cpu, accelerator (the first accelerator member certified bit-exact here that holds the state, falling back to the next if it fails during the run), a member's id or key (wai-quantum fabric lists them), or a list of members, a power of two of them, the state split by its top qubits into one partition on each (cpu is a member, and a member may be named more than once). A member certified bit-exact gives the CPU's bits. A placement this host cannot honour is refused (J013), never made elsewhere.", + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "array", + "minItems": 2, + "maxItems": 64, + "items": { + "type": "string", + "minLength": 1 + } + } + ] + }, + "repair": { + "description": "Repair the program first on its flagged lines: true, or the choices.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "max_iterations": { + "type": "integer", + "minimum": 1 + }, + "dyadic_bits": { + "type": "integer", + "minimum": 1, + "maximum": 32 + }, + "sizes": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + } + } + } + ] + }, + "history": { + "type": "object", + "description": "The program's history's account of the version the job runs: its digest, and the gates and lines in each hand. The receipt binds it; a history recomputes and checks it." + }, + "provider": { + "type": "string", + "description": "The person's own provider to run on, by the name their registry gives it. Only a host that holds their credentials runs such a job; every other host refuses it." + }, + "programs": { + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "type": "string", + "description": "A program's text." + }, + { + "type": "object", + "required": [ + "qasm" + ], + "description": "A job of its own, read as a job request is (no programs or sweep in it); each item of the set's result holds its request in full." + } + ] + }, + "description": "A set (engine::sets): the programs to run as one job, each a program's text or a job of its own; the request's other fields apply to every item that does not set them itself." + }, + "sweep": { + "type": "object", + "additionalProperties": { + "type": "array", + "minItems": 1, + "items": { + "type": "number" + } + }, + "description": "A set over the request's own qasm: values for each of the program's inputs (integer, float or angle), every combination run, the names in sorted order and the first varying slowest." + }, + "params": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "A value for each of the program's parameters (`input float theta;`, `input angle phi;`), bound exactly before the program is read: it runs as if each were written as a `const` at that double. A parameter left without a value is refused (Q114, J050). In a sweep, the parameters it fixes, each bound at every point." + }, + "dry_run": { + "type": "boolean", + "description": "With true: what the host would do with the job or set, running nothing." + }, + "mitigate": { + "description": "Mitigate the job's expectation values (or, for readout, its counts) under its noise (engine::mitigate): zne, pea, pec, cdr, vd or readout, or {\"method\", …} with its options. The result's mitigation gives each value raw and mitigated.", + "anyOf": [ + { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + { + "type": "object", + "required": [ + "method" + ] + } + ] + }, + "pulse": { + "type": "object", + "description": "A pulse run's options (method \"pulse\"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0.", + "additionalProperties": false, + "properties": { + "dt_ns": { + "type": "number", + "exclusiveMinimum": 0, + "maximum": 1000, + "description": "The sample period, ns (default 0.5)." + }, + "levels": { + "type": "integer", + "enum": [ + 2, + 3 + ], + "description": "Levels kept per qubit (default 2; 3 shows leakage)." + }, + "tolerance": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1, + "description": "The most the stated error may be (default 1e-6): a run whose bound and rounding estimate pass it is refused, naming the steps that would meet it." + }, + "substeps": { + "type": "integer", + "minimum": 1, + "maximum": 4096, + "description": "Steps per sample (default: chosen so each step times the generator's norm is at most 0.5)." + }, + "qubits": { + "type": "object", + "description": "Each qubit's parameters by its index, over the target's and the defaults.", + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "frequency_ghz": { + "type": "number", + "description": "Its frequency, GHz." + }, + "rabi_mhz": { + "type": "number", + "description": "Its Rabi frequency at full amplitude, MHz." + }, + "anharmonicity_mhz": { + "type": "number", + "description": "Its anharmonicity, MHz." + }, + "t1_us": { + "type": "number", + "description": "Its relaxation time, µs." + }, + "t2_us": { + "type": "number", + "description": "Its coherence time, µs (at most 2·T1)." + } + } + } + }, + "couplings": { + "type": "array", + "description": "Static ZZ couplings.", + "items": { + "type": "object", + "required": [ + "qubits", + "zz_khz" + ], + "additionalProperties": false, + "properties": { + "qubits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + }, + "minItems": 2, + "maxItems": 2 + }, + "zz_khz": { + "type": "number", + "description": "The coupling's rate, kHz." + } + } + } + }, + "ports": { + "type": "object", + "description": "Ports by name: what each is for and the qubit it reaches.", + "additionalProperties": { + "type": "object", + "required": [ + "kind", + "qubit" + ], + "additionalProperties": false, + "properties": { + "kind": { + "enum": [ + "drive", + "measure", + "acquire" + ] + }, + "qubit": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } + } + } + }, + "result": { + "title": "wai.quantum.job-result/1", + "description": "A job's result as the engine gives it, on every host: what was asked of the program, computed by the method its plan chose, with that method's accuracy class. The receipt seals the result without its receipt member, beside the request. A result names the engine that made it and this schema (engine and schema); results made before results carried them have neither and follow this schema all the same.", + "type": "object", + "required": [ + "method", + "qubits", + "gates", + "accuracy" + ], + "properties": { + "engine": { + "type": "object", + "description": "The engine that made the result: the wai-quantum crate's name and version.", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "const": "wai-quantum" + }, + "version": { + "type": "string", + "description": "Its semantic version, as MAJOR.MINOR.PATCH." + } + } + }, + "schema": { + "const": "wai.quantum.job-result/1", + "description": "The schema the result follows." + }, + "components": { + "type": "array", + "description": "The identity of every component that made the result, when a registered one took part (engine::registry): its program's format, the passes its compile ran, the noise channels it names, its method; each registered one marked so. Sealed by the receipt with the rest.", + "items": { + "type": "object", + "description": "One component that made the result (engine::registry): its kind, name and version, the BLAKE3 digest of its descriptor, and whether it is built in. A result carries these only when a registered component took part; one made by built-ins alone names them as it always has (its method, its compile's passes, its noise's channels and the engine's version), the digests of that version listed by the components list.", + "required": [ + "kind", + "name", + "version", + "digest", + "origin" + ], + "properties": { + "kind": { + "enum": [ + "method", + "pass", + "channel", + "front_end" + ] + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "digest": { + "type": "string", + "pattern": "^[0-9a-f]{64}$", + "description": "BLAKE3 of the component's descriptor in its canonical JSON (engine::registry::digest_of)." + }, + "origin": { + "enum": [ + "built-in", + "registered" + ], + "description": "built-in: the engine's own; registered: a host's own, added in its process, not part of the engine." + }, + "certified": { + "const": false, + "description": "Beside a registered component: the engine does not certify it." + } + } + } + }, + "method": { + "type": "string", + "description": "The method that ran the job (provider for a run on the person's own provider)." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": "integer", + "minimum": 0 + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "state_hash": { + "type": "string", + "description": "The bit-exact method's statevector hash (BLAKE3, hex): the same on every machine." + }, + "counts": { + "type": "object", + "description": "Outcomes and their counts, keyed by the program's classical bits, the highest bit first. At most 65536 outcomes are listed; omitted_shots holds the rest.", + "additionalProperties": { + "type": "integer", + "minimum": 0 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "outcome_dimension": { + "type": "integer", + "minimum": 0, + "description": "The stabilizer method: the dimension of the measured outcomes' affine space." + }, + "shots": { + "type": "integer", + "minimum": 0, + "description": "The shots, where the method names them in the result (trajectories, provider)." + }, + "expectations": { + "type": "array", + "items": { + "type": "object", + "required": [ + "observable", + "coeff", + "value" + ], + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "value": { + "type": "number", + "description": "The coefficient times the expectation value." + }, + "stderr": { + "type": "number", + "description": "The standard error, for an estimate." + }, + "bound": { + "type": "number", + "description": "A bound on |exact − value|: rigorous for the bounded class; with confidence beside it, holding with that probability." + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + }, + "max_terms": { + "type": "integer" + }, + "ladder": { + "type": "array", + "description": "The value at thresholds a decade apart, the asked one last.", + "items": { + "type": "object", + "required": [ + "threshold", + "value", + "bound" + ], + "properties": { + "threshold": { + "type": "number" + }, + "value": { + "type": "number" + }, + "bound": { + "type": "number" + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + } + } + } + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds, for a bound that holds with a stated probability (stabilizer_rank's sampled mode)." + } + } + } + }, + "amplitudes": { + "type": "array", + "items": { + "type": "object", + "required": [ + "bits", + "re", + "im" + ], + "properties": { + "bits": { + "type": "string", + "description": "One 0 or 1 per qubit, qubit n-1 first." + }, + "re": { + "type": "number" + }, + "im": { + "type": "number" + }, + "bound": { + "type": "number", + "minimum": 0, + "description": "A bound on |exact − value| of the amplitude, holding with the probability confidence states (stabilizer_rank's sampled mode)." + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds." + } + } + } + }, + "global_phase": { + "type": "string", + "description": "Why the amplitudes' global phase is not fixed, when it is not." + }, + "warning": { + "type": "string" + }, + "contraction_flops": { + "type": "number", + "description": "The tensor network's contraction cost." + }, + "dynamic": { + "type": "object", + "description": "A program that measures in the middle, resets or branches on a measured bit: how it ran.", + "properties": { + "measurements_and_resets": { + "type": "integer", + "minimum": 0 + }, + "branches_run": { + "type": "integer", + "minimum": 0 + }, + "states_at_once": { + "type": "integer", + "minimum": 0 + }, + "branches_weighed": { + "type": "integer", + "minimum": 0 + } + } + }, + "outputs": { + "type": "array", + "description": "The program's output declarations: each its name and type, and its value, or the places of its bits in each outcome.", + "items": { + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "bits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + } + }, + "value": { + "description": "A number, a boolean, a bit string, a duration's text, {\"re\", \"im\"}, or an array of them." + } + } + } + }, + "timing": { + "type": "object", + "description": "A program that states durations (delay, box, stretch) the method does not apply: said so, with the reader's code.", + "required": [ + "applied", + "why" + ], + "properties": { + "applied": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "diagnostics": { + "type": "array", + "description": "The reader's warnings and notes on the program, each with its code.", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "compiled": { + "description": "How the program was compiled before it ran: on the person's own provider, to the device's gates; or, asked with compile, to a basis within a budget. Either way, basis is the gate set it was compiled to.", + "anyOf": [ + { + "type": "object", + "description": "A provider job: the program sent, compiled exactly to the device's own gates: its basis (the device's gate set), its OpenQASM 3 text (qasm3) and that text's BLAKE3 (program), its counts of gates and swaps, its layouts, and the check it passed before it was sent. Results sealed before qasm3 carry the hash alone.", + "required": [ + "basis", + "program" + ], + "properties": { + "basis": { + "type": "string" + }, + "program": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "qasm3": { + "type": "string", + "description": "The program sent, as OpenQASM 3, $i being index i of the coupling map the provider described; program is the BLAKE3 of its UTF-8 bytes." + }, + "qubit_names": { + "type": "object", + "additionalProperties": { + "type": "string", + "minLength": 1 + }, + "description": "The device's own name for each index the program uses, as it was when the job was sent, where a client sends it under those names." + }, + "native_gates": { + "type": "integer" + }, + "two_qubit_gates": { + "type": "integer" + }, + "swaps": { + "type": "integer" + }, + "layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "final_layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "checked": { + "type": "string" + }, + "placement": { + "type": "object", + "description": "Where the program was placed on the device's qubits, and why." + } + } + }, + { + "type": "object", + "description": "A job asked to compile its program first: what ran is the compiled circuit, within distance of the program in the operator norm up to a global phase.", + "required": [ + "basis", + "verdict" + ], + "properties": { + "basis": { + "enum": [ + "clifford_t", + "standard" + ], + "description": "The gate set the program was compiled to." + }, + "level": { + "type": "integer", + "minimum": 0 + }, + "epsilon": { + "type": "number", + "description": "The budget asked for." + }, + "distance": { + "type": [ + "number", + "null" + ], + "description": "The bound the passes' distances add to." + }, + "verdict": { + "type": "string" + }, + "source": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "output": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ], + "description": "The BLAKE3 of the compile certificate's RFC 8785 text, in hex." + }, + "note": { + "type": "string" + } + } + } + ] + }, + "verdict": { + "title": "wai.quantum.verdict/1", + "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", + "type": "object", + "required": [ + "schema", + "level", + "rank", + "holds", + "statement", + "parsed", + "executed", + "intent", + "critique", + "repairs" + ], + "properties": { + "schema": { + "const": "wai.quantum.verdict/1" + }, + "level": { + "enum": [ + "refused", + "parsed", + "executed", + "evidence", + "proof" + ] + }, + "rank": { + "type": "integer", + "minimum": 0, + "maximum": 4, + "description": "The level's place on the ladder, from 0 (refused) to 4 (proof)." + }, + "holds": { + "type": [ + "boolean", + "null" + ] + }, + "statement": { + "type": "string", + "description": "The level in one plain line." + }, + "parsed": { + "type": "object", + "description": "Whether the reader took the program, and its warnings and notes with their codes, or its refusal.", + "required": [ + "ok" + ], + "properties": { + "ok": { + "type": "boolean" + }, + "diagnostics": { + "type": "array", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + }, + "text": { + "type": "string", + "description": "The refusal as the reader wrote it, with its line and code." + } + } + }, + "executed": { + "type": [ + "object", + "null" + ], + "description": "The method that ran and its accuracy class, and the distance a compile put between the program and what ran.", + "properties": { + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "compiled_distance": { + "type": [ + "number", + "null" + ] + } + } + }, + "intent": { + "type": "array", + "items": { + "type": "object", + "description": "One intent's check: what it asked, whether it held, how strong the check was and how it was made.", + "required": [ + "kind", + "outcome", + "strength", + "how" + ], + "properties": { + "kind": { + "enum": [ + "distribution", + "equivalent", + "prepares", + "sampled", + "compiled" + ] + }, + "outcome": { + "enum": [ + "holds", + "fails", + "unchecked" + ] + }, + "strength": { + "enum": [ + "proof", + "evidence", + "none" + ] + }, + "how": { + "type": "string" + }, + "why": { + "type": "string" + }, + "distance": { + "type": "number" + }, + "tolerance": { + "type": "number" + }, + "outcomes": { + "type": "integer", + "description": "The outcomes the distribution holds, or the samples' distinct outcomes." + }, + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The program's distribution, when its outcomes are few enough to list." + }, + "largest_gaps": { + "type": "array", + "items": { + "type": "object", + "properties": { + "outcome": { + "type": "string" + }, + "program": { + "type": "number" + }, + "intent": { + "type": "number" + } + } + } + }, + "global_phase": { + "type": [ + "number", + "null" + ] + }, + "method": { + "type": "string", + "description": "A sampled intent: the method the samples were run by." + }, + "seed": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "alpha": { + "type": "number" + }, + "fit": { + "type": "object", + "description": "A sampled intent: the test, its statistic, degrees of freedom and p-value, the level, and whether it rejected.", + "properties": { + "test": { + "type": "string" + }, + "statistic": { + "type": "number" + }, + "dof": { + "type": "integer" + }, + "p_value": { + "type": "number" + }, + "alpha": { + "type": "number" + }, + "shots": { + "type": "integer" + }, + "rejected": { + "type": "boolean" + }, + "smallest_expected": { + "type": [ + "number", + "null" + ] + }, + "impossible": { + "type": [ + "integer", + "array", + "boolean" + ] + }, + "note": { + "type": "string" + } + } + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "name": { + "type": "string" + }, + "note": { + "type": "string" + } + } + } + }, + "critique": { + "type": "array", + "description": "The program's smells, each with its lines.", + "items": { + "type": "object" + } + }, + "repairs": { + "type": "array", + "description": "Each edit a repair made, with the code it answered and the lines it changed.", + "items": { + "type": "object" + } + }, + "refusal": { + "type": "object", + "description": "For a refused job: its message and its codes.", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + }, + "sealed": { + "type": "boolean" + } + } + }, + "target": { + "type": "object", + "description": "A run on a device target: which target (its hash, as its receipt binds it), its calibration snapshot, where the program was placed and why, and the noise derived from the target.", + "required": [ + "name", + "hash" + ], + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "hash_is": { + "type": "string" + }, + "calibration": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "source": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "note": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "description": "The native gate set, the layout and routes chosen, the swaps, the expected success beside the fewest-swaps layout's, and the check of the compiled program." + }, + "noise": { + "type": "object", + "description": "The noise model derived from the target's calibration: its channels, durations and idling, and each qubit's readout." + } + } + }, + "fabric": { + "type": "object", + "description": "Where the state vector, or the pauli method's sum of terms, ran: the kernel, the placement the job asked for, the member that ran it (or each partition's), each with its certificate, and the energy. Present when the job asked for a placement, or when auto placed the state on a member by measurement (`auto`); a job auto leaves on the CPU names nothing; the receipt seals it with the rest of the result. Every member placed is certified bit-exact, so the answers are the CPU's, byte for byte.", + "required": [ + "kernel", + "asked", + "parity", + "energy" + ], + "properties": { + "kernel": { + "type": "string" + }, + "asked": { + "description": "The placement the job asked for, as it gave it.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "partitions": { + "type": "array", + "description": "Each partition's member, by the value of the state's top qubits: partition i holds the amplitudes whose top bits read i.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "partition_qubits": { + "type": "integer", + "minimum": 0 + }, + "local_qubits": { + "type": "integer", + "minimum": 0 + }, + "segments": { + "type": "integer", + "minimum": 0, + "description": "Runs of gates the partitions took in turn, between exchanges." + }, + "exchanges": { + "type": "integer", + "minimum": 0, + "description": "Partition qubits exchanged with local ones through the host's copy of the state." + }, + "fell_back_from": { + "type": "array", + "description": "An accelerator request whose member failed during the run: each member that failed, in turn, with how; the member named above ran the job.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "auto": { + "type": "object", + "description": "Why auto placed the state where it ran: the rule (a member is placed only where the committed measurements show it faster than this host's CPU for the job's size and fusion width) and the measured row it rests on, with the host, the day and the load it was measured under. Present only when auto placed a state on a member.", + "required": [ + "rule", + "host", + "fusion", + "from_qubits", + "to_qubits" + ], + "properties": { + "rule": { + "type": "string" + }, + "host": { + "type": "string", + "description": "The host's processor as the measurements name it (cpu--)." + }, + "measured": { + "type": "string", + "description": "The day the host was measured (UTC)." + }, + "about": { + "type": "string" + }, + "load": { + "type": "string" + }, + "discovery_ms": { + "type": "number", + "description": "What discovering and certifying the host's members took, once per process, as measured." + }, + "fusion": { + "type": "integer", + "minimum": 1 + }, + "from_qubits": { + "type": "integer", + "minimum": 0 + }, + "to_qubits": { + "type": "integer", + "minimum": 0 + }, + "min_launches": { + "type": "integer", + "minimum": 0 + }, + "basis": { + "type": "object", + "description": "The measured row the job is judged by: the largest measured size at or below its own, the launches of its plan, the runs of each, and the spread of the CPU's and the member's times in milliseconds.", + "required": [ + "qubits", + "launches", + "runs", + "cpu_ms", + "member_ms" + ], + "properties": { + "qubits": { + "type": "integer", + "minimum": 0 + }, + "launches": { + "type": "integer", + "minimum": 0 + }, + "runs": { + "type": "integer", + "minimum": 0 + }, + "cpu_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + }, + "member_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + } + } + } + } + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "why": { + "type": "string" + } + } + }, + "repaired": { + "type": "object", + "description": "A job asked to repair its program first: the program that ran, each repair, and what needs a person.", + "properties": { + "qasm": { + "type": "string" + }, + "repairs": { + "type": "array", + "items": { + "type": "object", + "required": [ + "code", + "by", + "edits" + ], + "properties": { + "code": { + "type": "string" + }, + "rule": { + "type": "string" + }, + "by": { + "enum": [ + "engine", + "proposal" + ] + }, + "flagged": { + "type": "array", + "items": { + "type": "integer" + } + }, + "edits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "line": { + "type": "integer" + }, + "before": { + "type": [ + "string", + "null" + ] + }, + "after": { + "type": [ + "string", + "null" + ] + } + } + } + } + } + } + }, + "needs_person": { + "type": "array", + "items": { + "type": "object" + } + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0, + "description": "Wall time of the run, where the host has a clock (not in a browser tab)." + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "receipt": { + "anyOf": [ + { + "title": "wai.quantum.receipt/2", + "description": "A result's receipt: an Ed25519 signature, by the key it names, over digest = BLAKE3(\"wai:quantum-service-receipt\\x02\" ‖ len ‖ request ‖ len ‖ result), each of request and result in its RFC 8785 canonical text (the result without its receipt member), each length 8 bytes big-endian. Whatever members the request and the result hold are sealed, the result's engine and schema among them. The first receipts (no canon member, $defs/first) sealed their writer's compact text under the domain ending \\x01; they still verify. wai/extensions/quantum-providers.md section 8.2 states the seal in full, and section 8.4 what a verifier checks.", + "type": "object", + "required": [ + "alg", + "canon", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "canon": { + "const": "rfc8785", + "description": "The canonical form the digest is taken over." + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The signing key, 32 bytes in lower-case hex." + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The digest signed, 32 bytes in lower-case hex." + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$", + "description": "The signature, 64 bytes in lower-case hex." + } + } + }, + { + "description": "The first form, before canon: the digest is over the compact text its writer wrote of each, members in the document's order (section 8.2 of wai/extensions/quantum-providers.md), under the domain ending \\x01. Never written now; still verified.", + "type": "object", + "required": [ + "alg", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$" + } + } + } + ] + }, + "provider": { + "type": "object", + "description": "A provider job: the provider's name, kind and protocol, the device, its provenance, and the hash of its description." + }, + "counts_source": { + "enum": [ + "shots", + "vendor_counts", + "probabilities" + ], + "description": "A provider job: where its counts come from (wai/extensions/quantum-providers.md section 8.3): tallied from one record a shot (shots), the provider's own counts (vendor_counts), or rebuilt from the probabilities it returned by largest remainders, derived and not shot records (probabilities). Results sealed before it carry neither it nor execution." + }, + "execution": { + "type": "object", + "description": "A provider job: how the device was asked to run the program (section 8.3): who states it (stated_by: client, provider or nobody); what the client sent (sent: the request's members and the settings among them); each of mitigation, twirling, decoupling, remapping and optimisation (off, on, default when the request sets nothing for it, none when the device has no such step, unknown when nobody states it); whether the gates were to run as written (verbatim); and a note.", + "required": [ + "stated_by", + "mitigation", + "twirling", + "decoupling", + "remapping", + "optimisation", + "verbatim" + ], + "properties": { + "stated_by": { + "enum": [ + "client", + "provider", + "nobody" + ] + }, + "sent": { + "type": "object", + "required": [ + "fields", + "settings" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "settings": { + "type": "object" + } + }, + "additionalProperties": false + }, + "mitigation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "twirling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "decoupling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "remapping": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "optimisation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "verbatim": { + "type": [ + "boolean", + "null" + ] + }, + "note": { + "type": "string" + } + }, + "additionalProperties": false + }, + "calibration": { + "type": [ + "string", + "null" + ], + "description": "A provider job: the calibration snapshot it ran under." + }, + "job": { + "type": "object", + "description": "A provider job: the provider's job id and its status checks." + }, + "ideal": { + "description": "A provider job: the circuit's exact distribution set beside the measured counts.", + "anyOf": [ + { + "type": "object", + "required": [ + "computed", + "total_variation_distance", + "hellinger_fidelity" + ], + "properties": { + "computed": { + "const": true + }, + "method": { + "type": "string" + }, + "total_variation_distance": { + "type": "number" + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number" + }, + "ideal_outcomes": { + "type": "integer" + }, + "note": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "computed", + "why" + ], + "properties": { + "computed": { + "const": false + }, + "why": { + "type": "string" + } + } + } + ] + }, + "cost": { + "type": "object", + "description": "A provider job: the estimate shown before it was sent, what the provider says it charged, and whether the person confirmed a run that was not free." + }, + "provenance": { + "title": "wai.quantum.provenance/1", + "description": "What a result came from, under the five categories cross-platform provenance surveys use: the circuit, the computer, the compilation, the execution and the software. A host adds it to the results it seals (the job service does, and each item of a set); a result without it reads as it always did. wai-quantum-service/docs/provenance.md maps every field to where it is and whether the receipt seals it.", + "type": "object", + "required": [ + "schema", + "circuit", + "computer", + "compilation", + "execution", + "software" + ], + "properties": { + "schema": { + "const": "wai.quantum.provenance/1" + }, + "circuit": { + "type": "object", + "description": "The program: the BLAKE3 digest of its text as given, its qubits and its gates.", + "required": [ + "program" + ], + "properties": { + "program": { + "type": "string", + "description": "BLAKE3 of the program's text, in hex." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": [ + "integer", + "null" + ] + } + } + }, + "computer": { + "type": "object", + "description": "What ran it: a classical simulator, the method and its accuracy class, a device target's hash when the job named one, and the fabric's members when the result names where its state ran.", + "required": [ + "kind", + "method" + ], + "properties": { + "kind": { + "const": "simulator" + }, + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "target": { + "type": "string", + "description": "The device target's hash; its layout, routes and noise are in the result's own target." + }, + "fabric": { + "type": "object", + "description": "The kernel and the member that ran the state, or each partition's, as the result's fabric names them.", + "properties": { + "kernel": { + "type": "string" + }, + "members": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "compilation": { + "type": "object", + "description": "Whether the job asked to be compiled; if it did, each pass in order with its check's verdict, the certificate's digest, the gate set compiled to (its basis), the level, the ε budget and the distance the result carries, and that no pass draws a random number.", + "required": [ + "asked" + ], + "properties": { + "asked": { + "type": "boolean" + }, + "passes": { + "type": [ + "array", + "null" + ], + "items": { + "type": "object", + "properties": { + "pass": { + "type": "string" + }, + "verdict": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ] + }, + "basis": { + "type": [ + "string", + "null" + ], + "description": "The gate set compiled to: clifford_t or standard." + }, + "level": { + "type": [ + "integer", + "null" + ] + }, + "epsilon": { + "type": [ + "number", + "null" + ] + }, + "distance": { + "type": [ + "number", + "null" + ] + }, + "seeded": { + "const": false + }, + "device": { + "type": "string", + "description": "A job on a device target, compiled exactly to its gates: where its layout and routes are." + }, + "status": { + "const": "not-applicable" + }, + "why": { + "type": "string" + } + } + }, + "execution": { + "type": "object", + "description": "The shots, the seed and the plan the job ran under; its identifier and times are the host's, outside the result.", + "required": [ + "plan" + ], + "properties": { + "shots": { + "type": [ + "integer", + "null" + ] + }, + "seed": { + "type": [ + "integer", + "null" + ] + }, + "plan": { + "type": "object", + "properties": { + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0 + } + } + } + } + }, + "software": { + "type": "object", + "description": "The engine's name and version, and the host's.", + "required": [ + "engine", + "host" + ], + "properties": { + "engine": { + "type": "string" + }, + "host": { + "type": "string" + } + } + } + } + }, + "mitigation": { + "title": "wai.quantum.mitigation/1", + "description": "A job's mitigation (its request's mitigate, engine::mitigate), in its result: the method and the options it ran with, its bias and variance assumptions, each observable raw and mitigated with a standard error each and the ideal value (or, for readout, the counts inverted as a quasi-distribution), the method's own details and what it spent. docs/qec.md describes each method.", + "type": "object", + "required": [ + "method", + "options", + "assumptions" + ], + "properties": { + "method": { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + "options": { + "type": "object", + "description": "The options it ran with, the defaults filled in.", + "properties": { + "method": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "factors": { + "type": "array", + "items": { + "type": "number" + } + }, + "extrapolation": { + "enum": [ + "richardson", + "linear", + "exponential" + ] + }, + "samples": { + "type": "integer" + }, + "training": { + "type": "integer" + }, + "keep": { + "type": "integer" + }, + "learn_shots": { + "type": "integer" + } + } + }, + "assumptions": { + "type": "object", + "properties": { + "bias": { + "type": "string" + }, + "variance": { + "type": "string" + } + } + }, + "noise": { + "type": "string", + "description": "How the job's noise model is read for the method." + }, + "note": { + "type": "string" + }, + "observables": { + "type": "array", + "items": { + "type": "object", + "description": "One observable: its raw value and the mitigated one, each with its standard error, and the ideal value a simulation knows.", + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "raw": { + "type": "number" + }, + "raw_stderr": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + }, + "ideal": { + "type": "number" + } + } + } + }, + "distribution": { + "type": "array", + "description": "readout: each outcome's raw share and its mitigated quasi-probability, with its standard error.", + "items": { + "type": "object", + "properties": { + "bits": { + "type": "string" + }, + "raw": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + } + } + } + }, + "details": { + "type": "object", + "description": "The method's own: the folded scales and the folding check (zne), the learned model and the amplified values (pea), the quasi-probability and the value it converges to (pec), the training fits (cdr), the purity (vd), the flip and its amplification (readout).", + "additionalProperties": true + }, + "cost": { + "type": "object", + "description": "The circuits and shots it spent beyond the job's own.", + "properties": { + "circuits": { + "type": "integer", + "minimum": 0 + }, + "shots": { + "type": "integer", + "minimum": 0 + }, + "note": { + "type": "string" + } + } + } + } + }, + "pulse": { + "type": "object", + "description": "A pulse run (method pulse, engine::pulse): what was read and its distribution, the final populations, each capture's reading, the final density matrix's digest, the schedule's length, the integrator and its step, the device and where each parameter came from, and what the receipt binds (calibration).", + "required": [ + "read", + "outcome_bits", + "populations", + "simulated_qubits", + "density_hash", + "integrator", + "device", + "calibration" + ], + "properties": { + "read": { + "type": "string", + "description": "What the distribution reads: the captures together (into the program's bits when each writes one), or the final state." + }, + "outcome_bits": { + "type": "array", + "items": { + "type": "string" + }, + "description": "What each character of an outcome is, left to right: a program bit (c[0]) or a qubit ($0)." + }, + "distribution": { + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "number" + }, + "description": "The probability of each outcome, which the counts sample; null when the captures start at different samples." + }, + "populations": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The final state read on every simulated qubit, the highest qubit first, a level above 0 read as 1." + }, + "simulated_qubits": { + "type": "array", + "items": { + "type": "integer" + } + }, + "captures": { + "type": "array", + "items": { + "type": "object", + "properties": { + "frame": { + "type": "string" + }, + "qubit": { + "type": "integer" + }, + "start": { + "type": "integer" + }, + "start_ns": { + "type": "number" + }, + "bit": { + "type": [ + "string", + "null" + ] + }, + "p1": { + "type": "number" + }, + "p2": { + "type": "number" + } + } + } + }, + "leakage": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "p2": { + "type": "number" + } + } + }, + "description": "With three levels: each qubit's final probability of level 2." + }, + "trace": { + "type": "number" + }, + "density_hash": { + "type": "string", + "description": "The BLAKE3 of the final density matrix's bits: the same on every platform." + }, + "duration": { + "type": "integer" + }, + "duration_ns": { + "type": "number" + }, + "integrator": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "order": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "substeps": { + "type": "integer" + }, + "step_ns": { + "type": "number" + }, + "steps": { + "type": "integer" + }, + "norm_max": { + "type": "number" + }, + "frame": { + "type": "string" + } + } + }, + "device": { + "type": "object", + "properties": { + "levels": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "qubits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "frequency_hz": { + "type": "number" + }, + "rabi_hz": { + "type": "number" + }, + "anharmonicity_hz": { + "type": "number" + }, + "t1_ns": { + "type": "number" + }, + "t2_ns": { + "type": "number" + }, + "from": { + "type": "object", + "additionalProperties": { + "enum": [ + "pulse", + "target", + "default", + "none" + ] + } + } + } + } + }, + "couplings": { + "type": "array" + }, + "model": { + "type": "string" + } + } + }, + "calibration": { + "type": "object", + "description": "What the receipt binds: the program's, its calibrations', the schedule's and the device's digests, and the target snapshot.", + "properties": { + "program": { + "type": "string" + }, + "calibrations": { + "type": "string" + }, + "schedule": { + "type": "string" + }, + "device": { + "type": "string" + }, + "target": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "calibration": { + "type": "object" + } + } + } + } + }, + "not_modelled": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, diff --git a/wai/wai-quantum-cli/docs/service-mcp.json b/wai/wai-quantum-cli/docs/service-mcp.json index 59ed06fb4..ecbb32a2c 100644 --- a/wai/wai-quantum-cli/docs/service-mcp.json +++ b/wai/wai-quantum-cli/docs/service-mcp.json @@ -531,7 +531,7 @@ "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read; a parameter left without one is refused (J050). In a sweep, the parameters it fixes." }, "contract": { - "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", "type": [ "object", "null" @@ -1438,7 +1438,7 @@ } }, "contract": { - "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", "type": [ "object", "null" @@ -4275,7 +4275,7 @@ } }, "planner": { - "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", "type": "object", "required": [ "format", @@ -4323,7 +4323,7 @@ "expectations", "amplitudes" ], - "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." }, "auto": { "type": [ @@ -4404,7 +4404,7 @@ "null" ], "minimum": 0, - "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." }, "price": { "anyOf": [ @@ -5116,7 +5116,7 @@ "type": "number", "minimum": 0, "maximum": 1, - "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -6136,7 +6136,7 @@ } }, "contract": { - "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", "type": [ "object", "null" @@ -8971,7 +8971,7 @@ } }, "planner": { - "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", "type": "object", "required": [ "format", @@ -9019,7 +9019,7 @@ "expectations", "amplitudes" ], - "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." }, "auto": { "type": [ @@ -9100,7 +9100,7 @@ "null" ], "minimum": 0, - "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." }, "price": { "anyOf": [ @@ -9812,7 +9812,7 @@ "type": "number", "minimum": 0, "maximum": 1, - "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -10476,7 +10476,7 @@ } }, "planner": { - "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", "type": "object", "required": [ "format", @@ -10524,7 +10524,7 @@ "expectations", "amplitudes" ], - "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." }, "auto": { "type": [ @@ -10605,7 +10605,7 @@ "null" ], "minimum": 0, - "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." }, "price": { "anyOf": [ @@ -14051,7 +14051,7 @@ } }, "contract": { - "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", "type": [ "object", "null" @@ -16888,7 +16888,7 @@ } }, "planner": { - "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", "type": "object", "required": [ "format", @@ -16936,7 +16936,7 @@ "expectations", "amplitudes" ], - "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." }, "auto": { "type": [ @@ -17017,7 +17017,7 @@ "null" ], "minimum": 0, - "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." }, "price": { "anyOf": [ @@ -17729,7 +17729,7 @@ "type": "number", "minimum": 0, "maximum": 1, - "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -18749,7 +18749,7 @@ } }, "contract": { - "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", "type": [ "object", "null" @@ -21584,7 +21584,7 @@ } }, "planner": { - "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", "type": "object", "required": [ "format", @@ -21632,7 +21632,7 @@ "expectations", "amplitudes" ], - "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." }, "auto": { "type": [ @@ -21713,7 +21713,7 @@ "null" ], "minimum": 0, - "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." }, "price": { "anyOf": [ @@ -22425,7 +22425,7 @@ "type": "number", "minimum": 0, "maximum": 1, - "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -23089,7 +23089,7 @@ } }, "planner": { - "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", "type": "object", "required": [ "format", @@ -23137,7 +23137,7 @@ "expectations", "amplitudes" ], - "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." }, "auto": { "type": [ @@ -23218,7 +23218,7 @@ "null" ], "minimum": 0, - "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." }, "price": { "anyOf": [ @@ -25855,7 +25855,7 @@ } }, "contract": { - "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", "type": [ "object", "null" @@ -26139,7 +26139,7 @@ } }, "planner": { - "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", "type": "object", "required": [ "format", @@ -26187,7 +26187,7 @@ "expectations", "amplitudes" ], - "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." }, "auto": { "type": [ @@ -26268,7 +26268,7 @@ "null" ], "minimum": 0, - "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." }, "price": { "anyOf": [ @@ -28407,7 +28407,7 @@ } }, "contract": { - "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", "type": [ "object", "null" @@ -31244,7 +31244,7 @@ } }, "planner": { - "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", "type": "object", "required": [ "format", @@ -31292,7 +31292,7 @@ "expectations", "amplitudes" ], - "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." }, "auto": { "type": [ @@ -31373,7 +31373,7 @@ "null" ], "minimum": 0, - "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." }, "price": { "anyOf": [ @@ -32085,7 +32085,7 @@ "type": "number", "minimum": 0, "maximum": 1, - "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -33105,7 +33105,7 @@ } }, "contract": { - "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", "type": [ "object", "null" @@ -35940,7 +35940,7 @@ } }, "planner": { - "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", "type": "object", "required": [ "format", @@ -35988,7 +35988,7 @@ "expectations", "amplitudes" ], - "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." }, "auto": { "type": [ @@ -36069,7 +36069,7 @@ "null" ], "minimum": 0, - "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." }, "price": { "anyOf": [ @@ -36781,7 +36781,7 @@ "type": "number", "minimum": 0, "maximum": 1, - "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -37445,7 +37445,7 @@ } }, "planner": { - "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", "type": "object", "required": [ "format", @@ -37493,7 +37493,7 @@ "expectations", "amplitudes" ], - "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." }, "auto": { "type": [ @@ -37574,7 +37574,7 @@ "null" ], "minimum": 0, - "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." }, "price": { "anyOf": [ @@ -52380,7 +52380,7 @@ } }, "contract": { - "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", "type": [ "object", "null" @@ -53732,7 +53732,7 @@ } }, "contract": { - "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", "type": [ "object", "null" @@ -56569,7 +56569,7 @@ } }, "planner": { - "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", "type": "object", "required": [ "format", @@ -56617,7 +56617,7 @@ "expectations", "amplitudes" ], - "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." }, "auto": { "type": [ @@ -56698,7 +56698,7 @@ "null" ], "minimum": 0, - "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." }, "price": { "anyOf": [ @@ -57410,7 +57410,7 @@ "type": "number", "minimum": 0, "maximum": 1, - "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -58430,7 +58430,7 @@ } }, "contract": { - "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", "type": [ "object", "null" @@ -61265,7 +61265,7 @@ } }, "planner": { - "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", "type": "object", "required": [ "format", @@ -61313,7 +61313,7 @@ "expectations", "amplitudes" ], - "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." }, "auto": { "type": [ @@ -61394,7 +61394,7 @@ "null" ], "minimum": 0, - "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." }, "price": { "anyOf": [ @@ -62106,7 +62106,7 @@ "type": "number", "minimum": 0, "maximum": 1, - "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.6): each outcome's pooled count split as a fair coin splits it." + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." }, "why": { "type": "string" @@ -62405,7 +62405,7 @@ } }, "planner": { - "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.6). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", "type": "object", "required": [ "format", @@ -62453,7 +62453,7 @@ "expectations", "amplitudes" ], - "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.6)." + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." }, "auto": { "type": [ @@ -62534,7 +62534,7 @@ "null" ], "minimum": 0, - "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.6's table." + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." }, "price": { "anyOf": [ @@ -63963,7 +63963,7 @@ } }, "contract": { - "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.6). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", "type": [ "object", "null" diff --git a/wai/wai-quantum-qpu/tests/clients.rs b/wai/wai-quantum-qpu/tests/clients.rs index 23db60b4d..e43ad45be 100644 --- a/wai/wai-quantum-qpu/tests/clients.rs +++ b/wai/wai-quantum-qpu/tests/clients.rs @@ -799,7 +799,7 @@ fn a_cost_estimated_at_the_least_it_can_come_to_meets_no_ceiling() { let service = TasksService::new(true, false); let t = kept(move |r: &Request| service.answer(r)); let keys = Keys::new("AKIDEXAMPLE", Secret::new("wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"), None); - let client = CloudTasks::new(t, keys, "us-west-1", "arn:test:simulator", "bucket").unwrap().with_endpoints("https://tasks.test", "https://bucket.test"); + let client = CloudTasks::new(t, keys, "us-west-1", "arn:test:simulator", "bucket").unwrap().with_base("https://tasks.test"); Target::new("tasks", Kind::CloudTasks, Box::new(client), None) }; let bell = "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n"; -- 2.54.0 (Apple Git-157) From c8e6ac44c38605b2edb75949aa209a6af194e49d Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Fri, 6 Nov 2026 23:39:04 -0500 Subject: [PATCH 09/42] wai-quantum: the tool lists blessed again on the merged tree Co-Authored-By: Claude Opus 5.5 --- wai/wai-quantum-cli/docs/llms-full.txt | 23 +- wai/wai-quantum-cli/docs/local-mcp.json | 563 +++++++++++++++++++++--- 2 files changed, 522 insertions(+), 64 deletions(-) diff --git a/wai/wai-quantum-cli/docs/llms-full.txt b/wai/wai-quantum-cli/docs/llms-full.txt index 1f350d963..417ff3dc9 100644 --- a/wai/wai-quantum-cli/docs/llms-full.txt +++ b/wai/wai-quantum-cli/docs/llms-full.txt @@ -28,7 +28,7 @@ Generated by `wai-quantum docs llms` from the tool lists both MCP servers serve, ## Receipts -Every result carries an Ed25519 signature over the BLAKE3 digest of the RFC 8785 canonical text of the request and of the result without its receipt. The job service signs with the key `GET /v1` publishes; the command line signs with the user's own key (`wai-quantum key` prints its did:key). `wai-quantum verify` checks either offline, and a result still verifies after any JSON reader has carried it. A receipt shows that the key signed this request and this result, and anyone can rerun the request to compare; it does not show who holds the key, nor that the physics is right. A result's `energy` is the CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or `unmetered` with the reason (the command line does not meter a run). +Every result carries an Ed25519 signature over the BLAKE3 digest of the RFC 8785 canonical text of the request and of the result without its receipt. The job service signs with the key `GET /v1` publishes; the command line signs with the user's own key (`wai-quantum key` prints its did:key). `wai-quantum verify` checks either offline, and a result still verifies after any JSON reader has carried it. A receipt shows that the key signed this request and this result, and anyone can rerun the request to compare; it does not show who holds the key, nor that the physics is right. A result's `energy` is the CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or `unmetered` with the reason (the command line seals no reading of a run: it reads some runs only to bound later ones). ## Versions and stability @@ -1888,9 +1888,10 @@ Options: it, and the receipt says whether it was kept (exit 4 when it was not) --max-joules - The most energy the run may take, in joules: a route whose energy is not known does not - meet it, and this command estimates none, so here every route is refused; the job service - estimates from what it has metered + The most energy the run may take, in joules, held before it runs to an upper bound from + this command line's own readings here: the highest power of the method's last three or + more runs read over the longest of their times, scaled up by the work, never an estimate. + A route with no bound does not meet it, and says why; a reading is never sealed --allow-providers Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods @@ -2079,9 +2080,10 @@ Options: it, and the receipt says whether it was kept (exit 4 when it was not) --max-joules - The most energy the run may take, in joules: a route whose energy is not known does not - meet it, and this command estimates none, so here every route is refused; the job service - estimates from what it has metered + The most energy the run may take, in joules, held before it runs to an upper bound from + this command line's own readings here: the highest power of the method's last three or + more runs read over the longest of their times, scaled up by the work, never an estimate. + A route with no bound does not meet it, and says why; a reading is never sealed --allow-providers Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods @@ -3207,9 +3209,10 @@ Options: it, and the receipt says whether it was kept (exit 4 when it was not) --max-joules - The most energy the run may take, in joules: a route whose energy is not known does not - meet it, and this command estimates none, so here every route is refused; the job service - estimates from what it has metered + The most energy the run may take, in joules, held before it runs to an upper bound from + this command line's own readings here: the highest power of the method's last three or + more runs read over the longest of their times, scaled up by the work, never an estimate. + A route with no bound does not meet it, and says why; a reading is never sealed --allow-providers Let the planner weigh your own providers (`wai-quantum providers list`) beside the methods diff --git a/wai/wai-quantum-cli/docs/local-mcp.json b/wai/wai-quantum-cli/docs/local-mcp.json index 8d63f6bf6..b22d795e0 100644 --- a/wai/wai-quantum-cli/docs/local-mcp.json +++ b/wai/wai-quantum-cli/docs/local-mcp.json @@ -587,7 +587,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -1476,7 +1476,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -4481,7 +4481,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -4567,7 +4584,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -4729,7 +4747,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -6174,7 +6209,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -9177,7 +9212,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -9263,7 +9315,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -9425,7 +9478,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -11257,7 +11327,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -11583,7 +11653,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -11669,7 +11756,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -11831,7 +11919,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -33435,7 +33540,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -34327,7 +34432,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -37332,7 +37437,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -37418,7 +37540,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -37580,7 +37703,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -39025,7 +39165,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -42028,7 +42168,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -42114,7 +42271,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -42276,7 +42434,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -55125,7 +55300,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -55412,7 +55587,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -55498,7 +55690,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -55660,7 +55853,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -55979,7 +56189,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -56875,7 +57085,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -59880,7 +60090,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -59966,7 +60193,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -60128,7 +60356,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -61573,7 +61818,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -64576,7 +64821,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -64662,7 +64924,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -64824,7 +65087,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -65431,7 +65711,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -65689,7 +65969,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -65775,7 +66072,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -65937,7 +66235,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -66419,7 +66734,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -66505,7 +66837,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -66667,7 +67000,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -67112,7 +67462,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -67198,7 +67565,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -67360,7 +67728,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -67708,7 +68093,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -68601,7 +68986,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -71606,7 +71991,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -71692,7 +72094,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -71854,7 +72257,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -73299,7 +73719,7 @@ "exclusiveMinimum": 0 }, "max_joules": { - "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "description": "The most energy it may take, held before it runs to an upper bound from the host's own readings, never to an estimate. A route with no bound does not meet it, so on a host that reads none every route is rejected.", "type": [ "number", "null" @@ -76302,7 +76722,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" @@ -76388,7 +76825,8 @@ "cost_at_least", "cost_no_ceiling", "energy", - "energy_unknown" + "energy_unknown", + "energy_at_least" ] }, "why": { @@ -76550,7 +76988,24 @@ "number", "null" ], - "minimum": 0 + "minimum": 0, + "description": "The most the run can take as the host bounds it, of what the basis says its readings cover, or, with at_least, the least it takes. A ceiling is held only to a figure that cannot be too low, never to an estimate." + }, + "at_least": { + "const": true, + "description": "The figure is the least the run takes: what the host reads leaves out a device the run uses, so nothing bounds it, and it meets no ceiling (energy_at_least)." + }, + "watts": { + "type": "number", + "description": "The power the bound rests on." + }, + "seconds": { + "type": "number", + "description": "The time the bound rests on; not the price's time, which is at the nominal rate." + }, + "estimate_joules": { + "type": "number", + "description": "A point estimate beside the bound, labelled one: no ceiling is held to it." }, "basis": { "type": "string" -- 2.54.0 (Apple Git-157) From 54dfe3c17f6562bce5bec69818ee60d8a7afa212 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sat, 7 Nov 2026 01:33:28 -0500 Subject: [PATCH 10/42] wai-quantum: the verification of the planner's review, fixed A provider-named job's local routes carry the class their shadow has, and the reasoning is held to section 8.7 before anything is sent, so a stabilizer shadow no longer costs a paid run its receipt. A table gives each built-in method its classes: both verifiers hold a route, a local result and a shadow to it, with host_dependent, a method's memory and work, the host's providers, and a shadow's outcomes. recheck plans the shadow again, compares its class, the job's named route, and auto over the host's own routes as stated. A provider a contract does not allow is told nothing; none is asked when no class it could give is named. The confirmation word binds who the provider is. Past a deadline only the provider's word ends a job, and a client that cannot cancel says so. A target's and a pulse program's deadline is reported from the host's time. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/wai-quantum-qpu.yml | 9 +- .github/workflows/wai-quantum-registry.yml | 7 +- wai/extensions/quantum-providers.md | 75 ++- wai/quantum-conformance/receipts/generate.py | 18 + .../jobs/cli-contract-provider-priced.json | 2 +- .../receipts/jobs/cli-contract-pulse.json | 2 +- .../jobs/cli-contract-routed-seed.json | 2 +- .../receipts/jobs/cli-contract-routed.json | 2 +- .../receipts/jobs/cli-contract-target.json | 2 +- ...crafted-contract-approximate-rejected.json | 6 +- .../crafted-contract-at-least-claimed.json | 16 +- .../jobs/crafted-contract-at-least-false.json | 6 +- .../crafted-contract-charged-over-stated.json | 16 +- .../jobs/crafted-contract-charged-over.json | 16 +- .../jobs/crafted-contract-currency-other.json | 16 +- ...crafted-contract-host-providers-other.json | 543 +++++++++++++++++ .../crafted-contract-kept-charged-other.json | 16 +- .../crafted-contract-named-approximate.json | 16 +- .../jobs/crafted-contract-named-other.json | 16 +- .../crafted-contract-price-amount-long.json | 6 +- .../crafted-contract-price-memory-null.json | 343 +++++++++++ ...rafted-contract-price-provider-memory.json | 544 ++++++++++++++++++ .../crafted-contract-price-seconds-past.json | 6 +- ...d-contract-provider-named-not-allowed.json | 16 +- .../crafted-contract-provider-not-chosen.json | 6 +- ...rafted-contract-providers-not-allowed.json | 6 +- ...crafted-contract-result-class-foreign.json | 343 +++++++++++ .../crafted-contract-route-class-by-job.json | 544 ++++++++++++++++++ .../crafted-contract-route-class-gpu.json | 343 +++++++++++ ...crafted-contract-route-host-dependent.json | 343 +++++++++++ ...afted-contract-route-provider-claimed.json | 6 +- ...tract-route-provider-host-independent.json | 544 ++++++++++++++++++ .../crafted-contract-shadow-bound-other.json | 6 +- ...crafted-contract-shadow-class-foreign.json | 544 ++++++++++++++++++ ...rafted-contract-shadow-count-fraction.json | 6 +- .../crafted-contract-shadow-count-short.json | 6 +- .../crafted-contract-shadow-count-sum.json | 6 +- .../crafted-contract-shadow-distinct.json | 544 ++++++++++++++++++ .../jobs/crafted-contract-shadow-missing.json | 6 +- .../crafted-contract-shadow-not-computed.json | 6 +- .../crafted-contract-shadow-numerator.json | 6 +- ...crafted-contract-shadow-omitted-spelt.json | 6 +- .../crafted-contract-shadow-plan-budget.json | 6 +- .../crafted-contract-shadow-plan-class.json | 6 +- .../crafted-contract-shadow-plan-code.json | 6 +- .../crafted-contract-shadow-plan-missing.json | 6 +- ...afted-contract-shadow-plan-price-over.json | 6 +- ...ted-contract-shadow-plan-route-absent.json | 6 +- ...ed-contract-shadow-plan-route-missing.json | 6 +- ...crafted-contract-shadow-request-extra.json | 6 +- ...crafted-contract-shadow-route-missing.json | 6 +- ...rafted-contract-shadow-route-provider.json | 6 +- .../crafted-contract-shadow-said-failed.json | 6 +- .../crafted-contract-shadow-said-none.json | 6 +- .../jobs/crafted-contract-shadow-seed.json | 6 +- .../jobs/scripted-contract-prx-circuits.json | 11 +- .../receipts/made.lock.json | 12 +- .../receipts/manifest.json | 82 +++ .../tools/receipt_verify.py | 105 +++- wai/wai-quantum-qpu/src/cloud_tasks.rs | 4 + wai/wai-quantum-qpu/src/job.rs | 225 +++++++- wai/wai-quantum-qpu/src/lib.rs | 10 + wai/wai-quantum-qpu/src/open_provider.rs | 4 + wai/wai-quantum-qpu/src/registry.rs | 3 +- wai/wai-quantum-qpu/tests/clients.rs | 2 +- wai/wai-quantum/src/engine/planner.rs | 171 +++++- wai/wai-quantum/src/engine/planner/tests.rs | 141 ++++- 67 files changed, 5566 insertions(+), 254 deletions(-) create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-host-providers-other.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-price-memory-null.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-price-provider-memory.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-result-class-foreign.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-route-class-by-job.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-route-class-gpu.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-route-host-dependent.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-route-provider-host-independent.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-class-foreign.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-distinct.json diff --git a/.github/workflows/wai-quantum-qpu.yml b/.github/workflows/wai-quantum-qpu.yml index 91075a04f..e75949f7e 100644 --- a/.github/workflows/wai-quantum-qpu.yml +++ b/.github/workflows/wai-quantum-qpu.yml @@ -79,10 +79,10 @@ jobs: # tests never touch one but the macOS leg's own. export WAI_QUANTUM_CREDENTIALS=file cargo test --locked 2>&1 | tee "$RUNNER_TEMP/test.log" - # The library (87, the cloud-tasks client's 26 and a job under a contract's - # 6 among them), the clients against their contracts (17), and the providers + # The library (90, the cloud-tasks client's 26 and a job under a contract's + # 9 among them), the clients against their contracts (17), and the providers # end to end (12), each binary's count pinned. - for n in 87 17 12; do + for n in 90 17 12; do grep -qE "^test result: ok\. $n passed; 0 failed" "$RUNNER_TEMP/test.log" || { echo "::error::a test binary did not pass all $n of its tests"; exit 1; } done for t in curl_carries_a_request_to_a_server_and_back every_operation_over_http every_operation_over_a_local_process \ @@ -114,6 +114,9 @@ jobs: job::tests::every_provider_is_weighed_against_the_engine_s_own_methods job::tests::a_shadow_and_its_reasoning_outlive_what_sent_the_job \ job::tests::a_deadline_it_cannot_be_held_to_is_refused_and_one_that_leaves_no_time_says_so \ job::tests::a_job_past_its_deadline_is_cancelled_where_it_waits \ + job::tests::a_provider_the_contract_does_not_allow_is_asked_nothing \ + job::tests::the_word_for_a_routed_run_binds_the_provider_and_says_only_itself \ + job::tests::a_job_past_its_deadline_ends_only_on_the_provider_s_word \ a_built_in_kind_runs_under_a_contract_and_a_classical_method_shadows_it a_cost_estimated_at_the_least_it_can_come_to_meets_no_ceiling; do grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/test.log" || { echo "::error::$t did not run and pass"; exit 1; } done diff --git a/.github/workflows/wai-quantum-registry.yml b/.github/workflows/wai-quantum-registry.yml index d056e20b5..5ff2f3351 100644 --- a/.github/workflows/wai-quantum-registry.yml +++ b/.github/workflows/wai-quantum-registry.yml @@ -119,7 +119,12 @@ jobs: engine::planner::tests::auto_is_what_the_routes_give_and_cannot_be_lowered \ engine::planner::tests::a_device_target_s_job_names_its_method_beside_the_host_s_providers \ engine::planner::tests::a_named_approximate_simulator_runs_under_a_contract_that_names_no_class \ - engine::planner::tests::the_sampling_bound_holds_for_sparse_and_dense_outcomes; do + engine::planner::tests::the_sampling_bound_holds_for_sparse_and_dense_outcomes \ + engine::planner::tests::a_named_provider_s_routes_carry_the_class_their_shadow_has \ + engine::planner::tests::a_built_in_route_and_a_result_are_held_to_their_method_s_classes \ + engine::planner::tests::what_a_receipt_states_of_itself_is_of_its_form \ + engine::planner::tests::recheck_plans_the_shadow_again_and_leaves_the_host_s_routes_to_the_host \ + engine::planner::tests::a_target_s_and_a_pulse_program_s_deadline_is_reported_kept; do grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/engine.log" || { echo "::error::$t did not run"; exit 1; } done - name: The example, tested and run diff --git a/wai/extensions/quantum-providers.md b/wai/extensions/quantum-providers.md index e6af50c1d..26477af13 100644 --- a/wai/extensions/quantum-providers.md +++ b/wai/extensions/quantum-providers.md @@ -735,8 +735,12 @@ finds it finished: the provider's queue and its run count, and a host that comes back to a job late (one sent without waiting, collected later) counts the wait too, so its `elapsed_ms` can only overstate. A shadow is not counted: it runs in what the deadline leaves, or not at all. A host that can stop a run stops it at -its deadline: the job service stops its worker, and the command line cancels a -provider's job still waiting there; nothing is sealed (`J074`). +its deadline: the job service stops its worker, and nothing is sealed (`J074`). A +provider's job is looked at only while a host follows it: past the deadline, the +next look cancels it where the client can, and it is `cancelled` once the provider +says so (`J074`). A job no one follows, or one a client cannot cancel (its route +says so: `cancel` in `leaves_out`), runs on and can be billed; when it finishes, +`kept.deadline` says it was missed. **The reasoning.** `planner` is an object of: @@ -748,7 +752,7 @@ provider's job still waiting there; nothing is sealed (`J074`). | `question` | the question the job asks, as below: `noise`, `counts`, `expectations` or `amplitudes` | | `auto` | the route `auto` picks for this job, or `null`, as below | | `wanted`, `wanted_from` | the class the routes are held to, and where it comes from, as below | -| `host` | `job_bytes`, the memory one job may take on the host, a whole number; `providers`, the names of the providers it brought, an array of strings | +| `host` | `job_bytes`, the memory one job may take on the host, a whole number; `providers`, the names of the providers it brought, an array of strings: exactly the provider routes' names, in their order | | `choice` | the name of the route chosen: a route of `routes` | | `why` | a sentence | | `stable` | below | @@ -761,8 +765,8 @@ A route, an object of: |---|---| | `route` | its name: `method:`, or `provider:`, neither name empty | | `kind` | `local` for a method, `provider` for a provider | -| `class` | a string: the class its result has at worst. A method that declares one class has that one; one that declares several has the first of `bit-exact`, `exact`, `single`, `bounded`, `estimate` and `heuristic` that each of them meets (so `single` and `bounded` together are `heuristic`). A method that can be truncated says so: `mps` is `heuristic`, though a result that was not truncated says `exact`. A provider that cannot run the job is `unknown` | -| `host_dependent` | `true` or `false`: whether the route depends on the host. A provider's, a method on a GPU (`statevector_single`, `cutrank_single`) and a method the host registered are | +| `class` | a string: the class its result has at worst on this job. A built-in method's is held to the table below; a method a host registered that declares one class has that one, and one that declares several has the first of `bit-exact`, `exact`, `single`, `bounded`, `estimate` and `heuristic` that each of them meets (so `single` and `bounded` together are `heuristic`). A provider that cannot run the job is `unknown` | +| `host_dependent` | `true` or `false`: whether the route depends on the host. A provider's, a method on a GPU (`statevector_single`, `cutrank_single`) and a method the host registered are, and no other built-in is | | `auto_rank` | on a local route: its rank in `auto`'s order for the job's `question`, a whole number, or `null` where `auto` does not try it. A built-in method's is the table's below; a registered method's is the host's word | | `price` | `null`, or an object: below | | `outcome` | `chosen`, `met` or `rejected`. Exactly one route is `chosen`, and it is `choice` | @@ -772,15 +776,34 @@ A route, an object of: and a provider's route may name its `provider`, `device` and `provenance`, a method's its `method`, as words a person reads. +The classes of the built-in methods, and which of them a route has on a job: + +| method | classes | a route's | +|---|---|---| +| `exact` | `bit-exact` | | +| `statevector`, `tensor_network`, `density_matrix` | `exact` | | +| `statevector_single`, `cutrank_single` | `single` | | +| `pauli`, `pulse` | `bounded` | | +| `trajectories` | `estimate` | | +| `mps` | `exact`, `heuristic` | either; a route says `heuristic`, since a run can be truncated, and a result not truncated says `exact` | +| `stabilizer` | `exact`, `estimate` | `estimate` where the request gives a `noise` or a device `target`, else `exact` | +| `stabilizer_rank` | `exact`, `estimate` | `estimate` where its `options` give `terms` or `epsilon`, else `exact` | +| `cutrank` | `exact`, `single` | either: the memory a job has chooses the precision of its table | + +Each is the class of the route listed in `routes`, priced or not, on a job that names +a provider as on any other: a shadow's class is its route's. The `accuracy.class` of a +result of a built-in method, and of a shadow's, is one of its method's; `contract_class` +and `shadow` hold them. + A price, an object of: | member | | |---|---| | `money` | `free`: `true`, or `false` with `amount` and `currency` (strings, the amount as the provider gives it, at most 64 characters, with an optional `unit`), or `false` with `unknown`, a sentence. An unknown cost is not free (§7). A local route's is `free` `true`: only a provider's costs. `at_least`, absent or `true`: the amount is the least the job can come to, and what it takes decides the rest | | `time` | `seconds`, a number from 0 to 10^12 or `null`; with a number, `basis`: `nominal`, at the engine's rate for the method's work, or `provider`, the provider's own estimate, queue included; with `null`, `why`. A host takes a provider's estimate past 10^12 seconds, or an amount past 64 characters, as no estimate: `null` here, `unknown` there, with why | -| `memory_bytes`, `work` | what a method takes, as whole numbers, a double past 2^53 − 1, or `null` on a provider's route | +| `memory_bytes`, `work` | what a method takes, as whole numbers, a double past 2^53 − 1; `null`, and only `null`, on a provider's route | | `energy` | `joules`, a number or `null`; with a number, `basis`; with `null`, `why`. No provider states a job's energy before it runs, so a provider's is `null`, and a host that estimates no job's energy states `null` for every route | -| `leaves_out` | what the price leaves out, an array of: `time`, it states no time; `amount`, it states no amount; `energy`, it states no energy; `mitigation`, what the provider's own mitigation costs or does, unless a client set it off or the device has none; `decoder`, any decoder's latency; `charged`, what the provider charges may differ from what it estimates | +| `leaves_out` | what the price leaves out, an array of: `time`, it states no time; `amount`, it states no amount; `energy`, it states no energy; `mitigation`, what the provider's own mitigation costs or does, unless a client set it off or the device has none; `decoder`, any decoder's latency; `charged`, what the provider charges may differ from what it estimates; `cancel`, its client cannot stop a job it sent | | `program` | on a provider's route, optional: the `shots`, `native_gates`, `two_qubit_gates` and `swaps` of what would be sent, and `expected_success` when a calibration states one | **What is named.** `named` is `provider:` the request's `provider`, where it gives @@ -869,13 +892,18 @@ not from exact to approximate, since a less exact route does not meet `wanted`; from a simulator to a device or the reverse, since neither's class meets the other's. A cost ceiling confirms nothing: a run that is not free still needs the person's word for that run (§7). Where a host chose the provider (the request names -none), that word names what the person saw: a host gives the route, its -estimate's `money` and the program and shots it would send, as a short digest, and -sends the job only when the word it is given is that digest made again at send -time; a route, an estimate or a program that changed since is not sent. A host -asks no provider anything (an estimate's request carries the compiled program) -where the contract does not allow one, or wants a class no provider's counts are -in. If no route is left, the job is refused (`J071`) with each route's reason, and +none), that word names what the person saw: a host gives the route, who it is (its +kind, device, provenance and description, and what the person's name for it stands +for: its endpoint, settings and credential's place), its estimate's `money` and the +program and shots it would send, as a short digest, and sends the job only when the +word it is given is that digest made again at send time; a route, a device, an +estimate or a program that changed since is not sent. A host asks no provider +anything (an estimate's request carries the compiled program, and a description +says a job is coming) where the contract does not allow one, or names no class a +provider's counts are in: with none named the job keeps a classical class, which +no provider's meets. And a host holds its reasoning to these rules before it sends +anything, since a receipt it would refuse afterwards would be a run paid for and +lost. If no route is left, the job is refused (`J071`) with each route's reason, and there is no result to seal. **The choice.** Of the routes these rules let through, the job runs the one this @@ -917,7 +945,7 @@ run stops it at its deadline (`J074`), and seals nothing. | member | | |---|---| -| `deadline` | `seconds`, the contract's; `elapsed_ms`, a whole number or `null`: the result's `elapsed_ms` by value when its `method` is not `provider` (`null` when it has none or it is not a number), and otherwise the host's time from the job's submission to its counts; `kept`, whether `elapsed_ms` ≤ `seconds` × 1000, or `null` when `elapsed_ms` is `null` | +| `deadline` | `seconds`, the contract's; `elapsed_ms`, a whole number or `null`: the result's `elapsed_ms` by value when its `method` is not `provider` and it states one; for a method's result that states none, so that its bits are the same on every host (a device target's, a pulse program's), the host's own time of the run; and for a provider's, the host's time from the job's submission to its counts; `kept`, whether `elapsed_ms` ≤ `seconds` × 1000, or `null` when `elapsed_ms` is `null` | | `energy` | `max_joules`, the contract's; `joules`, the result's `energy.joules_micro` ÷ 10^6, or `null` when it has none; `kept`, whether `joules` ≤ `max_joules`, or `null` when `joules` is `null` | | `cost` | `max_cost`, the contract's; `charged`, equal to the result's `cost.charged` (numbers by value), or `null` when it has none; `kept`: with a `charged` in the ceiling's currency and an amount in decimals, whether it is at most the ceiling; with any other `charged`, `null`; with no `charged`, `true` when the result's `cost.free` is `true` or it has none, and otherwise `null` | @@ -956,11 +984,13 @@ A result's `shadow` is one of: planned shadow, and a host whose failed shadow runs there is found. - `ran` `true`, where `planner.shadow` has a route: with `route` and `request`, equal to those of `planner.shadow` (numbers by value); `shots`, the result's; - `accuracy`, an object whose `class` is a string that meets `planner.shadow.class`; - `counts`, each a whole number written as one from 1 to 2^53 − 1, and + `accuracy`, an object whose `class` is a string that meets `planner.shadow.class` + and is one of its method's; `counts`, keyed by outcomes all of one length and each + of `0` and `1` only, each a whole number written as one from 1 to 2^53 − 1, and `omitted_shots`, a whole number of at least 0 by value, which sum exactly to the result's `shots` (a whole number by value); `distinct_outcomes`, a whole number - of at least 0; optionally `elapsed_ms`; and `distance`. + of at least 0, and, with no shot omitted, the number of outcomes listed; optionally + `elapsed_ms`; and `distance`. `distance` is an object. With `computed` `false`, it has `why`, and it is `false` only when the provider's or the shadow's `omitted_shots` is not 0 (by value: `0` @@ -1011,8 +1041,13 @@ A verifier also states, for a contract job, its `choice`, `wanted`, the class gi is the host's word, as everything it says it received, sent and checked is (§8.5): what a verifier recomputes is what follows from it. A verifier that holds the engine can price the routes again and run the shadow again -(`wai-quantum verify --recheck`), which holds `digest`, `auto` and the shadow's -counts to what a run here gives, and runs a shadow the host says failed. +(`wai-quantum verify --recheck`), which holds `digest`, `named` and `auto` to what +this engine gives (`auto` over the routes that depend on the host as the host stated +them: a verifier here has neither its GPU nor its registered methods); holds the +shadow's counts and class to a run here; runs a shadow the host says failed; and, +on the same engine, plans the shadow again, so that which method ran, or that none +could, is what this engine gives: a verifier without one takes those on the host's +word. The free job service reaches no provider. It lists none among its routes, a contract that wants a device's class is refused there (`J071`), and a request that diff --git a/wai/quantum-conformance/receipts/generate.py b/wai/quantum-conformance/receipts/generate.py index 2f00c40f4..e7c9f3080 100644 --- a/wai/quantum-conformance/receipts/generate.py +++ b/wai/quantum-conformance/receipts/generate.py @@ -840,6 +840,15 @@ def contract_cases(run, at, drop): b["result"]["planner"]["stable"]["choice"] = False add("energy-at-ceiling", edited(local, joules), [], "an energy ceiling met exactly, every route estimated within it: kept, and the choice depends on the host, whose estimate it is") add("energy-stable-claimed", edited(local, both(joules, at(P + ("stable", "choice"), True))), ["planner_stable"], "the same, the choice said to depend on nothing of the host") + # --- what a route states of itself (the verification of the review) + add("route-class-gpu", edited(local, route("method:statevector_single", lambda r: r.update({"class": "exact"}))), ["planner_route"], "the GPU's single precision stated exact: a class its method does not have") + add("route-class-by-job", edited(routed, route("method:stabilizer", lambda r: r.update({"class": "estimate"}))), ["planner_route", "planner_stable"], "the stabilizer stated estimate, on a job with no noise and no target") + add("route-host-dependent", edited(local, route("method:trajectories", lambda r: r.update(host_dependent=True))), ["planner_route", "planner_stable"], "a built-in on no GPU said to depend on the host, which takes it out of the digest") + add("route-provider-host-independent", edited(routed, route("provider:priced", lambda r: r.update(host_dependent=False))), ["planner_route"], "a provider's route said not to depend on the host") + add("result-class-foreign", edited(local, at(R + ("accuracy", "class"), "bit-exact")), ["contract_class"], "the stabilizer's result stated bit-exact: it meets what is wanted, and its method has no such class") + add("price-memory-null", edited(local, route("method:statevector", lambda r: r["price"].update(memory_bytes=None))), ["planner_form"], "a method's memory stated null, which passes the memory rule and wins its tie") + add("price-provider-memory", edited(routed, route("provider:priced", lambda r: r["price"].update(memory_bytes=1024))), ["planner_form"], "a provider's route stating a memory") + add("host-providers-other", edited(routed, at(P + ("host", "providers"), ["someone-else"])), ["planner_form"], "host.providers that are not the provider routes") # --- the shadow, a method's run of exactly the job's program (review: steered, suppressed, unverifiable) add("shadow-route-missing", edited(routed, drop(S + ("route",))), ["shadow"], "a shadow that names no route") add("shadow-plan-route-missing", edited(routed, drop(P + ("shadow", "route"))), ["shadow"], "a shadow planned with no route, where null would say why") @@ -868,6 +877,15 @@ def contract_cases(run, at, drop): add("shadow-count-fraction", edited(routed, fraction), ["shadow"], "a shadow's counts that are not whole, summing to the shots all the same") add("shadow-count-sum", edited(routed, lambda b: b["result"]["shadow"]["counts"].update({sorted(b["result"]["shadow"]["counts"])[0]: b["result"]["shadow"]["counts"][sorted(b["result"]["shadow"]["counts"])[0]] + 1})), ["shadow"], "a shadow's counts that sum to more than its shots") add("shadow-count-short", edited(routed, both(at(S + ("omitted_shots",), 1), at(S + ("distance",), {"computed": False, "why": "a shot is omitted"}))), ["shadow"], "a shot said omitted beside counts that are all the shots: they sum to one more, and the distance, not computed, is no help") + add("shadow-distinct", edited(routed, at(S + ("distinct_outcomes",), 7)), ["shadow"], "a shadow that says more outcomes than it lists, none omitted") + + def by_mps(b): + route("method:mps", lambda r: None)(b) + b["result"]["planner"]["shadow"].update({"route": "method:mps", "class": "heuristic"}) + b["result"]["planner"]["shadow"]["request"]["method"] = "mps" + b["result"]["shadow"]["route"] = "method:mps" + b["result"]["shadow"]["request"]["method"] = "mps" + add("shadow-class-foreign", edited(routed, by_mps), ["shadow"], "a shadow run by mps stated bit-exact: it meets its plan, and mps has no such class") add("shadow-bound-other", edited(routed, lambda b: b["result"]["shadow"]["distance"].update(sampling_tvd_bound=0.01)), ["shadow"], "a bound on the distance the shots alone leave that is not what the counts give") def host_failed(b): diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-provider-priced.json b/wai/quantum-conformance/receipts/jobs/cli-contract-provider-priced.json index 5219a719d..eb0b2558a 100644 --- a/wai/quantum-conformance/receipts/jobs/cli-contract-provider-priced.json +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-provider-priced.json @@ -1 +1 @@ -{"status":"done","method":"provider","why":"on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4,"contract":{"max_cost":{"amount":"1","currency":"USD"},"providers":"allowed"},"provider":"priced"},"result":{"method":"provider","qubits":2,"gates":2,"accuracy":{"class":"simulated","note":"counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would"},"shots":300,"provider":{"name":"priced","kind":"process","protocol":"wai.quantum.provider/1","device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","qubits":5,"basis":"rzsxxcz","describe":"c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439"},"calibration":"reference-f2d9fe570421","compiled":{"basis":"rzsxxcz","program":"b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9","hash":"BLAKE3 of the program's OpenQASM 3 text, qasm3","qasm3":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n","native_gates":9,"two_qubit_gates":1,"swaps":0,"layout":[0,1],"final_layout":[0,1],"checked":"the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent","placement":{"chosen":"the compiler's own layout, the fewest swaps: the description states no errors"}},"job":{"id":"ref-1","polls":1},"ideal":{"computed":true,"method":"exact","total_variation_distance":0.03666666666666665,"hellinger_fidelity":0.998653743148044,"sampling_tvd_expected":0.023032943298089033,"ideal_outcomes":2,"note":"the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent"},"cost":{"free":false,"estimate":{"free":false,"amount":"0.09","currency":"USD","unit":"shot","seconds":0.0},"charged":{"amount":"0.09","currency":"USD"},"confirmed":true},"energy":{"unmetered":"the work ran at the provider; this host's meter would read only the wait"},"counts_source":"shots","execution":{"stated_by":"provider","mitigation":"none","twirling":"none","decoupling":"none","remapping":"none","optimisation":"none","verbatim":true,"note":"the reference simulates the program's gates as written, on the qubits named, and corrects nothing"},"counts":{"11":161,"00":139},"distinct_outcomes":2,"omitted_shots":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"simulated","wanted_from":"named","named":"provider:priced","question":"counts","auto":null,"host":{"job_bytes":17179869184,"providers":["priced"]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"auto_rank":20,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"auto_rank":30,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"auto_rank":40,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"estimate","host_dependent":false,"auto_rank":10,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"auto_rank":60,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"estimate","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"auto_rank":50,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"provider:priced","kind":"provider","provider":"priced","class":"simulated","host_dependent":true,"price":{"money":{"free":false,"amount":"0.09","currency":"USD","unit":"shot"},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder","charged"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"chosen"}],"choice":"provider:priced","why":"the route the job names, which meets its contract (1 of 14 routes)","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c","choice":false},"shadow":{"route":"method:exact","class":"bit-exact","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"budget_seconds":300.0,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]}},"kept":{"cost":{"max_cost":{"amount":"1","currency":"USD"},"charged":{"amount":"0.09","currency":"USD"},"kept":true}}},"shadow":{"ran":true,"route":"method:exact","accuracy":{"class":"bit-exact"},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"shots":300,"counts":{"00":161,"11":139},"distinct_outcomes":2,"omitted_shots":0,"distance":{"computed":true,"numerator":44,"denominator":600,"total_variation":0.07333333333333333,"hellinger_fidelity":0.9946222222222221,"sampling_tvd_bound":0.04602751441903442},"elapsed_ms":0},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"483113df1f4fabe90c601cc424fbecab5a3c62d886f986749078987d756d935a","signature":"aaa742d8537a113c682fabcddfcf3d4a4291cd7904f0b9337cc4b5ac2d9edd6422aa5c45f5a37ebd22ba09c3e800d5c1049d5f402be5f331ae5ba6649512be09"}},"id":"pj-316b154641049d91","submitted_ms":1793974079084,"finished_ms":1793974079087} +{"status":"done","method":"provider","why":"on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4,"contract":{"max_cost":{"amount":"1","currency":"USD"},"providers":"allowed"},"provider":"priced"},"result":{"method":"provider","qubits":2,"gates":2,"accuracy":{"class":"simulated","note":"counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would"},"shots":300,"provider":{"name":"priced","kind":"process","protocol":"wai.quantum.provider/1","device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","qubits":5,"basis":"rzsxxcz","describe":"c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439"},"calibration":"reference-f2d9fe570421","compiled":{"basis":"rzsxxcz","program":"b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9","hash":"BLAKE3 of the program's OpenQASM 3 text, qasm3","qasm3":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n","native_gates":9,"two_qubit_gates":1,"swaps":0,"layout":[0,1],"final_layout":[0,1],"checked":"the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent","placement":{"chosen":"the compiler's own layout, the fewest swaps: the description states no errors"}},"job":{"id":"ref-1","polls":1},"ideal":{"computed":true,"method":"exact","total_variation_distance":0.03666666666666665,"hellinger_fidelity":0.998653743148044,"sampling_tvd_expected":0.023032943298089033,"ideal_outcomes":2,"note":"the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent"},"cost":{"free":false,"estimate":{"free":false,"amount":"0.09","currency":"USD","unit":"shot","seconds":0.0},"charged":{"amount":"0.09","currency":"USD"},"confirmed":true},"energy":{"unmetered":"the work ran at the provider; this host's meter would read only the wait"},"counts_source":"shots","execution":{"stated_by":"provider","mitigation":"none","twirling":"none","decoupling":"none","remapping":"none","optimisation":"none","verbatim":true,"note":"the reference simulates the program's gates as written, on the qubits named, and corrects nothing"},"counts":{"11":161,"00":139},"distinct_outcomes":2,"omitted_shots":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"simulated","wanted_from":"named","named":"provider:priced","question":"counts","auto":null,"host":{"job_bytes":17179869184,"providers":["priced"]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"auto_rank":20,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"auto_rank":30,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"auto_rank":40,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"auto_rank":10,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"auto_rank":60,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"auto_rank":50,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"provider:priced","kind":"provider","provider":"priced","class":"simulated","host_dependent":true,"price":{"money":{"free":false,"amount":"0.09","currency":"USD","unit":"shot"},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder","charged"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"chosen"}],"choice":"provider:priced","why":"the route the job names, which meets its contract (1 of 14 routes)","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"42dab8b20f638eeb9c1d46fd7a0890b574c641a1e11d1306da2abc201ca84c5f","choice":false},"shadow":{"route":"method:exact","class":"bit-exact","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"budget_seconds":300.0,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]}},"kept":{"cost":{"max_cost":{"amount":"1","currency":"USD"},"charged":{"amount":"0.09","currency":"USD"},"kept":true}}},"shadow":{"ran":true,"route":"method:exact","accuracy":{"class":"bit-exact"},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"shots":300,"counts":{"00":161,"11":139},"distinct_outcomes":2,"omitted_shots":0,"distance":{"computed":true,"numerator":44,"denominator":600,"total_variation":0.07333333333333333,"hellinger_fidelity":0.9946222222222221,"sampling_tvd_bound":0.04602751441903442},"elapsed_ms":0},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"adb960d9232ebd72080b05dcbde26df4cbc594e26b9a3c717178087302139864","signature":"884e8d86ca7373ceed84a319c6593bac1241bfba9ca74b4fe107c44947808e48ffc21d04b48abbca58367338a6915f74d0be578baa6b4a465b90ddc59e35e90e"}},"id":"pj-e158396f1fd8f81d","submitted_ms":1794033072602,"finished_ms":1794033072605} diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-pulse.json b/wai/quantum-conformance/receipts/jobs/cli-contract-pulse.json index f0a181c29..242aa74be 100644 --- a/wai/quantum-conformance/receipts/jobs/cli-contract-pulse.json +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-pulse.json @@ -1 +1 @@ -{"status":"done","method":"pulse","why":"a pulse schedule of 164 samples (82 ns) on $0 at 2 levels: 164 steps of 0.5 ns, each a series of order 12, the error within 3.512e-21 with rounding estimated at 2.840e-12; the cheapest of the 1 of 1 routes that meet the contract","estimate":{"memory_bytes":33566400,"work":55104},"request":{"qasm":"OPENQASM 3.0;\ndefcalgrammar \"openpulse\";\ncal {\n extern port d0;\n extern port a0;\n frame q0 = newframe(d0, 5.0e9, 0);\n frame c0 = newframe(a0, 5.0e9, 0);\n}\ndefcal x $0 { play(q0, drag(0.4, 64dt, 16dt, 0.2)); }\ndefcal measure $0 -> bit { return capture_v2(c0, 100dt); }\nbit c;\nx $0;\nc = measure $0;\n","shots":50,"seed":2,"method":"pulse","contract":{"exactness":"bounded","deadline_seconds":60.0}},"result":{"method":"pulse","qubits":1,"gates":2,"accuracy":{"class":"bounded","bound":2.8403945897125026e-12,"truncation_bound":3.511502073909511e-21,"rounding_estimate":2.8403945862010005e-12,"tolerance":1e-6,"norm":"trace","note":"every probability is within bound of the exact solution of the pulse model's master equation: the series' truncation proved, the rounding an estimate; the model itself (its levels, the rotating frame and the rotating-wave approximation, the envelope held for each sample) is what is solved"},"counts":{"1":46,"0":4},"distinct_outcomes":2,"omitted_shots":0,"shots":50,"diagnostics":[{"code":"Q453","outcome":"lowered","message":"a `cal` block read as OpenPulse and run here","line":3,"column":1,"length":5},{"code":"Q453","outcome":"lowered","message":"the `defcal` of x read as OpenPulse; it runs at each call","line":9,"column":1,"length":53},{"code":"Q453","outcome":"lowered","message":"the `defcal` of measure read as OpenPulse; it runs at each call","line":10,"column":1,"length":58}],"pulse":{"read":"the captures, at their one first sample, into the program's bits","outcome_bits":["c"],"distribution":{"0":0.12956041250210984,"1":0.8704395874978892},"populations":{"0":0.12956041250210984,"1":0.8704395874978892},"simulated_qubits":[0],"captures":[{"frame":"c0","qubit":0,"start":64,"start_ns":32.0,"bit":"c","p1":0.8704395874978892,"p2":0.0}],"trace":0.999999999999999,"density_hash":"09778fae666fc72fbac7b86d35f38c7a7e7fc16eb3c3799b0db32da0dc8767a4","duration":164,"duration_ns":82.0,"integrator":{"name":"taylor","order":12,"dt_ns":0.5,"substeps":1,"step_ns":0.5,"steps":164,"norm_max":0.2512047429452378,"frame":"each sample in the frame of each qubit's tone, the generator constant over it, then a diagonal phase back"},"device":{"levels":2,"dt_ns":0.5,"qubits":[{"qubit":0,"frequency_hz":5000000000.0,"rabi_hz":50000000.0,"anharmonicity_hz":-300000000.0,"from":{"frequency":"default","rabi":"default","anharmonicity":"default","t1":"none","t2":"none"}}],"couplings":[],"model":"each qubit a ladder of its levels in the frame rotating at its frequency, under the rotating-wave approximation, the envelope held for each sample; relaxation and pure dephasing from T1 and T2; static ZZ couplings"},"calibration":{"program":"f9b61296e932d2a5a5e9ab81f405f05bcf9900dacf27cbbeadf9ccaef001e0bb","calibrations":"48d81e250c5a875c58ba41229b4e2477f160e6e84f85a901dfff3fd7682b1a89","schedule":"9424e49a95d76eb70bf89923d05b5f7aca92678bd95520953373d415cc1b9267","device":"b18083ab12fd0d2f46d3d125c855119ca7f7dc0f2d73dace7d7fe5e557668b39"},"not_modelled":["the readout: a capture reads its qubit's state at its first sample, a level above 0 as 1"]},"verdict":{"schema":"wai.quantum.verdict/1","level":"executed","rank":2,"holds":null,"statement":"Executed on pulse (bounded); no intent was given, so nothing was checked against one.","parsed":{"ok":true,"diagnostics":[{"code":"Q453","outcome":"lowered","message":"a `cal` block read as OpenPulse and run here","line":3,"column":1,"length":5},{"code":"Q453","outcome":"lowered","message":"the `defcal` of x read as OpenPulse; it runs at each call","line":9,"column":1,"length":53},{"code":"Q453","outcome":"lowered","message":"the `defcal` of measure read as OpenPulse; it runs at each call","line":10,"column":1,"length":58}]},"executed":{"method":"pulse","accuracy":"bounded"},"intent":[],"critique":[],"repairs":[]},"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"bounded","wanted_from":"contract","named":"method:pulse","question":"counts","auto":null,"host":{"job_bytes":17179869184,"providers":[]},"routes":[{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":{"money":{"free":true},"time":{"seconds":0.000055104,"basis":"nominal"},"memory_bytes":33566400,"work":55104,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"chosen"}],"choice":"method:pulse","why":"the cheapest of the 1 of 1 routes that meet the contract","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:pulse"],"digest":"66699259c0f19f46979dc8a807893b52eaa894a2d6db6a3d7722004e484db32b","choice":true},"kept":{"deadline":{"seconds":60.0,"elapsed_ms":null,"kept":null}}},"energy":{"unmetered":"the command line does not meter a run's energy"},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"4ab608bd1b63101d9f156343d3c2a9c638101b2a06dde475be1f124a9a3921e0","signature":"94e0361bec90485d348c5cb786b20996149b9e78d8169db684b4f5e3efee7344efcf677d9374a9d7cc6918e8da46ad75ce45afad9bddfe4a9b031f323e0c8b0f"}}} +{"status":"done","method":"pulse","why":"a pulse schedule of 164 samples (82 ns) on $0 at 2 levels: 164 steps of 0.5 ns, each a series of order 12, the error within 3.512e-21 with rounding estimated at 2.840e-12; the cheapest of the 1 of 1 routes that meet the contract","estimate":{"memory_bytes":33566400,"work":55104},"request":{"qasm":"OPENQASM 3.0;\ndefcalgrammar \"openpulse\";\ncal {\n extern port d0;\n extern port a0;\n frame q0 = newframe(d0, 5.0e9, 0);\n frame c0 = newframe(a0, 5.0e9, 0);\n}\ndefcal x $0 { play(q0, drag(0.4, 64dt, 16dt, 0.2)); }\ndefcal measure $0 -> bit { return capture_v2(c0, 100dt); }\nbit c;\nx $0;\nc = measure $0;\n","shots":50,"seed":2,"method":"pulse","contract":{"exactness":"bounded","deadline_seconds":60.0}},"result":{"method":"pulse","qubits":1,"gates":2,"accuracy":{"class":"bounded","bound":2.8403945897125026e-12,"truncation_bound":3.511502073909511e-21,"rounding_estimate":2.8403945862010005e-12,"tolerance":1e-6,"norm":"trace","note":"every probability is within bound of the exact solution of the pulse model's master equation: the series' truncation proved, the rounding an estimate; the model itself (its levels, the rotating frame and the rotating-wave approximation, the envelope held for each sample) is what is solved"},"counts":{"1":46,"0":4},"distinct_outcomes":2,"omitted_shots":0,"shots":50,"diagnostics":[{"code":"Q453","outcome":"lowered","message":"a `cal` block read as OpenPulse and run here","line":3,"column":1,"length":5},{"code":"Q453","outcome":"lowered","message":"the `defcal` of x read as OpenPulse; it runs at each call","line":9,"column":1,"length":53},{"code":"Q453","outcome":"lowered","message":"the `defcal` of measure read as OpenPulse; it runs at each call","line":10,"column":1,"length":58}],"pulse":{"read":"the captures, at their one first sample, into the program's bits","outcome_bits":["c"],"distribution":{"0":0.12956041250210984,"1":0.8704395874978892},"populations":{"0":0.12956041250210984,"1":0.8704395874978892},"simulated_qubits":[0],"captures":[{"frame":"c0","qubit":0,"start":64,"start_ns":32.0,"bit":"c","p1":0.8704395874978892,"p2":0.0}],"trace":0.999999999999999,"density_hash":"09778fae666fc72fbac7b86d35f38c7a7e7fc16eb3c3799b0db32da0dc8767a4","duration":164,"duration_ns":82.0,"integrator":{"name":"taylor","order":12,"dt_ns":0.5,"substeps":1,"step_ns":0.5,"steps":164,"norm_max":0.2512047429452378,"frame":"each sample in the frame of each qubit's tone, the generator constant over it, then a diagonal phase back"},"device":{"levels":2,"dt_ns":0.5,"qubits":[{"qubit":0,"frequency_hz":5000000000.0,"rabi_hz":50000000.0,"anharmonicity_hz":-300000000.0,"from":{"frequency":"default","rabi":"default","anharmonicity":"default","t1":"none","t2":"none"}}],"couplings":[],"model":"each qubit a ladder of its levels in the frame rotating at its frequency, under the rotating-wave approximation, the envelope held for each sample; relaxation and pure dephasing from T1 and T2; static ZZ couplings"},"calibration":{"program":"f9b61296e932d2a5a5e9ab81f405f05bcf9900dacf27cbbeadf9ccaef001e0bb","calibrations":"48d81e250c5a875c58ba41229b4e2477f160e6e84f85a901dfff3fd7682b1a89","schedule":"9424e49a95d76eb70bf89923d05b5f7aca92678bd95520953373d415cc1b9267","device":"b18083ab12fd0d2f46d3d125c855119ca7f7dc0f2d73dace7d7fe5e557668b39"},"not_modelled":["the readout: a capture reads its qubit's state at its first sample, a level above 0 as 1"]},"verdict":{"schema":"wai.quantum.verdict/1","level":"executed","rank":2,"holds":null,"statement":"Executed on pulse (bounded); no intent was given, so nothing was checked against one.","parsed":{"ok":true,"diagnostics":[{"code":"Q453","outcome":"lowered","message":"a `cal` block read as OpenPulse and run here","line":3,"column":1,"length":5},{"code":"Q453","outcome":"lowered","message":"the `defcal` of x read as OpenPulse; it runs at each call","line":9,"column":1,"length":53},{"code":"Q453","outcome":"lowered","message":"the `defcal` of measure read as OpenPulse; it runs at each call","line":10,"column":1,"length":58}]},"executed":{"method":"pulse","accuracy":"bounded"},"intent":[],"critique":[],"repairs":[]},"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"bounded","wanted_from":"contract","named":"method:pulse","question":"counts","auto":null,"host":{"job_bytes":17179869184,"providers":[]},"routes":[{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":{"money":{"free":true},"time":{"seconds":0.000055104,"basis":"nominal"},"memory_bytes":33566400,"work":55104,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"chosen"}],"choice":"method:pulse","why":"the cheapest of the 1 of 1 routes that meet the contract","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:pulse"],"digest":"66699259c0f19f46979dc8a807893b52eaa894a2d6db6a3d7722004e484db32b","choice":true},"kept":{"deadline":{"seconds":60.0,"elapsed_ms":0,"kept":true}}},"energy":{"unmetered":"the command line does not meter a run's energy"},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"645a9ebd1f46804cf7c7e3eb4ea5f24bcceb875368f154a21a4bb1ea853ffd00","signature":"8c6b7778c8e3a1a7344f6c751e8c3f96dbbe24ba4363d3254af22980ec0769b23679cd7397c2a298c2221437550041a8d31534a9ea9320c203432575721a3203"}}} diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-routed-seed.json b/wai/quantum-conformance/receipts/jobs/cli-contract-routed-seed.json index f61a096bf..64bd128d0 100644 --- a/wai/quantum-conformance/receipts/jobs/cli-contract-routed-seed.json +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-routed-seed.json @@ -1 +1 @@ -{"status":"done","method":"provider","why":"on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":9007199254740990,"contract":{"exactness":"simulated","providers":"allowed"}},"result":{"method":"provider","qubits":2,"gates":2,"accuracy":{"class":"simulated","note":"counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would"},"shots":300,"provider":{"name":"ref","kind":"process","protocol":"wai.quantum.provider/1","device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","qubits":5,"basis":"rzsxxcz","describe":"0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0"},"calibration":"reference-f2d9fe570421","compiled":{"basis":"rzsxxcz","program":"b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9","hash":"BLAKE3 of the program's OpenQASM 3 text, qasm3","qasm3":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n","native_gates":9,"two_qubit_gates":1,"swaps":0,"layout":[0,1],"final_layout":[0,1],"checked":"the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent","placement":{"chosen":"the compiler's own layout, the fewest swaps: the description states no errors"}},"job":{"id":"ref-1","polls":1},"ideal":{"computed":true,"method":"exact","total_variation_distance":0.013333333333333308,"hellinger_fidelity":0.9998221906060416,"sampling_tvd_expected":0.023032943298089033,"ideal_outcomes":2,"note":"the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent"},"cost":{"free":true,"estimate":{"free":true,"seconds":0.0},"charged":null,"confirmed":false},"energy":{"unmetered":"the work ran at the provider; this host's meter would read only the wait"},"counts_source":"shots","execution":{"stated_by":"provider","mitigation":"none","twirling":"none","decoupling":"none","remapping":"none","optimisation":"none","verbatim":true,"note":"the reference simulates the program's gates as written, on the qubits named, and corrects nothing"},"counts":{"11":154,"00":146},"distinct_outcomes":2,"omitted_shots":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"simulated","wanted_from":"contract","named":null,"question":"counts","auto":"method:stabilizer","host":{"job_bytes":17179869184,"providers":["ref","priced"]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"auto_rank":20,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is bit-exact, and the job wants simulated"}},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"auto_rank":30,"price":{"money":{"free":true},"time":{"seconds":8e-9,"basis":"nominal"},"memory_bytes":268442722,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"auto_rank":40,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants simulated"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"auto_rank":10,"price":{"money":{"free":true},"time":{"seconds":7.296e-8,"basis":"nominal"},"memory_bytes":67128070,"work":608,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants simulated"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"auto_rank":60,"price":{"money":{"free":true},"time":{"seconds":0.010518528000000001,"basis":"nominal"},"memory_bytes":270532608,"work":7012352,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is heuristic, and the job wants simulated"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"auto_rank":50,"price":{"money":{"free":true},"time":{"seconds":4.05e-7,"basis":"nominal"},"memory_bytes":268435554,"work":2700,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants simulated"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is estimate, and the job wants simulated"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants simulated"}},{"route":"provider:ref","kind":"provider","provider":"ref","class":"simulated","host_dependent":true,"price":{"money":{"free":true},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"chosen"},{"route":"provider:priced","kind":"provider","provider":"priced","class":"simulated","host_dependent":true,"price":{"money":{"free":false,"amount":"0.09","currency":"USD","unit":"shot"},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder","charged"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"rejected","rejected":{"code":"cost_no_ceiling","why":"0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider"}}],"choice":"provider:ref","why":"the cheapest of the 1 of 15 routes that meet the contract","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a","choice":false},"shadow":{"route":"method:exact","class":"bit-exact","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967294,"method":"exact"},"budget_seconds":300.0,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]}},"kept":{}},"shadow":{"ran":true,"route":"method:exact","accuracy":{"class":"bit-exact"},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967294,"method":"exact"},"shots":300,"counts":{"00":151,"11":149},"distinct_outcomes":2,"omitted_shots":0,"distance":{"computed":true,"numerator":10,"denominator":600,"total_variation":0.016666666666666666,"hellinger_fidelity":0.9997221944339458,"sampling_tvd_bound":0.046103716364460375},"elapsed_ms":0},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"f6073ce2965dc9ad90ddd3fcb6cbcbdfc722ebaa30cdf540517ed93b5b394d39","signature":"fd220074ac10f205ffc4d2f99571cccd5e6a839a6409ad746b592f4c3500ee448969df9bc0b7bebf1e3bf43d87511ca8b3d2b61f5060317c31bf6baaf6c1dc0b"}},"id":"pj-a1065ac85f2a95ff","submitted_ms":1793974079068,"finished_ms":1793974079071} +{"status":"done","method":"provider","why":"on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":9007199254740990,"contract":{"exactness":"simulated","providers":"allowed"}},"result":{"method":"provider","qubits":2,"gates":2,"accuracy":{"class":"simulated","note":"counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would"},"shots":300,"provider":{"name":"ref","kind":"process","protocol":"wai.quantum.provider/1","device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","qubits":5,"basis":"rzsxxcz","describe":"0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0"},"calibration":"reference-f2d9fe570421","compiled":{"basis":"rzsxxcz","program":"b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9","hash":"BLAKE3 of the program's OpenQASM 3 text, qasm3","qasm3":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n","native_gates":9,"two_qubit_gates":1,"swaps":0,"layout":[0,1],"final_layout":[0,1],"checked":"the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent","placement":{"chosen":"the compiler's own layout, the fewest swaps: the description states no errors"}},"job":{"id":"ref-1","polls":1},"ideal":{"computed":true,"method":"exact","total_variation_distance":0.013333333333333308,"hellinger_fidelity":0.9998221906060416,"sampling_tvd_expected":0.023032943298089033,"ideal_outcomes":2,"note":"the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent"},"cost":{"free":true,"estimate":{"free":true,"seconds":0.0},"charged":null,"confirmed":false},"energy":{"unmetered":"the work ran at the provider; this host's meter would read only the wait"},"counts_source":"shots","execution":{"stated_by":"provider","mitigation":"none","twirling":"none","decoupling":"none","remapping":"none","optimisation":"none","verbatim":true,"note":"the reference simulates the program's gates as written, on the qubits named, and corrects nothing"},"counts":{"11":154,"00":146},"distinct_outcomes":2,"omitted_shots":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"simulated","wanted_from":"contract","named":null,"question":"counts","auto":"method:stabilizer","host":{"job_bytes":17179869184,"providers":["ref","priced"]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"auto_rank":20,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is bit-exact, and the job wants simulated"}},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"auto_rank":30,"price":{"money":{"free":true},"time":{"seconds":8e-9,"basis":"nominal"},"memory_bytes":268442722,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"auto_rank":40,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants simulated"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"auto_rank":10,"price":{"money":{"free":true},"time":{"seconds":7.296e-8,"basis":"nominal"},"memory_bytes":67128070,"work":608,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants simulated"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"auto_rank":60,"price":{"money":{"free":true},"time":{"seconds":0.010518528000000001,"basis":"nominal"},"memory_bytes":270532608,"work":7012352,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is heuristic, and the job wants simulated"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"auto_rank":50,"price":{"money":{"free":true},"time":{"seconds":4.05e-7,"basis":"nominal"},"memory_bytes":268435554,"work":2700,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants simulated"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is estimate, and the job wants simulated"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants simulated"}},{"route":"provider:ref","kind":"provider","provider":"ref","class":"simulated","host_dependent":true,"price":{"money":{"free":true},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"chosen"},{"route":"provider:priced","kind":"provider","provider":"priced","class":"simulated","host_dependent":true,"price":{"money":{"free":false,"amount":"0.09","currency":"USD","unit":"shot"},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder","charged"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"rejected","rejected":{"code":"cost_no_ceiling","why":"0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider"}}],"choice":"provider:ref","why":"the cheapest of the 1 of 15 routes that meet the contract","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a","choice":false},"shadow":{"route":"method:exact","class":"bit-exact","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967294,"method":"exact"},"budget_seconds":300.0,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]}},"kept":{}},"shadow":{"ran":true,"route":"method:exact","accuracy":{"class":"bit-exact"},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967294,"method":"exact"},"shots":300,"counts":{"00":151,"11":149},"distinct_outcomes":2,"omitted_shots":0,"distance":{"computed":true,"numerator":10,"denominator":600,"total_variation":0.016666666666666666,"hellinger_fidelity":0.9997221944339458,"sampling_tvd_bound":0.046103716364460375},"elapsed_ms":0},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"f6073ce2965dc9ad90ddd3fcb6cbcbdfc722ebaa30cdf540517ed93b5b394d39","signature":"fd220074ac10f205ffc4d2f99571cccd5e6a839a6409ad746b592f4c3500ee448969df9bc0b7bebf1e3bf43d87511ca8b3d2b61f5060317c31bf6baaf6c1dc0b"}},"id":"pj-255b9772ebc3d0cf","submitted_ms":1794033072543,"finished_ms":1794033072546} diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-routed.json b/wai/quantum-conformance/receipts/jobs/cli-contract-routed.json index c01511d25..c0012f747 100644 --- a/wai/quantum-conformance/receipts/jobs/cli-contract-routed.json +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-routed.json @@ -1 +1 @@ -{"status":"done","method":"provider","why":"on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4,"contract":{"exactness":"simulated","providers":"allowed"}},"result":{"method":"provider","qubits":2,"gates":2,"accuracy":{"class":"simulated","note":"counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would"},"shots":300,"provider":{"name":"ref","kind":"process","protocol":"wai.quantum.provider/1","device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","qubits":5,"basis":"rzsxxcz","describe":"0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0"},"calibration":"reference-f2d9fe570421","compiled":{"basis":"rzsxxcz","program":"b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9","hash":"BLAKE3 of the program's OpenQASM 3 text, qasm3","qasm3":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n","native_gates":9,"two_qubit_gates":1,"swaps":0,"layout":[0,1],"final_layout":[0,1],"checked":"the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent","placement":{"chosen":"the compiler's own layout, the fewest swaps: the description states no errors"}},"job":{"id":"ref-1","polls":1},"ideal":{"computed":true,"method":"exact","total_variation_distance":0.03666666666666665,"hellinger_fidelity":0.998653743148044,"sampling_tvd_expected":0.023032943298089033,"ideal_outcomes":2,"note":"the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent"},"cost":{"free":true,"estimate":{"free":true,"seconds":0.0},"charged":null,"confirmed":false},"energy":{"unmetered":"the work ran at the provider; this host's meter would read only the wait"},"counts_source":"shots","execution":{"stated_by":"provider","mitigation":"none","twirling":"none","decoupling":"none","remapping":"none","optimisation":"none","verbatim":true,"note":"the reference simulates the program's gates as written, on the qubits named, and corrects nothing"},"counts":{"11":161,"00":139},"distinct_outcomes":2,"omitted_shots":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"simulated","wanted_from":"contract","named":null,"question":"counts","auto":"method:stabilizer","host":{"job_bytes":17179869184,"providers":["ref","priced"]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"auto_rank":20,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is bit-exact, and the job wants simulated"}},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"auto_rank":30,"price":{"money":{"free":true},"time":{"seconds":8e-9,"basis":"nominal"},"memory_bytes":268442722,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"auto_rank":40,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants simulated"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"auto_rank":10,"price":{"money":{"free":true},"time":{"seconds":7.296e-8,"basis":"nominal"},"memory_bytes":67128070,"work":608,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants simulated"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"auto_rank":60,"price":{"money":{"free":true},"time":{"seconds":0.010518528000000001,"basis":"nominal"},"memory_bytes":270532608,"work":7012352,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is heuristic, and the job wants simulated"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"auto_rank":50,"price":{"money":{"free":true},"time":{"seconds":4.05e-7,"basis":"nominal"},"memory_bytes":268435554,"work":2700,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants simulated"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is estimate, and the job wants simulated"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants simulated"}},{"route":"provider:ref","kind":"provider","provider":"ref","class":"simulated","host_dependent":true,"price":{"money":{"free":true},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"chosen"},{"route":"provider:priced","kind":"provider","provider":"priced","class":"simulated","host_dependent":true,"price":{"money":{"free":false,"amount":"0.09","currency":"USD","unit":"shot"},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder","charged"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"rejected","rejected":{"code":"cost_no_ceiling","why":"0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider"}}],"choice":"provider:ref","why":"the cheapest of the 1 of 15 routes that meet the contract","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a","choice":false},"shadow":{"route":"method:exact","class":"bit-exact","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"budget_seconds":300.0,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]}},"kept":{}},"shadow":{"ran":true,"route":"method:exact","accuracy":{"class":"bit-exact"},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"shots":300,"counts":{"00":161,"11":139},"distinct_outcomes":2,"omitted_shots":0,"distance":{"computed":true,"numerator":44,"denominator":600,"total_variation":0.07333333333333333,"hellinger_fidelity":0.9946222222222221,"sampling_tvd_bound":0.04602751441903442},"elapsed_ms":0},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"71770ed37d2687b9f97392667c58c80a80836d6852619f0498aa1dcfec9e4996","signature":"ffe2160d7de0f0939ebb0146de12a9617976cff8049ab415f5ce85b3964cf66cdc3a3f216926f69820f2b6d9d4ebe0b206442d1e6aac5931bf27d2808671e508"}},"id":"pj-fc95adf1a5d6f2a3","submitted_ms":1793974079041,"finished_ms":1793974079044} +{"status":"done","method":"provider","why":"on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4,"contract":{"exactness":"simulated","providers":"allowed"}},"result":{"method":"provider","qubits":2,"gates":2,"accuracy":{"class":"simulated","note":"counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would"},"shots":300,"provider":{"name":"ref","kind":"process","protocol":"wai.quantum.provider/1","device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","qubits":5,"basis":"rzsxxcz","describe":"0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0"},"calibration":"reference-f2d9fe570421","compiled":{"basis":"rzsxxcz","program":"b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9","hash":"BLAKE3 of the program's OpenQASM 3 text, qasm3","qasm3":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n","native_gates":9,"two_qubit_gates":1,"swaps":0,"layout":[0,1],"final_layout":[0,1],"checked":"the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent","placement":{"chosen":"the compiler's own layout, the fewest swaps: the description states no errors"}},"job":{"id":"ref-1","polls":1},"ideal":{"computed":true,"method":"exact","total_variation_distance":0.03666666666666665,"hellinger_fidelity":0.998653743148044,"sampling_tvd_expected":0.023032943298089033,"ideal_outcomes":2,"note":"the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent"},"cost":{"free":true,"estimate":{"free":true,"seconds":0.0},"charged":null,"confirmed":false},"energy":{"unmetered":"the work ran at the provider; this host's meter would read only the wait"},"counts_source":"shots","execution":{"stated_by":"provider","mitigation":"none","twirling":"none","decoupling":"none","remapping":"none","optimisation":"none","verbatim":true,"note":"the reference simulates the program's gates as written, on the qubits named, and corrects nothing"},"counts":{"11":161,"00":139},"distinct_outcomes":2,"omitted_shots":0,"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"simulated","wanted_from":"contract","named":null,"question":"counts","auto":"method:stabilizer","host":{"job_bytes":17179869184,"providers":["ref","priced"]},"routes":[{"route":"method:exact","kind":"local","method":"exact","class":"bit-exact","host_dependent":false,"auto_rank":20,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is bit-exact, and the job wants simulated"}},{"route":"method:statevector","kind":"local","method":"statevector","class":"exact","host_dependent":false,"auto_rank":30,"price":{"money":{"free":true},"time":{"seconds":8e-9,"basis":"nominal"},"memory_bytes":268442722,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:statevector_single","kind":"local","method":"statevector_single","class":"single","host_dependent":true,"auto_rank":40,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants simulated"}},{"route":"method:stabilizer","kind":"local","method":"stabilizer","class":"exact","host_dependent":false,"auto_rank":10,"price":{"money":{"free":true},"time":{"seconds":7.296e-8,"basis":"nominal"},"memory_bytes":67128070,"work":608,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:pauli","kind":"local","method":"pauli","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants simulated"}},{"route":"method:mps","kind":"local","method":"mps","class":"heuristic","host_dependent":false,"auto_rank":60,"price":{"money":{"free":true},"time":{"seconds":0.010518528000000001,"basis":"nominal"},"memory_bytes":270532608,"work":7012352,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is heuristic, and the job wants simulated"}},{"route":"method:stabilizer_rank","kind":"local","method":"stabilizer_rank","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:tensor_network","kind":"local","method":"tensor_network","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:cutrank","kind":"local","method":"cutrank","class":"exact","host_dependent":false,"auto_rank":50,"price":{"money":{"free":true},"time":{"seconds":4.05e-7,"basis":"nominal"},"memory_bytes":268435554,"work":2700,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:cutrank_single","kind":"local","method":"cutrank_single","class":"single","host_dependent":true,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is single, and the job wants simulated"}},{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is exact, and the job wants simulated"}},{"route":"method:trajectories","kind":"local","method":"trajectories","class":"estimate","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is estimate, and the job wants simulated"}},{"route":"method:pulse","kind":"local","method":"pulse","class":"bounded","host_dependent":false,"auto_rank":null,"price":null,"outcome":"rejected","rejected":{"code":"class","why":"its class is bounded, and the job wants simulated"}},{"route":"provider:ref","kind":"provider","provider":"ref","class":"simulated","host_dependent":true,"price":{"money":{"free":true},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"chosen"},{"route":"provider:priced","kind":"provider","provider":"priced","class":"simulated","host_dependent":true,"price":{"money":{"free":false,"amount":"0.09","currency":"USD","unit":"shot"},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder","charged"],"program":{"shots":300,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"rejected","rejected":{"code":"cost_no_ceiling","why":"0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider"}}],"choice":"provider:ref","why":"the cheapest of the 1 of 15 routes that meet the contract","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:exact","method:statevector","method:stabilizer","method:pauli","method:mps","method:stabilizer_rank","method:tensor_network","method:cutrank","method:density_matrix","method:trajectories","method:pulse"],"digest":"e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a","choice":false},"shadow":{"route":"method:exact","class":"bit-exact","request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"budget_seconds":300.0,"price":{"money":{"free":true},"time":{"seconds":4e-8,"basis":"nominal"},"memory_bytes":134217920,"work":8,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]}},"kept":{}},"shadow":{"ran":true,"route":"method:exact","accuracy":{"class":"bit-exact"},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":300,"seed":4294967300,"method":"exact"},"shots":300,"counts":{"00":161,"11":139},"distinct_outcomes":2,"omitted_shots":0,"distance":{"computed":true,"numerator":44,"denominator":600,"total_variation":0.07333333333333333,"hellinger_fidelity":0.9946222222222221,"sampling_tvd_bound":0.04602751441903442},"elapsed_ms":0},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"71770ed37d2687b9f97392667c58c80a80836d6852619f0498aa1dcfec9e4996","signature":"ffe2160d7de0f0939ebb0146de12a9617976cff8049ab415f5ce85b3964cf66cdc3a3f216926f69820f2b6d9d4ebe0b206442d1e6aac5931bf27d2808671e508"}},"id":"pj-6059aefb7ace70bc","submitted_ms":1794033072508,"finished_ms":1794033072511} diff --git a/wai/quantum-conformance/receipts/jobs/cli-contract-target.json b/wai/quantum-conformance/receipts/jobs/cli-contract-target.json index dce1cb2c3..2256afece 100644 --- a/wai/quantum-conformance/receipts/jobs/cli-contract-target.json +++ b/wai/quantum-conformance/receipts/jobs/cli-contract-target.json @@ -1 +1 @@ -{"status":"done","method":"density_matrix","why":"density matrix of the 2 physical qubits the program touches, each gate and channel one superoperator pass, under the noise of the target synthetic-line-5 (calibration content:0b152c6f06102941): the program compiled to rzsxxcz on physical qubits [3, 4], 0 swaps, expected success 0.9563; each gate costed as the target's own, equal up to one-qubit gates; the route the job names, which meets its contract (1 of 3 routes)","estimate":{"memory_bytes":268435720,"work":400},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":50,"seed":2,"contract":{"deadline_seconds":60.0,"providers":"allowed"},"target":"synthetic-line-5"},"result":{"method":"density_matrix","qubits":2,"gates":2,"accuracy":{"class":"exact","note":"the noisy state under the target's noise model, exactly: a model of the device from its calibration snapshot: each gate's reported error as depolarising noise beside the amplitude damping and dephasing its T1, T2 and duration give, idling relaxed the same way, and each qubit's readout by its assignment errors; Markovian and gate-local, so crosstalk, leakage, coherent over-rotation and drift are not modelled; counts are seeded samples of its distribution, each bit misread by its qubit's assignment errors; expectation values are of the state before the measurement, with no readout error"},"counts":{"00":26,"11":22,"01":2},"distinct_outcomes":3,"omitted_shots":0,"ideal":{"computed":true,"total_variation_distance":0.03964591211886446,"hellinger_fidelity":0.960218501561203,"note":"the noisy distribution over the classical bits, exactly, against the circuit's ideal one by the bit-exact state vector: how far the target's noise moves the answer"},"target":{"name":"synthetic-line-5","hash":"a618b0e1c671834a0a8967524b4a7018752f50e3c11d98c1c49a687806e81701","hash_is":"BLAKE3 of the target document's RFC 8785 text","calibration":{"id":"content:0b152c6f06102941","timestamp":"2026-10-01T09:00:00+00:00"},"source":{"format":"device-properties","note":"synthetic: written for wai-quantum in the shape of the device-properties format, its numbers made up; no device's data"},"placement":{"basis":"rzsxxcz","exact":false,"layout":[3,4],"final_layout":[3,4],"swaps":0,"native_gates":9,"two_qubit_gates":1,"expected_success":0.9563103156162862,"fewest_swaps":{"layout":[0,1],"swaps":0,"expected_success":0.9491455074213893},"layouts_compared":8,"chosen":"noise-aware: of 8 layouts and their routes, the highest expected success (0.956310, against 0.949146 for the fewest swaps)","expected_success_is":"the product of each gate's success (one less its reported error, or where none is reported its relaxation over its duration) and each measured qubit's readout success (one less the mean of its assignment errors); idling is in the noise model, not in this figure","checked":"the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator","notes":["the target's gates do not hold one of the compiler's sets, so the program is compiled to rz sx x cz and each gate costed as the target's (cz as cx): the same up to one-qubit gates, which are not counted; a simulation of the device, not a program it runs as it is"]},"noise":{"model":"a model of the device from its calibration snapshot: each gate's reported error as depolarising noise beside the amplitude damping and dephasing its T1, T2 and duration give, idling relaxed the same way, and each qubit's readout by its assignment errors; Markovian and gate-local, so crosstalk, leakage, coherent over-rotation and drift are not modelled","simulated_qubits":[3,4],"duration_ns":491.0,"idle_ns":35.5,"channels":16,"one_qubit_depolarizing":{"gates":8,"mean":0.000025084801525975534},"two_qubit_depolarizing":{"gates":1,"mean":0.0029999418028110424},"readout":[{"logical":0,"physical":3,"p01":0.006877,"p10":0.03886},{"logical":1,"physical":4,"p01":0.007857,"p10":0.01804}],"notes":[]}},"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"exact","wanted_from":"named","named":"method:density_matrix","question":"counts","auto":null,"host":{"job_bytes":17179869184,"providers":["ref","priced"]},"routes":[{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":{"money":{"free":true},"time":{"seconds":7.2e-8,"basis":"nominal"},"memory_bytes":268435720,"work":400,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"chosen"},{"route":"provider:ref","kind":"provider","provider":"ref","class":"simulated","host_dependent":true,"price":{"money":{"free":true},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder"],"program":{"shots":50,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}},{"route":"provider:priced","kind":"provider","provider":"priced","class":"simulated","host_dependent":true,"price":{"money":{"free":false,"amount":"0.015","currency":"USD","unit":"shot"},"time":{"seconds":0.0,"basis":"provider"},"memory_bytes":null,"work":null,"energy":{"joules":null,"why":"no provider states a job's energy before it runs"},"leaves_out":["energy","mitigation","decoder","charged"],"program":{"shots":50,"native_gates":9,"two_qubit_gates":1,"swaps":0}},"device":"reference:line-5","provenance":"simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given","outcome":"rejected","rejected":{"code":"not_named","why":"the job names another route"}}],"choice":"method:density_matrix","why":"the route the job names, which meets its contract (1 of 3 routes)","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:density_matrix"],"digest":"16b4bfb6541720b9990c891168f637b933f09ef1134cd0bfb5165ac5d248a7e3","choice":false},"kept":{"deadline":{"seconds":60.0,"elapsed_ms":null,"kept":null}}},"energy":{"unmetered":"the command line does not meter a run's energy"},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"c60b7c322fcc2ceb37334ff4a9f4c4201bf03bb98349918e7d3cf47d097948a9","signature":"0a06f15970af18dc74d92d35d1fb7c30b956e65669f8a42a2b451c4072841afff2eaa427b322454d94c1b8fdb9b23183bb97f5bc7e17bbba34d24f54a702260f"}}} +{"status":"done","method":"density_matrix","why":"density matrix of the 2 physical qubits the program touches, each gate and channel one superoperator pass, under the noise of the target synthetic-line-5 (calibration content:0b152c6f06102941): the program compiled to rzsxxcz on physical qubits [3, 4], 0 swaps, expected success 0.9563; each gate costed as the target's own, equal up to one-qubit gates; the route the job names, which meets its contract (1 of 1 routes)","estimate":{"memory_bytes":268435720,"work":400},"request":{"qasm":"OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n","shots":50,"seed":2,"contract":{"deadline_seconds":60.0,"providers":"allowed"},"target":"synthetic-line-5"},"result":{"method":"density_matrix","qubits":2,"gates":2,"accuracy":{"class":"exact","note":"the noisy state under the target's noise model, exactly: a model of the device from its calibration snapshot: each gate's reported error as depolarising noise beside the amplitude damping and dephasing its T1, T2 and duration give, idling relaxed the same way, and each qubit's readout by its assignment errors; Markovian and gate-local, so crosstalk, leakage, coherent over-rotation and drift are not modelled; counts are seeded samples of its distribution, each bit misread by its qubit's assignment errors; expectation values are of the state before the measurement, with no readout error"},"counts":{"00":26,"11":22,"01":2},"distinct_outcomes":3,"omitted_shots":0,"ideal":{"computed":true,"total_variation_distance":0.03964591211886446,"hellinger_fidelity":0.960218501561203,"note":"the noisy distribution over the classical bits, exactly, against the circuit's ideal one by the bit-exact state vector: how far the target's noise moves the answer"},"target":{"name":"synthetic-line-5","hash":"a618b0e1c671834a0a8967524b4a7018752f50e3c11d98c1c49a687806e81701","hash_is":"BLAKE3 of the target document's RFC 8785 text","calibration":{"id":"content:0b152c6f06102941","timestamp":"2026-10-01T09:00:00+00:00"},"source":{"format":"device-properties","note":"synthetic: written for wai-quantum in the shape of the device-properties format, its numbers made up; no device's data"},"placement":{"basis":"rzsxxcz","exact":false,"layout":[3,4],"final_layout":[3,4],"swaps":0,"native_gates":9,"two_qubit_gates":1,"expected_success":0.9563103156162862,"fewest_swaps":{"layout":[0,1],"swaps":0,"expected_success":0.9491455074213893},"layouts_compared":8,"chosen":"noise-aware: of 8 layouts and their routes, the highest expected success (0.956310, against 0.949146 for the fewest swaps)","expected_success_is":"the product of each gate's success (one less its reported error, or where none is reported its relaxation over its duration) and each measured qubit's readout success (one less the mean of its assignment errors); idling is in the noise model, not in this figure","checked":"the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator","notes":["the target's gates do not hold one of the compiler's sets, so the program is compiled to rz sx x cz and each gate costed as the target's (cz as cx): the same up to one-qubit gates, which are not counted; a simulation of the device, not a program it runs as it is"]},"noise":{"model":"a model of the device from its calibration snapshot: each gate's reported error as depolarising noise beside the amplitude damping and dephasing its T1, T2 and duration give, idling relaxed the same way, and each qubit's readout by its assignment errors; Markovian and gate-local, so crosstalk, leakage, coherent over-rotation and drift are not modelled","simulated_qubits":[3,4],"duration_ns":491.0,"idle_ns":35.5,"channels":16,"one_qubit_depolarizing":{"gates":8,"mean":0.000025084801525975534},"two_qubit_depolarizing":{"gates":1,"mean":0.0029999418028110424},"readout":[{"logical":0,"physical":3,"p01":0.006877,"p10":0.03886},{"logical":1,"physical":4,"p01":0.007857,"p10":0.01804}],"notes":[]}},"engine":{"name":"wai-quantum","version":"0.8.1"},"schema":"wai.quantum.job-result/1","planner":{"format":"wai.quantum.planner/1","wanted":"exact","wanted_from":"named","named":"method:density_matrix","question":"counts","auto":null,"host":{"job_bytes":17179869184,"providers":[]},"routes":[{"route":"method:density_matrix","kind":"local","method":"density_matrix","class":"exact","host_dependent":false,"auto_rank":null,"price":{"money":{"free":true},"time":{"seconds":7.2e-8,"basis":"nominal"},"memory_bytes":268435720,"work":400,"energy":{"joules":null,"why":"this host estimates no job's energy before it runs"},"leaves_out":[]},"outcome":"chosen"}],"choice":"method:density_matrix","why":"the route the job names, which meets its contract (1 of 1 routes)","stable":{"scope":"digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host","routes":["method:density_matrix"],"digest":"16b4bfb6541720b9990c891168f637b933f09ef1134cd0bfb5165ac5d248a7e3","choice":false},"kept":{"deadline":{"seconds":60.0,"elapsed_ms":1,"kept":true}}},"energy":{"unmetered":"the command line does not meter a run's energy"},"receipt":{"alg":"ed25519","canon":"rfc8785","key":"197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61","digest":"756e787363f6c18d3392c97f574846e8d5ec9642cb5eade81f698068fa650d9a","signature":"03bfebaee776044398a164427e01924ded2bce9c4ae4bf5dbad6e408b02e49564e7017f6beaf5b5b42e8655825b2306942fc448b4ea0b8e902b0580848761405"}}} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-approximate-rejected.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-approximate-rejected.json index 51e2627ea..529aadf79 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-approximate-rejected.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-approximate-rejected.json @@ -539,7 +539,7 @@ "signature": "741787b0d0037eb20eb5d2de281be60608910d2cc4eb00900e9c0d82409a2f8f6e55813115d9c9d4259054c1dfceb00f82f3dbe74f24d1fc1573ef6ab687b306" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-claimed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-claimed.json index f65050724..3186c745f 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-claimed.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-claimed.json @@ -169,7 +169,7 @@ "route": "method:stabilizer", "kind": "local", "method": "stabilizer", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": 10, "price": null, @@ -211,7 +211,7 @@ "route": "method:stabilizer_rank", "kind": "local", "method": "stabilizer_rank", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": null, "price": null, @@ -364,7 +364,7 @@ "method:trajectories", "method:pulse" ], - "digest": "b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c", + "digest": "42dab8b20f638eeb9c1d46fd7a0890b574c641a1e11d1306da2abc201ca84c5f", "choice": false }, "shadow": { @@ -441,11 +441,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "ab05e414c2fa45db84b6453b3feccfa2c7b24610b8f57d34ce9dfba33140f8a7", - "signature": "18a71d01d8ab530809628fad41835300c1167c9dc2a0659a0464753e96a8567499ddcc7df83825bbaa9cd51117738dc787d8d37209daf2061dca99ac7ec19406" + "digest": "4b2da8950e2e4033a403221c00b50ef935350c51e7f78b3857ec0bf85e4ed274", + "signature": "66c587831dc4ceabf0b3bf30dcba86c89412f88bd0b649d79e9c3eb4037272d01139b82b99c307d39412e7f1868e1df520791e4312d442e7ceda639ba5ce850b" } }, - "id": "pj-316b154641049d91", - "submitted_ms": 1793974079084, - "finished_ms": 1793974079087 + "id": "pj-e158396f1fd8f81d", + "submitted_ms": 1794033072602, + "finished_ms": 1794033072605 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-false.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-false.json index 31adc08d8..7c13456c7 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-false.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-at-least-false.json @@ -539,7 +539,7 @@ "signature": "a865c48455b9443faec53460fa8e38f4bebae7b2d868fbf71c37beba7fc90a75ab31a24c4330d8c52e775c960595ce666c07e14d368db1b6ee326cf4fbc9a60d" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over-stated.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over-stated.json index 1274c825c..199616ac8 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over-stated.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over-stated.json @@ -169,7 +169,7 @@ "route": "method:stabilizer", "kind": "local", "method": "stabilizer", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": 10, "price": null, @@ -211,7 +211,7 @@ "route": "method:stabilizer_rank", "kind": "local", "method": "stabilizer_rank", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": null, "price": null, @@ -363,7 +363,7 @@ "method:trajectories", "method:pulse" ], - "digest": "b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c", + "digest": "42dab8b20f638eeb9c1d46fd7a0890b574c641a1e11d1306da2abc201ca84c5f", "choice": false }, "shadow": { @@ -440,11 +440,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "7b8b89db3f1d38f4f14aa0e6a2a03a39cfc304edfc54dc099cb17196aaf797e8", - "signature": "6769f018dd440126a7fa92a6e7d43de59a42682f47e6d019122a763ae11e51a21a0b0ed4e15b7269aaab2993669eee95a2ba95624890799b058f55155e34360a" + "digest": "49804035ae6d80eef4306d45aa936976c2dfc4f466d75ed7ac01d4b3048e22c0", + "signature": "d65f8d157543b5f5fc506f96b9aea9cc1134e43d4248d8e2091a8df92c2227c6a30e85ff73dc9a2e08b97a90aa03cebc94dfb60c5ed568813bff22ddacc33700" } }, - "id": "pj-316b154641049d91", - "submitted_ms": 1793974079084, - "finished_ms": 1793974079087 + "id": "pj-e158396f1fd8f81d", + "submitted_ms": 1794033072602, + "finished_ms": 1794033072605 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over.json index 04c0e1d1a..e9690bad2 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-charged-over.json @@ -169,7 +169,7 @@ "route": "method:stabilizer", "kind": "local", "method": "stabilizer", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": 10, "price": null, @@ -211,7 +211,7 @@ "route": "method:stabilizer_rank", "kind": "local", "method": "stabilizer_rank", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": null, "price": null, @@ -363,7 +363,7 @@ "method:trajectories", "method:pulse" ], - "digest": "b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c", + "digest": "42dab8b20f638eeb9c1d46fd7a0890b574c641a1e11d1306da2abc201ca84c5f", "choice": false }, "shadow": { @@ -440,11 +440,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "65352c64f82ab8d8d16ef9577d758e1deb10263b52b981e82bce6255e9e95361", - "signature": "279b28b8720ddecb7986316a970ee8b50ff3cd581e99755204b3e1ff985d6f5d3a995264c9921a1e82eece6d61c562c0f5c5633919ec3ba3bccc10019fd90f06" + "digest": "330b81d67073190de3693ade958c3facf8d27315ed3a94045113681aca7166f2", + "signature": "8df3472930b69fe0b157fbff36c648aa3c70a6324b5e3295ab2a1af2c563367cf2924b8d6eee354cf1e8409f1ba269c974af1bb6ae9042f3b346569706085402" } }, - "id": "pj-316b154641049d91", - "submitted_ms": 1793974079084, - "finished_ms": 1793974079087 + "id": "pj-e158396f1fd8f81d", + "submitted_ms": 1794033072602, + "finished_ms": 1794033072605 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-currency-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-currency-other.json index 4f40cd605..5cc8d5141 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-currency-other.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-currency-other.json @@ -169,7 +169,7 @@ "route": "method:stabilizer", "kind": "local", "method": "stabilizer", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": 10, "price": null, @@ -211,7 +211,7 @@ "route": "method:stabilizer_rank", "kind": "local", "method": "stabilizer_rank", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": null, "price": null, @@ -363,7 +363,7 @@ "method:trajectories", "method:pulse" ], - "digest": "b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c", + "digest": "42dab8b20f638eeb9c1d46fd7a0890b574c641a1e11d1306da2abc201ca84c5f", "choice": false }, "shadow": { @@ -440,11 +440,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "570d84bcf61e55b373c25a03553030a89db2c0ef10d74743b6b4cd98ab5559ee", - "signature": "28778cfcd50fa78ac54c2ad944d0e1d2074fc2f906b0e6014177ea8c64ace8bd860c7d334bc9c3978c8f270ca6f1e0223713004d3c79a6abc675bec4e8c81104" + "digest": "6addfa40b6f4b7c0a2e9138143e62fcfc82e8c1dbc696e279b615c1978936c63", + "signature": "3d7c4c8bf556f0a0cd5449e2f8c440931f98cb6dec1b65932349ff78985e6af65c6992fa971f331ed9550fb4d5cb6cb114c29a9d0ddf203839b37bd05484f206" } }, - "id": "pj-316b154641049d91", - "submitted_ms": 1793974079084, - "finished_ms": 1793974079087 + "id": "pj-e158396f1fd8f81d", + "submitted_ms": 1794033072602, + "finished_ms": 1794033072605 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-host-providers-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-host-providers-other.json new file mode 100644 index 000000000..f39352881 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-host-providers-other.json @@ -0,0 +1,543 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "someone-else" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "72207a76a4132c47fc16379ad71ae19b1a0330d56af0f444f191398a3643463b", + "signature": "b4e5821cbbb4bbe9ac08a2db61fdd4be892dc0331ced5e9c7a70588843541ec83f042c86b774a26bc2526caa3478d1ce33fc3a7a2522eab1d6c4a6adb0fa1509" + } + }, + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-charged-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-charged-other.json index 37ba96367..7f2e8d74f 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-charged-other.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-kept-charged-other.json @@ -169,7 +169,7 @@ "route": "method:stabilizer", "kind": "local", "method": "stabilizer", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": 10, "price": null, @@ -211,7 +211,7 @@ "route": "method:stabilizer_rank", "kind": "local", "method": "stabilizer_rank", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": null, "price": null, @@ -363,7 +363,7 @@ "method:trajectories", "method:pulse" ], - "digest": "b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c", + "digest": "42dab8b20f638eeb9c1d46fd7a0890b574c641a1e11d1306da2abc201ca84c5f", "choice": false }, "shadow": { @@ -440,11 +440,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "a65a7bb80c70d8f076174784661aba1646195d01130a38b958103a42222fa6d4", - "signature": "d03e8cf20060933bfa4c30e867a68e46f093723ec66e91f4f266a7db2273e7d38acc12664d7796400071ab1d9c22ce819a428ce4b0381745dad53fe661557f0a" + "digest": "ddaad12efd8d7b2a16a3dcaccec8d005a0187fbea011b5f4e3cb18cbd7b1a4ed", + "signature": "da9df33d567d113fdcd20c619604f9b6dee438d51e9baea100e4a0031966eaa0691b7f1a5967e1809bfac71f9c2e08933f90c8478c7cffccb8012676bb469804" } }, - "id": "pj-316b154641049d91", - "submitted_ms": 1793974079084, - "finished_ms": 1793974079087 + "id": "pj-e158396f1fd8f81d", + "submitted_ms": 1794033072602, + "finished_ms": 1794033072605 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-named-approximate.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-named-approximate.json index d6dcefa3a..85ed9e853 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-named-approximate.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-named-approximate.json @@ -169,7 +169,7 @@ "route": "method:stabilizer", "kind": "local", "method": "stabilizer", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": 10, "price": null, @@ -211,7 +211,7 @@ "route": "method:stabilizer_rank", "kind": "local", "method": "stabilizer_rank", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": null, "price": null, @@ -364,7 +364,7 @@ "method:trajectories", "method:pulse" ], - "digest": "b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c", + "digest": "42dab8b20f638eeb9c1d46fd7a0890b574c641a1e11d1306da2abc201ca84c5f", "choice": false }, "shadow": { @@ -441,11 +441,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "6e3aaf31d04fd5ebc52dd524cf1608fb19d52269ee86927a4c79a774d4955a1d", - "signature": "761cd9075407a576ed11f3df402dbf209069f9e582f5b7b9af0dc71f8cf4674a3704ebc52e49de44d4945da7fb6d40cbd1f4dc270266bb1d722c43904f548906" + "digest": "3c033b370d47efec1066305384cdef56dabb468c32f0700450fc29cdb585e5f3", + "signature": "a2b107e198584b95e29622573061090d1597246ade1eaaa71dae6cfab0814a7ee37c6db1dbaedfd0462806b0d09297d361db7aa842b728dc24abc4be99d5180b" } }, - "id": "pj-316b154641049d91", - "submitted_ms": 1793974079084, - "finished_ms": 1793974079087 + "id": "pj-e158396f1fd8f81d", + "submitted_ms": 1794033072602, + "finished_ms": 1794033072605 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-named-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-named-other.json index 376c6bdd1..352b29c79 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-named-other.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-named-other.json @@ -169,7 +169,7 @@ "route": "method:stabilizer", "kind": "local", "method": "stabilizer", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": 10, "price": null, @@ -211,7 +211,7 @@ "route": "method:stabilizer_rank", "kind": "local", "method": "stabilizer_rank", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": null, "price": null, @@ -363,7 +363,7 @@ "method:trajectories", "method:pulse" ], - "digest": "b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c", + "digest": "42dab8b20f638eeb9c1d46fd7a0890b574c641a1e11d1306da2abc201ca84c5f", "choice": false }, "shadow": { @@ -440,11 +440,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "8d8b450392d362b8e348c741bb39b5780b1dfd8f5ca56737f47e7c36870a022f", - "signature": "0696feb2aadf21e318ef609eda4933b30d90696023f184ca07f7c73dce021ca61d1394aec758f1514afddf464b03e18252d55754998c6bb964ae5cdf34d2220a" + "digest": "16dee06551ccdd2d87094719105185f33e94bce3ae2314bcdbb3027cc52b927d", + "signature": "b951de24191d26a16f04fd37e5d792da1bcfdb4b8b310639da7fda86a2c74723fcf357b9ab5b794e38e00091a0297bf0eadedb97bdd7ec0f1ee6d9a2cc728205" } }, - "id": "pj-316b154641049d91", - "submitted_ms": 1793974079084, - "finished_ms": 1793974079087 + "id": "pj-e158396f1fd8f81d", + "submitted_ms": 1794033072602, + "finished_ms": 1794033072605 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-price-amount-long.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-price-amount-long.json index 8222de6cd..9686ceb83 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-price-amount-long.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-price-amount-long.json @@ -538,7 +538,7 @@ "signature": "0f1b72780bfcaf25fa169581b8a4c634d288e17f76e86ee7bbcc368476d53afd8f2b115cd8ae6f3d32321454d1ce52ddfaca6b050328aa6f41a851b93fad0c0e" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-price-memory-null.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-price-memory-null.json new file mode 100644 index 000000000..c4da63d49 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-price-memory-null.json @@ -0,0 +1,343 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": null, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "2c019f7c04589a39b9fec2a6d2528df7d6377d8f3282448efaeb3475d02a4447", + "signature": "79eb96edfdd5c7650d3bc45a0b7eae317df7eec141d1bff9f7bc280a14cdd2e989db9b7ff2ed70e4762859cc0214cb02f8d9bde2689a8571ef27b6e783af6e0c" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-price-provider-memory.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-price-provider-memory.json new file mode 100644 index 000000000..24072251b --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-price-provider-memory.json @@ -0,0 +1,544 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": 1024, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "f618c6f0098c2d65dcbc8084b0a00c93cfa21b06f4e3a882b353dede692c80ef", + "signature": "4e1aaa87fdda1240b3d411b433a2fcc1515dfef24c27748804911947898ac7f2aa0377f388bef416074fe79ae8b85cdb5c9a5e92a98af32ae6ed7feeee12cd02" + } + }, + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-price-seconds-past.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-price-seconds-past.json index b38dbd4b1..9d630170f 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-price-seconds-past.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-price-seconds-past.json @@ -538,7 +538,7 @@ "signature": "30b1568f0f5e9579053b2ebf4d97f278300625d612a10e4487c5b1f8770a0599eb8729589eda4a3bf4596859f985683e7c6ffd6382f5c8c62ebea1fcde6dcd08" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-named-not-allowed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-named-not-allowed.json index 5b1ca67dd..92c6d18c1 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-named-not-allowed.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-named-not-allowed.json @@ -168,7 +168,7 @@ "route": "method:stabilizer", "kind": "local", "method": "stabilizer", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": 10, "price": null, @@ -210,7 +210,7 @@ "route": "method:stabilizer_rank", "kind": "local", "method": "stabilizer_rank", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": null, "price": null, @@ -362,7 +362,7 @@ "method:trajectories", "method:pulse" ], - "digest": "b950b266962b726a77c20b591ee5b4910615dbce2755f1e22334ef9d81c5698c", + "digest": "42dab8b20f638eeb9c1d46fd7a0890b574c641a1e11d1306da2abc201ca84c5f", "choice": false }, "shadow": { @@ -439,11 +439,11 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "238ae4cd6d408880508a6c0083dae60bb35337226437ab6d389b092b78ff54da", - "signature": "7e209f3646e47be62fafba59a38625316775d78d65e4dc4ae750ef9d190525ec00b1205772713d0625227876e0b55c0ac230b7105bc6169d55667373ad04b201" + "digest": "5457b269284d4b4d29885508227abccfb634705b295c810d473c7aab923e3a24", + "signature": "c0d647ee7137bc594eaa005c6f206da08b24b5449aa0945670447ed5e1d1f35982b11906c483bcad3bdb2e7d8637617c622d373e81c5882500e5071a6d39a20f" } }, - "id": "pj-316b154641049d91", - "submitted_ms": 1793974079084, - "finished_ms": 1793974079087 + "id": "pj-e158396f1fd8f81d", + "submitted_ms": 1794033072602, + "finished_ms": 1794033072605 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-not-chosen.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-not-chosen.json index c5da8f44d..d8d399ab6 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-not-chosen.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-provider-not-chosen.json @@ -538,7 +538,7 @@ "signature": "26c1542acd6cb9632be2a885b34be090840761a8658df4965ea73bff805ad5af76487485445be454c365ce564af2ded296a1f3e70ac01f0e195794e8f739f701" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-providers-not-allowed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-providers-not-allowed.json index 86c2c50c9..df8f4e1ae 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-providers-not-allowed.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-providers-not-allowed.json @@ -537,7 +537,7 @@ "signature": "82af7c4478995abef9e4f12222f81b956c90a45a666a9b4168d11187fc22158a24d7a52eeccf2e6021e3f50c1c16e00210ed03d7d44297924dad2b0bf427600e" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-result-class-foreign.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-result-class-foreign.json new file mode 100644 index 000000000..2260ec379 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-result-class-foreign.json @@ -0,0 +1,343 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "bit-exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "de187e27decaf890ba2e96ac57bc908087f76bd4917fb6ce7e5cfbbbf453addd", + "signature": "abf8ec3aea805b1e7e7e72d51a00456b9a57a1a9d18656f8f4ec1ebf521a2a54d0e7f42699aa0445e361c4782ee50dd138d5b787129b2c08dc4969870a30760c" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-class-by-job.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-class-by-job.json new file mode 100644 index 000000000..97f9872f3 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-class-by-job.json @@ -0,0 +1,544 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "estimate", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "b8c7e82812f75a33dcb1bce744afca76b17b326ee25f94bd142713d554f42c36", + "signature": "f21b33c936bf314d82630512231f6a287ff8fc48a8736ac1b8caa065e05e354eb8a82f12e0850c480f8575a0c547b176896f50aa3e24713f49e1e17b9d514a0c" + } + }, + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-class-gpu.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-class-gpu.json new file mode 100644 index 000000000..c7dda034d --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-class-gpu.json @@ -0,0 +1,343 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "exact", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "f59a50c43a5bbe79f98a8eb2b6316a7659789c464a41cfb86898be3338427607", + "signature": "9a93e7ac6f88d85a2b5e3f8a08b1f99d5e0ea89f6116950085dc91e6cc90ca37ed5d07c8d40527640ea511aae01816bc213218b4797100c1b0fcf070ae6d4906" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-host-dependent.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-host-dependent.json new file mode 100644 index 000000000..9b70408f8 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-host-dependent.json @@ -0,0 +1,343 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "2aaa878a1cd4478d73c11ba5a924cf8224bf3f0903e558b7f87f5bf5a24d17cd", + "signature": "7f67e87bc54c328cdc4318be9b8c037fd8cf93ee273aec9f7349ba9699af6e330d23f6c907ec48616c15f3a2e89dbfa787a585f25bbdf2a4c718a6d2452ad703" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provider-claimed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provider-claimed.json index 5146700d4..5c3423960 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provider-claimed.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provider-claimed.json @@ -534,7 +534,7 @@ "signature": "b0979f55f6410a2557aaacc4cd7fec407311861d761e04f6679030d759be8504252f09747c3e0b430082bdab044e79aad443d3b48fc336d6ea25fb5fa25b6c00" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provider-host-independent.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provider-host-independent.json new file mode 100644 index 000000000..0954318cb --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provider-host-independent.json @@ -0,0 +1,544 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": false, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "0f80f41049e7d36fe2eb45823e6715c3a2411ccafdc09c9f90aca759302ae08a", + "signature": "7dd34bf8f72237c6185bc80cd66cc7b14ccc8e31c8e95b9af30b682e4d8ed293601439268305c7b639e616cd53d1bcb40bfdbcacf059dbae596720f6c2abda07" + } + }, + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-bound-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-bound-other.json index ab13d4430..6a68bac8c 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-bound-other.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-bound-other.json @@ -538,7 +538,7 @@ "signature": "411241bb7b7dcda3797437f02a7b4386954e306b33b3a1ffda7da183d3bd8a4ac6af2b8cd72409d3629d076af9ee6e8a2d4186431b61a845957ff3f109e93a06" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-class-foreign.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-class-foreign.json new file mode 100644 index 000000000..b9eba23fd --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-class-foreign.json @@ -0,0 +1,544 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:mps", + "class": "heuristic", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "mps" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:mps", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "mps" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "e278bbdf50e8c8f202aaeab7db2dc1e8b0ed5e203d3359f86deda7b2962bdf4a", + "signature": "c3c16c5544d85e3b23f82cfb69b0df552c581dc06327c82b89658c13c74e7c72388a01cf7590a56c690ad57fabde599ed95ced04c02666f12363d0640b79d707" + } + }, + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-fraction.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-fraction.json index e54d29b8d..2a34ffd9c 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-fraction.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-fraction.json @@ -538,7 +538,7 @@ "signature": "121390ef6e78d718c930f8d2ddc0ade35e88f90de72b3e904b9ec74ff6af39118c2fedaf46568daa3ab8435cba12cbb11b22920f55e207792bc44d8ee3166e0a" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-short.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-short.json index ad5443ad0..4c7cc63ad 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-short.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-short.json @@ -534,7 +534,7 @@ "signature": "61523dd3b3a93da79bca41d411e494e280293f3b73d3b12862a8d7dab30b0af19419128a10af408513e9f0925455a281de94215357b1bb19c3dcc8b1fd9fbf01" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-sum.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-sum.json index f654dbd8c..897684c63 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-sum.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-count-sum.json @@ -538,7 +538,7 @@ "signature": "769872dc617089401cd5e5610b1f84548ae8db33a1078edc93e9ecce88dbdba31c7214a7230be6d2e3e7c04379ab2602ba93f9b0d3343ff8582f69f9866f3405" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-distinct.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-distinct.json new file mode 100644 index 000000000..937931bcd --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-distinct.json @@ -0,0 +1,544 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 7, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "719bc67c37b909860b07d9c2fed9ff228906a3d89775ce53544302ebfb455d85", + "signature": "10ed44e40b3b5c69e2427cc73b77b1065b4dbda9f46afa740972e2aac63f99191355ac7e1613f27334881f69fd5530fffb14cc5ee562eea7bc53d80555a96a0d" + } + }, + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-missing.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-missing.json index a4b096f65..6a558f548 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-missing.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-missing.json @@ -509,7 +509,7 @@ "signature": "51c78059c14776ec04d14e98349c8155e33b304bdf747cf023211c8abcaf206bb89a963eee1369e13b0f250570d951f0337562636dc4b39178513ec001ba580f" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-not-computed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-not-computed.json index b3355c23f..f7bab7c99 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-not-computed.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-not-computed.json @@ -534,7 +534,7 @@ "signature": "f71eed95f50de214b1ee6daa2166d2fe0eef384b54f12dea260d7e2c20e3f41214c2a76577c5cb0259a6215149ec3b13d5eeac57ec610e4cd160f480953e8708" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-numerator.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-numerator.json index 376180000..895425b57 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-numerator.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-numerator.json @@ -538,7 +538,7 @@ "signature": "7a243c18b9d1f35053dbeb1ecda4449eabbdc828cf9e413df572544439ed2c4d411b6fb5b3790fad9a97ef181ad561c421438c09a20cd52174b705d294841606" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-omitted-spelt.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-omitted-spelt.json index b2026ea76..dd20f20d4 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-omitted-spelt.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-omitted-spelt.json @@ -538,7 +538,7 @@ "signature": "ffe2160d7de0f0939ebb0146de12a9617976cff8049ab415f5ce85b3964cf66cdc3a3f216926f69820f2b6d9d4ebe0b206442d1e6aac5931bf27d2808671e508" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-budget.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-budget.json index df4cd21d9..b92a16783 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-budget.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-budget.json @@ -538,7 +538,7 @@ "signature": "2fa03a7fb3a161d62528cf23938b754ff608314ddbbf2467e0c3c35ef17b79a1f54814e2b55f147f67b111b335739207b2b9f70fc066ceaa7206d8a7f862560c" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-class.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-class.json index 90ec91c9b..b4640b24b 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-class.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-class.json @@ -538,7 +538,7 @@ "signature": "ee2d077e5bc1cb4d5a6aea31a46f35aafcdcdb5e1f5163afab7bab014dc48a5c3500f098abec81f51ecf5a785e35f8cac241eef8a45f7880deaf23d469ff760d" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-code.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-code.json index 03b2e6c41..459f7cea7 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-code.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-code.json @@ -492,7 +492,7 @@ "signature": "7b5228b3e105f8ed38f98a9d1412d64bfef5d99a6755113ca387204ab6c7f17767745240a3a6c427cc72d633106681481b7ad1b81277f8b9f7f614156d41440a" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-missing.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-missing.json index 84477101a..5dd38a3d4 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-missing.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-missing.json @@ -511,7 +511,7 @@ "signature": "186f1fa8390f69975387fc83797ee1963ad245d24ea675414138677d06935f15af6c6542732d04deb6178229799e3bb23436b6fcea985cf5d2cb6e87e6d5b905" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-price-over.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-price-over.json index 72c998a1c..11b442d00 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-price-over.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-price-over.json @@ -538,7 +538,7 @@ "signature": "b863211c9e7458ec68c9fcf394bb164c94cb0b03633f3b2fa23fe3ad94737c329b4e27eb1bb54a84dcdda341b87d1f91cc4bb3393ea17743ae9e38d9a6e72903" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-route-absent.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-route-absent.json index e4da858ec..18f09e634 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-route-absent.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-route-absent.json @@ -491,7 +491,7 @@ "signature": "60c49731de91da7900db1c82c0428391866e50d63a0dbdd05a18a5baf17c072e7007657c522d77812c66a2639df213dc4b44bca5782e2577d7f50f8d2e4fc907" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-route-missing.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-route-missing.json index 6bf9b0ee3..07e30e88c 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-route-missing.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-plan-route-missing.json @@ -537,7 +537,7 @@ "signature": "d4e6431979ef31a25be0ca0abfbbabb923da30b3f2cc5d06b1b4693b124d169da0a250b0df1d745e253ddccc2d90ee006514aa4160425d005e1fbeba79c6bb02" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-request-extra.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-request-extra.json index 5eac71ba8..44599a17e 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-request-extra.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-request-extra.json @@ -544,7 +544,7 @@ "signature": "c1c439c39fea7343ce0ea8fa3d004c33cca34caa82431adc0292acde520f72f8b5e91852664986c49e42e95b3e391a62fef5a1f354a3846680fc00125bc0c00f" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-route-missing.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-route-missing.json index 394b253fb..f11287e51 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-route-missing.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-route-missing.json @@ -537,7 +537,7 @@ "signature": "b2485daa7cb1ff6fdedaa0ca71c61d9cb01a9b2248e97c67fb69157ba1d49a75d6b30e19884db85f55fcf69c2ec78c12fa625d61f0bd282d159d07d733095a03" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-route-provider.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-route-provider.json index 85bc1ce98..8b8e04237 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-route-provider.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-route-provider.json @@ -536,7 +536,7 @@ "signature": "c3b623c0b6013d644db0d1b4eacf368373e7a75f50e7d9a771933d22d1c2ff0f38a3ea8b69668e671e3009022a8a37f4b91745e41598e562546d0fb7d4c71208" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-failed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-failed.json index 22113ce14..f77b0fe66 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-failed.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-failed.json @@ -514,7 +514,7 @@ "signature": "e6dcf4695c5e903911ba37897aa518690059b4b0bb166a24d50bd0466f99baa8fe86e3c457f5b49fd85d513ffefe94f3e44514d1d2afac31854628c4f6b56300" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-none.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-none.json index bdd823869..517c380e4 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-none.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-said-none.json @@ -514,7 +514,7 @@ "signature": "bcbcbd47d2cb90720e376de4dd53526f65ab41c060e2bdc07d44d5adbe5e5ed364cf5a42e41de7d316403548ecf7d33a22a4bb9cc6a1fa55985eb6e141b22207" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-seed.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-seed.json index 75cb2f582..30ba33ad1 100644 --- a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-seed.json +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-seed.json @@ -538,7 +538,7 @@ "signature": "d58f23d423b717248aa8ec599e3b50554214ffa7d5d6958af6ce56da4defe68bfd604c2ffce733a6da7bbcf3169acb11ee72cb8e1ab6a730130b90b6c75c4e01" } }, - "id": "pj-fc95adf1a5d6f2a3", - "submitted_ms": 1793974079041, - "finished_ms": 1793974079044 + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 } diff --git a/wai/quantum-conformance/receipts/jobs/scripted-contract-prx-circuits.json b/wai/quantum-conformance/receipts/jobs/scripted-contract-prx-circuits.json index edb064730..4e3ac8ece 100644 --- a/wai/quantum-conformance/receipts/jobs/scripted-contract-prx-circuits.json +++ b/wai/quantum-conformance/receipts/jobs/scripted-contract-prx-circuits.json @@ -170,7 +170,7 @@ "route": "method:stabilizer", "kind": "local", "method": "stabilizer", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": 10, "price": null, @@ -212,7 +212,7 @@ "route": "method:stabilizer_rank", "kind": "local", "method": "stabilizer_rank", - "class": "estimate", + "class": "exact", "host_dependent": false, "auto_rank": null, "price": null, @@ -333,6 +333,7 @@ "energy", "mitigation", "decoder", + "cancel", "charged" ], "program": { @@ -364,7 +365,7 @@ "method:trajectories", "method:pulse" ], - "digest": "3e22ca81f2ba0b868442a8909bce52f4731136875b2d3305be07332444b8cfbd", + "digest": "d603bacb92daa1043db820e5b85f4b2aec8f9e9ec8aff536d0d04019e153074d", "choice": false }, "shadow": { @@ -429,8 +430,8 @@ "alg": "ed25519", "canon": "rfc8785", "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", - "digest": "7accadcb1d4c565d8572f2ef4140e000d100b76a3d08dd4539ab77152e55191a", - "signature": "2046d13ef4f6d65c8b3959cbdde19dd949f271f310ed164312e0f6b937b4aeba06665cd821947e49bc61b93c0162dccea80989a52f25ac9c2ed2a256d5db0903" + "digest": "eb120bfdd0deddf496a319b69627b745f522e00c4918c6ca2c1781490320b2e6", + "signature": "d6f57c66f6f68d729af292c4602a30b68e9439558e638b8273528e7b94c45222dccf9528135ade9b373663bb33f547cf3e486c166b3a30ba8e45c2ce94c54503" } } } diff --git a/wai/quantum-conformance/receipts/made.lock.json b/wai/quantum-conformance/receipts/made.lock.json index 4c1b46635..bd83864b5 100644 --- a/wai/quantum-conformance/receipts/made.lock.json +++ b/wai/quantum-conformance/receipts/made.lock.json @@ -5,11 +5,11 @@ "cli-contract-bounded.json": "6a0d2e10c024f4ae8ffc185d800d7fd507dd30b24e0c52b4f5d01f0453298a47", "cli-contract-fabric-cpu.json": "61ce33ef961b5f2fda544834743484debc8d687f28644fc614b82d930f96932a", "cli-contract-local.json": "f8c3f3f2c85c85a6ed0c7da3b15e55af884fd8d06c441e13d93a5e72347cf5a7", - "cli-contract-provider-priced.json": "e2e741f626311733c3cb7f60019d2642a53d94c32a39cccb760409a5defc38ac", - "cli-contract-pulse.json": "16648cdfaeed225bdb98b5431ba1a570971d823fd531df65b79406a0508fb533", - "cli-contract-routed-seed.json": "a663c21f0c421dee1515fb7b0853ba63852cbbbbab14dbdd640b0e846164b55f", - "cli-contract-routed.json": "6ebe882a9d078095b61f501c601b24a93cae4d29f775b0bd2b74301be4736d86", - "cli-contract-target.json": "3ac678c68effba76bfb13a05e3d5e7c8fa862f2c1146dab05a7680c46b11a1a5", + "cli-contract-provider-priced.json": "5f6dce9e461a3aa12ec7cf7c4975734b75c23cfecc53636a5d102788fa645cbc", + "cli-contract-pulse.json": "ecad0f4f3100d67d6cffabe320c842c7c7a5f663e923452af54f92eb3157fab0", + "cli-contract-routed-seed.json": "ea670c35884bdc5d03cb53fee8b2db4d5bec46c9c021a2b409c97ee0cb170f32", + "cli-contract-routed.json": "1375789f3936028fb6b7147ee1869e1f7782e86d15c1a58c9808ec017e831b78", + "cli-contract-target.json": "50c16b8f42b3ab6e13a31268a3d6a48c58f17234f9a7aa3b1ae57c34650bc310", "cli-provider-reference-priced.json": "e569e1810da66580c9da4c4fb1185490919d03066f104de8332f99ac214a728b", "cli-provider-reference.json": "ade872d1a9e34a70f9f3928218b64b91ef2df8c21229778d79cd9cbbbb436f0c", "cli-run-mps.json": "9f8fdd7f57566b63e66e979769caae330a32fe01520d909a82f1ecba5c5a6f04", @@ -26,7 +26,7 @@ "scripted-cloud-tasks-processor-probabilities.json": "63f457f817d940d8af7e161b66aeb6b089e46c80a06c8b640b0a8ad3bd4c46cb", "scripted-cloud-tasks-processor.json": "1eb499584183085209fa4597e0f8956826f18cf29d0885e7ad9a1c55a656f66d", "scripted-cloud-tasks-simulator.json": "cc99f5d91138569f7584f913c88293a8581085ef6a38944f7425ad86591252c4", - "scripted-contract-prx-circuits.json": "61f23584bd53ee5edbebd1c9f4e7cf2a60afa6dd09c174509737cbabeb9d1f50", + "scripted-contract-prx-circuits.json": "1ec0c24711183e27e7f83752abf35a2ef53c852313cf65240161dacd58cf1592", "scripted-native-turns-noise.json": "8a6c1bac37f1b6a856d891dbc657d91c252a40eb7a5a09ab0ec9474233425385", "scripted-native-turns.json": "9cc3b887aba07437b2a3ad6e20e7f656853c63bf8c94c21c715efdfddf95ee77", "scripted-prx-circuits.json": "d1c74db10b01a23a7b66d90356a33b8f7afc37efd7c75a5af26fbd87f99cda6b", diff --git a/wai/quantum-conformance/receipts/manifest.json b/wai/quantum-conformance/receipts/manifest.json index 4a8a50e8d..89bbd5ff4 100644 --- a/wai/quantum-conformance/receipts/manifest.json +++ b/wai/quantum-conformance/receipts/manifest.json @@ -1682,6 +1682,72 @@ "made_by": "crafted", "what": "the same, the choice said to depend on nothing of the host" }, + { + "file": "jobs/crafted-contract-route-class-gpu.json", + "reasons": [ + "planner_route" + ], + "made_by": "crafted", + "what": "the GPU's single precision stated exact: a class its method does not have" + }, + { + "file": "jobs/crafted-contract-route-class-by-job.json", + "reasons": [ + "planner_route", + "planner_stable" + ], + "made_by": "crafted", + "what": "the stabilizer stated estimate, on a job with no noise and no target" + }, + { + "file": "jobs/crafted-contract-route-host-dependent.json", + "reasons": [ + "planner_route", + "planner_stable" + ], + "made_by": "crafted", + "what": "a built-in on no GPU said to depend on the host, which takes it out of the digest" + }, + { + "file": "jobs/crafted-contract-route-provider-host-independent.json", + "reasons": [ + "planner_route" + ], + "made_by": "crafted", + "what": "a provider's route said not to depend on the host" + }, + { + "file": "jobs/crafted-contract-result-class-foreign.json", + "reasons": [ + "contract_class" + ], + "made_by": "crafted", + "what": "the stabilizer's result stated bit-exact: it meets what is wanted, and its method has no such class" + }, + { + "file": "jobs/crafted-contract-price-memory-null.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "a method's memory stated null, which passes the memory rule and wins its tie" + }, + { + "file": "jobs/crafted-contract-price-provider-memory.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "a provider's route stating a memory" + }, + { + "file": "jobs/crafted-contract-host-providers-other.json", + "reasons": [ + "planner_form" + ], + "made_by": "crafted", + "what": "host.providers that are not the provider routes" + }, { "file": "jobs/crafted-contract-shadow-route-missing.json", "reasons": [ @@ -1778,6 +1844,22 @@ "made_by": "crafted", "what": "a shot said omitted beside counts that are all the shots: they sum to one more, and the distance, not computed, is no help" }, + { + "file": "jobs/crafted-contract-shadow-distinct.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a shadow that says more outcomes than it lists, none omitted" + }, + { + "file": "jobs/crafted-contract-shadow-class-foreign.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a shadow run by mps stated bit-exact: it meets its plan, and mps has no such class" + }, { "file": "jobs/crafted-contract-shadow-bound-other.json", "reasons": [ diff --git a/wai/quantum-conformance/tools/receipt_verify.py b/wai/quantum-conformance/tools/receipt_verify.py index 6f69d1368..3c9123aab 100644 --- a/wai/quantum-conformance/tools/receipt_verify.py +++ b/wai/quantum-conformance/tools/receipt_verify.py @@ -1060,7 +1060,7 @@ MEETS = { } CLASSES_WANTED = tuple(MEETS) + ("any",) LADDER = ("bit-exact", "exact", "single", "bounded", "estimate", "heuristic") -LEAVES_OUT = ("time", "amount", "energy", "mitigation", "decoder", "charged") +LEAVES_OUT = ("time", "amount", "energy", "mitigation", "decoder", "charged", "cancel") QUESTIONS = ("noise", "counts", "expectations", "amplitudes") _DECIMAL = re.compile(r"[0-9]+(?:\.[0-9]+)?") _GPU_METHODS = ("method:statevector_single", "method:cutrank_single") @@ -1085,6 +1085,25 @@ AUTO_RANKS = { } +# §8.7: the classes each built-in method can have; which of two, on a job, by _route_class. +METHOD_CLASSES = { + "exact": ("bit-exact",), + "statevector": ("exact",), + "statevector_single": ("single",), + "stabilizer": ("exact", "estimate"), + "pauli": ("bounded",), + "mps": ("exact", "heuristic"), + "stabilizer_rank": ("exact", "estimate"), + "tensor_network": ("exact",), + "cutrank": ("exact", "single"), + "cutrank_single": ("single",), + "density_matrix": ("exact",), + "trajectories": ("estimate",), + "pulse": ("bounded",), +} +_GPU_NAMES = ("statevector_single", "cutrank_single") + + def meets(wanted, got): """§8.7's table. `any` takes every class; a class nobody knows meets nothing else.""" return wanted == "any" or (wanted in MEETS and got in MEETS[wanted]) @@ -1159,7 +1178,8 @@ def _price_form(p, local): if not isinstance(left, list) or any(w not in LEAVES_OUT for w in left): return False for k in ("memory_bytes", "work"): - if k not in p or not (p[k] is None or (_whole(p[k]) and p[k].value >= 0)): + # A method's are whole numbers, and a provider's null: it states neither. + if k not in p or not ((_whole(p[k]) and p[k].value >= 0) if local else p[k] is None): return False return True @@ -1193,6 +1213,32 @@ def _route_form(r): return isinstance(r.get("class"), str) and isinstance(r.get("host_dependent"), bool) +def _class_of_method(method, cls): + """§8.7: whether cls is one the built-in method has; any class of another.""" + return method not in METHOD_CLASSES or cls in METHOD_CLASSES[method] + + +def _states_itself(r, request): + """§8.7: a built-in method has the class its table gives it on this request, and + depends on the host only when it runs on a GPU; a provider's route depends on it.""" + name = r["route"] + if not name.startswith("method:"): + return r["host_dependent"] is True + m = name[len("method:"):] + if m not in METHOD_CLASSES: + return True + cls = r["class"] + options = request.get("options") + given = lambda k: isinstance(options, dict) and options.get(k) is not None + if m == "stabilizer": + want = "estimate" if request.get("noise") is not None or request.get("target") is not None else "exact" + if cls != want: + return False + if m == "stabilizer_rank" and cls != ("estimate" if given("terms") or given("epsilon") else "exact"): + return False + return cls in METHOD_CLASSES[m] and r["host_dependent"] is (m in _GPU_NAMES) + + def _planner_form(p): if not isinstance(p, dict) or p.get("format") != "wai.quantum.planner/1": return False @@ -1411,7 +1457,8 @@ def _kept_holds(p, contract, result): want = None if e is None else e.value <= d * 1000.0 if _value_of(k.get("seconds")) != d or k.get("kept") is not want: return False - if result.get("method") != "provider" and _value_of(result.get("elapsed_ms")) != _value_of(e): + # A method's time is its result's, where its result states one. + if result.get("method") != "provider" and "elapsed_ms" in result and _value_of(result.get("elapsed_ms")) != _value_of(e): return False if contract["joules"] is not None: j = contract["joules"] @@ -1574,6 +1621,10 @@ def _shadow_holds(request, contract, p, result): return False if not (_whole(s.get("distinct_outcomes")) and s["distinct_outcomes"].value >= 0): return False + # Its outcomes are a counts' form: of 0 and 1, of one width; with none omitted, as said. + width = len(next(iter(counts), "")) + if any(len(k) != width or set(k) - {"0", "1"} for k in counts) or (omitted == 0 and s["distinct_outcomes"].value != len(counts)): + return False d = s.get("distance") if not isinstance(d, dict): return False @@ -1593,6 +1644,8 @@ def _shadow_holds(request, contract, p, result): else: return False cls = _member(s, "accuracy", "class") + if not _class_of_method(plan["route"][len("method:"):], cls): + return False return (s.get("route") == plan["route"] and isinstance(cls, str) and meets(plan.get("class"), cls) and _same(s.get("request"), plan.get("request")) and _same(s.get("shots"), result.get("shots"))) @@ -1617,6 +1670,11 @@ def check_contract(request, result, reasons): if request.get("provider") is not None and contract["providers"] != "allowed": reasons.add("contract_provider") routes = planner["routes"] + # The providers the host brought are its provider routes, in their order. + brought = [r["route"][len("provider:"):] for r in routes if r["kind"] == "provider"] + if planner["host"]["providers"] != brought: + reasons.add("planner_form") + return # What the job names, the question it asks and what auto picks: from the request # and the routes, never from what the reasoning says of itself. named = _request_names(request) @@ -1654,7 +1712,7 @@ def check_contract(request, result, reasons): chosen = [r["route"] for r in routes if r["outcome"] == "chosen"] if "route-unchecked" not in PLANTS: # PLANT for r in routes: - if _member(r, "rejected", "code") != gate(r): + if _member(r, "rejected", "code") != gate(r) or not _states_itself(r, request): broken = True if len(chosen) != 1 or chosen[0] != planner["choice"]: broken = True @@ -1673,10 +1731,12 @@ def check_contract(request, result, reasons): reasons.add("planner_stable") if not _kept_holds(planner, contract, result): reasons.add("planner_kept") - if wanted is not None: - cls = _member(result, "accuracy", "class") - if not meets(wanted, cls) or (from_contract and wanted == "simulated" and _member(result, "accuracy", "approximate") is True): - reasons.add("contract_class") + cls = _member(result, "accuracy", "class") + short = wanted is not None and (not meets(wanted, cls) or (from_contract and wanted == "simulated" and _member(result, "accuracy", "approximate") is True)) + # A method's result has a class its method has. + method = result.get("method") + if short or (isinstance(method, str) and method != "provider" and not _class_of_method(method, cls)): + reasons.add("contract_class") is_provider = planner["choice"].startswith("provider:") if is_provider != ("shadow" in result) or is_provider != ("shadow" in planner) or (is_provider and not _shadow_holds(request, contract, planner, result)): reasons.add("shadow") @@ -2221,7 +2281,7 @@ def _lr(name, cls, rank, outcome, code=None, seconds=0.001, memory=1024, joules= return r -def _local_contract_job(contract, routes, choice, auto, stable_choice, kept, request_extra=None, energy=None, providers=()): +def _local_contract_job(contract, routes, choice, auto, stable_choice, kept, request_extra=None, energy=None, providers=(), result_class="bit-exact"): """§8.7: a job under a contract run on one of the engine's methods, for the self-test only: (request text, result text). Every outcome, the choice, auto and stable.choice are written by the caller, never computed here.""" @@ -2241,7 +2301,7 @@ def _local_contract_job(contract, routes, choice, auto, stable_choice, kept, req "why": "the cheapest", "kept": kept, "stable": {"scope": "the host-independent routes", "routes": [r["route"] for r in covered], "digest": digest, "choice": stable_choice}, } - result = {"method": choice[len("method:"):], "qubits": 1, "gates": 1, "accuracy": {"class": "bit-exact"}, + result = {"method": choice[len("method:"):], "qubits": 1, "gates": 1, "accuracy": {"class": result_class}, "counts": {"1": 4}, "elapsed_ms": 3, "planner": planner, "energy": energy if energy is not None else {"unmetered": "a test"}, "engine": {"name": "wai-quantum", "version": "0.9.0"}, "schema": "wai.quantum.job-result/1"} @@ -2821,6 +2881,31 @@ def self_test(args): result__shadow__counts={"1": 1}, result__shadow__distance={"computed": True, "numerator": 3, "denominator": 8, "total_variation": 0.375, "hellinger_fidelity": 0.25, "sampling_tvd_bound": 0.234375}), ["shadow"]), + # By hand: "1" 4 and "x" 4 times, each pooled 4, E|2B - 4| = 1.5 twice; half of it over 4. + ("a shadow's outcomes that are not bits, the distance what they give", contract_body( + result__shadow__counts={"x": 4}, + result__shadow__distance={"computed": True, "numerator": 8, "denominator": 8, "total_variation": 1.0, + "hellinger_fidelity": 0.0, "sampling_tvd_bound": 0.375}), ["shadow"]), + ("a shadow that says more outcomes than it lists", contract_body(result__shadow__distinct_outcomes=7), ["shadow"]), + ("a shadow's class its method does not have", contract_body( + result__planner__routes__0__route="method:mps", result__planner__routes__0__method="mps", + result__planner__routes__0__class="heuristic", result__planner__routes__0__auto_rank=60, result__planner__stable__routes=["method:mps"], + result__planner__shadow__route="method:mps", result__planner__shadow__class="heuristic", + result__planner__shadow__request__method="mps", result__shadow__route="method:mps", + result__shadow__request__method="mps"), ["planner_stable", "shadow"]), + ("host.providers that are not its provider routes", contract_body(result__planner__host__providers=["someone-else"]), ["planner_form"]), + ("a provider that states its memory", contract_body(result__planner__routes__1__price__memory_bytes=1024), ["planner_form"]), + ("a provider's route said not to depend on the host", contract_body(result__planner__routes__1__host_dependent=False), ["planner_route"]), + ("a method on no GPU said to depend on the host", contract_body(result__planner__routes__0__host_dependent=True), ["planner_route", "planner_stable"]), + ("a built-in route stated a class it does not have", contract_body(result__planner__routes__0__class="exact"), ["planner_route", "planner_stable", "shadow"]), + ("a method's result of a class it does not have", local_body({"exactness": "exact"}, [ + _lr("exact", "bit-exact", 20, "chosen"), _lr("statevector", "exact", 30, "met", memory=2048), + _lr("statevector_single", "single", 40, "rejected", "class", host_dependent=True, priced=False), + _lr("mps", "heuristic", 60, "rejected", "class", memory=4096)], "method:exact", "method:exact", True, {}, result_class="exact"), ["contract_class"]), + ("a method's memory that is not stated", local_body({"exactness": "exact"}, [ + _lr("exact", "bit-exact", 20, "chosen"), dict(_lr("statevector", "exact", 30, "met"), price={"money": {"free": True}, "time": {"seconds": 0.001, "basis": "nominal"}, "memory_bytes": None, "work": 8, "energy": {"joules": None, "why": "none"}, "leaves_out": []}), + _lr("statevector_single", "single", 40, "rejected", "class", host_dependent=True, priced=False), + _lr("mps", "heuristic", 60, "rejected", "class", memory=4096)], "method:exact", "method:exact", True, {}), ["planner_form"]), ("a shadow planned at a class its route is not listed with", contract_body(result__planner__shadow__class="heuristic"), ["shadow"]), ("a time past what a price states", contract_body(result__planner__routes__1__price__time__seconds=1e306), ["planner_form"]), diff --git a/wai/wai-quantum-qpu/src/cloud_tasks.rs b/wai/wai-quantum-qpu/src/cloud_tasks.rs index 84abf247f..7c215bb7e 100644 --- a/wai/wai-quantum-qpu/src/cloud_tasks.rs +++ b/wai/wai-quantum-qpu/src/cloud_tasks.rs @@ -692,6 +692,10 @@ impl Provider for CloudTasks { Ok((counts, JobInfo::default(), Stated::counts(source))) } + fn can_cancel(&self) -> bool { + true + } + fn cancel(&self, id: &str) -> Result<(), QpuError> { let region = self.region_of_task(id); let url = format!("{}/quantum-task/{}/cancel", self.base(region), encode(id)); diff --git a/wai/wai-quantum-qpu/src/job.rs b/wai/wai-quantum-qpu/src/job.rs index 9dbd24bce..b6bb74b36 100644 --- a/wai/wai-quantum-qpu/src/job.rs +++ b/wai/wai-quantum-qpu/src/job.rs @@ -68,6 +68,8 @@ pub struct Target { pub provider: Box, secrets: Vec, job_bytes: u64, + /// What the name stands for: where the provider is, and whose account. + identity: String, } /// The memory a classical method may take here beside a provider's job, unless a @@ -78,7 +80,15 @@ impl Target { /// `provider` under the person's name for it, with the credential it was /// given (kept only to take out of messages). pub fn new(name: impl Into, kind: Kind, provider: Box, secret: Option) -> Target { - Target { name: name.into(), kind, provider, secrets: secret.into_iter().collect(), job_bytes: SHADOW_BYTES } + Target { name: name.into(), kind, provider, secrets: secret.into_iter().collect(), job_bytes: SHADOW_BYTES, identity: String::new() } + } + + /// The same, with what its name stands for (its endpoint, its settings and + /// where its credential is kept): a word that confirms a run is the word for + /// this provider, and a name pointed elsewhere is not it. + pub fn with_identity(mut self, identity: impl Into) -> Target { + self.identity = identity.into(); + self } /// Takes these out of messages too: the parts of a credential that is @@ -274,6 +284,12 @@ pub struct Plan { names: Option, /// The planner's reasoning, for a job with a contract. reasoning: Option, + /// What it costs, in words. + cost: String, + /// What the target's name stood for when this was planned. + identity: String, + /// Whether its client can stop a job it sent. + stoppable: bool, } impl Plan { @@ -329,6 +345,9 @@ impl Plan { left.push("mitigation"); } left.push("decoder"); + if !self.stoppable { + left.push("cancel"); + } if !free { left.push("charged"); } @@ -355,11 +374,19 @@ fn plan_with(t: &Target, sampler: &QpuSampler<&dyn Provider>, request: &Value) - let chosen = d.reasoning["choice"].as_str().unwrap_or_default(); return Err(JobError::Failed(format!("this job's contract is met here by {chosen}, not by {}: the planner chose the cheaper route, and nothing was sent", t.name))); } + planner::before_sending(request, &d.reasoning, &t.name, p.read.shots).map_err(JobError::Failed)?; p.reason_with(d.reasoning); } Ok(p) } +/// Under a contract a provider is asked nothing where the contract does not allow +/// one: not its description, and not an estimate, whose request carries the +/// program. This comes before any of them. +fn allowed(t: &Target, request: &Value) -> Result<(), JobError> { + planner::provider_allowed(request).map_err(|e| t.fail(e)) +} + fn priced(t: &Target, sampler: &QpuSampler<&dyn Provider>, request: &Value) -> Result { let read = provider::read_named(request, Some(&t.name)).map_err(|e| t.fail(e))?; if read.provider != t.name { @@ -375,8 +402,8 @@ fn priced(t: &Target, sampler: &QpuSampler<&dyn Provider>, request: &Value) -> R Ok(None) => details.billing == Billing::Free, Err(_) => false, }; - let confirm = if free { - "free: it runs without a confirmation".to_string() + let cost = if free { + "free".to_string() } else { let cost = match &estimate { Ok(Some(Estimate { cost: Some(c), unit, at_least, .. })) => format!("the provider estimates {}{} {}{}", if *at_least { "at least " } else { "" }, c.amount, c.currency, unit.as_ref().map(|u| format!(", billed by the {u}")).unwrap_or_default()), @@ -386,8 +413,9 @@ fn priced(t: &Target, sampler: &QpuSampler<&dyn Provider>, request: &Value) -> R Billing::Free => "its cost is unknown".into(), }, }; - format!("not free: {cost}; it runs only when you confirm it (--yes on the command line, confirm_cost: true for an agent, the dialog in the desktop app)") + format!("not free: {cost}") }; + let confirm = if free { "free: it runs without a confirmation".to_string() } else { format!("{cost}; it runs only when you confirm it (--yes on the command line, confirm_cost: true for an agent, the dialog in the desktop app)") }; let json = json!({ "dry_run": true, "provider": provider_json(t, &device, &details), @@ -405,7 +433,7 @@ fn priced(t: &Target, sampler: &QpuSampler<&dyn Provider>, request: &Value) -> R "confirm": confirm, }); let execution = t.provider.execution(&program); - Ok(Plan { json, free, read, program, placement, device, details, execution, estimate, names, reasoning: None }) + Ok(Plan { json, free, read, program, placement, device, details, execution, estimate, names, reasoning: None, cost, identity: t.identity.clone(), stoppable: t.provider.can_cancel() }) } impl Plan { @@ -442,7 +470,7 @@ impl Routed { "token": token, "route": format!("provider:{name}"), "money": money, - "says": format!("not free: {}; a ceiling confirms nothing. It runs only on the person's word for this route, this estimate and this program: --confirm {token} on the command line, confirm: \"{token}\" for an agent", self.plans.iter().find(|(n, _)| n == name).map(|(_, p)| p.confirmation()).unwrap_or_default()), + "says": self.says(name, &token), }); } } @@ -451,17 +479,26 @@ impl Routed { v } + /// What a person reads of a routed run that is not free: what it costs, and + /// the word, which is the one thing that confirms it. + fn says(&self, name: &str, token: &str) -> String { + let cost = self.plans.iter().find(|(n, _)| n == name).map(|(_, p)| p.cost.clone()).unwrap_or_default(); + format!("{cost}; a ceiling confirms nothing. It runs only on the person's word for this route, this device, this estimate and this program: --confirm {token} on the command line, confirm: \"{token}\" for an agent") + } + fn chosen_route(&self) -> &Value { let name = self.reasoning["choice"].as_str().unwrap_or(""); self.reasoning["routes"].as_array().and_then(|a| a.iter().find(|r| r["route"] == name)).unwrap_or(&Value::Null) } /// What a person confirms a routed run that is not free by: a digest of the - /// route chosen, what its provider estimates it at (its amount, currency and - /// unit, or why that is not known) and the program and shots it would send. - /// A run is sent only with this word, made again at send time, so a route, - /// an estimate or a program that changed since the person saw it is not - /// sent. `None` for a route that is free, or one of the engine's methods. + /// route chosen, who it is (its kind, device, provenance and description, and + /// what its name stands for), what its provider estimates it at (its amount, + /// currency and unit, or why that is not known) and the program and shots it + /// would send. A run is sent only with this word, made again at send time, so + /// a route, a device, an estimate or a program that changed since the person + /// saw it is not sent. `None` for a route that is free, or one of the + /// engine's methods. pub fn confirmation(&self) -> Option { let planner::Choice::Provider(name) = &self.choice else { return None }; let (_, p) = self.plans.iter().find(|(n, _)| n == name)?; @@ -471,6 +508,8 @@ impl Routed { let said = json!({ "route": format!("provider:{name}"), "money": self.chosen_route()["price"]["money"], + "provider": p.json["provider"], + "identity": p.identity, "program": compiled_json(&p.program)["program"], "shots": p.read.shots, }); @@ -501,7 +540,7 @@ pub fn route(targets: &[Target], request: &Value, job_bytes: u64) -> Result, request: &Value, job_bytes: u64) -> Result { let contract = planner::Contract::read(request).map_err(JobError::Failed)?; - let asks_providers = contract.as_ref().is_some_and(|c| c.providers == Some(true) && c.exactness.as_deref().is_none_or(|w| matches!(w, "measured" | "simulated" | "any"))); + let asks_providers = contract.as_ref().is_some_and(|c| c.providers == Some(true) && c.exactness.as_deref().is_some_and(|w| matches!(w, "measured" | "simulated" | "any"))); let (targets, also) = if asks_providers { (targets, also) } else { (&[][..], Vec::new()) }; let mut quotes = also; let mut plans = Vec::new(); @@ -520,6 +559,7 @@ pub fn route_with(targets: &[Target], also: Vec, request: &Value if let planner::Choice::Provider(name) = &d.choice && let Some((_, p)) = plans.iter_mut().find(|(n, _)| n == name) { + planner::before_sending(request, &d.reasoning, name, p.read.shots).map_err(JobError::Failed)?; p.reason_with(d.reasoning.clone()); } Ok(Routed { reasoning: d.reasoning, choice: d.choice, plans }) @@ -529,8 +569,7 @@ pub fn route_with(targets: &[Target], also: Vec, request: &Value /// reasoning and sealed with `key`: `energy` is the host's word on it. pub fn run_routed_here(routed: &Routed, request: &Value, key: &SigningKey, energy: Value) -> Result { let planner::Choice::Local(plan) = &routed.choice else { return Err(JobError::Failed("the planner chose a provider, and this runs what it chose here".into())) }; - let mut result = Registry::builtins().run(request, plan).map_err(JobError::Failed)?; - planner::complete(&mut result, &routed.reasoning).map_err(JobError::Failed)?; + let result = planner::run_chosen(Registry::builtins(), request, plan, &routed.reasoning).map_err(JobError::Failed)?; let body = wai_quantum::engine::job::seal(request, plan, result, key, energy); // A host gives no receipt its own verifier refuses. let own = wai_quantum::engine::job::check(&body); @@ -556,16 +595,20 @@ pub fn start_routed(t: &Target, routed: &Routed, request: &Value, confirm: Optio Some(_) => "the word given is not this route's at this estimate: what is chosen now, or what it costs, is not what was confirmed. ", None => "", }; - // The provider's plan, as a run on a provider named is refused with, and the word. + // The provider's plan, as a run on a provider named is refused with, saying + // what confirms this one. + let says = routed.says(&t.name, &token); let mut plan = p.json.clone(); - plan["confirm"] = routed.json()["confirm"].clone(); - return Err(JobError::Unconfirmed { plan, message: format!("{seen}this run on {} is not free: {}; it runs only on the person's word for this route and estimate: {token}", t.name, p.confirmation()) }); + plan["confirm"] = json!(says); + plan["token"] = json!(token); + return Err(JobError::Unconfirmed { plan, message: format!("{seen}this run on {}: {says}", t.name) }); } start_planned(t, p, request, true, ledger) } /// The dry run: the plan for `request` on `t`, with nothing submitted. pub fn plan(t: &Target, request: &Value) -> Result { + allowed(t, request)?; let sampler = QpuSampler::new(&*t.provider).map_err(|e| t.fail(e))?; plan_with(t, &sampler, request) } @@ -657,6 +700,7 @@ fn sealed(t: &Target, request: &Value, read: &provider::Request, sealing: &Value /// within `wait` is cancelled, where the provider can cancel one: this keeps /// no record to come back to. [`start`] and [`follow`] keep one. pub fn run(t: &Target, request: &Value, confirmed: bool, key: &SigningKey, wait: Wait, sleep: impl Fn(Duration) + 'static) -> Result { + allowed(t, request)?; let sampler = QpuSampler::new(&*t.provider).map_err(|e| t.fail(e))?.with_wait(wait, sleep); let p = plan_with(t, &sampler, request)?; refuse_unconfirmed(t, &p, confirmed)?; @@ -708,6 +752,7 @@ pub fn progress_of(ticket: &Ticket) -> Progress { /// that did not complete may have reached the provider, so it is `unknown`, /// and is not sent again: that could be a second bill. pub fn start(t: &Target, request: &Value, confirmed: bool, ledger: &Ledger) -> Result { + allowed(t, request)?; let sampler = QpuSampler::new(&*t.provider).map_err(|e| t.fail(e))?; let p = plan_with(t, &sampler, request)?; start_planned(t, &p, request, confirmed, ledger) @@ -755,15 +800,22 @@ fn ask(t: &Target, ticket: &mut Ticket, key: &SigningKey, ledger: &Ledger) -> Re ticket.polled(); let mut status = t.provider.status(&id); // A contract's deadline, from the job's submission: past it, the job is - // cancelled, since this host can, and nothing is sealed (J074). One that - // finished first gives its result: it has been paid for. - if matches!(status, Ok(JobStatus::Pending)) - && let Some(d) = planner::deadline_ms(ticket.request()) - && ticket.elapsed_ms() as f64 > d - { - t.provider.cancel(&id).map_err(|e| t.fail(e))?; - status = t.provider.status(&id); - if !matches!(status, Ok(JobStatus::Done)) { + // cancelled where this client can, and nothing is sealed (J074). One that + // finished first gives its result: it has been paid for. Only the provider's + // word ends the record: a cancel it has not finished, or a status that did + // not read, leaves the job to be asked after, since it can still finish and + // bill. A client that cannot cancel leaves it running, and it is reported so. + let late = matches!(status, Ok(JobStatus::Pending)) && planner::deadline_ms(ticket.request()).is_some_and(|d| ticket.elapsed_ms() as f64 > d); + if late { + match t.provider.cancel(&id) { + Ok(()) => status = t.provider.status(&id), + Err(QpuError::Unsupported(_)) => {} + Err(e) => return Err(t.fail(e)), + } + if let Ok(JobStatus::Ended { status: said, .. }) = &status + && said == "cancelled" + { + let d = planner::deadline_ms(ticket.request()).unwrap_or(0.0); ticket.ended("cancelled", &t.redact(&tag(refusal::DEADLINE_PASSED, format!("cancelled at {}: it ran past its contract's deadline of {} s, and nothing was sealed", t.name, d / 1000.0)))); ledger.put(ticket).map_err(|e| JobError::Failed(format!("the job was cancelled at its deadline, and that could not be recorded: {e}")))?; return Ok(progress_of(ticket)); @@ -1477,11 +1529,130 @@ mod tests { assert!(e.to_string().ends_with("[J071]") && e.to_string().contains("above the ceiling"), "{e}"); // One that cannot run it is a route with why, and the rest are still weighed. let wide = "OPENQASM 3.0; qubit[6] q; bit[6] c; h q[0]; c = measure q;"; - let routed = route(&targets, &json!({ "qasm": wide, "shots": 10, "contract": { "providers": "allowed" } }), 1 << 30).unwrap(); + let routed = route(&targets, &json!({ "qasm": wide, "shots": 10, "contract": { "providers": "allowed", "exactness": "any" } }), 1 << 30).unwrap(); assert_eq!(routed.reasoning["routes"].as_array().unwrap().iter().find(|r| r["route"] == "provider:cheap").unwrap()["rejected"]["code"], "cannot", "{}", routed.reasoning); assert_eq!(routed.reasoning["choice"], "method:stabilizer"); } + /// Under a contract that does not allow a provider, the one a job names is told + /// nothing: no description, and no estimate, whose request carries the program. + #[test] + fn a_provider_the_contract_does_not_allow_is_asked_nothing() { + let records = Records::new("not-allowed"); + let key = SigningKey::from_bytes(&[4; 32]); + let r = Arc::new(Reference::new(Config::default()).unwrap()); + let (t, ops, _) = watched(&r); + let req = json!({ "qasm": BELL, "shots": 100, "provider": "lab", "contract": { "exactness": "simulated" } }); + for refused in [plan(&t, &req).map(|_| ()).unwrap_err(), start(&t, &req, true, &records.ledger()).map(|_| ()).unwrap_err(), run(&t, &req, true, &key, no_wait(), |_| {}).map(|_| ()).unwrap_err()] { + assert!(refused.to_string().ends_with("[J070]"), "{refused}"); + } + assert!(ops.lock().unwrap().is_empty(), "{:?}", ops.lock().unwrap()); + // Allowed with no class named, a job keeps a classical class no provider's + // counts meet: none is asked for what could never be chosen. + let routed = route(&[t], &json!({ "qasm": BELL, "shots": 100, "contract": { "providers": "allowed" } }), 1 << 30).unwrap(); + assert_eq!(routed.reasoning["host"]["providers"], json!([]), "{}", routed.reasoning); + assert!(ops.lock().unwrap().is_empty(), "{:?}", ops.lock().unwrap()); + } + + /// The word for a routed run names who it goes to, not only the name: another + /// device under the same name and price, or the name pointed at another + /// endpoint, is not what was confirmed. And what a person reads says what + /// confirms it, the word, and nothing that does not. + #[test] + fn the_word_for_a_routed_run_binds_the_provider_and_says_only_itself() { + let want = json!({ "qasm": BELL, "shots": 1000, "seed": 2, "contract": { "providers": "allowed", "exactness": "simulated", "max_cost": { "amount": "5", "currency": "USD" } } }); + let word = |t: Target| route(&[t], &want, 1 << 30).unwrap().confirmation().expect("not free"); + let priced = |device: &str| { + let r = Arc::new(Reference::new(Config { name: device.into(), price: Some(("0.001".into(), "USD".into(), Per::Shot)), ..Config::default() }).unwrap()); + Target::new("lab", Kind::Process, Box::new(OpenProvider::new(Local(move |m: &Value| r.handle(m, None)))), None) + }; + assert_eq!(word(priced("qpu-a")), word(priced("qpu-a"))); + assert_ne!(word(priced("qpu-a")), word(priced("qpu-b")), "another device under the name"); + assert_ne!(word(priced("qpu-a")), word(priced("qpu-a").with_identity("https://elsewhere")), "the name pointed elsewhere"); + let routed = route(&[priced("qpu-a")], &want, 1 << 30).unwrap(); + let says = routed.json()["confirm"]["says"].as_str().unwrap().to_string(); + assert!(says.contains(&routed.confirmation().unwrap()) && !says.contains("--yes") && !says.contains("confirm_cost"), "{says}"); + let records = Records::new("word"); + let t = priced("qpu-a"); + let Err(JobError::Unconfirmed { plan, message }) = start_routed(&t, &routed, &want, None, &records.ledger()) else { panic!("sent without a word") }; + assert!(!message.contains("--yes") && !message.contains("confirm_cost"), "{message}"); + assert!(plan["confirm"].is_string() && plan["token"] == routed.confirmation().unwrap().as_str(), "{plan}"); + } + + /// Only the provider's word ends a job past its deadline. A cancel it has not + /// finished, or a status that does not read, leaves the job to be asked after, + /// and if it finishes it is sealed, saying the deadline was missed. A client + /// that cannot cancel leaves it running, says nothing failed, and its route says + /// so in what its price leaves out. + #[test] + fn a_job_past_its_deadline_ends_only_on_the_provider_s_word() { + let records = Records::new("cancelling"); + let key = SigningKey::from_bytes(&[4; 32]); + let req = json!({ "qasm": BELL, "shots": 100, "provider": "lab", "contract": { "providers": "allowed", "deadline_seconds": 0.01 } }); + // A cancel taken, the job still running at the provider, then done. + let r = Arc::new(Reference::new(Config { polls: 0, ..Config::default() }).unwrap()); + let holding = Arc::new(std::sync::atomic::AtomicBool::new(true)); + let cancels = Arc::new(std::sync::atomic::AtomicUsize::new(0)); + let scripted = |refuse_cancel: bool| { + let (r, holding, cancels) = (Arc::clone(&r), Arc::clone(&holding), Arc::clone(&cancels)); + Local(move |m: &Value| { + let held = holding.load(std::sync::atomic::Ordering::SeqCst); + match m["op"].as_str() { + Some("cancel") if refuse_cancel => json!({ "ok": false, "error": { "code": "unsupported", "message": "this device cannot" } }), + Some("cancel") => { + cancels.fetch_add(1, std::sync::atomic::Ordering::SeqCst); + json!({ "ok": true }) + } + Some("status") if held => json!({ "ok": true, "status": "running" }), + Some("estimate") => { + let mut a = r.handle(m, None); + a["seconds"] = json!(0); + a + } + _ => r.handle(m, None), + } + }) + }; + for refuse_cancel in [false, true] { + holding.store(true, std::sync::atomic::Ordering::SeqCst); + let t = Target::new("lab", Kind::Process, Box::new(OpenProvider::new(scripted(refuse_cancel))), None); + let mut ticket = start(&t, &req, false, &records.ledger()).unwrap(); + std::thread::sleep(Duration::from_millis(30)); + let asked = check(&t, &mut ticket, &key, &records.ledger()).unwrap(); + assert!(matches!(asked, Progress::Waiting(_)), "{refuse_cancel}: {:?}", asked.job()); + assert!(ticket.waiting(), "the record stays open: the job can still finish and bill"); + holding.store(false, std::sync::atomic::Ordering::SeqCst); + let Progress::Done(body) = check(&t, &mut ticket, &key, &records.ledger()).unwrap() else { panic!("not collected") }; + assert_eq!(body["result"]["planner"]["kept"]["deadline"]["kept"], false, "{}", body["result"]["planner"]["kept"]); + assert!(wai_quantum::engine::job::check(&body).valid(), "{:?}", wai_quantum::engine::job::check(&body).reasons); + } + assert!(cancels.load(std::sync::atomic::Ordering::SeqCst) >= 1); + // A client with no cancel at all: said in the price, before anything is sent. + struct Uncancellable(Box); + impl Provider for Uncancellable { + fn device(&self) -> Result { + self.0.device() + } + fn details(&self) -> Result { + self.0.details() + } + fn submit(&self, program: &NativeProgram, shots: u64) -> Result { + self.0.submit(program, shots) + } + fn status(&self, id: &str) -> Result { + self.0.status(id) + } + fn counts(&self, id: &str, program: &NativeProgram, shots: u64) -> Result<(Counts, JobInfo), crate::QpuError> { + self.0.counts(id, program, shots) + } + } + let t = Target::new("lab", Kind::Process, Box::new(Uncancellable(target(Config::default()).provider)), None); + let p = plan(&t, &json!({ "qasm": BELL, "shots": 100, "provider": "lab", "contract": { "providers": "allowed" } })).unwrap(); + let routes = p.json["planner"]["routes"].as_array().unwrap().clone(); + let lab = routes.iter().find(|r| r["route"] == "provider:lab").unwrap(); + assert!(lab["price"]["leaves_out"].as_array().unwrap().iter().any(|w| w == "cancel"), "{lab}"); + } + /// A job still at the provider past its contract's deadline is cancelled /// there, since this host can, and nothing is sealed (J074); a job that /// finished first is sealed all the same, saying it missed. diff --git a/wai/wai-quantum-qpu/src/lib.rs b/wai/wai-quantum-qpu/src/lib.rs index 90bece0ef..70b47ab92 100644 --- a/wai/wai-quantum-qpu/src/lib.rs +++ b/wai/wai-quantum-qpu/src/lib.rs @@ -398,6 +398,12 @@ pub trait Provider { Err(QpuError::Unsupported("this client cannot cancel a job".into())) } + /// Whether this client can stop a job it sent: under a deadline, one that + /// cannot leaves a late job running, and the planner's price says so. + fn can_cancel(&self) -> bool { + false + } + /// What this client sets at the provider when it sends `program`, as /// a result's `execution` states it (§8.3), built from the very request it /// sends: its members, the settings among them, the five things a @@ -462,6 +468,10 @@ macro_rules! forward_provider { (**self).cancel(id) } + fn can_cancel(&self) -> bool { + (**self).can_cancel() + } + fn execution(&self, program: &NativeProgram) -> Option { (**self).execution(program) } diff --git a/wai/wai-quantum-qpu/src/open_provider.rs b/wai/wai-quantum-qpu/src/open_provider.rs index 8388a3060..37e8d9ff3 100644 --- a/wai/wai-quantum-qpu/src/open_provider.rs +++ b/wai/wai-quantum-qpu/src/open_provider.rs @@ -706,6 +706,10 @@ impl Provider for OpenProvider { Ok((counts, info, Stated::counts(source).with_execution(execution))) } + fn can_cancel(&self) -> bool { + true + } + fn cancel(&self, id: &str) -> Result<(), QpuError> { match self.call("cancel", json!({ "job": id })) { Ok(_) => Ok(()), diff --git a/wai/wai-quantum-qpu/src/registry.rs b/wai/wai-quantum-qpu/src/registry.rs index e08c850f4..bb2de854f 100644 --- a/wai/wai-quantum-qpu/src/registry.rs +++ b/wai/wai-quantum-qpu/src/registry.rs @@ -772,7 +772,8 @@ pub fn open(entry: &Entry, stores: &Stores) -> Result { } Kind::Http | Kind::Process => (Box::new(OpenProvider::new(channel(entry, secret.clone())?).with_settings(entry.settings.clone())), secret), }; - Ok(Target::new(entry.name.clone(), entry.kind, provider, secret).with_secrets(parts)) + let identity = serde_json::json!({ "kind": entry.kind.name(), "endpoint": entry.endpoint, "command": entry.command, "settings": entry.settings, "credential": entry.credential.describe() }); + Ok(Target::new(entry.name.clone(), entry.kind, provider, secret).with_secrets(parts).with_identity(identity.to_string())) } #[cfg(test)] diff --git a/wai/wai-quantum-qpu/tests/clients.rs b/wai/wai-quantum-qpu/tests/clients.rs index e43ad45be..fdc34a562 100644 --- a/wai/wai-quantum-qpu/tests/clients.rs +++ b/wai/wai-quantum-qpu/tests/clients.rs @@ -775,7 +775,7 @@ fn a_built_in_kind_runs_under_a_contract_and_a_classical_method_shadows_it() { let r = &body["result"]; assert_eq!((r["accuracy"]["class"].as_str(), r["planner"]["choice"].as_str()), (Some("measured"), Some("provider:lab"))); let route = r["planner"]["routes"].as_array().unwrap().iter().find(|x| x["route"] == "provider:lab").unwrap(); - assert_eq!(route["price"]["leaves_out"], json!(["time", "amount", "energy", "mitigation", "decoder", "charged"]), "{route}"); + assert_eq!(route["price"]["leaves_out"], json!(["time", "amount", "energy", "mitigation", "decoder", "cancel", "charged"]), "{route}"); assert!(route["price"]["money"]["unknown"].is_string(), "{route}"); let s = &r["shadow"]; assert_eq!((s["ran"].as_bool(), s["accuracy"]["class"].as_str()), (Some(true), Some("bit-exact")), "{s}"); diff --git a/wai/wai-quantum/src/engine/planner.rs b/wai/wai-quantum/src/engine/planner.rs index d5da880d3..77b42e6e6 100644 --- a/wai/wai-quantum/src/engine/planner.rs +++ b/wai/wai-quantum/src/engine/planner.rs @@ -280,7 +280,7 @@ pub struct Quote { } /// What an estimate can leave out (section 8.7). -pub const LEFT_OUT: [&str; 6] = ["time", "amount", "energy", "mitigation", "decoder", "charged"]; +pub const LEFT_OUT: [&str; 7] = ["time", "amount", "energy", "mitigation", "decoder", "charged", "cancel"]; impl Quote { /// A provider that can run the job, with nothing known of it yet: its @@ -848,16 +848,24 @@ fn local_routes(reg: &Registry, v: &Value, host: &Host<'_>, q: Question) -> Resu Ok(out) } +/// Whether a job that names a provider may reach it: under a contract a provider +/// is used only where the contract allows one, the job's own named one among +/// them, and `providers: never` is the default. A host holds this before it asks +/// the provider anything. +pub fn provider_allowed(v: &Value) -> Result<(), String> { + let Some(contract) = Contract::read(v)? else { return Ok(()) }; + if v.get("provider").is_some_and(|p| !p.is_null()) && contract.providers != Some(true) { + return Err(tag(refusal::CONTRACT_FORM, "the job names a provider, and its contract does not allow one: under a contract a provider is used only with providers: allowed")); + } + Ok(()) +} + /// `contract` weighed against every route `host` can see. An error is a job that /// does not read, or a contract that does not; a contract no route meets gives /// the reasoning with the refusal in it. pub fn consider(reg: &Registry, v: &Value, host: &Host<'_>) -> Result { let contract = Contract::read(v)?.ok_or_else(|| "internal: a job with no contract was brought to the planner".to_string())?; - // Under a contract a provider is used only where the contract allows one, - // the job's own named one among them: providers: never is the default. - if v.get("provider").is_some_and(|p| !p.is_null()) && contract.providers != Some(true) { - return Err(tag(refusal::CONTRACT_FORM, "the job names a provider, and its contract does not allow one: under a contract a provider is used only with providers: allowed")); - } + provider_allowed(v)?; let provider = v.get("provider").and_then(Value::as_str); if v.get("provider").is_some_and(|p| !p.is_null()) && !provider.is_some_and(|p| host.quotes.iter().any(|q| q.name == p)) { // Refused as a job that names a provider is refused where none is reached. @@ -865,11 +873,21 @@ pub fn consider(reg: &Registry, v: &Value, host: &Host<'_>) -> Result) -> Result<(Pl let d = decide(reg, v, host)?; match d.choice { Choice::Local(p) => { - let mut result = reg.run(v, &p)?; - complete(&mut result, &d.reasoning)?; + let result = run_chosen(reg, v, &p, &d.reasoning)?; own_check(v, &result)?; Ok((p, result)) } @@ -1012,6 +1029,21 @@ pub fn plan_and_run_in(reg: &Registry, v: &Value, host: &Host<'_>) -> Result<(Pl } } +/// The route chosen run here, its result completed with `reasoning`. A result +/// that states no `elapsed_ms` of its own, so that its bits are the same on every +/// host (a device target's, a pulse program's), has the host's time of the run +/// in what it kept: a deadline is reported kept or missed all the same. +pub fn run_chosen(reg: &Registry, v: &Value, p: &Plan, reasoning: &Value) -> Result { + let began = std::time::Instant::now(); + let mut result = reg.run(v, p)?; + let ms = u64::try_from(began.elapsed().as_millis()).unwrap_or(u64::MAX); + complete(&mut result, reasoning)?; + if result.get("elapsed_ms").is_none() { + finish(v, &mut result, Some(ms)); + } + Ok(result) +} + /// What a job's `contract` takes, as its committed schema has it: for the tool /// lists. pub fn contract_schema() -> Value { @@ -1052,6 +1084,23 @@ pub fn own_check(v: &Value, result: &Value) -> Result<(), String> { Err(format!("internal: no receipt is given: this host's verifier would refuse its reasoning ({})", broken.join(", "))) } +/// A provider's route held to section 8.7 before anything is sent: whatever a +/// receipt of this reasoning cannot give should cost nothing. The reasoning, +/// with a result that says only that the provider ran. +pub fn before_sending(v: &Value, reasoning: &Value, provider: &str, shots: u64) -> Result<(), String> { + let mut r = json!({ "method": "provider", "provider": { "name": provider }, "shots": shots, "planner": reasoning, "shadow": { "ran": false, "code": "failed", "why": "not yet run" } }); + if reasoning["shadow"]["route"].is_null() { + r["shadow"]["code"] = reasoning["shadow"]["code"].clone(); + } + r["planner"]["kept"] = json!({}); + finish(v, &mut r, None); + let broken: Vec<&str> = check(v, &r).into_iter().filter(|c| !matches!(*c, CONTRACT_CLASS | PLANNER_KEPT)).collect(); + if broken.is_empty() { + return Ok(()); + } + Err(format!("internal: nothing was sent: this host's verifier would refuse its reasoning ({})", broken.join(", "))) +} + /// A result's class held to the contract once it has run: a method that gave /// less than the job wants gives no answer ([`refusal::CLASS_BROKEN`]). What the /// run is held to here is the class the contract names; `check` also holds a @@ -1078,7 +1127,7 @@ pub fn finish(v: &Value, result: &mut Value, elapsed_ms: Option) { } let mut kept = Map::new(); if let Some(d) = c.deadline_seconds { - let e = elapsed_ms.or_else(|| result.get("elapsed_ms").and_then(Value::as_u64)); + let e = elapsed_ms.or_else(|| result.get("elapsed_ms").and_then(Value::as_u64)).or_else(|| result.pointer("/planner/kept/deadline/elapsed_ms").and_then(Value::as_u64)); kept.insert("deadline".into(), json!({ "seconds": d, "elapsed_ms": e, "kept": e.map(|e| e as f64 <= d * 1000.0) })); } if let Some(j) = c.max_joules { @@ -1130,15 +1179,21 @@ fn shadow_budget(contract: &Contract, provider_seconds: Option) -> f64 { } } +/// The request a shadow of `v` runs: its program and shots on a seed of its own, +/// and nothing else. None for a job that does not read as a provider's. +fn shadow_request(v: &Value) -> Option { + let read = super::provider::read_named(v, Some("shadow")).ok()?; + Some(json!({ "qasm": v.get("qasm").cloned().unwrap_or(Value::Null), "shots": read.shots, "seed": shadow_seed(v) })) +} + /// The classical method that can reach the provider's counts within the /// contract, the most exact first and then the cheapest, or why none can: what /// the contract leaves after the provider's own time, or [`SHADOW_MAX_SECONDS`]. fn shadow_plan(reg: &Registry, v: &Value, host: &Host<'_>, contract: &Contract, provider_seconds: Option) -> Value { let budget = shadow_budget(contract, provider_seconds); - let Ok(read) = super::provider::read_named(v, Some("shadow")) else { + let Some(mut req) = shadow_request(v) else { return json!({ "route": null, "code": "none", "why": "the job does not read as a provider job" }); }; - let mut req = json!({ "qasm": v.get("qasm").cloned().unwrap_or(Value::Null), "shots": read.shots, "seed": shadow_seed(v) }); let auto = match catalog::read_in(reg, &req) { Ok(a) => a, Err(e) => return json!({ "route": null, "code": "none", "why": e }), @@ -1331,7 +1386,8 @@ fn price_form(p: &Value, local: bool) -> bool { let time_ok = p["time"].is_object() && (p["time"]["seconds"].is_null() || seconds_ok(&p["time"]["seconds"])); let energy_ok = p["energy"].is_object() && (p["energy"]["joules"].is_null() || p["energy"]["joules"].is_number()); let left_ok = p["leaves_out"].as_array().is_some_and(|a| a.iter().all(|w| w.as_str().is_some_and(|w| LEFT_OUT.contains(&w)))); - let counted = ["memory_bytes", "work"].iter().all(|k| p.get(*k).is_some_and(|x| x.is_null() || is_whole(x))); + // A method's are whole numbers, and a provider's `null`: it states neither. + let counted = ["memory_bytes", "work"].iter().all(|k| p.get(*k).is_some_and(|x| if local { is_whole(x) } else { x.is_null() })); money_ok && time_ok && energy_ok && left_ok && counted } @@ -1411,6 +1467,12 @@ pub fn check(request: &Value, result: &Value) -> Vec<&'static str> { out.push(CONTRACT_PROVIDER); } let routes = p["routes"].as_array().map_or(&[][..], Vec::as_slice); + // The providers the host brought are its provider routes, in their order. + let brought: Vec<&str> = routes.iter().filter(|r| r["kind"] == "provider").filter_map(|r| r["route"].as_str()?.strip_prefix("provider:")).collect(); + if p["host"]["providers"].as_array().is_none_or(|a| a.iter().map(Value::as_str).ne(brought.iter().map(|b| Some(*b)))) { + out.push(PLANNER_FORM); + return out; + } // What the job names, the question it asks and what auto picks, each from // the request and the routes, never from what the reasoning says of itself. let named = match request_names(request) { @@ -1446,7 +1508,7 @@ pub fn check(request: &Value, result: &Value) -> Vec<&'static str> { } choice = r["route"].as_str(); } - if r["rejected"]["code"].as_str() != gate(r, &held) { + if r["rejected"]["code"].as_str() != gate(r, &held) || !states_itself(r, request) { route_broken = true; } } @@ -1467,9 +1529,10 @@ pub fn check(request: &Value, result: &Value) -> Vec<&'static str> { } let class = result.pointer("/accuracy/class").and_then(Value::as_str).unwrap_or(""); let approximate = result.pointer("/accuracy/approximate") == Some(&Value::Bool(true)); - if let Some(w) = wanted.as_deref() - && (!meets(w, class) || (from == Some("contract") && w == "simulated" && approximate)) - { + let short = wanted.as_deref().is_some_and(|w| !meets(w, class) || (from == Some("contract") && w == "simulated" && approximate)); + // A method's result has a class its method has. + let foreign = result["method"].as_str().filter(|m| *m != "provider").is_some_and(|m| !class_of_method(m, class)); + if short || foreign { out.push(CONTRACT_CLASS); } let is_provider = p["choice"].as_str().is_some_and(|c| c.starts_with("provider:")); @@ -1479,6 +1542,32 @@ pub fn check(request: &Value, result: &Value) -> Vec<&'static str> { out } +/// Whether `class` is one the built-in `method` has; any class of a method that +/// is not one of the built-ins, whose word it is. +fn class_of_method(method: &str, class: &str) -> bool { + Registry::builtins().method(method).is_none_or(|m| m.classes().iter().any(|c| c == class)) +} + +/// Whether a route states of itself what section 8.7 gives it. A built-in method +/// has the class its table gives it, on `request`, and depends on the host only +/// when it runs on a GPU; a provider's route depends on the host. +fn states_itself(r: &Value, request: &Value) -> bool { + let class = r["class"].as_str().unwrap_or(""); + let Some(m) = r["route"].as_str().and_then(|n| n.strip_prefix("method:")) else { + return r["host_dependent"] == true; + }; + if Registry::builtins().method(m).is_none() { + return true; + } + let given = |k: &str| request["options"].get(k).is_some_and(|x| !x.is_null()); + let by_job = match m { + "stabilizer" => class == if request.get("noise").is_some_and(|x| !x.is_null()) || crate::engine::targets::job::names_target(request) { "estimate" } else { "exact" }, + "stabilizer_rank" => class == if given("terms") || given("epsilon") { "estimate" } else { "exact" }, + _ => true, + }; + by_job && class_of_method(m, class) && r["host_dependent"] == is_gpu(m) +} + /// A `kept` member as its table gives it: true, false, or `null` where it is not /// known. Nothing else reads as `null`. fn kept_is(v: &Value, want: Option) -> bool { @@ -1498,7 +1587,8 @@ fn kept_holds(c: &Contract, p: &Value, result: &Value) -> bool { let e = &kept["deadline"]["elapsed_ms"]; let want = e.as_f64().map(|e| e <= d * 1000.0); // A local result's own elapsed_ms, by value, and null when it has none. - let local_e = result["method"] != "provider" && result.get("elapsed_ms").and_then(Value::as_f64) != e.as_f64(); + // A method's time is its result's, where its result states one. + let local_e = result["method"] != "provider" && result.get("elapsed_ms").is_some_and(|x| x.as_f64() != e.as_f64()); if !has_exactly(&kept["deadline"], &["seconds", "elapsed_ms", "kept"]) || kept["deadline"]["seconds"].as_f64() != Some(d) || !(e.is_null() || is_whole(e)) || !kept_is(&kept["deadline"]["kept"], want) || local_e { return false; } @@ -1578,6 +1668,14 @@ fn shadow_plan_holds(request: &Value, contract: &Contract, p: &Value, result: &V } } +/// Whether a shadow's outcomes are of a counts' form: each a string of `0` and +/// `1`, all of one width, and, with none omitted, as many as it says. +fn outcomes_hold(s: &Value, omitted: Option) -> bool { + let Some(counts) = s["counts"].as_object() else { return false }; + let width = counts.keys().next().map_or(0, String::len); + counts.keys().all(|k| k.len() == width && k.bytes().all(|b| b == b'0' || b == b'1')) && (omitted != Some(0) || s["distinct_outcomes"].as_f64() == Some(counts.len() as f64)) +} + /// Whether a sealed shadow is of its form, what its plan says, and its distance /// what its counts give. fn shadow_holds(request: &Value, contract: &Contract, p: &Value, result: &Value) -> bool { @@ -1595,10 +1693,12 @@ fn shadow_holds(request: &Value, contract: &Contract, p: &Value, result: &Value) let shots = by_value(&result["shots"]); let counts: Option> = s["counts"].as_object().and_then(|o| o.values().map(count_of).collect()); let listed: Option = counts.map(|c| c.iter().map(|&n| u128::from(n)).sum()); - let counts_ok = match (listed, by_value(&s["omitted_shots"]), shots) { + let omitted = by_value(&s["omitted_shots"]); + let counts_ok = match (listed, omitted, shots) { (Some(l), Some(o), Some(n)) => l + u128::from(o) == u128::from(n), _ => false, - } && is_whole(&s["distinct_outcomes"]); + } && is_whole(&s["distinct_outcomes"]) + && outcomes_hold(s, omitted); let whole_lists = result["omitted_shots"].as_f64() == Some(0.0) && s["omitted_shots"].as_f64() == Some(0.0); let distance_ok = match s["distance"]["computed"].as_bool() { Some(false) => s["distance"]["why"].is_string() && !whole_lists, @@ -1610,7 +1710,8 @@ fn shadow_holds(request: &Value, contract: &Contract, p: &Value, result: &Value) } None => false, }; - let class_ok = s["accuracy"]["class"].as_str().is_some_and(|c| plan["class"].as_str().is_some_and(|w| meets(w, c))); + let method = route.strip_prefix("method:").unwrap_or(""); + let class_ok = s["accuracy"]["class"].as_str().is_some_and(|c| class_of_method(method, c) && plan["class"].as_str().is_some_and(|w| meets(w, c))); counts_ok && distance_ok && class_ok && s["route"].as_str() == Some(route) && same(&s["request"], &plan["request"]) && same(&s["shots"], &result["shots"]) } None => false, @@ -1647,24 +1748,40 @@ pub fn recheck(reg: &Registry, job: &Value) -> Result { let engine = result.pointer("/engine/version").and_then(Value::as_str); let same_engine = engine == Some(super::schema::ENGINE_VERSION); let job_bytes = p["host"]["job_bytes"].as_u64().ok_or("the reasoning names no job memory")?; + let routes = p["routes"].as_array().map_or(&[][..], Vec::as_slice); let priced = if request.get("provider").is_some_and(|x| !x.is_null()) { json!({ "checked": false, "why": "the job names its provider, so no local route was priced" }) } else { let host = Host::new(job_bytes); let local = local_routes(reg, request, &host, question(question_of(request)))?; let digest = stable_of(&local.routes, &p["host"]["job_bytes"], None, &Contract::default())["digest"].clone(); - let auto = auto_of(&local.routes, request, local.named.as_deref()); + // What auto picks over the routes as this engine prices them, those that + // depend on the host as the sealing host stated them: a verifier here has + // neither its GPU nor its registered methods. + let mixed: Vec = routes.iter().filter(|r| r["kind"] == "local").map(|r| if r["host_dependent"] == false { local.routes.iter().find(|l| l["route"] == r["route"]).unwrap_or(r).clone() } else { r.clone() }).collect(); + let auto = auto_of(&mixed, request, local.named.as_deref()); let auto_same = json!(auto) == p["auto"]; - json!({ "checked": true, "digest": digest, "auto": auto, "same": digest == p["stable"]["digest"] && auto_same }) + let named_same = json!(local.named) == p["named"]; + json!({ "checked": true, "digest": digest, "auto": auto, "named": local.named, "same": digest == p["stable"]["digest"] && auto_same && named_same }) }; let s = &result["shadow"]; let plan = &p["shadow"]; + // Which method a shadow runs, or why none can: planned again from the same + // job, memory and budget, by a verifier of the same engine. + let replanned = (plan.is_object() && same_engine).then(|| Contract::read(request).ok().flatten()).flatten().map(|c| { + let chosen = p["choice"].as_str().unwrap_or(""); + shadow_plan(reg, request, &Host::new(job_bytes), &c, provider_seconds(&p["routes"], chosen)) + }); + let as_planned = replanned.as_ref().is_none_or(|again| again["route"] == plan["route"] && (!again["route"].is_null() || again["code"] == plan["code"])); let shadow = if s.get("ran").is_none() { json!({ "checked": false, "why": "no provider answered this job, so it has no shadow" }) + } else if !as_planned { + let again = replanned.as_ref().map_or(Value::Null, |a| if a["route"].is_null() { a["code"].clone() } else { a["route"].clone() }); + json!({ "checked": true, "same": false, "why": format!("this engine plans {again} for this shadow, and the reasoning says otherwise") }) } else if s["ran"] == true { let req = &s["request"]; let run = catalog::plan_plain(reg, req, job_bytes).and_then(|pl| reg.run(req, &pl))?; - json!({ "checked": true, "same": run["counts"] == s["counts"] }) + json!({ "checked": true, "same": run["counts"] == s["counts"] && run["accuracy"]["class"] == s["accuracy"]["class"] }) } else if s["code"] == "failed" && plan["route"].is_string() { // The host says the shadow it planned failed: run it, and see. let req = &plan["request"]; @@ -1672,8 +1789,10 @@ pub fn recheck(reg: &Registry, job: &Value) -> Result { Ok(_) => json!({ "checked": true, "same": false, "why": "the host says its shadow failed, and it runs here" }), Err(e) => json!({ "checked": true, "same": true, "why": format!("it fails here too: {e}") }), } + } else if replanned.is_some() { + json!({ "checked": true, "same": true, "why": "no shadow could be planned, and none can here" }) } else { - json!({ "checked": false, "why": "no shadow could be planned, as the reasoning says why" }) + json!({ "checked": false, "why": "no shadow could be planned, as the reasoning says why; another engine's plan is not held here" }) }; let holds = priced["same"] != false && shadow["same"] != false; Ok(json!({ "holds": holds, "engine": { "sealed_by": engine, "this": super::schema::ENGINE_VERSION, "same": same_engine }, "priced": priced, "shadow": shadow })) diff --git a/wai/wai-quantum/src/engine/planner/tests.rs b/wai/wai-quantum/src/engine/planner/tests.rs index d63f8f0df..fcb9c4177 100644 --- a/wai/wai-quantum/src/engine/planner/tests.rs +++ b/wai/wai-quantum/src/engine/planner/tests.rs @@ -761,7 +761,8 @@ fn when_no_shadow_was_possible_the_result_says_so_and_why() { assert!(s.get("counts").is_none()); assert!(job::check(&body).valid(), "{:?}", job::check(&body).reasons); let rc = recheck(reg(), &body).unwrap(); - assert_eq!((rc["holds"].as_bool(), rc["shadow"]["checked"].as_bool()), (Some(true), Some(false)), "{rc}"); + // No shadow can be planned here either, so what the reasoning says is what holds. + assert_eq!((rc["holds"].as_bool(), rc["shadow"]["checked"].as_bool(), rc["shadow"]["same"].as_bool()), (Some(true), Some(true), Some(true)), "{rc}"); // No memory: on a host with less than any method's margin. let host = Host::new(1 << 20).with_quotes(vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))]); let c = consider(reg(), &device_contract(), &host).unwrap(); @@ -1281,3 +1282,141 @@ fn the_sampling_bound_holds_for_sparse_and_dense_outcomes() { fn binomial(n: u128, k: u128) -> f64 { (0..k).fold(1.0, |c, i| c * (n - i) as f64 / (i + 1) as f64) } + +/// A provider-named job whose shadow is the stabilizer: its route is listed with +/// the class the shadow has, the reasoning holds before anything is sent, and the +/// receipt a host seals afterwards is one its verifier takes. With the class of an +/// unpriced route, the run would be paid for and its receipt refused. +#[test] +fn a_named_provider_s_routes_carry_the_class_their_shadow_has() { + // 34 qubits of Clifford gates: past exact's and the state vector's memory. + let qasm = format!("OPENQASM 3.0;\nqubit[34] q;\nbit[34] c;\nh q[0];\n{}c = measure q;\n", (0..33).map(|i| format!("cx q[{i}], q[{}];\n", i + 1)).collect::()); + let req = json!({ "qasm": qasm, "shots": 100, "provider": "qpu", "contract": { "providers": "allowed", "max_cost": { "amount": "1", "currency": "USD" } } }); + let d = decide(reg(), &req, &Host::new(GIB).with_quotes(vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))])).unwrap(); + assert_eq!((d.reasoning["shadow"]["route"].as_str(), d.reasoning["shadow"]["class"].as_str()), (Some("method:stabilizer"), Some("exact")), "{}", d.reasoning["shadow"]); + assert_eq!(route(&d.reasoning, "method:stabilizer")["class"], "exact", "{}", d.reasoning); + before_sending(&req, &d.reasoning, "qpu", 100).unwrap(); + // What is checked before sending is the verifier's own: a shadow that does not + // hold is found while nothing has been spent. + let mut broken = d.reasoning.clone(); + broken["shadow"]["class"] = json!("estimate"); + assert!(before_sending(&req, &broken, "qpu", 100).unwrap_err().contains("shadow")); +} + +/// A route states the class its table gives it, and depends on the host only as +/// the rule says; a method's result and a shadow have a class their method has. +#[test] +fn a_built_in_route_and_a_result_are_held_to_their_method_s_classes() { + let local = seal_local(&json!({ "qasm": BELL, "shots": 100, "contract": { "exactness": "exact", "deadline_seconds": 60 } })); + assert_eq!(reasons(&local), Vec::<&str>::new()); + cases(&local, vec![ + // The GPU's single precision, stated exact: a class it never has. + (&[PLANNER_ROUTE], Box::new(|b| at(b, "method:statevector_single")["class"] = json!("exact"))), + // Stated estimate on a job with neither noise nor a target: its class is in + // the digest, and it no longer meets what is wanted. + (&[PLANNER_CHOICE, PLANNER_ROUTE, PLANNER_STABLE], Box::new(|b| at(b, "method:stabilizer")["class"] = json!("estimate"))), + // Out of the digest or into it, by what it says of the host. + (&[PLANNER_ROUTE, PLANNER_STABLE], Box::new(|b| at(b, "method:trajectories")["host_dependent"] = json!(true))), + (&[PLANNER_ROUTE, PLANNER_STABLE], Box::new(|b| at(b, "method:statevector_single")["host_dependent"] = json!(false))), + // A method's result of a class it does not have, whatever is wanted. + (&[CONTRACT_CLASS], Box::new(|b| b["result"]["accuracy"]["class"] = json!("bit-exact"))), + ]); + let noisy = seal_local(&json!({ "qasm": BELL, "shots": 100, "noise": { "depolarizing_2q": 0.01 }, "contract": { "deadline_seconds": 60 } })); + assert_eq!(reasons(&noisy), Vec::<&str>::new()); + assert_eq!(route(&noisy["result"]["planner"], "method:stabilizer")["class"], "estimate"); + let good = provider_body(&device_contract(), vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))], vec![450, 100, 0, 450]); + cases(&good, vec![ + (&[PLANNER_ROUTE], Box::new(|b| at(b, "provider:qpu")["host_dependent"] = json!(false))), + // A shadow run by a method stated stronger than it is. + (&[SHADOW], Box::new(|b| b["result"]["shadow"]["accuracy"]["class"] = json!("exact"))), + ]); +} + +/// What a route, its host and a shadow state of their form: a method's memory and +/// work are whole numbers and a provider's null, the host's providers are the +/// provider routes, and a shadow's outcomes are a counts' form. +#[test] +fn what_a_receipt_states_of_itself_is_of_its_form() { + let good = provider_body(&device_contract(), vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))], vec![450, 100, 0, 450]); + assert_eq!(reasons(&good), Vec::<&str>::new()); + cases(&good, vec![ + (&[PLANNER_FORM], Box::new(|b| at(b, "method:statevector")["price"]["memory_bytes"] = Value::Null)), + (&[PLANNER_FORM], Box::new(|b| at(b, "method:statevector")["price"]["work"] = Value::Null)), + (&[PLANNER_FORM], Box::new(|b| at(b, "provider:qpu")["price"]["memory_bytes"] = json!(1024))), + (&[PLANNER_FORM], Box::new(|b| b["result"]["planner"]["host"]["providers"] = json!(["someone-else"]))), + (&[PLANNER_FORM], Box::new(|b| b["result"]["planner"]["host"]["providers"] = json!([]))), + (&[SHADOW], Box::new(|b| b["result"]["shadow"]["distinct_outcomes"] = json!(7))), + (&[SHADOW], Box::new(|b| { + let shadow = &mut b["result"]["shadow"]; + let n = shadow["counts"]["00"].take(); + let o = shadow["counts"].as_object_mut().unwrap(); + o.shift_remove("00"); + o.insert("ab".into(), n); + })), + ]); +} + +/// What `--recheck` adds to a verifier: which method a shadow ran, or that none +/// could, is what this engine plans; a shadow's class is what it gives; a device +/// target's method is its own; and a route only a sealing host could price does +/// not make an honest receipt look wrong. +#[test] +fn recheck_plans_the_shadow_again_and_leaves_the_host_s_routes_to_the_host() { + let good = provider_body(&device_contract(), vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))], vec![450, 100, 0, 450]); + assert_eq!(recheck(reg(), &good).unwrap()["holds"], true); + let edited = |edit: &dyn Fn(&mut Value)| recheck(reg(), &resealed(&good, edit)).unwrap(); + // No shadow, said to be for want of a method, on a Bell pair. + let skipped = edited(&|b| { + b["result"]["planner"]["shadow"] = json!({ "route": null, "code": "none", "why": "said so" }); + b["result"]["shadow"] = json!({ "ran": false, "code": "none", "why": "said so" }); + }); + assert_eq!((skipped["holds"].as_bool(), skipped["shadow"]["same"].as_bool()), (Some(false), Some(false)), "{skipped}"); + assert!(skipped["shadow"]["why"].as_str().unwrap().contains("method:exact"), "{skipped}"); + // A weaker method run where a stronger one reaches the counts. + let weaker = edited(&|b| { + for side in ["/result/planner/shadow", "/result/shadow"] { + let s = b.pointer_mut(side).unwrap(); + s["route"] = json!("method:statevector"); + s["request"]["method"] = json!("statevector"); + } + }); + assert_eq!(weaker["shadow"]["same"], false, "{weaker}"); + // The class it ran at, stated stronger than a run here gives. + let stated = edited(&|b| b["result"]["shadow"]["accuracy"]["class"] = json!("exact")); + assert_eq!(stated["shadow"]["same"], false, "{stated}"); + // A device target's method is the engine's, not the host's word. + let target = seal_local(&json!({ "qasm": BELL, "shots": 50, "target": "synthetic-line-5", "contract": { "deadline_seconds": 60 } })); + assert_eq!(recheck(reg(), &target).unwrap()["priced"]["same"], true); + let other = resealed(&target, |b| b["result"]["planner"]["named"] = json!("method:trajectories")); + assert_eq!(recheck(reg(), &other).unwrap()["priced"]["same"], false); + // An honest receipt whose auto is a route only its host prices: the GPU's, + // where exact and the state vector are past the job's memory. + let sealed_on_a_gpu = seal_local(&json!({ "qasm": BELL, "shots": 100, "contract": { "deadline_seconds": 60 } })); + let gpu = resealed(&sealed_on_a_gpu, |b| { + let price = at(b, "method:exact")["price"].clone(); + let r = at(b, "method:statevector_single"); + r["price"] = price; + r["auto_rank"] = json!(0); + b["result"]["planner"]["auto"] = json!("method:statevector_single"); + }); + assert_eq!(recheck(reg(), &gpu).unwrap()["priced"]["same"], true, "a route this host cannot price is the sealing host's word"); +} + +/// A deadline is reported for every local run: a result that states no time of its +/// own, so that its bits are the same everywhere, has the host's. +#[test] +fn a_target_s_and_a_pulse_program_s_deadline_is_reported_kept() { + let target = seal_local(&json!({ "qasm": BELL, "shots": 50, "target": "synthetic-line-5", "contract": { "deadline_seconds": 60 } })); + assert!(target["result"].get("elapsed_ms").is_none()); + let kept = &target["result"]["planner"]["kept"]["deadline"]; + assert!(kept["elapsed_ms"].is_u64() && kept["kept"] == true, "{kept}"); + assert_eq!(reasons(&target), Vec::<&str>::new()); + // Stated past it, by the host's clock, it says so. + let late = resealed(&target, |b| { + let k = &mut b["result"]["planner"]["kept"]["deadline"]; + k["elapsed_ms"] = json!(61_000); + k["kept"] = json!(false); + }); + assert_eq!(reasons(&late), Vec::<&str>::new()); + assert_eq!(reasons(&resealed(&target, |b| b["result"]["planner"]["kept"]["deadline"]["kept"] = json!(false))), vec![PLANNER_KEPT]); +} -- 2.54.0 (Apple Git-157) From 989c0b160a8c00e4987f7cbf3eaf5e5732bbdf79 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sat, 7 Nov 2026 02:37:53 -0500 Subject: [PATCH 11/42] wai-quantum: the planner's verification, closed out - The schema takes `cancel` in `leaves_out`: every word a price can leave out is now held to its schema by a test. - A provider's plan takes up its reasoning only once it is held to what a receipt of it must be (`Plan::reason_held`): one place, so the check and the reasoning cannot part. - A provider-named job shadowed by cut-rank in single precision: its route has the class of the plan its shadow would have. - A deadline a host's timer kept on a result with no time of its own, in the second verifier's self-test. - The changelog and both READMEs say when a provider is asked, what the word binds and when a job past its deadline ends. The qpu library's pin is 91, with the new test's name. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/wai-quantum-qpu.yml | 7 ++-- ...06-wai-quantum-planner-under-a-contract.md | 16 ++++++++-- .../tools/receipt_verify.py | 7 ++++ wai/wai-quantum-cli/README.md | 2 +- wai/wai-quantum-cli/README.zh-CN.md | 2 +- wai/wai-quantum-qpu/src/job.rs | 32 ++++++++++++++++--- wai/wai-quantum/schemas/job-result.v1.json | 5 +-- wai/wai-quantum/src/engine/planner/tests.rs | 14 ++++++++ 8 files changed, 72 insertions(+), 13 deletions(-) diff --git a/.github/workflows/wai-quantum-qpu.yml b/.github/workflows/wai-quantum-qpu.yml index e75949f7e..c691303ba 100644 --- a/.github/workflows/wai-quantum-qpu.yml +++ b/.github/workflows/wai-quantum-qpu.yml @@ -79,10 +79,10 @@ jobs: # tests never touch one but the macOS leg's own. export WAI_QUANTUM_CREDENTIALS=file cargo test --locked 2>&1 | tee "$RUNNER_TEMP/test.log" - # The library (90, the cloud-tasks client's 26 and a job under a contract's - # 9 among them), the clients against their contracts (17), and the providers + # The library (91, the cloud-tasks client's and a job under a contract's among + # them), the clients against their contracts (17), and the providers # end to end (12), each binary's count pinned. - for n in 90 17 12; do + for n in 91 17 12; do grep -qE "^test result: ok\. $n passed; 0 failed" "$RUNNER_TEMP/test.log" || { echo "::error::a test binary did not pass all $n of its tests"; exit 1; } done for t in curl_carries_a_request_to_a_server_and_back every_operation_over_http every_operation_over_a_local_process \ @@ -117,6 +117,7 @@ jobs: job::tests::a_provider_the_contract_does_not_allow_is_asked_nothing \ job::tests::the_word_for_a_routed_run_binds_the_provider_and_says_only_itself \ job::tests::a_job_past_its_deadline_ends_only_on_the_provider_s_word \ + job::tests::a_reasoning_no_receipt_could_give_is_not_taken_up \ a_built_in_kind_runs_under_a_contract_and_a_classical_method_shadows_it a_cost_estimated_at_the_least_it_can_come_to_meets_no_ceiling; do grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/test.log" || { echo "::error::$t did not run and pass"; exit 1; } done diff --git a/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md b/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md index 466513ca5..56b94d663 100644 --- a/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md +++ b/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md @@ -10,7 +10,7 @@ - **The planner** (`engine::planner`) lists every route the host can see: each method here, and each of the person's providers a host brings. It prices each with what is known: a method's memory and work as the planner counts them, its time at the planner's nominal rate where its work predicts it, its energy where the host estimates one; a provider's - own estimate, with what it leaves out (`time`, `amount`, `energy`, `mitigation`, `decoder`, `charged`). It rejects + own estimate, with what it leaves out (`time`, `amount`, `energy`, `mitigation`, `decoder`, `charged`, `cancel`). It rejects every route that cannot meet the contract, each with a code and a sentence, and runs the cheapest of the rest. An unknown never passes: a time nobody states does not meet a deadline, nor an unknown cost a ceiling, nor an estimate that is only the least a job can come to (`cost_at_least`), nor an energy nobody estimates. Nothing falls back, from @@ -29,7 +29,7 @@ outcome and the choice from what the receipt states, and give nine new reasons (`contract_form`, `contract_provider`, `planner_form`, `planner_route`, `planner_choice`, `planner_stable`, `planner_kept`, `contract_class`, `shadow`); the differential holds them to the same choice, class, kept and shadow distance, not - only the same reasons. The corpus gains eleven made receipts under a contract and seventy-one crafted ones, + only the same reasons. The corpus gains eleven made receipts under a contract and eighty-one crafted ones, each of the review's single-rule changes to the second verifier is found by them, and three plants prove the differential sees a route, a choice and a distance taken as they stand. - **A provider's answer is shadowed.** When a provider answers a contract job, the most exact classical method that can @@ -39,6 +39,18 @@ run of exactly the job's program, shots and a seed of its own, with no other member; its counts are whole and sum to its shots. Where none can run, the result says which tried and why. `wai-quantum verify --recheck` prices the routes again, checks `auto`, and runs the shadow again, a shadow the host says failed among them. +- **What a receipt states of itself is held to the job.** A built-in method's route, and a local result, have a class of + that method's, as section 8.7's table gives; a shadow's class too. A route to a method is host-dependent or not by + what it is, `host.providers` names exactly the provider routes, and a method a provider-named job shadows is listed + with the class it has on this job. `wai-quantum verify --recheck` plans the shadow again on the same engine, compares + what the job named, and leaves the routes a host brought to that host, in text as in a parsed value. +- **Nothing is sent that could not be sealed.** A provider's route is held to section 8.7 before it is sent (`before_sending`), + so a paid job whose receipt would be refused costs nothing, and a provider the contract does not allow is asked + nothing, in `plan`, `start` and `run` alike. Under a contract a provider is asked only where the contract names a + class one could give (`measured`, `simulated` or `any`). The word that confirms a routed run binds the provider, the + device and its identity beside the route, the estimate and the program, and says only itself. A job past its deadline + ends only on the provider's word that it was cancelled: one whose client cannot cancel says so (`cancel` in + `leaves_out`), and stays waiting. A target's and a pulse program's deadline is held to a host's timer. - **Every host seals only what its verifier accepts.** A result short of the class its reasoning wants gives no answer (`J072`), and each host checks a contract job's reasoning before it seals it. A run past its contract's deadline on the job service is stopped, and the command line cancels a provider's job still waiting at it (`J074`). A deadline holds diff --git a/wai/quantum-conformance/tools/receipt_verify.py b/wai/quantum-conformance/tools/receipt_verify.py index 3c9123aab..c1da4d6f5 100644 --- a/wai/quantum-conformance/tools/receipt_verify.py +++ b/wai/quantum-conformance/tools/receipt_verify.py @@ -2856,6 +2856,12 @@ def self_test(args): def local_body(contract, routes, choice, auto, stable_choice, kept, **kw): return _seal(seed, *_local_contract_job(contract, routes, choice, auto, stable_choice, kept, **kw)) + def timed_by_host(kept): + request, text = _local_contract_job({"exactness": "exact", "deadline_seconds": 60}, base(), "method:exact", "method:exact", True, kept) + result = json.loads(text) + del result["elapsed_ms"] + return _seal(seed, request, json.dumps(result, separators=(",", ":"))) + contract_ok = contract_body() check("a contract job's reasoning and shadow", reasons_of(contract_ok) == []) for name, raw_case, want in ( @@ -2964,6 +2970,7 @@ def self_test(args): _lr("statevector_single", "single", 40, "rejected", "class", host_dependent=True, priced=False), _lr("mps", "heuristic", 60, "rejected", "class", memory=4096)], "method:exact", "method:exact", True, {"deadline": {"seconds": 60, "elapsed_ms": 3, "kept": True}}), []), + ("a deadline a host's timer kept, the result stating no time of its own", timed_by_host({"deadline": {"seconds": 60, "elapsed_ms": 3, "kept": True}}), []), ("a deadline's time that is not the result's", local_body({"exactness": "exact", "deadline_seconds": 60}, base(), "method:exact", "method:exact", True, {"deadline": {"seconds": 60, "elapsed_ms": 4, "kept": True}}), ["planner_kept"]), diff --git a/wai/wai-quantum-cli/README.md b/wai/wai-quantum-cli/README.md index 6687fbe03..9e8057adf 100644 --- a/wai/wai-quantum-cli/README.md +++ b/wai/wai-quantum-cli/README.md @@ -109,7 +109,7 @@ wai-quantum run circuit.qasm --method statevector --fabric cpu --fabric cpu --sh wai-quantum run prog.qasm --fabric a-member-elsewhere # exits 1 ``` -**Under a contract.** `--exactness CLASS`, `--deadline SECONDS`, `--max-cost 0.50:USD`, `--max-joules J` and `--allow-providers` (or `--contract` with the JSON of [the provider protocol's section 8.7](../extensions/quantum-providers.md)) say what the answer must be. The planner then prices every route it can see: each method here, at its memory and the time its work predicts, and with `--allow-providers` each of your own providers, by its own estimate and what that leaves out (each is asked, and sent nothing). It rejects every route that cannot meet the contract, runs the cheapest of the rest, and seals its reasoning in the receipt. An unknown never passes: a time nobody states does not meet a deadline, nor an unknown cost a ceiling, nor an estimate that is only the least a job can come to. Nothing falls back, from exact to approximate or between a simulator and a device, and with no route left the job is refused with every route's reason (`J071`). A contract that names no class keeps the class `auto` would give, and a device's counts are reached only by asking for `measured` (or `any`). A provider's answer carries a classical method's counts beside it, with their distance, wherever a method here can reach them in the time the contract leaves, and the receipt says why where none can. Under a contract no provider is asked anything without `--allow-providers`, and one you name is refused without it (`J070`). A ceiling bounds the estimate a route is chosen by, not what is charged after, and confirms nothing: a run on a provider you name that is not free still takes `--yes`, and one the planner routes to a provider that is not free takes `--confirm WORD`, the word its `--dry-run` prints for that route, that estimate and that program, and is refused if any of them has changed when it would be sent. A deadline holds a method's own run time here, and a provider's from its submission to its counts; the command line cancels a provider's job still waiting at it (`J074`). `wai-quantum plan` with the same options shows every route's price or reason and sends nothing; `wai-quantum verify --recheck` prices the routes again here and runs the shadow again; a run that kept less than its contract asked is still sealed, says so, and exits 4. +**Under a contract.** `--exactness CLASS`, `--deadline SECONDS`, `--max-cost 0.50:USD`, `--max-joules J` and `--allow-providers` (or `--contract` with the JSON of [the provider protocol's section 8.7](../extensions/quantum-providers.md)) say what the answer must be. The planner then prices every route it can see: each method here, at its memory and the time its work predicts, and with `--allow-providers` each of your own providers, by its own estimate and what that leaves out (each is asked, and sent nothing). It rejects every route that cannot meet the contract, runs the cheapest of the rest, and seals its reasoning in the receipt. An unknown never passes: a time nobody states does not meet a deadline, nor an unknown cost a ceiling, nor an estimate that is only the least a job can come to. Nothing falls back, from exact to approximate or between a simulator and a device, and with no route left the job is refused with every route's reason (`J071`). A contract that names no class keeps the class `auto` would give, and a device's counts are reached only by asking for `measured` (or `any`). A provider's answer carries a classical method's counts beside it, with their distance, wherever a method here can reach them in the time the contract leaves, and the receipt says why where none can. Under a contract no provider is asked anything without `--allow-providers` and a class one could give (`--exactness measured`, `simulated` or `any`), and one you name is refused without them (`J070`). A ceiling bounds the estimate a route is chosen by, not what is charged after, and confirms nothing: a run on a provider you name that is not free still takes `--yes`, and one the planner routes to a provider that is not free takes `--confirm WORD`, the word its `--dry-run` prints for that route, that provider and device, that estimate and that program, and is refused if any of them has changed when it would be sent. A deadline holds a method's own run time here, and a provider's from its submission to its counts; the command line cancels a provider's job still waiting at it (`J074`), and a job ends there only on the provider's word that it was cancelled: a provider that cannot cancel says so in its price, and its job stays waiting. `wai-quantum plan` with the same options shows every route's price or reason and sends nothing; `wai-quantum verify --recheck` prices the routes again here and runs the shadow again; a run that kept less than its contract asked is still sealed, says so, and exits 4. Each result names: diff --git a/wai/wai-quantum-cli/README.zh-CN.md b/wai/wai-quantum-cli/README.zh-CN.md index fd7604006..f8307d95a 100644 --- a/wai/wai-quantum-cli/README.zh-CN.md +++ b/wai/wai-quantum-cli/README.zh-CN.md @@ -112,7 +112,7 @@ wai-quantum run circuit.qasm --method statevector --fabric cpu --fabric cpu --sh wai-quantum run prog.qasm --fabric a-member-elsewhere # exits 1:别处的成员,被拒绝 ``` -**在契约之下。** `--exactness CLASS`、`--deadline SECONDS`、`--max-cost 0.50:USD`、`--max-joules J` 和 `--allow-providers`(或用 `--contract` 给出 [提供方协议第 8.7 节](../extensions/quantum-providers.md) 的 JSON)说明答案必须满足什么。规划器随后为它能看到的每条路径定价:本机的每个方法,按其内存和其工作量所预示的时间;加上 `--allow-providers` 时,还有你自己的每个提供方,按其自身的估算以及该估算未包含的内容(每个都会被询问,但不会发送任何东西)。它拒绝每条无法满足契约的路径,运行其余路径中最便宜的一条,并把它的推理封入收据。未知量从不算作满足:无人说明的时间不满足截止时间,未知的费用不满足上限,只是作业最低可能费用的估算也不满足。不会回退:既不会从精确退到近似,也不会在模拟器与设备之间互换;没有路径剩下时,作业被拒绝,并列出每条路径的原因(`J071`)。未指明类别的契约保留 `auto` 会给出的类别;只有请求 `measured`(或 `any`)才会用到设备的计数。提供方的答案旁边附有经典方法的计数及两者的距离,只要本机有方法能在契约留下的时间内得到它们;没有方法能做到时,收据会说明原因。在契约之下,没有 `--allow-providers` 时不会询问任何提供方,你指定的提供方也会被拒绝(`J070`)。上限约束的是选择路径所依据的估算,而不是之后实际收取的费用,它也不构成确认:在你指定的提供方上运行、且不免费时,仍需要 `--yes`;规划器选到的提供方不免费时,需要 `--confirm WORD`,即它的 `--dry-run` 为该路径、该估算和该程序打印的词,发送时只要其中任何一项已有变化就会被拒绝。截止时间约束本机方法自身的运行时间,以及提供方从提交到得出计数的时间;命令行会在截止时取消仍在等待的提供方作业(`J074`)。带相同选项的 `wai-quantum plan` 显示每条路径的价格或原因,不发送任何东西;`wai-quantum verify --recheck` 在本机重新为路径定价并重新运行影子运行;未能满足契约全部要求的运行仍会被封存,并如实说明,退出状态为 4。 +**在契约之下。** `--exactness CLASS`、`--deadline SECONDS`、`--max-cost 0.50:USD`、`--max-joules J` 和 `--allow-providers`(或用 `--contract` 给出 [提供方协议第 8.7 节](../extensions/quantum-providers.md) 的 JSON)说明答案必须满足什么。规划器随后为它能看到的每条路径定价:本机的每个方法,按其内存和其工作量所预示的时间;加上 `--allow-providers` 时,还有你自己的每个提供方,按其自身的估算以及该估算未包含的内容(每个都会被询问,但不会发送任何东西)。它拒绝每条无法满足契约的路径,运行其余路径中最便宜的一条,并把它的推理封入收据。未知量从不算作满足:无人说明的时间不满足截止时间,未知的费用不满足上限,只是作业最低可能费用的估算也不满足。不会回退:既不会从精确退到近似,也不会在模拟器与设备之间互换;没有路径剩下时,作业被拒绝,并列出每条路径的原因(`J071`)。未指明类别的契约保留 `auto` 会给出的类别;只有请求 `measured`(或 `any`)才会用到设备的计数。提供方的答案旁边附有经典方法的计数及两者的距离,只要本机有方法能在契约留下的时间内得到它们;没有方法能做到时,收据会说明原因。在契约之下,没有 `--allow-providers` 以及提供方能够给出的类别(`--exactness measured`、`simulated` 或 `any`)时,不会询问任何提供方,你指定的提供方也会被拒绝(`J070`)。上限约束的是选择路径所依据的估算,而不是之后实际收取的费用,它也不构成确认:在你指定的提供方上运行、且不免费时,仍需要 `--yes`;规划器选到的提供方不免费时,需要 `--confirm WORD`,即它的 `--dry-run` 为该路径、该提供方和设备、该估算和该程序打印的词,发送时只要其中任何一项已有变化就会被拒绝。截止时间约束本机方法自身的运行时间,以及提供方从提交到得出计数的时间;命令行会在截止时取消仍在等待的提供方作业(`J074`),且只有提供方确认已取消时作业才在此结束:无法取消的提供方会在其价格中说明,其作业继续等待。带相同选项的 `wai-quantum plan` 显示每条路径的价格或原因,不发送任何东西;`wai-quantum verify --recheck` 在本机重新为路径定价并重新运行影子运行;未能满足契约全部要求的运行仍会被封存,并如实说明,退出状态为 4。 每个结果都注明: diff --git a/wai/wai-quantum-qpu/src/job.rs b/wai/wai-quantum-qpu/src/job.rs index b6bb74b36..83f0db0d2 100644 --- a/wai/wai-quantum-qpu/src/job.rs +++ b/wai/wai-quantum-qpu/src/job.rs @@ -374,8 +374,7 @@ fn plan_with(t: &Target, sampler: &QpuSampler<&dyn Provider>, request: &Value) - let chosen = d.reasoning["choice"].as_str().unwrap_or_default(); return Err(JobError::Failed(format!("this job's contract is met here by {chosen}, not by {}: the planner chose the cheaper route, and nothing was sent", t.name))); } - planner::before_sending(request, &d.reasoning, &t.name, p.read.shots).map_err(JobError::Failed)?; - p.reason_with(d.reasoning); + p.reason_held(request, d.reasoning, &t.name)?; } Ok(p) } @@ -441,6 +440,15 @@ impl Plan { self.json["planner"] = reasoning.clone(); self.reasoning = Some(reasoning); } + + /// `reasoning` taken up for a run on `name`, once it is held to what a receipt + /// of it must be: a run whose receipt would be refused is not sent, and costs + /// nothing. Nothing else gives a plan that goes to a provider its reasoning. + fn reason_held(&mut self, request: &Value, reasoning: Value, name: &str) -> Result<(), JobError> { + planner::before_sending(request, &reasoning, name, self.read.shots).map_err(JobError::Failed)?; + self.reason_with(reasoning); + Ok(()) + } } /// What the planner made of a contract job, with every provider brought. @@ -559,8 +567,7 @@ pub fn route_with(targets: &[Target], also: Vec, request: &Value if let planner::Choice::Provider(name) = &d.choice && let Some((_, p)) = plans.iter_mut().find(|(n, _)| n == name) { - planner::before_sending(request, &d.reasoning, name, p.read.shots).map_err(JobError::Failed)?; - p.reason_with(d.reasoning.clone()); + p.reason_held(request, d.reasoning.clone(), name)?; } Ok(Routed { reasoning: d.reasoning, choice: d.choice, plans }) } @@ -1554,6 +1561,23 @@ mod tests { assert!(ops.lock().unwrap().is_empty(), "{:?}", ops.lock().unwrap()); } + /// A reasoning no receipt could give is not taken up, so nothing goes out on it. + /// The planner gives none today: this holds the rule for the day one slips. + #[test] + fn a_reasoning_no_receipt_could_give_is_not_taken_up() { + let r = Arc::new(Reference::new(Config::default()).unwrap()); + let (t, _, _) = watched(&r); + let req = json!({ "qasm": BELL, "shots": 100, "provider": "lab", "contract": { "providers": "allowed", "exactness": "simulated" } }); + let mut p = plan(&t, &req).unwrap(); + let good = p.reasoning.clone().expect("a contract's plan is reasoned"); + let mut broken = good.clone(); + broken["shadow"]["class"] = json!("estimate"); + let refused = p.reason_held(&req, broken, "lab").unwrap_err(); + assert!(refused.to_string().contains("shadow"), "{refused}"); + assert_eq!(p.reasoning.as_ref(), Some(&good), "what was refused was not taken up"); + p.reason_held(&req, good, "lab").unwrap(); + } + /// The word for a routed run names who it goes to, not only the name: another /// device under the same name and price, or the name pointed at another /// endpoint, is not what was confirmed. And what a person reads says what diff --git a/wai/wai-quantum/schemas/job-result.v1.json b/wai/wai-quantum/schemas/job-result.v1.json index 42ab4cf85..34dda8fa0 100644 --- a/wai/wai-quantum/schemas/job-result.v1.json +++ b/wai/wai-quantum/schemas/job-result.v1.json @@ -1623,7 +1623,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -1632,7 +1632,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, diff --git a/wai/wai-quantum/src/engine/planner/tests.rs b/wai/wai-quantum/src/engine/planner/tests.rs index fcb9c4177..e66c271a4 100644 --- a/wai/wai-quantum/src/engine/planner/tests.rs +++ b/wai/wai-quantum/src/engine/planner/tests.rs @@ -505,6 +505,8 @@ fn a_contract_s_plan_states_its_reasoning_in_its_schema() { assert_eq!(body["result"]["planner"]["kept"]["cost"]["kept"], true, "{}", body["result"]["planner"]["kept"]); assert_eq!(body["result"]["planner"]["kept"]["deadline"]["kept"], true); assert_eq!(body["result"]["planner"]["kept"]["deadline"]["seconds"].as_f64(), Some(30.0)); + // Every word a price can leave out is one its schema takes. + bad(r.check_value(&json!({ "$ref": "job-result.v1.json#/$defs/route_price/properties/leaves_out" }), &json!(LEFT_OUT)), "what a price leaves out"); // A refusal, with every route's reason. let refused = considered(&json!({ "qasm": ROT, "shots": 10, "contract": { "exactness": "bit-exact" } }), GIB); bad(r.check_value(&json!({ "$ref": "job-result.v1.json#/$defs/planner" }), &refused.reasoning), "the refused reasoning"); @@ -1301,6 +1303,18 @@ fn a_named_provider_s_routes_carry_the_class_their_shadow_has() { let mut broken = d.reasoning.clone(); broken["shadow"]["class"] = json!("estimate"); assert!(before_sending(&req, &broken, "qpu", 100).unwrap_err().contains("shadow")); + // A class the job's memory decides: with room only for a single-precision table, + // cut-rank's route has the class of the plan its shadow would have, not `exact`. + let wide = format!("OPENQASM 3.0;\nqubit[34] q;\nbit[34] c;\nh q[0];\n{}{}c = measure q;\n", (0..33).map(|i| format!("cx q[{i}], q[{}];\n", i + 1)).collect::(), (0..34).map(|i| format!("rx(pi/8) q[{i}];\n")).collect::()); + let req = json!({ "qasm": wide, "shots": 100, "provider": "qpu", "contract": { "providers": "allowed", "max_cost": { "amount": "1", "currency": "USD" } } }); + let (r, _) = catalog::read_in(reg(), &shadow_request(&req).unwrap()).unwrap(); + let pm = catalog::product_measured(&r, false).unwrap(); + let single = catalog::cutrank_bytes(&pm, crate::quantum_cutrank::Precision::Single); + assert!(single < catalog::cutrank_bytes(&pm, crate::quantum_cutrank::Precision::Double)); + let d = decide(reg(), &req, &Host::new(single).with_quotes(vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))])).unwrap(); + assert_eq!(route(&d.reasoning, "method:cutrank")["class"], "single", "{}", d.reasoning); + assert_eq!(d.reasoning["shadow"]["class"], "single", "{}", d.reasoning["shadow"]); + before_sending(&req, &d.reasoning, "qpu", 100).unwrap(); } /// A route states the class its table gives it, and depends on the host only as -- 2.54.0 (Apple Git-157) From 4cfaca16cd956773766fa7d84db25e2d6fcb847f Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sat, 7 Nov 2026 02:55:49 -0500 Subject: [PATCH 12/42] wai-quantum: the tool lists blessed with `cancel` in what a price leaves out Co-Authored-By: Claude Opus 5.5 --- wai/wai-quantum-cli/docs/local-mcp.json | 130 +++++++++++++--------- wai/wai-quantum-cli/docs/service-mcp.json | 130 +++++++++++++--------- 2 files changed, 156 insertions(+), 104 deletions(-) diff --git a/wai/wai-quantum-cli/docs/local-mcp.json b/wai/wai-quantum-cli/docs/local-mcp.json index 8d63f6bf6..43bfecf04 100644 --- a/wai/wai-quantum-cli/docs/local-mcp.json +++ b/wai/wai-quantum-cli/docs/local-mcp.json @@ -4492,7 +4492,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -4501,7 +4501,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -4740,7 +4741,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -4749,7 +4750,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -9188,7 +9190,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -9197,7 +9199,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -9436,7 +9439,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -9445,7 +9448,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -11594,7 +11598,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -11603,7 +11607,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -11842,7 +11847,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -11851,7 +11856,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -37343,7 +37349,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -37352,7 +37358,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -37591,7 +37598,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -37600,7 +37607,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -42039,7 +42047,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -42048,7 +42056,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -42287,7 +42296,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -42296,7 +42305,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -55423,7 +55433,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -55432,7 +55442,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -55671,7 +55682,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -55680,7 +55691,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -59891,7 +59903,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -59900,7 +59912,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -60139,7 +60152,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -60148,7 +60161,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -64587,7 +64601,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -64596,7 +64610,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -64835,7 +64850,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -64844,7 +64859,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -65700,7 +65716,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -65709,7 +65725,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -65948,7 +65965,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -65957,7 +65974,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -66430,7 +66448,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -66439,7 +66457,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -66678,7 +66697,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -66687,7 +66706,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -67123,7 +67143,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -67132,7 +67152,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -67371,7 +67392,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -67380,7 +67401,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -71617,7 +71639,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -71626,7 +71648,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -71865,7 +71888,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -71874,7 +71897,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -76313,7 +76337,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -76322,7 +76346,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -76561,7 +76586,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -76570,7 +76595,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, diff --git a/wai/wai-quantum-cli/docs/service-mcp.json b/wai/wai-quantum-cli/docs/service-mcp.json index ecbb32a2c..e69b1fc3d 100644 --- a/wai/wai-quantum-cli/docs/service-mcp.json +++ b/wai/wai-quantum-cli/docs/service-mcp.json @@ -4508,7 +4508,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -4517,7 +4517,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -4756,7 +4757,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -4765,7 +4766,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -9204,7 +9206,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -9213,7 +9215,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -9452,7 +9455,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -9461,7 +9464,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -10709,7 +10713,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -10718,7 +10722,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -10957,7 +10962,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -10966,7 +10971,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -17121,7 +17127,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -17130,7 +17136,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -17369,7 +17376,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -17378,7 +17385,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -21817,7 +21825,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -21826,7 +21834,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -22065,7 +22074,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -22074,7 +22083,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -23322,7 +23332,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -23331,7 +23341,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -23570,7 +23581,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -23579,7 +23590,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -26372,7 +26384,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -26381,7 +26393,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -26620,7 +26633,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -26629,7 +26642,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -31477,7 +31491,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -31486,7 +31500,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -31725,7 +31740,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -31734,7 +31749,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -36173,7 +36189,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -36182,7 +36198,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -36421,7 +36438,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -36430,7 +36447,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -37678,7 +37696,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -37687,7 +37705,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -37926,7 +37945,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -37935,7 +37954,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -56802,7 +56822,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -56811,7 +56831,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -57050,7 +57071,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -57059,7 +57080,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -61498,7 +61520,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -61507,7 +61529,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -61746,7 +61769,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -61755,7 +61778,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -62638,7 +62662,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -62647,7 +62671,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, @@ -62886,7 +62911,7 @@ } }, "leaves_out": { - "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates).", + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", "type": "array", "items": { "enum": [ @@ -62895,7 +62920,8 @@ "energy", "mitigation", "decoder", - "charged" + "charged", + "cancel" ] } }, -- 2.54.0 (Apple Git-157) From 3867b6ecefeb9d358799171236544fab7b22e44e Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sat, 7 Nov 2026 02:59:11 -0500 Subject: [PATCH 13/42] wai-quantum-cli: a key appears whole or not at all; an estimate at a ceiling refuses nothing Two processes starting together with no key: one created the file empty and wrote it, and the other read it empty, or found it there, and died. A fresh XDG_CONFIG_HOME in CI opens that window on every run. A key is now written beside its path and linked in, and the one that finds a key there reads it. The mutants of the second verifier found a rule nothing held: an estimate exactly at a ceiling is not past it. A crafted receipt and a self-test case hold it, and the self-test now holds what the corpus alone held of a stop. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/wai-quantum-cli.yml | 1 + ...6-11-06-wai-quantum-cli-energy-estimate.md | 3 + wai/quantum-conformance/receipts/generate.py | 1 + ...d-contract-energy-estimate-at-ceiling.json | 354 ++++++++++++++++++ .../receipts/manifest.json | 6 + .../tools/receipt_verify.py | 21 +- wai/wai-quantum-cli/src/keys.rs | 83 +++- 7 files changed, 453 insertions(+), 16 deletions(-) create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-energy-estimate-at-ceiling.json diff --git a/.github/workflows/wai-quantum-cli.yml b/.github/workflows/wai-quantum-cli.yml index c3c3c679f..b2c866720 100644 --- a/.github/workflows/wai-quantum-cli.yml +++ b/.github/workflows/wai-quantum-cli.yml @@ -126,6 +126,7 @@ jobs: estimates::tests::a_route_nothing_can_read_or_stop_has_no_watch \ estimates::tests::a_run_is_stopped_by_a_live_reading_at_its_ceiling \ estimates::tests::readings_are_kept_under_the_machine_reader_and_build \ + keys::tests::processes_starting_together_share_one_whole_key \ estimates::tests::a_run_is_read_only_where_something_needs_the_reading \ estimates::tests::the_wait_for_a_counter_is_in_no_run_s_power \ estimates::tests::a_package_counter_is_read_over_a_few_of_its_updates \ diff --git a/wai/changes/2026-11-06-wai-quantum-cli-energy-estimate.md b/wai/changes/2026-11-06-wai-quantum-cli-energy-estimate.md index 2311f4cf6..5cb160e08 100644 --- a/wai/changes/2026-11-06-wai-quantum-cli-energy-estimate.md +++ b/wai/changes/2026-11-06-wai-quantum-cli-energy-estimate.md @@ -27,5 +27,8 @@ - **What is read is read fairly.** The wait for a process's counter is in the energy and not in the time the power is taken over. A package counter is read over at least four of its updates, the step it can be short by added, and a reading past the time a counter can wrap twice is no reading. +- **Two processes making a key at once.** A new key was created empty and then written, so a process starting in that + moment read an empty file and died, or found the file there and died; a test that discards standard error saw only + silence. A key now appears whole or not at all, and the one that finds a key there reads it. - **Nothing is sealed that is not a reading.** A run that finished, read in its own process, is never a complete reading, so a result here still says its energy is unmetered, and a contract's `kept.energy` says it is not known. diff --git a/wai/quantum-conformance/receipts/generate.py b/wai/quantum-conformance/receipts/generate.py index c96825772..e065ff44b 100644 --- a/wai/quantum-conformance/receipts/generate.py +++ b/wai/quantum-conformance/receipts/generate.py @@ -852,6 +852,7 @@ def contract_cases(run, at, drop): add("energy-unwatched", edited(local, both(joules, route("method:statevector", unwatched("rejected", "energy_unwatched")))), [], "a route nothing can read while it runs, under a ceiling: refused, though its estimate is under it") add("energy-unwatched-claimed", edited(local, both(joules, route("method:statevector", unwatched("met")))), ["planner_route"], "a route nothing can stop, said to meet a ceiling") add("energy-over-estimate", edited(local, both(joules, route("method:statevector", lambda r: (r["price"]["energy"].update(joules=3), r.update(outcome="rejected"), r.update(rejected={"code": "energy", "why": "said so"}))))), [], "an estimate clearly past the ceiling refuses a watched route") + add("energy-estimate-at-ceiling", edited(local, both(joules, route("method:statevector", lambda r: r["price"]["energy"].update(joules=2)))), [], "an estimate exactly at the ceiling is not past it, and refuses nothing") add("energy-watch-form", edited(local, both(joules, route("method:statevector", lambda r: r["price"]["energy"].update(watch=True)))), ["planner_form"], "a watch that is no sentence") def stopped(b): diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-estimate-at-ceiling.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-estimate-at-ceiling.json new file mode 100644 index 000000000..3f6c4c4d9 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-energy-estimate-at-ceiling.json @@ -0,0 +1,354 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0, + "max_joules": 2 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": 2, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": false + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + }, + "energy": { + "max_joules": 2, + "joules": 2, + "kept": true + } + } + }, + "energy": { + "joules_micro": 2000000 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "fdffe2430bb7caf05f78894e831e7de1d472f4ce0704a54c2b86c2adcd411f86", + "signature": "520ac3748766d1cc5eda266885bdb88cb0dc33e3612561845b0112cd14f52a7510d0ceb7f6a97dcfb7d311bb6d9fef7628512b2eb542910bd22cafc671d16605" + } + } +} diff --git a/wai/quantum-conformance/receipts/manifest.json b/wai/quantum-conformance/receipts/manifest.json index 1ba31aae0..65821de3f 100644 --- a/wai/quantum-conformance/receipts/manifest.json +++ b/wai/quantum-conformance/receipts/manifest.json @@ -1702,6 +1702,12 @@ "made_by": "crafted", "what": "an estimate clearly past the ceiling refuses a watched route" }, + { + "file": "jobs/crafted-contract-energy-estimate-at-ceiling.json", + "reasons": [], + "made_by": "crafted", + "what": "an estimate exactly at the ceiling is not past it, and refuses nothing" + }, { "file": "jobs/crafted-contract-energy-watch-form.json", "reasons": [ diff --git a/wai/quantum-conformance/tools/receipt_verify.py b/wai/quantum-conformance/tools/receipt_verify.py index 3ac4459b2..93f33211d 100644 --- a/wai/quantum-conformance/tools/receipt_verify.py +++ b/wai/quantum-conformance/tools/receipt_verify.py @@ -2898,7 +2898,10 @@ def self_test(args): parts = path.split("__") for part in parts[:-1]: node = node[part] - node[parts[-1]] = value + if value is _DELETE: + del node[parts[-1]] + else: + node[parts[-1]] = value return _seal(seed, json.dumps(both["request"], separators=(",", ":")), json.dumps(both["result"], separators=(",", ":"))) def energy_routes(statevector): @@ -2908,6 +2911,13 @@ def self_test(args): _lr("mps", "heuristic", 60, "rejected", "class", memory=4096, joules=1.0)], "method:exact", "method:exact", False, {"energy": {"max_joules": 2, "joules": 2.0, "kept": True}}, energy={"joules_micro": 2000000}) + def read_and_not(): + r = _lr("statevector", "exact", 30, "met", memory=2048, joules=1.0) + r["price"]["energy"]["unwatched"] = "and yet" + return r + + check("a stop on a provider's run, which nothing here reads", "stopped" in reasons_of(stopped_body(result__method="provider"))) + def timed_by_host(kept): request, text = _local_contract_job({"exactness": "exact", "deadline_seconds": 60}, base(), "method:exact", "method:exact", True, kept) result = json.loads(text) @@ -2946,6 +2956,15 @@ def self_test(args): ("a stopped run that gives an answer", stopped_body(result__counts={"1": 4}), ["stopped"]), ("a stopped run said to have kept its ceiling", stopped_body(result__planner__kept__energy__kept=True), ["planner_kept"]), ("a run stopped with no ceiling", stopped_body(request__contract={"exactness": "exact"}), ["planner_kept", "planner_stable", "stopped"]), + ("a run stopped with no contract", stopped_body(request__contract=_DELETE), ["planner_form", "stopped"]), + ("a reading exactly at the ceiling stops a run", stopped_body(result__stopped__joules=2, result__planner__kept__energy__joules=2), []), + ("a stopped run that claims a class", stopped_body(result__accuracy__class="exact"), ["stopped"]), + ("a stop that does not say what read it", stopped_body(result__stopped__read=7), ["stopped"]), + ("a stop at a time that is no whole number", stopped_body(result__stopped__elapsed_ms=1.5), ["stopped"]), + ("a stop with a member its form does not have", stopped_body(result__stopped__note="more"), ["stopped"]), + ("a stop at something other than the energy ceiling", stopped_body(result__stopped__at="deadline"), ["stopped"]), + ("an estimate exactly at the ceiling refuses nothing", energy_routes(_lr("statevector", "exact", 30, "met", memory=2048, joules=2.0)), []), + ("a route said both to be read and to have no reading", energy_routes(read_and_not()), ["planner_form"]), # By hand: "1" 4 and 1 times, 5 pooled, E|2B - 5| = 1.875; half of it over 4. ("a shadow's counts short of its shots, the distance what they give", contract_body( result__shadow__counts={"1": 1}, diff --git a/wai/wai-quantum-cli/src/keys.rs b/wai/wai-quantum-cli/src/keys.rs index e71ffbfad..8eb2d9810 100644 --- a/wai/wai-quantum-cli/src/keys.rs +++ b/wai/wai-quantum-cli/src/keys.rs @@ -57,25 +57,48 @@ pub fn load(given: Option<&Path>, demo: bool) -> Result { Some(p) => p.clone(), 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 }) - } + load_at(&path, named.is_none()) +} + +/// The key at `path`, made there when there is none and `make`. +fn load_at(path: &Path, make: bool) -> Result { + match std::fs::read_to_string(path) { + Ok(text) => read(path, &text), + Err(e) if e.kind() == std::io::ErrorKind::NotFound && make => made(path), Err(e) => Err(format!("{}: {e}", path.display())), } } +fn read(path: &Path, text: &str) -> Result { + 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 }) +} + +/// A new key at `path`. Two processes can start together with none there, so a key +/// appears whole or not at all: it is written beside `path` and linked in, and the +/// one that finds a key there already reads that one. +fn made(path: &Path) -> Result { + let at = |e: std::io::Error| format!("{}: {e}", path.display()); + 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(); + let text = format!("{text}\n"); + let beside = path.with_extension(format!("{}-{:?}.new", std::process::id(), std::thread::current().id())); + write_private(&beside, &text).map_err(at)?; + let linked = std::fs::hard_link(&beside, path); + let _ = std::fs::remove_file(&beside); + match linked { + Ok(()) => {} + Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => return read(path, &std::fs::read_to_string(path).map_err(at)?), + // A file system with no links: as near as it can come. + Err(_) => write_private(path, &text).map_err(at)?, + } + Ok(Key { key: SigningKey::from_bytes(&seed), path: Some(path.to_path_buf()), made: true }) +} + fn write_private(path: &Path, text: &str) -> std::io::Result<()> { use std::io::Write as _; let mut f = std::fs::OpenOptions::new(); @@ -132,4 +155,34 @@ mod tests { } let _ = std::fs::remove_dir_all(&dir); } + + /// Processes that start together on a new machine share one key: none reads a + /// file half made, none is refused for finding one there, and exactly one made + /// it. Nothing is left beside it. + #[test] + fn processes_starting_together_share_one_whole_key() { + const AT_ONCE: usize = 8; + let dir = std::env::temp_dir().join(format!("wai-quantum-cli-keys-at-once-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(&dir).unwrap(); + for round in 0..100 { + let path = dir.join(format!("key-{round}")); + let gate = std::sync::Barrier::new(AT_ONCE); + let keys: Vec = std::thread::scope(|s| { + let going: Vec<_> = (0..AT_ONCE) + .map(|_| { + s.spawn(|| { + gate.wait(); + load_at(&path, true) + }) + }) + .collect(); + going.into_iter().map(|t| t.join().unwrap().unwrap_or_else(|e| panic!("round {round}: {e}"))).collect() + }); + assert_eq!(keys.iter().filter(|k| k.made).count(), 1, "round {round}"); + assert!(keys.iter().all(|k| k.key.to_bytes() == keys[0].key.to_bytes()), "round {round}"); + } + assert_eq!(std::fs::read_dir(&dir).unwrap().count(), 100, "nothing but the keys is left"); + let _ = std::fs::remove_dir_all(&dir); + } } -- 2.54.0 (Apple Git-157) From 2812bb708eec0443daa36b516a0eb6816225d36d Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sat, 7 Nov 2026 03:40:42 -0500 Subject: [PATCH 14/42] wai-quantum: the stop's tests close their gaps; clippy's two findings - A reading exactly at the ceiling stops a run, and its `kept` is false; a stop on a provider's result is refused. Two mutants survived without these. - The fake package counter's test takes a window again where a busy host starved its writer; every window still has to cover the updates probed. - A test that would skip on a Mac fails there instead, without a constant assertion; the service the stop's test starts is waited for. Co-Authored-By: Claude Opus 5.5 --- wai/wai-quantum-cli/src/estimates.rs | 8 +++++--- wai/wai-quantum-cli/tests/estimates.rs | 4 +++- wai/wai-quantum-service/tests/contract.rs | 6 +++++- wai/wai-quantum/src/engine/planner/tests.rs | 7 +++++++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/wai/wai-quantum-cli/src/estimates.rs b/wai/wai-quantum-cli/src/estimates.rs index 256c49a2d..a09110b1f 100644 --- a/wai/wai-quantum-cli/src/estimates.rs +++ b/wai/wai-quantum-cli/src/estimates.rs @@ -710,8 +710,10 @@ mod tests { // can starve it through a whole probe, which says nothing of what is tested. let open = || (0..20).find_map(|_| energy::Packages::open_in(&d).ok()).expect("the counter never ticked through a probe"); let p: &'static energy::Packages = Box::leak(Box::new(open())); - let around = Around { began: Instant::now(), before: Around::on(p) }; - let read = around.end(); + // Every window is over the updates the probe found; a window the writer was + // starved through reads nothing, as it should, so it is taken again. + let reads: Vec = std::iter::repeat_with(|| Around { began: Instant::now(), before: Around::on(p) }.end()).take(50).scan(false, |read, r| (!*read).then(|| { *read = r.joules.is_some(); r })).collect(); + let read = *reads.last().unwrap(); // A range one millisecond of the most a package draws can pass: the same // counter, and a window it can have wrapped twice in. std::fs::write(zone.join("max_energy_range_uj"), "1000000\n").unwrap(); @@ -722,7 +724,7 @@ mod tests { going.store(false, Ordering::Relaxed); ticking.join().unwrap(); assert!(read.joules.is_some() && read.watts().is_some(), "{read:?}"); - assert!(read.window_us >= p.probe.update_ns.saturating_mul(LEAST_UPDATES) / 1000, "{read:?} {:?}", p.probe); + assert!(reads.iter().all(|r| r.window_us >= p.probe.update_ns.saturating_mul(LEAST_UPDATES) / 1000), "{reads:?} {:?}", p.probe); assert_eq!(wrapped.joules, None, "{wrapped:?}"); // Standing still, it reads nothing: no reading of zero, and no step alone. let before = p.read().unwrap(); diff --git a/wai/wai-quantum-cli/tests/estimates.rs b/wai/wai-quantum-cli/tests/estimates.rs index 74815be0c..df34de0f6 100644 --- a/wai/wai-quantum-cli/tests/estimates.rs +++ b/wai/wai-quantum-cli/tests/estimates.rs @@ -61,7 +61,9 @@ const BUSY: &str = "OPENQASM 3.0;\nqubit[24] q;\nbit[24] c;\nrx(0.3) q[0];\nc = fn a_run_is_stopped_at_its_ceiling_by_a_live_reading_and_its_receipt_says_so() { let h = Home::new("ceiling"); if !reads_here(&h) { - assert!(!cfg!(target_os = "macos"), "a Mac reads its own process's energy, so this test may not pass by skipping"); + if cfg!(target_os = "macos") { + panic!("a Mac reads its own process's energy, so this test may not pass by skipping"); + } println!("nothing reads a run on this host: a route is refused under a ceiling, as the next test holds"); return; } diff --git a/wai/wai-quantum-service/tests/contract.rs b/wai/wai-quantum-service/tests/contract.rs index 20ba346d6..ee76c4d81 100644 --- a/wai/wai-quantum-service/tests/contract.rs +++ b/wai/wai-quantum-service/tests/contract.rs @@ -152,7 +152,10 @@ fn a_job_is_stopped_at_its_energy_ceiling_and_its_receipt_says_so() { if about["energy"]["meter"] == "unmetered" || about["energy"].get("meter").is_none() { println!("nothing reads a worker on this host: {}", about["energy"]); let _ = service.kill(); - assert!(!cfg!(target_os = "macos"), "a Mac reads its worker's energy, so this test may not pass by skipping"); + let _ = service.wait(); + if cfg!(target_os = "macos") { + panic!("a Mac reads its worker's energy, so this test may not pass by skipping"); + } return; } let slow = json!({ "qasm": "OPENQASM 3.0;\nqubit[24] q;\nbit[24] c;\nrx(0.3) q[0];\nc = measure q;\n", "method": "statevector", "shots": 1000000, "contract": { "max_joules": 0.01 } }); @@ -160,6 +163,7 @@ fn a_job_is_stopped_at_its_energy_ceiling_and_its_receipt_says_so() { assert_eq!(code, 202, "{made}"); let job = until_done(port, made["id"].as_str().unwrap()); let _ = service.kill(); + let _ = service.wait(); let _ = std::fs::remove_dir_all(&dir); assert_eq!(job["status"], "done", "{job}"); let r = &job["result"]; diff --git a/wai/wai-quantum/src/engine/planner/tests.rs b/wai/wai-quantum/src/engine/planner/tests.rs index 256d84546..b5d696d34 100644 --- a/wai/wai-quantum/src/engine/planner/tests.rs +++ b/wai/wai-quantum/src/engine/planner/tests.rs @@ -342,6 +342,13 @@ fn an_energy_ceiling_is_held_by_a_live_reading_and_a_stopped_run_says_so() { assert_eq!(reasons(&stopped), Vec::<&str>::new(), "{}", stopped["result"]); assert_eq!(stopped["result"]["planner"]["kept"]["energy"], json!({ "max_joules": 2.0, "joules": 2.25, "kept": false })); assert!(missed(&stopped["result"])); + // A reading exactly at the ceiling stops a run, and a stopped run kept nothing. + let mut at = stopped_result(reg(), &job, plan, &d.reasoning, &Stopped { joules: 2.0, elapsed_ms: 7, read: "a test's reading".into() }); + assert_eq!(at["planner"]["kept"]["energy"], json!({ "max_joules": 2.0, "joules": 2.0, "kept": false })); + complete(&mut at, &d.reasoning).unwrap(); + assert_eq!(reasons(&job::seal(&job, plan, at, &SigningKey::from_bytes(&[3; 32]), json!({ "unmetered": "a test" }))), Vec::<&str>::new()); + // Nothing here reads a provider's run, so none is stopped by a reading here. + assert!(reasons(&resealed(&stopped, |b| b["result"]["method"] = json!("provider"))).contains(&STOPPED)); cases(&stopped, vec![ (&[STOPPED], Box::new(|b| b["result"]["stopped"]["at"] = json!("deadline"))), (&[STOPPED], Box::new(|b| b["result"]["stopped"]["max_joules"] = json!(9))), -- 2.54.0 (Apple Git-157) From e5faff75387f68d25249ce793385947e2c7632d5 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sat, 7 Nov 2026 08:03:46 -0500 Subject: [PATCH 15/42] wai-quantum: a run under a ceiling is a process of its own, killed at the ceiling and read whole The third check of #670 found that a stop on the command line left the run computing while it re-read the program and sealed: a run passed its ceiling by up to five times, and the receipt said only the reading at the decision. A run that ended between two reads was sealed with its answer and kept.energy null. - The command line runs a job under a ceiling in a process of its own (`estimates::run_watched`), reads it about every 10 ms as the host schedules it, and kills it at the ceiling, so the work stops there. Its whole figure is read when it ends, killed or not, and sealed; a run past its ceiling that finished between two reads is sealed as having missed it (exit 4). - A stopped receipt says the longest time between two reads; a counter silent for a second of time, not a hundred reads, stops the run. On macOS the watching thread asks for the quality of service of work a person waits on. - A run that fails ends the watch at once; nothing hangs on a still counter. - The job service reads a stopped worker whole before it is reaped, and seals that figure; a Mac whose counter reads nothing gives no meter, so its routes are refused under a ceiling. - A stopped result has no member but those it is built with, in both verifiers: no verdict, outputs, mitigation or distribution beside it. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/wai-quantum-cli.yml | 2 +- .github/workflows/wai-quantum-service.yml | 3 +- ...6-11-06-wai-quantum-cli-energy-estimate.md | 11 +- wai/extensions/quantum-providers.md | 27 +- wai/quantum-conformance/receipts/generate.py | 2 + ...crafted-contract-stopped-with-outputs.json | 358 ++++++++++++++++++ ...crafted-contract-stopped-with-verdict.json | 358 ++++++++++++++++++ .../receipts/manifest.json | 16 + .../tools/receipt_verify.py | 4 +- wai/wai-quantum-cli/README.md | 2 +- wai/wai-quantum-cli/README.zh-CN.md | 2 +- wai/wai-quantum-cli/src/estimates.rs | 257 ++++++++----- wai/wai-quantum-cli/src/main.rs | 87 +++-- wai/wai-quantum-cli/src/providers.rs | 16 +- wai/wai-quantum-cli/tests/estimates.rs | 24 +- wai/wai-quantum-service/README.md | 2 +- wai/wai-quantum-service/src/energy.rs | 23 +- wai/wai-quantum-service/src/jobs.rs | 38 +- wai/wai-quantum-service/tests/contract.rs | 4 + wai/wai-quantum/src/engine/energy.rs | 119 +++--- wai/wai-quantum/src/engine/planner.rs | 6 +- 21 files changed, 1130 insertions(+), 231 deletions(-) create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-with-outputs.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-with-verdict.json diff --git a/.github/workflows/wai-quantum-cli.yml b/.github/workflows/wai-quantum-cli.yml index b2c866720..88dc9ad1d 100644 --- a/.github/workflows/wai-quantum-cli.yml +++ b/.github/workflows/wai-quantum-cli.yml @@ -124,7 +124,7 @@ jobs: estimates::tests::the_timings_keep_each_method_s_last_runs_and_read_back \ estimates::tests::three_runs_read_give_an_estimate_and_none_of_them_a_promise \ estimates::tests::a_route_nothing_can_read_or_stop_has_no_watch \ - estimates::tests::a_run_is_stopped_by_a_live_reading_at_its_ceiling \ + estimates::tests::a_run_in_its_own_process_is_killed_at_its_ceiling_and_read_whole \ estimates::tests::readings_are_kept_under_the_machine_reader_and_build \ keys::tests::processes_starting_together_share_one_whole_key \ estimates::tests::a_run_is_read_only_where_something_needs_the_reading \ diff --git a/.github/workflows/wai-quantum-service.yml b/.github/workflows/wai-quantum-service.yml index b19752dfe..b034ba83a 100644 --- a/.github/workflows/wai-quantum-service.yml +++ b/.github/workflows/wai-quantum-service.yml @@ -81,6 +81,7 @@ jobs: grep -qE '^test result: ok\. [1-9][0-9]* passed; 0 failed' "$RUNNER_TEMP/test.log" || { echo "::error::no test ran"; exit 1; } grep -q '^test the_service_gives_every_receipt_the_verdict_the_corpus_gives_it \.\.\. ok$' "$RUNNER_TEMP/test.log" || { echo "::error::the service was not held to the corpus of receipts"; exit 1; } grep -q '^test jobs::tests::a_route_s_figure_is_an_estimate_and_what_reads_the_run \.\.\. ok$' "$RUNNER_TEMP/test.log" || { echo "::error::the service's routes did not say what reads them"; exit 1; } + grep -q '^test energy::meter_tests::a_mac_whose_counter_reads_nothing_has_no_meter \.\.\. ok$' "$RUNNER_TEMP/test.log" || { echo "::error::a Mac that reads nothing was given a meter"; exit 1; } grep -q '^test a_job_is_stopped_at_its_energy_ceiling_and_its_receipt_says_so \.\.\. ok$' "$RUNNER_TEMP/test.log" || { echo "::error::the service did not stop a job at its ceiling"; exit 1; } # A job under a contract: met or refused with every route's reason, never routed to a # provider, stopped at its deadline, and its reasoning kept across a restart. @@ -109,7 +110,7 @@ jobs: engine::energy::tests::only_top_level_package_zones_are_read_and_a_frozen_one_is_not_live \ engine::energy::tests::a_package_figure_names_its_scope_and_declares_its_edges \ engine::energy::tests::a_host_s_estimate_rests_on_its_own_runs_and_says_whose \ - engine::energy::tests::a_live_reading_stops_at_the_ceiling_and_not_before \ + engine::energy::tests::a_live_reading_stops_at_the_ceiling_and_a_silent_second_loses_it \ engine::energy::tests::a_counter_s_reading_is_trusted_only_within_one_wrap \ qasm::tests::a_bound_parameter_reads_as_the_program_written_with_its_value; do grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/engine.log" || { echo "::error::$t did not run"; exit 1; } diff --git a/wai/changes/2026-11-06-wai-quantum-cli-energy-estimate.md b/wai/changes/2026-11-06-wai-quantum-cli-energy-estimate.md index 5cb160e08..ca0d5d1a4 100644 --- a/wai/changes/2026-11-06-wai-quantum-cli-energy-estimate.md +++ b/wai/changes/2026-11-06-wai-quantum-cli-energy-estimate.md @@ -1,12 +1,15 @@ ### wai-quantum: an energy ceiling is held by a live reading, and the command line can give one - **A `max_joules` is held while the job runs.** No figure before a run can promise what it will take: the work a plan - states leaves out what drives its time. So a live reading stops the run when it reaches the ceiling, on the command - line and in the service's worker, every ten milliseconds (`engine::energy::watch`). A run so stopped gives no answer, + states leaves out what drives its time. So the run is a process of its own, on the command line as in the service, + read about every ten milliseconds as the host schedules it and killed at the ceiling, so the work stops there + (`engine::energy::Watcher`). Its whole figure is read when it ends, killed or not, and sealed: a stopped receipt says + what the run took in all and the longest time between two reads, and a run that passed its ceiling between two reads + and finished is sealed as having missed it. A run so stopped gives no answer, its result has `stopped` and the accuracy class `none`, its `kept.energy` says the ceiling was not kept, it is sealed like any result, and a command line exits 4 (section 8.7, the new reason `stopped`, in both verifiers). A counter that - stops reading during a run leaves nothing holding the ceiling, so the run is stopped within about a second and nothing - is sealed. + stops reading for a second of time leaves nothing holding the ceiling, so the run is stopped and nothing is sealed; a + run that fails ends the watch at once. - **Where nothing can read and stop a run, the route is refused** under a ceiling, with why (`energy_unwatched`, the new route code): a host with no counter, a method on a device no counter reads, a provider, and a run in a process with other work in it, as an MCP or LSP server's is. A route states what would read it (`energy.watch`) or why nothing diff --git a/wai/extensions/quantum-providers.md b/wai/extensions/quantum-providers.md index de209aa40..1cf252f62 100644 --- a/wai/extensions/quantum-providers.md +++ b/wai/extensions/quantum-providers.md @@ -743,9 +743,10 @@ says so: `cancel` in `leaves_out`), runs on and can be billed; when it finishes, `kept.deadline` says it was missed. **What a ceiling measures, and how it is held.** `max_joules` is held by a live -reading, while the run goes: a host reads the route's `watch` every few milliseconds -and stops the run when the reading reaches the ceiling, and only a host that can stop -a run can give a route a `watch`. The reading is of what `watch` says, and of nothing +reading, while the run goes: a host runs the job in a process of its own, reads the +route's `watch` every few milliseconds as the host's scheduler allows, and kills that +process when the reading reaches the ceiling, so the work stops there; only a host +that can stop a run can give a route a `watch`. The reading is of what `watch` says, and of nothing else: a process's own CPU energy leaves out memory, the host's idle draw and any device it drives, so a method on a GPU or an accelerator has no `watch`; a processor package's counts every process on it, so a busy host stops a run sooner. A run can @@ -753,16 +754,22 @@ pass the ceiling by what it takes between two reads, and by what a counter has n yet shown. A host that runs a job inside a process doing other work, or that reads nothing, gives no `watch`, nor does a provider's route: the route is refused under a ceiling (`energy_unwatched`). A counter that stops reading during a run leaves nothing -holding the ceiling: the host stops the run within about a second, and seals nothing. +holding the ceiling: the host stops the run after a second of time without a reading, +and seals nothing. A host reads the run's process whole when it ends, killed or not, +and seals that figure in `energy`, so a run that passed its ceiling between two reads +and finished is sealed as having missed it. -A run so stopped gave no answer. Its result has none of `counts`, `expectations`, -`amplitudes`, `state_hash` and `distinct_outcomes`; its `accuracy.class` is `none`; +A run so stopped gave no answer. Its result has no member but `method`, `qubits`, +`gates`, `accuracy`, `stopped`, `elapsed_ms`, `planner`, `energy`, `engine`, `schema` +and `receipt`, so no counts, expectations, amplitudes, verdict, outputs, mitigation or +distribution of any kind; its `accuracy.class` is `none`; and it has `stopped`, an object of exactly `at`, the string `max_joules`; `joules`, what the reading had come to, a number at or above the ceiling; `max_joules`, the contract's; -`elapsed_ms`, a whole number; and `read`, a sentence saying what read it. It is sealed -like any result, its `kept.energy` says the ceiling was not kept, and a command line -exits 4. A result that did not stop may still state `kept.energy.joules` `null`: a -reading in a run's own process is not sealed. +`elapsed_ms`, a whole number; and `read`, a sentence saying what read it and the +longest time between two reads. It is sealed like any result, `energy` the whole +figure of the process killed where the host could read it, its `kept.energy` says the +ceiling was not kept, and a command line exits 4. A result whose energy was not read +whole states `kept.energy.joules` `null`. **The reasoning.** `planner` is an object of: diff --git a/wai/quantum-conformance/receipts/generate.py b/wai/quantum-conformance/receipts/generate.py index e065ff44b..37344c775 100644 --- a/wai/quantum-conformance/receipts/generate.py +++ b/wai/quantum-conformance/receipts/generate.py @@ -867,6 +867,8 @@ def contract_cases(run, at, drop): add("stopped-kept-claimed", edited(local, both(stopped, at(P + ("kept", "energy", "kept"), True))), ["planner_kept"], "a stopped run said to have kept its ceiling") add("stopped-under", edited(local, both(stopped, at(R + ("stopped", "joules"), 1.5), at(P + ("kept", "energy", "joules"), 1.5))), ["stopped"], "a run said stopped under its ceiling") add("stopped-with-counts", edited(local, both(stopped, at(R + ("counts",), {"00": 100}))), ["stopped"], "a stopped run that gives an answer") + add("stopped-with-verdict", edited(local, both(stopped, at(R + ("verdict",), {"holds": True}))), ["stopped"], "a stopped run that gives a verdict, an answer by another name") + add("stopped-with-outputs", edited(local, both(stopped, at(R + ("outputs",), {"x": 1}))), ["stopped"], "a stopped run that gives outputs") add("stopped-other-ceiling", edited(local, both(stopped, at(R + ("stopped", "max_joules"), 9))), ["stopped"], "a stop at a ceiling the contract does not give") add("stopped-at-ceiling", edited(local, both(stopped, at(R + ("stopped", "joules"), 2), at(P + ("kept", "energy", "joules"), 2))), [], "a reading exactly at the ceiling stops a run") add("stopped-class", edited(local, both(stopped, at(R + ("accuracy", "class"), "exact"))), ["stopped"], "a stopped run that claims a class") diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-with-outputs.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-with-outputs.json new file mode 100644 index 000000000..54d21e28f --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-with-outputs.json @@ -0,0 +1,358 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0, + "max_joules": 2 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "none", + "note": "stopped at its ceiling" + }, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": false + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + }, + "energy": { + "max_joules": 2, + "joules": 2.5, + "kept": false + } + } + }, + "energy": { + "unmetered": "stopped" + }, + "stopped": { + "at": "max_joules", + "joules": 2.5, + "max_joules": 2, + "elapsed_ms": 0, + "read": "a host's live reading" + }, + "outputs": { + "x": 1 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "6ee6afa1da2f9967cb3fd535c9217d78fbe885a3e1915cf9507ad31f589cd28e", + "signature": "b5949fd51d910e66108c279f93eed36a79e6498d7052adb1c8f6fb866ead8649846e2405f877f97f880e8f1b57e81fd2bdcca7abf76aa614692fa4805eaa7a0d" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-with-verdict.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-with-verdict.json new file mode 100644 index 000000000..c4a9dbde1 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-with-verdict.json @@ -0,0 +1,358 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0, + "max_joules": 2 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "none", + "note": "stopped at its ceiling" + }, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": false + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + }, + "energy": { + "max_joules": 2, + "joules": 2.5, + "kept": false + } + } + }, + "energy": { + "unmetered": "stopped" + }, + "stopped": { + "at": "max_joules", + "joules": 2.5, + "max_joules": 2, + "elapsed_ms": 0, + "read": "a host's live reading" + }, + "verdict": { + "holds": true + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "0de3887f607d3ddd75dbbe2caeb9c683f7354263ab1e7d3bbadf333aa16f630f", + "signature": "9e19a821b664944e918e0356d28982233e2f987f17aa08a0fb4a808fe4b1789d55df9098a2c5d0420eba9196d606ac8861c494e7991600b16b7904e33a630900" + } + } +} diff --git a/wai/quantum-conformance/receipts/manifest.json b/wai/quantum-conformance/receipts/manifest.json index 65821de3f..014756379 100644 --- a/wai/quantum-conformance/receipts/manifest.json +++ b/wai/quantum-conformance/receipts/manifest.json @@ -1746,6 +1746,22 @@ "made_by": "crafted", "what": "a stopped run that gives an answer" }, + { + "file": "jobs/crafted-contract-stopped-with-verdict.json", + "reasons": [ + "stopped" + ], + "made_by": "crafted", + "what": "a stopped run that gives a verdict, an answer by another name" + }, + { + "file": "jobs/crafted-contract-stopped-with-outputs.json", + "reasons": [ + "stopped" + ], + "made_by": "crafted", + "what": "a stopped run that gives outputs" + }, { "file": "jobs/crafted-contract-stopped-other-ceiling.json", "reasons": [ diff --git a/wai/quantum-conformance/tools/receipt_verify.py b/wai/quantum-conformance/tools/receipt_verify.py index 93f33211d..a845a72be 100644 --- a/wai/quantum-conformance/tools/receipt_verify.py +++ b/wai/quantum-conformance/tools/receipt_verify.py @@ -1654,7 +1654,7 @@ def _shadow_holds(request, contract, p, result): and _same(s.get("request"), plan.get("request")) and _same(s.get("shots"), result.get("shots"))) -ANSWERS = ("counts", "expectations", "amplitudes", "state_hash", "distinct_outcomes") +STOPPED_MEMBERS = ("method", "qubits", "gates", "accuracy", "stopped", "elapsed_ms", "planner", "energy", "engine", "schema", "receipt") def _stopped_holds(contract, result): @@ -1668,7 +1668,7 @@ def _stopped_holds(contract, result): return (s.get("at") == "max_joules" and _value_of(s.get("max_joules")) == j and x is not None and x >= j and _whole(s.get("elapsed_ms")) and s["elapsed_ms"].value >= 0 and isinstance(s.get("read"), str) and result.get("method") != "provider" and _member(result, "accuracy", "class") == "none" - and not any(k in result for k in ANSWERS)) + and all(k in STOPPED_MEMBERS for k in result)) def check_contract(request, result, reasons): diff --git a/wai/wai-quantum-cli/README.md b/wai/wai-quantum-cli/README.md index 9724af8b7..6985b3858 100644 --- a/wai/wai-quantum-cli/README.md +++ b/wai/wai-quantum-cli/README.md @@ -109,7 +109,7 @@ wai-quantum run circuit.qasm --method statevector --fabric cpu --fabric cpu --sh wai-quantum run prog.qasm --fabric a-member-elsewhere # exits 1 ``` -**Under a contract.** `--exactness CLASS`, `--deadline SECONDS`, `--max-cost 0.50:USD`, `--max-joules J` and `--allow-providers` (or `--contract` with the JSON of [the provider protocol's section 8.7](../extensions/quantum-providers.md)) say what the answer must be. The planner then prices every route it can see: each method here, at its memory and the time its work predicts, and with `--allow-providers` each of your own providers, by its own estimate and what that leaves out (each is asked, and sent nothing). It rejects every route that cannot meet the contract, runs the cheapest of the rest, and seals its reasoning in the receipt. An unknown never passes: a time nobody states does not meet a deadline, nor an unknown cost a ceiling, nor an estimate that is only the least a job can come to. Nothing falls back, from exact to approximate or between a simulator and a device, and with no route left the job is refused with every route's reason (`J071`). A contract that names no class keeps the class `auto` would give, and a device's counts are reached only by asking for `measured` (or `any`). A provider's answer carries a classical method's counts beside it, with their distance, wherever a method here can reach them in the time the contract leaves, and the receipt says why where none can. Under a contract no provider is asked anything without `--allow-providers` and a class one could give (`--exactness measured`, `simulated` or `any`), and one you name is refused without them (`J070`). A ceiling bounds the estimate a route is chosen by, not what is charged after, and confirms nothing: a run on a provider you name that is not free still takes `--yes`, and one the planner routes to a provider that is not free takes `--confirm WORD`, the word its `--dry-run` prints for that route, that provider and device, that estimate and that program, and is refused if any of them has changed when it would be sent. A deadline holds a method's own run time here, and a provider's from its submission to its counts; the command line cancels a provider's job still waiting at it (`J074`), and a job ends there only on the provider's word that it was cancelled: a provider that cannot cancel says so in its price, and its job stays waiting. A ceiling on energy is held by a live reading while the run goes: `--max-joules` reads the energy counter the engine reads (on macOS this process's own CPU energy, on Linux the processor packages', where you may read them) every ten milliseconds, and at the ceiling the run is stopped, gives no answer, says so, seals a receipt that says so, and exits 4. A counter that stops reading stops the run too, and nothing is sealed. No figure before a run can promise what it will take, since a job's work leaves out what drives its time. So a route nothing here can read and stop is refused and says why (`energy_unwatched`): no counter that reads here, a method on a GPU or an accelerator no counter here reads, a provider, and every run from a server, from `mcp` or from anything else with other work in its process, which a ceiling could not stop alone. Beside each route is an estimate, from the power and the time of that method's last runs read here, labelled one: it can refuse a job clearly past the ceiling (`energy`), and it promises nothing under it. Around a `run` the command line reads when a ceiling asks or the method has fewer than three runs read, and keeps the reading only on this machine, under this build's version, profile and features, in `$WAI_QUANTUM_TIMINGS`, or `$XDG_CONFIG_HOME/wai/quantum-timings.json`, or `~/.config/wai/quantum-timings.json` (`WAI_QUANTUM_TIMINGS=off` keeps none). The reading of a run that finished is not sealed, since a run read in its own process is not read completely. `plan` and `run` show the estimate and what would read the run. `wai-quantum plan` with the same options shows every route's price or reason and sends nothing; `wai-quantum verify --recheck` prices the routes again here and runs the shadow again; a run that kept less than its contract asked is still sealed, says so, and exits 4. +**Under a contract.** `--exactness CLASS`, `--deadline SECONDS`, `--max-cost 0.50:USD`, `--max-joules J` and `--allow-providers` (or `--contract` with the JSON of [the provider protocol's section 8.7](../extensions/quantum-providers.md)) say what the answer must be. The planner then prices every route it can see: each method here, at its memory and the time its work predicts, and with `--allow-providers` each of your own providers, by its own estimate and what that leaves out (each is asked, and sent nothing). It rejects every route that cannot meet the contract, runs the cheapest of the rest, and seals its reasoning in the receipt. An unknown never passes: a time nobody states does not meet a deadline, nor an unknown cost a ceiling, nor an estimate that is only the least a job can come to. Nothing falls back, from exact to approximate or between a simulator and a device, and with no route left the job is refused with every route's reason (`J071`). A contract that names no class keeps the class `auto` would give, and a device's counts are reached only by asking for `measured` (or `any`). A provider's answer carries a classical method's counts beside it, with their distance, wherever a method here can reach them in the time the contract leaves, and the receipt says why where none can. Under a contract no provider is asked anything without `--allow-providers` and a class one could give (`--exactness measured`, `simulated` or `any`), and one you name is refused without them (`J070`). A ceiling bounds the estimate a route is chosen by, not what is charged after, and confirms nothing: a run on a provider you name that is not free still takes `--yes`, and one the planner routes to a provider that is not free takes `--confirm WORD`, the word its `--dry-run` prints for that route, that provider and device, that estimate and that program, and is refused if any of them has changed when it would be sent. A deadline holds a method's own run time here, and a provider's from its submission to its counts; the command line cancels a provider's job still waiting at it (`J074`), and a job ends there only on the provider's word that it was cancelled: a provider that cannot cancel says so in its price, and its job stays waiting. A ceiling on energy is held by a live reading while the run goes: under `--max-joules` the run is a process of its own, which the command line reads about every ten milliseconds as the host schedules it (on macOS that process's CPU energy, on Linux the processor packages', where you may read them) and kills at the ceiling, so the work stops there; the run gives no answer, says so, seals a receipt that says so with what the run took in all and the longest time between two reads, and exits 4. A run that ends between two reads is read whole all the same, and one past its ceiling is sealed as having missed it and exits 4. A counter silent for a second stops the run too, and nothing is sealed. No figure before a run can promise what it will take, since a job's work leaves out what drives its time. So a route nothing here can read and stop is refused and says why (`energy_unwatched`): no counter that reads here, a method on a GPU or an accelerator no counter here reads, a provider, and every run from a server, from `mcp` or from anything else with other work in its process, which a ceiling could not stop alone. Beside each route is an estimate, from the power and the time of that method's last runs read here, labelled one: it can refuse a job clearly past the ceiling (`energy`), and it promises nothing under it. Around a `run` the command line reads when a ceiling asks or the method has fewer than three runs read, and keeps the reading only on this machine, under this build's version, profile and features, in `$WAI_QUANTUM_TIMINGS`, or `$XDG_CONFIG_HOME/wai/quantum-timings.json`, or `~/.config/wai/quantum-timings.json` (`WAI_QUANTUM_TIMINGS=off` keeps none). A run under a ceiling is read whole, in its own process, and that figure is sealed; a run without one is not, since a run read in the command line's own process is not read completely. `plan` and `run` show the estimate and what would read the run. `wai-quantum plan` with the same options shows every route's price or reason and sends nothing; `wai-quantum verify --recheck` prices the routes again here and runs the shadow again; a run that kept less than its contract asked is still sealed, says so, and exits 4. Each result names: diff --git a/wai/wai-quantum-cli/README.zh-CN.md b/wai/wai-quantum-cli/README.zh-CN.md index fcc4abc8d..f8679eeb0 100644 --- a/wai/wai-quantum-cli/README.zh-CN.md +++ b/wai/wai-quantum-cli/README.zh-CN.md @@ -112,7 +112,7 @@ wai-quantum run circuit.qasm --method statevector --fabric cpu --fabric cpu --sh wai-quantum run prog.qasm --fabric a-member-elsewhere # exits 1:别处的成员,被拒绝 ``` -**在契约之下。** `--exactness CLASS`、`--deadline SECONDS`、`--max-cost 0.50:USD`、`--max-joules J` 和 `--allow-providers`(或用 `--contract` 给出 [提供方协议第 8.7 节](../extensions/quantum-providers.md) 的 JSON)说明答案必须满足什么。规划器随后为它能看到的每条路径定价:本机的每个方法,按其内存和其工作量所预示的时间;加上 `--allow-providers` 时,还有你自己的每个提供方,按其自身的估算以及该估算未包含的内容(每个都会被询问,但不会发送任何东西)。它拒绝每条无法满足契约的路径,运行其余路径中最便宜的一条,并把它的推理封入收据。未知量从不算作满足:无人说明的时间不满足截止时间,未知的费用不满足上限,只是作业最低可能费用的估算也不满足。不会回退:既不会从精确退到近似,也不会在模拟器与设备之间互换;没有路径剩下时,作业被拒绝,并列出每条路径的原因(`J071`)。未指明类别的契约保留 `auto` 会给出的类别;只有请求 `measured`(或 `any`)才会用到设备的计数。提供方的答案旁边附有经典方法的计数及两者的距离,只要本机有方法能在契约留下的时间内得到它们;没有方法能做到时,收据会说明原因。在契约之下,没有 `--allow-providers` 以及提供方能够给出的类别(`--exactness measured`、`simulated` 或 `any`)时,不会询问任何提供方,你指定的提供方也会被拒绝(`J070`)。上限约束的是选择路径所依据的估算,而不是之后实际收取的费用,它也不构成确认:在你指定的提供方上运行、且不免费时,仍需要 `--yes`;规划器选到的提供方不免费时,需要 `--confirm WORD`,即它的 `--dry-run` 为该路径、该提供方和设备、该估算和该程序打印的词,发送时只要其中任何一项已有变化就会被拒绝。截止时间约束本机方法自身的运行时间,以及提供方从提交到得出计数的时间;命令行会在截止时取消仍在等待的提供方作业(`J074`),且只有提供方确认已取消时作业才在此结束:无法取消的提供方会在其价格中说明,其作业继续等待。能量上限由运行期间的实时读数来保证:`--max-joules` 每十毫秒读取一次引擎所读的能量计数器(macOS 上是本进程自身的 CPU 能量,Linux 上是你有权读取的处理器封装计数器),达到上限时运行被停止,不给出答案,如实说明,封存一份说明此事的收据,并以状态 4 退出。计数器停止读数时运行同样被停止,且不封存任何内容。运行之前的任何数字都无法保证它实际的能耗,因为作业的工作量并不包含决定其时间的全部因素。因此,本机无法读取并停止的路径会被拒绝并说明原因(`energy_unwatched`):此处没有可读的计数器、方法运行在此处没有计数器读取的 GPU 或加速器上、提供方,以及来自服务器、`mcp` 或其进程中还有其他工作的任何运行,上限无法单独停止它们。每条路径旁边有一个估算,来自该方法在本机最近读取过的运行的功率和时间,并标明是估算:它可以拒绝明显超过上限的作业(`energy`),但不对上限以下作任何保证。当有上限要求,或该方法读取过的运行少于三次时,命令行会在 `run` 前后读取,读数只保存在本机,按此构建的版本、配置和特性区分,存于 `$WAI_QUANTUM_TIMINGS`、`$XDG_CONFIG_HOME/wai/quantum-timings.json` 或 `~/.config/wai/quantum-timings.json` 中(`WAI_QUANTUM_TIMINGS=off` 表示不保存)。已完成运行的读数不封存,因为在自身进程内读取的运行读不完整。`plan` 和 `run` 会显示估算以及将由什么读取这次运行。带相同选项的 `wai-quantum plan` 显示每条路径的价格或原因,不发送任何东西;`wai-quantum verify --recheck` 在本机重新为路径定价并重新运行影子运行;未能满足契约全部要求的运行仍会被封存,并如实说明,退出状态为 4。 +**在契约之下。** `--exactness CLASS`、`--deadline SECONDS`、`--max-cost 0.50:USD`、`--max-joules J` 和 `--allow-providers`(或用 `--contract` 给出 [提供方协议第 8.7 节](../extensions/quantum-providers.md) 的 JSON)说明答案必须满足什么。规划器随后为它能看到的每条路径定价:本机的每个方法,按其内存和其工作量所预示的时间;加上 `--allow-providers` 时,还有你自己的每个提供方,按其自身的估算以及该估算未包含的内容(每个都会被询问,但不会发送任何东西)。它拒绝每条无法满足契约的路径,运行其余路径中最便宜的一条,并把它的推理封入收据。未知量从不算作满足:无人说明的时间不满足截止时间,未知的费用不满足上限,只是作业最低可能费用的估算也不满足。不会回退:既不会从精确退到近似,也不会在模拟器与设备之间互换;没有路径剩下时,作业被拒绝,并列出每条路径的原因(`J071`)。未指明类别的契约保留 `auto` 会给出的类别;只有请求 `measured`(或 `any`)才会用到设备的计数。提供方的答案旁边附有经典方法的计数及两者的距离,只要本机有方法能在契约留下的时间内得到它们;没有方法能做到时,收据会说明原因。在契约之下,没有 `--allow-providers` 以及提供方能够给出的类别(`--exactness measured`、`simulated` 或 `any`)时,不会询问任何提供方,你指定的提供方也会被拒绝(`J070`)。上限约束的是选择路径所依据的估算,而不是之后实际收取的费用,它也不构成确认:在你指定的提供方上运行、且不免费时,仍需要 `--yes`;规划器选到的提供方不免费时,需要 `--confirm WORD`,即它的 `--dry-run` 为该路径、该提供方和设备、该估算和该程序打印的词,发送时只要其中任何一项已有变化就会被拒绝。截止时间约束本机方法自身的运行时间,以及提供方从提交到得出计数的时间;命令行会在截止时取消仍在等待的提供方作业(`J074`),且只有提供方确认已取消时作业才在此结束:无法取消的提供方会在其价格中说明,其作业继续等待。能量上限由运行期间的实时读数来保证:在 `--max-joules` 之下,运行在独立的进程中进行,命令行大约每十毫秒(视主机调度而定)读取一次(macOS 上是该进程的 CPU 能量,Linux 上是你有权读取的处理器封装计数器),达到上限时立即终止该进程,工作随即停止;运行不给出答案,如实说明,封存一份说明此事的收据,其中写明运行总共耗用的能量以及两次读取之间的最长间隔,并以状态 4 退出。在两次读取之间结束的运行同样会被完整读取,超过上限的会被封存为未满足上限,并以状态 4 退出。计数器沉默一秒时运行同样被停止,且不封存任何内容。运行之前的任何数字都无法保证它实际的能耗,因为作业的工作量并不包含决定其时间的全部因素。因此,本机无法读取并停止的路径会被拒绝并说明原因(`energy_unwatched`):此处没有可读的计数器、方法运行在此处没有计数器读取的 GPU 或加速器上、提供方,以及来自服务器、`mcp` 或其进程中还有其他工作的任何运行,上限无法单独停止它们。每条路径旁边有一个估算,来自该方法在本机最近读取过的运行的功率和时间,并标明是估算:它可以拒绝明显超过上限的作业(`energy`),但不对上限以下作任何保证。当有上限要求,或该方法读取过的运行少于三次时,命令行会在 `run` 前后读取,读数只保存在本机,按此构建的版本、配置和特性区分,存于 `$WAI_QUANTUM_TIMINGS`、`$XDG_CONFIG_HOME/wai/quantum-timings.json` 或 `~/.config/wai/quantum-timings.json` 中(`WAI_QUANTUM_TIMINGS=off` 表示不保存)。在上限之下的运行在其独立进程中被完整读取,该数字会被封存;没有上限的运行则不封存,因为在命令行自身进程内读取的运行读不完整。`plan` 和 `run` 会显示估算以及将由什么读取这次运行。带相同选项的 `wai-quantum plan` 显示每条路径的价格或原因,不发送任何东西;`wai-quantum verify --recheck` 在本机重新为路径定价并重新运行影子运行;未能满足契约全部要求的运行仍会被封存,并如实说明,退出状态为 4。 每个结果都注明: diff --git a/wai/wai-quantum-cli/src/estimates.rs b/wai/wai-quantum-cli/src/estimates.rs index a09110b1f..84b061dcf 100644 --- a/wai/wai-quantum-cli/src/estimates.rs +++ b/wai/wai-quantum-cli/src/estimates.rs @@ -2,13 +2,16 @@ //! reading that holds a contract's `max_joules` (`--max-joules`) while it runs. //! //! No figure before a run can promise a ceiling: a job's work leaves out what -//! drives its time, and the same job read twice differs. So a ceiling is enforced -//! by the counter the engine reads (on macOS, this process's own CPU energy; on -//! Linux, the processor packages', where this user may read them), read every few -//! milliseconds around a `run`: at the ceiling the run is stopped, and its receipt -//! says so. Where nothing can read the run, or stop it, the route is refused under -//! a ceiling and says why: a method on a device no counter here reads, a host with -//! no counter that reads, or a server, whose process has other work in it. +//! drives its time, and the same job read twice differs. So a run under a ceiling +//! runs in a process of its own ([`run_watched`]), which this one reads about every +//! ten milliseconds as the host schedules it (on macOS that process's CPU energy; +//! on Linux the processor packages', where this user may read them) and kills at +//! the ceiling, so the work stops there. Its whole figure is read when it ends, +//! killed or not, and sealed; a stopped run's receipt says so, and the longest time +//! between two reads. Where nothing can read the run, or stop it, the route is +//! refused under a ceiling and says why: a method on a device no counter here +//! reads, a host with no counter that reads, or a server, which runs jobs in its +//! own process. //! //! What was read is kept, in `$WAI_QUANTUM_TIMINGS` (`off` keeps none), or //! `$XDG_CONFIG_HOME/wai/quantum-timings.json`, or @@ -20,16 +23,15 @@ //! reads: a server, a test or an embedded runner adds nothing to what is kept. A //! wasm build keeps no file and reads no counter. //! -//! A reading here is never sealed as a run's energy, only as what stopped it: what -//! a process reads of itself leaves out memory, the host's idle draw and any device -//! it drives, and the packages count every process on them. A result that finished -//! still says it is unmetered. +//! A run without a ceiling runs in this process, and a reading there is never +//! sealed: what a process reads of itself leaves out memory, the host's idle draw +//! and any device it drives, and the packages count every process on them. use serde_json::{Map, Value, json}; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use std::sync::OnceLock; -use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::atomic::{AtomicU64, Ordering}; use std::time::{Duration, Instant}; use wai_quantum::engine::catalog::Plan; use wai_quantum::engine::energy::{self, Held, TIMINGS, Timing}; @@ -88,9 +90,9 @@ fn identity() -> String { fn scope() -> String { let every = energy::WATCH_MS; if cfg!(target_os = "macos") { - format!("this process's own CPU energy, read every {every} ms; not memory or the host's idle draw") + format!("the CPU energy of the run's own process, read about every {every} ms as the host schedules it; not memory or the host's idle draw") } else { - format!("the processor packages' energy, read every {every} ms: every process on them, so a busy host stops a run sooner; not memory") + format!("the processor packages' energy, read about every {every} ms as the host schedules it: every process on them, so a busy host stops a run sooner; not memory") } } @@ -362,61 +364,136 @@ pub fn read_run(wanted: bool, run: impl FnOnce() -> T) -> (T, Read) { (out, around.end()) } -/// A reading of everything since it began, as it stands, or none where one does -/// not read. A package's counter is added up as it is read, so that a long run -/// wraps it as often as it likes. -fn live_reader() -> Option Option + Send>> { - if cfg!(target_os = "macos") { - let before = energy::own()?; - return Some(Box::new(move || energy::own().map(|now| now.joules() - before.joules()))); - } - let p = packages().as_ref().ok()?; - let first = p.read()?; - Some(Box::new(p.since(first))) +/// The argument a run under a ceiling is started with in its own process. +pub const WORKER: &str = "__run-under-a-ceiling"; + +/// How a run under a ceiling in its own process ended. +pub enum Ended { + /// It finished: what it wrote, its exit, its energy as a figure to seal, and + /// what was read of it. + Finished { out: Vec, err: Vec, status: std::process::ExitStatus, figure: Value, read: Read }, + /// It reached the ceiling and was killed: what stopped it, and its whole figure. + Stopped { stopped: planner::Stopped, figure: Value }, } -/// `run` under `ceiling` joules, its energy read as it goes by `read`: at the -/// ceiling `stop` is called, on the thread that read it, and is the end of the -/// process (the run has no other way to stop), and `lost` likewise where the -/// counter stops reading, since nothing then holds the ceiling. Otherwise the run's -/// answer. Whichever comes first has it: a run that finishes as the ceiling is -/// reached is not also stopped. -fn watching(ceiling: f64, read: impl FnMut() -> Option + Send, stop: impl FnOnce(planner::Stopped) + Send, lost: impl FnOnce() + Send, run: impl FnOnce() -> T + Send) -> T { - let done = AtomicBool::new(false); +/// What reads a run in its own process: on macOS that process's CPU energy, on +/// Linux the processor packages' since it began. None where nothing reads. +enum Meter { + Process, + Packages(&'static energy::Packages, energy::PackageSnapshot), +} + +/// `input` run by `exe WORKER` in its own process under `ceiling` joules: read every +/// [`energy::WATCH_MS`] as the host schedules this one, and killed at once at the +/// ceiling, so the work stops there; its whole figure is read after it ends, killed +/// or not, and sealed. A counter silent for a second stops it too ([`energy::Watcher`]). +pub fn run_watched(exe: &Path, input: &Value, ceiling: f64) -> Result { + use std::io::{Read as _, Write as _}; + use std::process::{Command, Stdio}; + raise_watch(); + let meter = if cfg!(target_os = "macos") { + energy::own().ok_or("this process's CPU energy counter does not read here")?; + Meter::Process + } else { + let p = packages().as_ref().map_err(String::clone)?; + Meter::Packages(p, p.read().ok_or("the processor packages' counter did not read")?) + }; let began = Instant::now(); - std::thread::scope(|s| { - let done = &done; - s.spawn(move || { - let end = energy::watch(read, ceiling, Duration::from_millis(energy::WATCH_MS), done); - if end == energy::Watched::Finished || done.swap(true, Ordering::AcqRel) { - return; - } - match end { - energy::Watched::Reached(joules) => stop(planner::Stopped { joules, elapsed_ms: u64::try_from(began.elapsed().as_millis()).unwrap_or(u64::MAX), read: scope() }), - _ => lost(), - } - }); - let out = run(); - // Stopping has begun: the process ends with it. - if done.swap(true, Ordering::AcqRel) { - loop { - std::thread::park(); + let mut child = Command::new(exe).arg(WORKER).stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn().map_err(|e| format!("the run's process did not start: {e}"))?; + let pid = child.id(); + if let Some(mut stdin) = child.stdin.take() { + let _ = stdin.write_all(input.to_string().as_bytes()); + } + let drain = |r: Option>| { + std::thread::spawn(move || { + let mut out = Vec::new(); + if let Some(mut r) = r { + let _ = r.read_to_end(&mut out); } + out + }) + }; + let out = drain(child.stdout.take().map(|o| Box::new(o) as Box)); + let err = drain(child.stderr.take().map(|e| Box::new(e) as Box)); + let mut since = match &meter { + Meter::Packages(p, before) => Some(p.since(before.clone())), + Meter::Process => None, + }; + let mut watcher = energy::Watcher::new(ceiling); + let whole = |reading: Option, after: Option| match &meter { + Meter::Process => (energy::figure(reading.as_ref(), false, "the run's process could not be read when it ended"), reading.map(|r| r.joules())), + Meter::Packages(p, before) => { + let r = after.and_then(|a| p.between(before, &a, 0)); + (energy::package_figure(r.as_ref(), "the processor packages' counter did not read when the run ended"), r.map(|r| r.energy_uj as f64 / 1e6)) } - out + }; + let ended = loop { + // Ended: read whole, then reaped (on macOS a process is readable whole + // between its exit and its reaping). + let exited = match &meter { + Meter::Process => energy::read(pid).map(Some), + Meter::Packages(..) => child.try_wait().map_err(|e| format!("the run's process could not be watched: {e}"))?.map(|_| None), + }; + if let Some(reading) = exited { + let after = match &meter { + Meter::Packages(p, _) => p.read(), + Meter::Process => None, + }; + let status = child.wait().map_err(|e| format!("the run's process could not be reaped: {e}"))?; + let (figure, joules) = whole(reading, after); + break Ended::Finished { out: Vec::new(), err: Vec::new(), status, figure, read: Read::over(began.elapsed(), joules) }; + } + let now = match &meter { + Meter::Process => energy::running(pid).map(|r| r.joules()), + Meter::Packages(..) => since.as_mut().and_then(|read| read()), + }; + match watcher.take(now) { + Some(energy::Watched::Reached(joules)) => { + let _ = child.kill(); + let elapsed_ms = u64::try_from(began.elapsed().as_millis()).unwrap_or(u64::MAX); + let reading = match &meter { + Meter::Process => (0..2000).find_map(|_| energy::read(pid).or_else(|| { + std::thread::sleep(Duration::from_millis(1)); + None + })), + Meter::Packages(..) => None, + }; + let _ = child.wait(); + let after = match &meter { + Meter::Packages(p, _) => p.read(), + Meter::Process => None, + }; + let (figure, _) = whole(reading, after); + break Ended::Stopped { stopped: planner::Stopped { joules, elapsed_ms, read: watcher.said(&scope()) }, figure }; + } + Some(energy::Watched::Lost) => { + let _ = child.kill(); + let _ = child.wait(); + return Err("the counter holding this run's energy ceiling stopped reading, so the run was stopped: nothing is sealed".into()); + } + None => std::thread::sleep(Duration::from_millis(energy::WATCH_MS)), + } + }; + let (o, e) = (out.join().unwrap_or_default(), err.join().unwrap_or_default()); + Ok(match ended { + Ended::Finished { status, figure, read, .. } => Ended::Finished { out: o, err: e, status, figure, read }, + stopped => stopped, }) } -/// `run` under `ceiling` joules, read live: at the ceiling `stop` is given what -/// stopped it. Otherwise its answer, and what was read of it, as any run is read. -/// `None` where nothing here reads: the planner has refused such a route. -pub fn under_ceiling(ceiling: f64, stop: impl FnOnce(planner::Stopped) + Send, run: impl FnOnce() -> T + Send) -> Option<(T, Read)> { - let read = live_reader()?; - let lost = || { - eprintln!("error: the counter holding this run's energy ceiling stopped reading, so the run was stopped: nothing is sealed"); - std::process::exit(1); - }; - Some(read_run(true, || watching(ceiling, read, stop, lost, run))) +/// On macOS, this thread's reads at the quality of service of work a person waits +/// on, so that the host does not put them off as it does a background thread's. +fn raise_watch() { + #[cfg(target_os = "macos")] + { + unsafe extern "C" { + fn pthread_set_qos_class_self_np(qos_class: u32, relative_priority: i32) -> i32; + } + /// `QOS_CLASS_USER_INTERACTIVE` in ``. + const USER_INTERACTIVE: u32 = 0x21; + // SAFETY: it sets this thread's own class, and takes no pointer. + let _ = unsafe { pthread_set_qos_class_self_np(USER_INTERACTIVE, 0) }; + } } /// A job body run here, read as `read`: kept beside the runs an estimate rests on, @@ -613,39 +690,37 @@ mod tests { let _ = std::fs::remove_dir_all(&d); } - /// A run under a ceiling is watched as it goes: at the ceiling it is stopped, with - /// what stopped it; finished first, it is left alone. A counter that stops - /// reading stops it too. + /// A run under a ceiling is a process of its own: at the ceiling it is killed at + /// once and read whole, the receipt saying the longest time between reads; one + /// that finishes is read whole too; one that fails ends the watch, whatever its + /// counter does. #[test] - fn a_run_is_stopped_by_a_live_reading_at_its_ceiling() { - use std::sync::mpsc::channel; - // Reaches it: the run does not finish, as in the command line, where `stop` ends the process. - let (told, heard) = channel(); - std::thread::spawn(move || { - let mut joules = 0.0; - watching(0.5, move || { joules += 0.2; Some(joules) }, move |s| told.send(s).unwrap(), || panic!("lost"), || loop { - std::thread::park(); - }); - }); - let s = heard.recv_timeout(Duration::from_secs(10)).unwrap(); - assert!(s.joules >= 0.5 && s.read == scope(), "{s:?}"); - // Finishes first. - let out = watching(1e9, || Some(0.25), |s| panic!("stopped: {s:?}"), || panic!("lost"), || { - std::thread::sleep(Duration::from_millis(3 * energy::WATCH_MS)); - 7 - }); - assert_eq!(out, 7); - // A counter that stops reading stops the run too: nothing holds its ceiling. - let (told, heard) = channel(); - std::thread::spawn(move || { - watching(0.5, || None, |s| panic!("stopped: {s:?}"), move || told.send(()).unwrap(), || loop { - std::thread::park(); - }); - }); - heard.recv_timeout(Duration::from_secs(10)).unwrap(); + fn a_run_in_its_own_process_is_killed_at_its_ceiling_and_read_whole() { + use std::os::unix::fs::PermissionsExt; + if unmetered(true).is_some() { + assert!(!cfg!(target_os = "macos"), "a Mac reads a process's own energy, so this test may not pass by skipping"); + return; + } + let d = dir("own-process"); + let script = |name: &str, body: &str| { + let p = d.join(name); + std::fs::write(&p, format!("#!/bin/sh\n{body}\n")).unwrap(); + std::fs::set_permissions(&p, std::fs::Permissions::from_mode(0o755)).unwrap(); + p + }; + let began = Instant::now(); + let Ended::Stopped { stopped, figure } = run_watched(&script("busy", "while :; do :; done"), &json!({}), 0.05).unwrap() else { panic!("a busy run was not stopped") }; + assert!(began.elapsed() < Duration::from_secs(30)); + assert!(stopped.joules >= 0.05 && stopped.read.contains("the longest time between two reads was"), "{stopped:?}"); + let whole = figure["joules_micro"].as_u64().map(|u| u as f64 / 1e6); + assert!(whole.is_some_and(|w| w >= stopped.joules), "read whole after the kill, and no less than what stopped it: {figure} {stopped:?}"); + let Ended::Finished { status, .. } = run_watched(&script("fails", "exit 101"), &json!({}), 1e9).unwrap() else { panic!("a failed run said stopped") }; + assert_eq!(status.code(), Some(101)); + let Ended::Finished { out, status, figure, .. } = run_watched(&script("quick", "cat > /dev/null; echo done"), &json!({ "x": 1 }), 1e9).unwrap() else { panic!("a quick run said stopped") }; + assert!(status.success() && out == b"done\n" && figure.is_object(), "{figure}"); + let _ = std::fs::remove_dir_all(&d); } - /// A run is read where a ceiling or an estimate needs it, and otherwise the /// counter costs it nothing. #[test] fn a_run_is_read_only_where_something_needs_the_reading() { diff --git a/wai/wai-quantum-cli/src/main.rs b/wai/wai-quantum-cli/src/main.rs index 311d5e5ef..e65835295 100644 --- a/wai/wai-quantum-cli/src/main.rs +++ b/wai/wai-quantum-cli/src/main.rs @@ -956,10 +956,11 @@ fn request(job: &Job, qasm: String) -> Value { r } -/// What a result says of its energy: the command line seals no reading of a -/// run (one read in its own process is never complete), and keeps what it reads -/// only to bound later runs by (estimates). -pub(crate) const UNMETERED: &str = "the command line seals no reading of a run's energy: a run in its own process cannot be read completely, so what it reads of a run only holds its ceiling and estimates later runs"; +/// What a result says of its energy, run in this process: no reading of it is +/// sealed (one read in its own process is never complete), and what is read of it +/// is kept for estimates. A run under a ceiling runs in a process of its own, read +/// whole, and its figure is sealed ([`run_under_ceiling`]). +pub(crate) const UNMETERED: &str = "the command line seals no reading of a run in its own process: one read there cannot be read completely, so what it reads of it only estimates later runs"; /// The exit status of a run that kept not all its contract asked: a deadline, a /// ceiling on energy or on cost, as the result states. Its answer is sealed. @@ -979,22 +980,56 @@ pub fn run_here(req: &Value, memory_gb: u64, key: &wai_quantum::ed25519_dalek::S job::run_with(req, memory_gb << 30, key, json!({ "unmetered": UNMETERED }), Some(&joules)) } -/// A run stopped at its ceiling: its receipt shown, said so, and this process ended, -/// which is what stops it. `reasoning` is why this route ran. -pub(crate) fn stop_at_ceiling(req: &Value, plan: &catalog::Plan, reasoning: &Value, stopped: wai_quantum::engine::planner::Stopped, key: &wai_quantum::ed25519_dalek::SigningKey, show: &(dyn Fn(&Value) + Sync)) { +/// `req` on `plan` under `ceiling` joules, in a process of its own that this one +/// reads and kills at the ceiling ([`estimates::run_watched`]): sealed with `key`, +/// its whole figure in it, whether it finished or was stopped (then with no answer, +/// and a receipt that says so). `reasoning` is why this route ran. What was read of +/// a run that finished is returned to be kept. +pub(crate) fn run_under_ceiling(req: &Value, plan: &catalog::Plan, reasoning: &Value, ceiling: f64, key: &wai_quantum::ed25519_dalek::SigningKey) -> Result<(Value, estimates::Read), String> { use wai_quantum::engine::{planner, registry::Registry}; - let joules = stopped.joules; - let result = planner::stopped_result(Registry::builtins(), req, plan, reasoning, &stopped); - let body = job::seal(req, plan, result, key, json!({ "unmetered": UNMETERED })); - show(&body); - eprintln!("note: stopped at its ceiling: a live reading came to {joules} J, and the run gave no answer"); - std::process::exit(CONTRACT_MISSED); + let exe = std::env::current_exe().map_err(|e| format!("this command line could not find itself to run the job: {e}"))?; + let input = json!({ "request": req, "plan": plan, "reasoning": reasoning }); + match estimates::run_watched(&exe, &input, ceiling)? { + estimates::Ended::Stopped { stopped, figure } => { + eprintln!("note: stopped at its ceiling: a live reading came to {} J, and the run's process was killed there and gave no answer", stopped.joules); + let result = planner::stopped_result(Registry::builtins(), req, plan, reasoning, &stopped); + Ok((job::seal(req, plan, result, key, figure), estimates::Read::default())) + } + estimates::Ended::Finished { out, err, status, figure, read } => { + let r: Value = serde_json::from_slice(&out).map_err(|_| { + let said = String::from_utf8_lossy(&err); + format!("the run's process ended ({status}) with no result{}", said.lines().last().map(|l| format!(": {l}")).unwrap_or_default()) + })?; + if let Some(e) = r.get("error").and_then(Value::as_str) { + return Err(e.to_string()); + } + planner::own_check(req, &r)?; + Ok((job::seal(req, plan, r, key, figure), read)) + } + } } -/// The `run` command's job, this process's one run: under a ceiling, read live and -/// stopped at it, with `show` shown its receipt; otherwise read around where an +/// A run under a ceiling, in the process [`run_under_ceiling`] started for it: the +/// request, the plan and the reasoning on standard input, the result, or +/// `{"error"}`, on standard output. +fn worker() { + use std::io::Read as _; + use wai_quantum::engine::{planner, registry::Registry}; + let mut input = String::new(); + let out = match std::io::stdin().read_to_string(&mut input).map_err(|e| e.to_string()).and_then(|_| serde_json::from_str::(&input).map_err(|e| e.to_string())) { + Ok(v) => match serde_json::from_value::(v["plan"].clone()) { + Ok(plan) => planner::run_chosen(Registry::builtins(), &v["request"], &plan, &v["reasoning"]).unwrap_or_else(|e| json!({ "error": e })), + Err(e) => json!({ "error": format!("the job's plan does not read: {e}") }), + }, + Err(e) => json!({ "error": format!("the job did not arrive: {e}") }), + }; + println!("{out}"); +} + +/// The `run` command's job, this process's one run: under a ceiling, in a process of +/// its own read live and killed at the ceiling; otherwise read around where an /// estimate needs it. What was read is kept. -fn run_read(req: &Value, memory_gb: u64, key: &wai_quantum::ed25519_dalek::SigningKey, show: &(dyn Fn(&Value) + Sync)) -> Result { +fn run_read(req: &Value, memory_gb: u64, key: &wai_quantum::ed25519_dalek::SigningKey) -> Result { use wai_quantum::engine::{planner, registry::Registry}; if catalog::is_set(req) { return run_here(req, memory_gb, key); @@ -1013,13 +1048,7 @@ fn run_read(req: &Value, memory_gb: u64, key: &wai_quantum::ed25519_dalek::Signi let reg = Registry::builtins(); let d = planner::decide(reg, req, &planner::Host::new(memory_gb << 30).with_joules(&joules))?; let planner::Choice::Local(plan) = &d.choice else { return Err("internal: a provider chosen with none brought".into()) }; - let (out, read) = estimates::under_ceiling(ceiling, |s| stop_at_ceiling(req, plan, &d.reasoning, s, key, show), || { - let r = planner::run_chosen(reg, req, plan, &d.reasoning)?; - planner::own_check(req, &r)?; - Ok::(job::seal(req, plan, r, key, unmetered.clone())) - }) - .ok_or("the counter that was to read this run does not read now: nothing was run")?; - let body = out?; + let (body, read) = run_under_ceiling(req, plan, &d.reasoning, ceiling, key)?; estimates::keep(&body, &read); Ok(body) } @@ -1389,6 +1418,9 @@ fn convert(file: Option<&Path>, to: wai_quantum::engine::formats::Format, profil fn main() { // The help a parse prints is in the person's language, so the language is read first. let args: Vec = std::env::args().collect(); + if args.get(1).map(String::as_str) == Some(estimates::WORKER) { + return worker(); + } let loc = locale::resolve(locale::arg_lang(&args).as_deref()); locale::set(loc); let cli = Cli::from_arg_matches(&locale::localize(Cli::command(), loc).get_matches_from(&args)).unwrap_or_else(|e| e.exit()); @@ -1400,14 +1432,7 @@ fn main() { Command::Run { job, out, key, .. } => { let req = job_request(&job).unwrap_or_else(|e| die(&e)); let k = load_key(&key); - let show = |body: &Value| { - if out.json { - println!("{body}"); - } else { - print_job(body, out.top); - } - }; - let body = match run_read(&req, job.memory_gb, &k.key, &show) { + let body = match run_read(&req, job.memory_gb, &k.key) { Ok(b) => b, // A job that asked for a verdict is refused with one. Err(e) if wai_quantum::engine::verdict::asked(&req) || job.repair => { diff --git a/wai/wai-quantum-cli/src/providers.rs b/wai/wai-quantum-cli/src/providers.rs index a4994ce84..e40f3f9b6 100644 --- a/wai/wai-quantum-cli/src/providers.rs +++ b/wai/wai-quantum-cli/src/providers.rs @@ -353,19 +353,15 @@ fn run_routed(job: &Job, out: &Output, key: &KeyArgs, args: &RunArgs) { let k = load_key(key); let Some(name) = routed.provider().map(str::to_string) else { let unmetered = json!({ "unmetered": crate::UNMETERED }); - let run = || pjob::run_routed_here(&routed, &req, &k.key, unmetered.clone()); - let show = |body: &Value| { - if out.json { - println!("{body}"); - } else { - print_job(body, out.top); - } - }; + let run = || pjob::run_routed_here(&routed, &req, &k.key, unmetered.clone()).map_err(|e| e.to_string()); let (body, read) = match (crate::estimates::ceiling(&req), &routed.choice) { - (Some(ceiling), wai_quantum::engine::planner::Choice::Local(plan)) => crate::estimates::under_ceiling(ceiling, |s| crate::stop_at_ceiling(&req, plan, &routed.reasoning, s, &k.key, &show), run).unwrap_or_else(|| die("the counter that was to read this run does not read now: nothing was run")), + (Some(ceiling), wai_quantum::engine::planner::Choice::Local(plan)) => match crate::run_under_ceiling(&req, plan, &routed.reasoning, ceiling, &k.key) { + Ok((body, read)) => (Ok(body), read), + Err(e) => (Err(e), crate::estimates::Read::default()), + }, _ => crate::estimates::read_run(crate::estimates::wanted(&book, &req, job.memory_gb << 30), run), }; - let body = body.unwrap_or_else(|e| die(&e.to_string())); + let body = body.unwrap_or_else(|e| die(&e)); crate::estimates::keep(&body, &read); if out.json { println!("{body}"); diff --git a/wai/wai-quantum-cli/tests/estimates.rs b/wai/wai-quantum-cli/tests/estimates.rs index df34de0f6..6a262d2db 100644 --- a/wai/wai-quantum-cli/tests/estimates.rs +++ b/wai/wai-quantum-cli/tests/estimates.rs @@ -55,8 +55,9 @@ fn reads_here(h: &Home) -> bool { const BUSY: &str = "OPENQASM 3.0;\nqubit[24] q;\nbit[24] c;\nrx(0.3) q[0];\nc = measure q;\n"; -/// A ceiling is held by a live reading: under it a job runs, at it the run is -/// stopped, with no answer and a receipt that says so, and the command exits 4. +/// A ceiling is held by a live reading of the run's own process: under it a job +/// runs and its whole figure is sealed; at it the process is killed, with no answer +/// and a receipt that says so and what the run took in all, and the command exits 4. #[test] fn a_run_is_stopped_at_its_ceiling_by_a_live_reading_and_its_receipt_says_so() { let h = Home::new("ceiling"); @@ -71,9 +72,10 @@ fn a_run_is_stopped_at_its_ceiling_by_a_live_reading_and_its_receipt_says_so() { assert_eq!(out.status.code(), Some(0), "{}", String::from_utf8_lossy(&out.stderr)); let body: Value = serde_json::from_slice(&out.stdout).unwrap(); let p = &body["result"]["planner"]; - assert!(route(p, "method:stabilizer")["price"]["energy"]["watch"].as_str().unwrap().contains("read every"), "{p}"); - assert!(body["result"]["energy"]["unmetered"].as_str().unwrap().contains("seals no reading"), "{}", body["result"]["energy"]); - assert!(p["kept"]["energy"]["kept"].is_null(), "{}", p["kept"]); + assert!(route(p, "method:stabilizer")["price"]["energy"]["watch"].as_str().unwrap().contains("read about every"), "{p}"); + let whole = body["result"]["energy"]["joules_micro"].as_u64().map(|u| u as f64 / 1e6); + assert!(whole.is_some(), "a run under a ceiling is read whole: {}", body["result"]["energy"]); + assert_eq!(p["kept"]["energy"]["kept"], true, "{}", p["kept"]); // A job that takes seconds, under a ceiling it reaches at once. std::fs::write(h.0.join("busy.qasm"), BUSY).unwrap(); let began = std::time::Instant::now(); @@ -84,7 +86,9 @@ fn a_run_is_stopped_at_its_ceiling_by_a_live_reading_and_its_receipt_says_so() { assert!(said.contains("stopped at its ceiling"), "{said}"); let body: Value = serde_json::from_slice(&out.stdout).unwrap(); let r = &body["result"]; - assert!(r["stopped"]["joules"].as_f64().unwrap() >= 0.01 && r["stopped"]["read"].as_str().unwrap().contains("read every") && r.get("counts").is_none(), "{r}"); + assert!(r["stopped"]["joules"].as_f64().unwrap() >= 0.01 && r["stopped"]["read"].as_str().unwrap().contains("the longest time between two reads") && r.get("counts").is_none(), "{r}"); + let whole = r["energy"]["joules_micro"].as_u64().map(|u| u as f64 / 1e6); + assert!(whole.is_some_and(|w| w >= r["stopped"]["joules"].as_f64().unwrap()), "what the killed run took in all is sealed: {}", r["energy"]); assert_eq!((r["planner"]["kept"]["energy"]["kept"].as_bool(), r["accuracy"]["class"].as_str()), (Some(false), Some("none")), "{r}"); std::fs::write(h.0.join("job.json"), body.to_string()).unwrap(); let v = h.run(&["verify", "job.json", "--json"]); @@ -98,6 +102,14 @@ fn a_run_is_stopped_at_its_ceiling_by_a_live_reading_and_its_receipt_says_so() { let out = h.run(&["run", "busy.qasm", "--shots", "1000000", "--exactness", "any", "--allow-providers", "--max-joules", "0.01", "--demo-key", "--json"]); assert_eq!(out.status.code(), Some(4), "{}", String::from_utf8_lossy(&out.stderr)); assert!(serde_json::from_slice::(&out.stdout).unwrap()["result"]["stopped"].is_object()); + // A run that ends between two reads is read whole all the same: past its + // ceiling it is sealed as having missed it, and the command exits 4. + for _ in 0..3 { + let out = h.run(&["run", "bell.qasm", "--shots", "100", "--exactness", "exact", "--max-joules", "0.000001", "--demo-key", "--json"]); + let body: Value = serde_json::from_slice(&out.stdout).unwrap(); + let kept = &body["result"]["planner"]["kept"]["energy"]; + assert_eq!((out.status.code(), kept["kept"].as_bool()), (Some(4), Some(false)), "{kept} {}", body["result"]["energy"]); + } // Read and kept, as what an estimate rests on. let kept: Value = serde_json::from_str(&std::fs::read_to_string(h.timings()).unwrap()).unwrap(); assert!(kept["machines"].as_object().unwrap().values().next().unwrap().as_object().is_some_and(|m| !m.is_empty()), "{kept}"); diff --git a/wai/wai-quantum-service/README.md b/wai/wai-quantum-service/README.md index 4a6a8cafd..629a9c125 100644 --- a/wai/wai-quantum-service/README.md +++ b/wai/wai-quantum-service/README.md @@ -104,7 +104,7 @@ How the methods run: ### Under a contract -A job may carry a `contract`: the class wanted, a deadline, a cost ceiling, an energy ceiling, and whether a provider may be used ([section 8.7](../extensions/quantum-providers.md) of the provider protocol). The service prices each method here for it, rejects those that cannot meet it, runs the cheapest of the rest and seals its reasoning in the receipt. A job no method here meets is refused at once, and in a dry run, with every method's reason (`J071`). The service reaches no provider: none is among its routes, whatever the contract allows, and a contract that wants a device's counts is refused. A dry run's energy is an estimate from what it has metered, and it promises nothing. A `max_joules` is held by a live reading of the worker while it runs, every ten milliseconds: at the ceiling the worker is killed and a receipt is sealed that says so, with no answer in it. A route on a host or a device nothing here reads is refused under a ceiling (`energy_unwatched`), and an estimate clearly past the ceiling refuses a job before it runs (`energy`). A run past its contract's deadline is stopped (`J074`), and nothing is sealed. A queued job keeps the reasoning it was admitted with across a restart. A contract is one job's: a set refuses one (`J073`). +A job may carry a `contract`: the class wanted, a deadline, a cost ceiling, an energy ceiling, and whether a provider may be used ([section 8.7](../extensions/quantum-providers.md) of the provider protocol). The service prices each method here for it, rejects those that cannot meet it, runs the cheapest of the rest and seals its reasoning in the receipt. A job no method here meets is refused at once, and in a dry run, with every method's reason (`J071`). The service reaches no provider: none is among its routes, whatever the contract allows, and a contract that wants a device's counts is refused. A dry run's energy is an estimate from what it has metered, and it promises nothing. A `max_joules` is held by a live reading of the worker while it runs, about every ten milliseconds as the host schedules the service: at the ceiling the worker is killed, read whole before it is reaped where the host allows, and a receipt is sealed that says so, with no answer in it, the worker's whole figure and the longest time between two reads. A Mac whose counter reads nothing for a process (an Intel one) reads no worker, so its routes are refused under a ceiling. A route on a host or a device nothing here reads is refused under a ceiling (`energy_unwatched`), and an estimate clearly past the ceiling refuses a job before it runs (`energy`). A run past its contract's deadline is stopped (`J074`), and nothing is sealed. A queued job keeps the reasoning it was admitted with across a restart. A contract is one job's: a set refuses one (`J073`). ### Programs that measure in the middle diff --git a/wai/wai-quantum-service/src/energy.rs b/wai/wai-quantum-service/src/energy.rs index 2dcdd5219..9002e0128 100644 --- a/wai/wai-quantum-service/src/energy.rs +++ b/wai/wai-quantum-service/src/energy.rs @@ -57,7 +57,7 @@ pub fn meter() -> &'static Meter { if std::env::var("WAI_QSVC_ENERGY").is_ok_and(|v| v == "0") { Meter::Unmetered("the service was started with energy metering off (WAI_QSVC_ENERGY=0)".into()) } else if cfg!(target_os = "macos") { - Meter::Process + mac_meter(wai_quantum::engine::energy::own().is_some()) } else if cfg!(target_os = "linux") { match Packages::open() { Ok(p) => Meter::Packages(p), @@ -69,6 +69,27 @@ pub fn meter() -> &'static Meter { }) } +/// A Mac's meter, by whether this process's own counter reads: one that reads +/// nothing (an Intel Mac's) gives no live reading, so no route a `watch`. +fn mac_meter(reads: bool) -> Meter { + if reads { + Meter::Process + } else { + Meter::Unmetered("this Mac's CPU energy counter reads nothing for a process here".into()) + } +} + +#[cfg(test)] +mod meter_tests { + /// A Mac whose counter reads nothing is no meter, so a contract's ceiling is + /// refused there rather than admitted and lost a second into the run. + #[test] + fn a_mac_whose_counter_reads_nothing_has_no_meter() { + assert!(matches!(super::mac_meter(false), super::Meter::Unmetered(_))); + assert!(matches!(super::mac_meter(true), super::Meter::Process)); + } +} + /// Whether child `pid` has exited, without reaping it: `Some(true)` once it /// has (it is then readable by [`read`] until reaped), `Some(false)` while it /// runs, `None` where this cannot be told (off macOS, or the wait failed), in diff --git a/wai/wai-quantum-service/src/jobs.rs b/wai/wai-quantum-service/src/jobs.rs index a1745021f..e3c0b74e2 100644 --- a/wai/wai-quantum-service/src/jobs.rs +++ b/wai/wai-quantum-service/src/jobs.rs @@ -1196,6 +1196,7 @@ impl Service { }; let mut watcher = ceiling.map(wai_quantum::engine::energy::Watcher::new); let mut stopped = None; + let mut stopped_figure = Value::Null; let mut peak = 0u64; let mut reading = None; let mut after = None; @@ -1237,12 +1238,37 @@ impl Service { match w.take(now) { Some(wai_quantum::engine::energy::Watched::Reached(joules)) => { kill(pid); - let _ = child.wait().await; - let read = match meter { - energy::Meter::Process => "the CPU energy of the job's worker", - _ => "the processor packages' energy over the job's window: every process on them", + let elapsed_ms = began.elapsed().as_millis() as u64; + // What the worker took in all, read after the kill and before + // it is reaped, where it can be. + stopped_figure = match meter { + energy::Meter::Process => { + let mut whole = None; + for _ in 0..2000 { + if energy::exited_unreaped(pid) == Some(true) { + whole = energy::read(pid); + break; + } + tokio::time::sleep(Duration::from_millis(1)).await; + } + let _ = child.wait().await; + energy::figure(whole.as_ref(), gpu, "the worker could not be read after it was stopped") + } + energy::Meter::Packages(p) => { + let _ = child.wait().await; + let r = before.as_ref().zip(p.read()).and_then(|(b, a)| p.between(b, &a, others + self.starts.load(Ordering::SeqCst).saturating_sub(start))); + energy::package_figure(r.as_ref(), "the processor packages' counter did not read when the worker was stopped") + } + energy::Meter::Unmetered(why) => { + let _ = child.wait().await; + json!({ "unmetered": why }) + } }; - stopped = Some(planner::Stopped { joules, elapsed_ms: began.elapsed().as_millis() as u64, read: read.to_string() }); + let read = match meter { + energy::Meter::Process => "the CPU energy of the job's worker, read about every 10 ms as the host schedules the service", + _ => "the processor packages' energy over the job's window, read about every 10 ms as the host schedules the service: every process on them", + }; + stopped = Some(planner::Stopped { joules, elapsed_ms, read: w.said(read) }); break Ok(()); } Some(_) => { @@ -1287,7 +1313,7 @@ impl Service { if let Some(s) = stopped { let Some(plan) = self.jobs.lock().unwrap().get(id).map(|j| j.plan.clone()) else { return failed("the job is gone".into()) }; let result = planner::stopped_result(wai_quantum::engine::registry::Registry::builtins(), &input["request"], &plan, &Value::Null, &s); - return Ran { outcome: Ok(result), peak, energy: json!({ "unmetered": "the worker was stopped at its contract's ceiling, so no figure of it was read after it exited" }), elapsed_ms }; + return Ran { outcome: Ok(result), peak, energy: stopped_figure, elapsed_ms }; } if let Err(e) = why { let detail = String::from_utf8_lossy(&err); diff --git a/wai/wai-quantum-service/tests/contract.rs b/wai/wai-quantum-service/tests/contract.rs index ee76c4d81..d96981223 100644 --- a/wai/wai-quantum-service/tests/contract.rs +++ b/wai/wai-quantum-service/tests/contract.rs @@ -171,6 +171,10 @@ fn a_job_is_stopped_at_its_energy_ceiling_and_its_receipt_says_so() { assert!(r["stopped"]["joules"].as_f64().unwrap() >= 0.01 && r.get("counts").is_none(), "{r}"); assert_eq!(r["planner"]["kept"]["energy"]["kept"], false, "{}", r["planner"]["kept"]); assert_eq!(r["accuracy"]["class"], "none"); + // What the killed worker took in all is sealed, with the longest time between reads. + let whole = r["energy"]["joules_micro"].as_u64().map(|u| u as f64 / 1e6); + assert!(whole.is_some_and(|w| w >= r["stopped"]["joules"].as_f64().unwrap()), "{}", r["energy"]); + assert!(r["stopped"]["read"].as_str().unwrap().contains("the longest time between two reads"), "{}", r["stopped"]); let body = json!({ "request": job["request"], "result": r }); assert!(wai_quantum::engine::job::check(&body).valid(), "{:?}", wai_quantum::engine::job::check(&body).reasons); } diff --git a/wai/wai-quantum/src/engine/energy.rs b/wai/wai-quantum/src/engine/energy.rs index 4b8759a56..9e772c5fd 100644 --- a/wai/wai-quantum/src/engine/energy.rs +++ b/wai/wai-quantum/src/engine/energy.rs @@ -101,10 +101,11 @@ pub struct Held { /// How often a run under a ceiling is read, in milliseconds. pub const WATCH_MS: u64 = 10; -/// How many reads in a row a run under a ceiling may go unread: a second's, at -/// [`WATCH_MS`]. A counter can lag a read, but a ceiling nothing reads is held by -/// nothing, so a run past this is stopped. -pub const WATCH_LOST: u32 = 100; +/// How long a run under a ceiling may go unread, in milliseconds. A counter can lag +/// a read, but a ceiling nothing reads is held by nothing, so a run past this is +/// stopped. Time, not a count of reads: a watcher the host schedules late still +/// loses the run after a second. +pub const WATCH_LOST_MS: u64 = 1000; /// What a live reading of a run came to. #[derive(Clone, Copy, Debug, PartialEq)] @@ -113,49 +114,53 @@ pub enum Watched { Reached(f64), /// The counter stopped reading. Lost, - /// The run finished first. - Finished, } -/// A run under a ceiling, read by read. +/// A run under a ceiling, read by read: what ends it, and the longest time the +/// host let pass between two reads, which is what the ceiling is held to. #[derive(Debug)] pub struct Watcher { ceiling: f64, - unread: u32, + read_at: std::time::Instant, + taken_at: Option, + /// The longest time between two reads so far. + pub longest_gap: std::time::Duration, } impl Watcher { pub fn new(ceiling: f64) -> Watcher { - Watcher { ceiling, unread: 0 } + Watcher::new_at(ceiling, std::time::Instant::now()) } - /// One read, or one that did not read: what ends the run, where it does. + pub fn new_at(ceiling: f64, at: std::time::Instant) -> Watcher { + Watcher { ceiling, read_at: at, taken_at: None, longest_gap: std::time::Duration::ZERO } + } + + /// One read now, or one that did not read: what ends the run, where it does. pub fn take(&mut self, read: Option) -> Option { + self.take_at(read, std::time::Instant::now()) + } + + /// [`Watcher::take`], read at `at`. + pub fn take_at(&mut self, read: Option, at: std::time::Instant) -> Option { + if let Some(before) = self.taken_at { + self.longest_gap = self.longest_gap.max(at.saturating_duration_since(before)); + } + self.taken_at = Some(at); match read { Some(j) if j >= self.ceiling => Some(Watched::Reached(j)), Some(_) => { - self.unread = 0; + self.read_at = at; None } - None => { - self.unread += 1; - (self.unread >= WATCH_LOST).then_some(Watched::Lost) - } + None => (at.saturating_duration_since(self.read_at) >= std::time::Duration::from_millis(WATCH_LOST_MS)).then_some(Watched::Lost), } } -} -/// `read`, every `every`, until a reading reaches `ceiling` joules, the counter is -/// lost or `done` is set: what stops a run under a contract's `max_joules`. -pub fn watch(mut read: impl FnMut() -> Option, ceiling: f64, every: std::time::Duration, done: &std::sync::atomic::AtomicBool) -> Watched { - let mut watcher = Watcher::new(ceiling); - while !done.load(std::sync::atomic::Ordering::Acquire) { - if let Some(end) = watcher.take(read()) { - return end; - } - std::thread::sleep(every); + /// What the reads were, as a stopped run's receipt says it. + pub fn said(&self, what: &str) -> String { + format!("{what}; the longest time between two reads was {} ms", self.longest_gap.as_millis()) } - Watched::Finished } /// The middle of the positive, finite values among `v`, once there are three. @@ -1068,43 +1073,33 @@ mod tests { assert_eq!((pauli.time["at_most"].as_u64(), pauli.energy["unestimated"].as_str()), (Some(5), Some("no time estimate to take the power over"))); } - /// A run is stopped by the first reading at or past its ceiling and left alone - /// once it is done. A read that fails is passed over, as a counter's lag is, and - /// is not taken for none; a counter that stays silent loses the run its ceiling. + /// A run is stopped by the first reading at or past its ceiling. A read that + /// fails is passed over, as a counter's lag is; a counter silent for a second + /// of time loses the run its ceiling, however few reads the host allowed in it; + /// and the longest time between two reads is kept, to be said. #[test] - fn a_live_reading_stops_at_the_ceiling_and_not_before() { - use std::sync::atomic::{AtomicBool, Ordering}; - let done = AtomicBool::new(false); - let every = std::time::Duration::from_micros(1); - let mut readings = [Some(0.5), None, Some(1.5), Some(2.0), Some(9.0)].into_iter(); - assert_eq!(watch(|| readings.next().flatten(), 2.0, every, &done), Watched::Reached(2.0)); - assert_eq!(readings.next(), Some(Some(9.0)), "it stopped at the first at the ceiling"); - // Silent for as long as it may be, and read again: the run goes on. - let mut w = Watcher::new(2.0); - for _ in 1..WATCH_LOST { - assert_eq!(w.take(None), None); - } - assert_eq!(w.take(Some(1.0)), None); - for _ in 1..WATCH_LOST { - assert_eq!(w.take(None), None); - } - assert_eq!(w.take(None), Some(Watched::Lost)); - assert_eq!(watch(|| None, 2.0, every, &done), Watched::Lost); - // A run that finishes under it: read until it is done, and nothing is stopped. - let mut n = 0; - let finished = watch( - || { - n += 1; - if n == 3 { - done.store(true, Ordering::Release); - } - Some(0.1) - }, - 2.0, - every, - &done, - ); - assert_eq!((finished, n), (Watched::Finished, 3)); + fn a_live_reading_stops_at_the_ceiling_and_a_silent_second_loses_it() { + use std::time::{Duration, Instant}; + let t0 = Instant::now(); + let ms = |n: u64| t0 + Duration::from_millis(n); + let mut w = Watcher::new_at(2.0, t0); + assert_eq!(w.take_at(Some(0.5), ms(10)), None); + assert_eq!(w.take_at(None, ms(20)), None); + assert_eq!(w.take_at(Some(1.5), ms(250)), None); + assert_eq!(w.take_at(Some(2.0), ms(260)), Some(Watched::Reached(2.0)), "at the ceiling, not only past it"); + assert_eq!(w.longest_gap, Duration::from_millis(230)); + assert!(w.said("a counter").ends_with("the longest time between two reads was 230 ms")); + // Silent: two late reads a second apart lose it, where a hundred quick ones did not. + let mut w = Watcher::new_at(2.0, t0); + assert_eq!(w.take_at(Some(1.0), ms(10)), None); + assert_eq!(w.take_at(None, ms(500)), None); + assert_eq!(w.take_at(None, ms(1010)), Some(Watched::Lost)); + // A read between keeps it. + let mut w = Watcher::new_at(2.0, t0); + assert_eq!(w.take_at(None, ms(900)), None); + assert_eq!(w.take_at(Some(1.0), ms(950)), None); + assert_eq!(w.take_at(None, ms(1900)), None); + assert_eq!(w.take_at(None, ms(1950)), Some(Watched::Lost)); } /// A reading past the time a counter can wrap twice is not to be trusted: at the diff --git a/wai/wai-quantum/src/engine/planner.rs b/wai/wai-quantum/src/engine/planner.rs index 150615ec2..fe036557d 100644 --- a/wai/wai-quantum/src/engine/planner.rs +++ b/wai/wai-quantum/src/engine/planner.rs @@ -1622,8 +1622,8 @@ fn states_itself(r: &Value, request: &Value) -> bool { by_job && class_of_method(m, class) && r["host_dependent"] == is_gpu(m) } -/// The members a run's answer is in: a stopped run gave none. -const ANSWERS: [&str; 5] = ["counts", "expectations", "amplitudes", "state_hash", "distinct_outcomes"]; +/// The members a stopped run's result has, and no other: it gave no answer of any kind. +const STOPPED_MEMBERS: [&str; 11] = ["method", "qubits", "gates", "accuracy", "stopped", "elapsed_ms", "planner", "energy", "engine", "schema", "receipt"]; /// Whether a run stopped at its ceiling says so of its form: on a contract that /// gives one, a reading at or past it, on a method's run, with no answer. @@ -1636,7 +1636,7 @@ fn stopped_holds(c: &Contract, result: &Value) -> bool { && s["read"].is_string() && result["method"] != "provider" && result.pointer("/accuracy/class").and_then(Value::as_str) == Some(STOPPED_CLASS) - && ANSWERS.iter().all(|k| result.get(*k).is_none()) + && result.as_object().is_some_and(|o| o.keys().all(|k| STOPPED_MEMBERS.contains(&k.as_str()))) } /// A `kept` member as its table gives it: true, false, or `null` where it is not -- 2.54.0 (Apple Git-157) From cafcc168342af67db306c677442765d60b73d249 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sat, 7 Nov 2026 08:41:07 -0500 Subject: [PATCH 16/42] wai-quantum: the planner's third check: what ran is the route chosen, and a word sends one run Each finding reproduced first, by a crafted receipt both verifiers accepted or a test of the old code, and each has a receipt or test that fails without it. - What ran is the route chosen (`planner_choice`): a provider's result has its route's money as its cost (free alike; amount, currency, unit and at_least alike), and the device and provenance its route names. A run sealed at 50 USD on a route called free, a paid run sealed free and unconfirmed, and a route naming another device are found by both verifiers. - A provider's route has the class its provenance gives; every built-in method's route but stabilizer's, stabilizer-rank's and cut-rank's has the one class its table gives (a matrix product state's is heuristic); a method the host registered depends on the host; a shadow's outcomes are as long as the provider's. - A recheck of a receipt sealed by another engine whose shadow did not run says what this engine plans and does not say it holds (holds null). - A routed run's word binds the job's contract and how many runs of the job the ledger holds: one word sends one run, and a dry run after it gives the next run's word. - An open-protocol provider may say in describe that it cannot cancel (`cancels: false`, section 5.1) and in an estimate that its amount is the least the job can come to (`at_least`, section 5.2); its price says so. The qpu library's pin is 93, with the two new tests' names. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/wai-quantum-qpu.yml | 6 +- ...06-wai-quantum-planner-under-a-contract.md | 9 + wai/extensions/quantum-providers.md | 27 +- wai/quantum-conformance/receipts/generate.py | 61 ++ .../crafted-contract-cost-amount-other.json | 450 ++++++++++++++ ...ted-contract-cost-route-free-run-paid.json | 547 ++++++++++++++++++ ...ted-contract-cost-route-paid-run-free.json | 441 ++++++++++++++ ...rafted-contract-cost-unknown-run-free.json | 426 ++++++++++++++ .../crafted-contract-route-device-other.json | 544 +++++++++++++++++ .../crafted-contract-route-mps-exact.json | 339 +++++++++++ ...afted-contract-route-provenance-class.json | 544 +++++++++++++++++ ...act-route-registered-host-independent.json | 368 ++++++++++++ .../crafted-contract-shadow-width-other.json | 544 +++++++++++++++++ .../receipts/manifest.json | 74 +++ .../tools/receipt_verify.py | 62 +- wai/wai-quantum-cli/README.md | 2 +- wai/wai-quantum-cli/README.zh-CN.md | 2 +- wai/wai-quantum-cli/src/providers.rs | 14 +- wai/wai-quantum-cli/tests/providers.rs | 16 +- wai/wai-quantum-qpu/src/job.rs | 128 +++- wai/wai-quantum-qpu/src/ledger.rs | 10 + wai/wai-quantum-qpu/src/open_provider.rs | 7 +- wai/wai-quantum/src/engine/planner.rs | 73 ++- wai/wai-quantum/src/engine/planner/tests.rs | 23 +- 24 files changed, 4663 insertions(+), 54 deletions(-) create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-cost-amount-other.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-cost-route-free-run-paid.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-cost-route-paid-run-free.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-cost-unknown-run-free.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-route-device-other.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-route-mps-exact.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-route-provenance-class.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-route-registered-host-independent.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-width-other.json diff --git a/.github/workflows/wai-quantum-qpu.yml b/.github/workflows/wai-quantum-qpu.yml index c691303ba..6dbfbcd8e 100644 --- a/.github/workflows/wai-quantum-qpu.yml +++ b/.github/workflows/wai-quantum-qpu.yml @@ -79,10 +79,10 @@ jobs: # tests never touch one but the macOS leg's own. export WAI_QUANTUM_CREDENTIALS=file cargo test --locked 2>&1 | tee "$RUNNER_TEMP/test.log" - # The library (91, the cloud-tasks client's and a job under a contract's among + # The library (93, the cloud-tasks client's and a job under a contract's among # them), the clients against their contracts (17), and the providers # end to end (12), each binary's count pinned. - for n in 91 17 12; do + for n in 93 17 12; do grep -qE "^test result: ok\. $n passed; 0 failed" "$RUNNER_TEMP/test.log" || { echo "::error::a test binary did not pass all $n of its tests"; exit 1; } done for t in curl_carries_a_request_to_a_server_and_back every_operation_over_http every_operation_over_a_local_process \ @@ -118,6 +118,8 @@ jobs: job::tests::the_word_for_a_routed_run_binds_the_provider_and_says_only_itself \ job::tests::a_job_past_its_deadline_ends_only_on_the_provider_s_word \ job::tests::a_reasoning_no_receipt_could_give_is_not_taken_up \ + job::tests::a_word_confirms_one_run_and_binds_its_contract \ + job::tests::an_open_provider_says_it_cannot_cancel_and_that_its_estimate_is_the_least \ a_built_in_kind_runs_under_a_contract_and_a_classical_method_shadows_it a_cost_estimated_at_the_least_it_can_come_to_meets_no_ceiling; do grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/test.log" || { echo "::error::$t did not run and pass"; exit 1; } done diff --git a/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md b/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md index 56b94d663..465842b5b 100644 --- a/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md +++ b/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md @@ -51,6 +51,15 @@ device and its identity beside the route, the estimate and the program, and says only itself. A job past its deadline ends only on the provider's word that it was cancelled: one whose client cannot cancel says so (`cancel` in `leaves_out`), and stays waiting. A target's and a pulse program's deadline is held to a host's timer. +- **What ran is the route chosen.** A provider's result names its route's device and provenance, and its cost is the + route's money, or the choice does not hold (`planner_choice`): a run sealed at 50 USD on a route called free, or a + paid run sealed as free, is found. A provider's route has the class its provenance gives; every built-in method's + route but stabilizer's, stabilizer-rank's and cut-rank's has the one class its table gives (a matrix product state's + is `heuristic`); a method the host registered is host-dependent; a shadow's outcomes are as long as the provider's. + A recheck of a receipt sealed by another engine whose shadow did not run says what this engine plans and does not + say it holds. A routed run's word binds the contract too and sends one run. An open-protocol provider may say in + `describe` that it cannot cancel (`cancels`), and in an estimate that its amount is the least the job can come to + (`at_least`), and its price says so. - **Every host seals only what its verifier accepts.** A result short of the class its reasoning wants gives no answer (`J072`), and each host checks a contract job's reasoning before it seals it. A run past its contract's deadline on the job service is stopped, and the command line cancels a provider's job still waiting at it (`J074`). A deadline holds diff --git a/wai/extensions/quantum-providers.md b/wai/extensions/quantum-providers.md index 26477af13..9820cdaf9 100644 --- a/wai/extensions/quantum-providers.md +++ b/wai/extensions/quantum-providers.md @@ -180,6 +180,7 @@ No fields. The answer describes the device: | `max_shots` | optional: the most shots a job may ask | | `seeded` | optional: `true` when a job's `seed` makes its counts reproducible (a simulator) | | `approximate` | optional, with `simulator` or `emulator`: `true` when its results are approximate (a truncated tensor network, a sampled Pauli path); a result is then labelled so (§8.1) | +| `cancels` | optional: `false` when it cannot cancel a job it took (§5.6), so that a client can say so before it sends one | A client MUST NOT take a device to be free unless `billing` says `"free": true`, or an estimate says so (§5.2). @@ -200,6 +201,7 @@ Fields: `program` (§4), `shots`. The answer, before anything is submitted: | `amount`, `currency` | when it is not: the cost, the amount as a decimal string | | `unit` | optional: the billing unit the cost counts | | `seconds` | optional: how long it is expected to take, queue included | +| `at_least` | optional: `true` when the amount is only the least the job can come to, as with a device billed by the time a job turns out to take | | `note` | optional | A provider that cannot estimate answers `unsupported`; the client then treats @@ -765,7 +767,7 @@ A route, an object of: |---|---| | `route` | its name: `method:`, or `provider:`, neither name empty | | `kind` | `local` for a method, `provider` for a provider | -| `class` | a string: the class its result has at worst on this job. A built-in method's is held to the table below; a method a host registered that declares one class has that one, and one that declares several has the first of `bit-exact`, `exact`, `single`, `bounded`, `estimate` and `heuristic` that each of them meets (so `single` and `bounded` together are `heuristic`). A provider that cannot run the job is `unknown` | +| `class` | a string: the class its result has at worst on this job. A built-in method's is held to the table below; a method a host registered that declares one class has that one, and one that declares several has the first of `bit-exact`, `exact`, `single`, `bounded`, `estimate` and `heuristic` that each of them meets (so `single` and `bounded` together are `heuristic`). A provider's route has the class its `provenance` gives (§8.4), and one that cannot run the job is `unknown` | | `host_dependent` | `true` or `false`: whether the route depends on the host. A provider's, a method on a GPU (`statevector_single`, `cutrank_single`) and a method the host registered are, and no other built-in is | | `auto_rank` | on a local route: its rank in `auto`'s order for the job's `question`, a whole number, or `null` where `auto` does not try it. A built-in method's is the table's below; a registered method's is the host's word | | `price` | `null`, or an object: below | @@ -774,7 +776,9 @@ A route, an object of: | `approximate` | `true`, on a provider's route whose provider states its simulator is approximate | and a provider's route may name its `provider`, `device` and `provenance`, a -method's its `method`, as words a person reads. +method's its `method`, as words a person reads. Where a provider's route names its +`provenance`, its class is the one that gives (§8.4), and where the route chosen names +its `device` or `provenance`, they are the result's provider's (`planner_choice`). The classes of the built-in methods, and which of them a route has on a job: @@ -894,10 +898,12 @@ other's. A cost ceiling confirms nothing: a run that is not free still needs the person's word for that run (§7). Where a host chose the provider (the request names none), that word names what the person saw: a host gives the route, who it is (its kind, device, provenance and description, and what the person's name for it stands -for: its endpoint, settings and credential's place), its estimate's `money` and the -program and shots it would send, as a short digest, and sends the job only when the -word it is given is that digest made again at send time; a route, a device, an -estimate or a program that changed since is not sent. A host asks no provider +for: its endpoint, settings and credential's place), its estimate's `money`, the +program and shots it would send, the job's `contract`, and how many runs of this job +the host has sent on such a word before, as a short digest, and sends the job only when +the word it is given is that digest made again at send time; a route, a device, an +estimate, a program or a contract that changed since is not sent, and a word sends +one run: the next run of the same job has another word. A host asks no provider anything (an estimate's request carries the compiled program, and a description says a job is coming) where the contract does not allow one, or names no class a provider's counts are in: with none named the job keeps a classical class, which @@ -985,8 +991,8 @@ A result's `shadow` is one of: - `ran` `true`, where `planner.shadow` has a route: with `route` and `request`, equal to those of `planner.shadow` (numbers by value); `shots`, the result's; `accuracy`, an object whose `class` is a string that meets `planner.shadow.class` - and is one of its method's; `counts`, keyed by outcomes all of one length and each - of `0` and `1` only, each a whole number written as one from 1 to 2^53 − 1, and + and is one of its method's; `counts`, keyed by outcomes all as long as the + provider's counts' (where they list one) and each of `0` and `1` only, each a whole number written as one from 1 to 2^53 − 1, and `omitted_shots`, a whole number of at least 0 by value, which sum exactly to the result's `shots` (a whole number by value); `distinct_outcomes`, a whole number of at least 0, and, with no shot omitted, the number of outcomes listed; optionally @@ -1030,7 +1036,7 @@ written, so that every verifier gets the same bits. | `contract_provider` | the request names a `provider` and its contract's `providers` is not `allowed` | | `planner_form` | a contract job's result has no `planner`, or one not of the form above: `format`, `routes` and each route's members (a local route's `auto_rank`, its money free, every `seconds` and amount within its bounds), `named`, `auto` and `choice` each naming a route of `routes` or `null` (`choice` a route), `question`, `host`, `why`, `stable` and `kept` an object, each present; or `named`, `question`, a built-in method's `auto_rank`, `auto`, `wanted` or `wanted_from` is not what the request and the routes give. Or a result with no contract carries a `planner`. Reported alone of §8.7, beside `contract_provider` | | `planner_route` | a route's `rejected.code` is not what the rules above give it (or it is rejected when they let it through, or not when they do not), or the route `chosen` is not one and `choice` | -| `planner_choice` | `choice` is not the route the choice's rules pick from those the rules let through, whatever their `outcome` says; or it is not what ran | +| `planner_choice` | `choice` is not the route the choice's rules pick from those the rules let through, whatever their `outcome` says; or it is not what ran: a method's result is of another method, and a provider's names another provider, or its `cost` is not its route's `money` (`free` alike, and `amount`, `currency`, `unit` and `at_least` in its `estimate` alike), or the route names a `device` or `provenance` that is not its provider's | | `planner_stable` | `stable.routes`, `digest` or `choice` is not what the routes give | | `planner_kept` | `kept` does not hold exactly a member for each the contract gives, or any of those members is not what the table gives | | `contract_class` | the result's class does not meet `wanted` | @@ -1047,7 +1053,8 @@ them: a verifier here has neither its GPU nor its registered methods); holds the shadow's counts and class to a run here; runs a shadow the host says failed; and, on the same engine, plans the shadow again, so that which method ran, or that none could, is what this engine gives: a verifier without one takes those on the host's -word. +word. A receipt sealed by another engine whose shadow did not run is held neither +way: what this engine plans is said, and the recheck does not say it holds. The free job service reaches no provider. It lists none among its routes, a contract that wants a device's class is refused there (`J071`), and a request that diff --git a/wai/quantum-conformance/receipts/generate.py b/wai/quantum-conformance/receipts/generate.py index e7c9f3080..658944686 100644 --- a/wai/quantum-conformance/receipts/generate.py +++ b/wai/quantum-conformance/receipts/generate.py @@ -28,6 +28,7 @@ import copy import hashlib import importlib.util import json +import math import os import struct import sys @@ -302,6 +303,21 @@ def seal_set(body, seed=DEMO): return out +def coin_split(n): + """Section 8.7's m(n): what a fair coin's split of n leaves between its sides on average.""" + if n == 0: + return 0.0 + j = (n - 1) // 2 + if j < 4096: + m = 1.0 + for i in range(j): + m = m * float(2 * i + 3) / float(2 * i + 2) + return m + jj = float(j) + c = (1.0 - 1.0 / (8.0 * jj) + 1.0 / (128.0 * jj * jj) + 5.0 / (1024.0 * jj * jj * jj)) / math.sqrt(math.pi * jj) + return (2.0 * jj + 1.0) * c + + def edited(body, edit, form="canonical"): """body changed by edit (which may change request, result or both), sealed again.""" b = copy.deepcopy(body) @@ -888,6 +904,51 @@ def contract_cases(run, at, drop): add("shadow-class-foreign", edited(routed, by_mps), ["shadow"], "a shadow run by mps stated bit-exact: it meets its plan, and mps has no such class") add("shadow-bound-other", edited(routed, lambda b: b["result"]["shadow"]["distance"].update(sampling_tvd_bound=0.01)), ["shadow"], "a bound on the distance the shots alone leave that is not what the counts give") + # --- what ran is the route chosen (the third check) + def paid_estimate(b): + b["result"]["cost"] = {"free": False, "estimate": {"free": False, "amount": "50", "currency": "USD", "unit": "job", "seconds": 0.0}, "charged": None, "confirmed": True} + add("cost-route-free-run-paid", edited(routed, paid_estimate), ["planner_choice"], "a run sealed at 50 USD on a route the reasoning calls free: not the route chosen") + + def sealed_free(b): + b["result"]["cost"] = {"free": True, "estimate": {"free": True, "seconds": 0.0}, "charged": None, "confirmed": False} + b["result"]["planner"]["kept"]["cost"]["charged"] = None + add("cost-route-paid-run-free", edited(named, sealed_free), ["planner_choice"], "a paid route chosen, its run sealed as free and unconfirmed") + add("cost-amount-other", edited(named, at(R + ("cost", "estimate", "amount"), "0.08")), ["planner_choice"], "a run sealed at another estimate than its route's") + + def unknown_sealed_free(b): + del b["request"]["contract"]["max_cost"] + del b["result"]["planner"]["kept"]["cost"] + route("provider:priced", lambda r: r["price"].update(money={"free": False, "unknown": "the provider gives no estimate"}))(b) + b["result"]["cost"] = {"free": True, "estimate": {"free": True, "seconds": 0.0}, "charged": None, "confirmed": False} + add("cost-unknown-run-free", edited(named, unknown_sealed_free), ["planner_choice"], "a route whose cost is not known, its run sealed as free and unconfirmed") + add("route-device-other", edited(routed, route("provider:ref", lambda r: r.update(device="reference:line-6"))), ["planner_choice"], "the route chosen names another device than the one that ran") + add("route-provenance-class", edited(routed, route("provider:priced", lambda r: r.update(provenance="silicon"))), ["planner_route"], "a provider's route whose class is not its provenance's") + + def shadow_width(b): + s = b["result"]["shadow"] + s["counts"] = dict(("0" + k, v) for k, v in s["counts"].items()) + a, c = b["result"]["counts"], s["counts"] + shots = sum(a.values()) + keys = sorted(set(a) | set(c)) + root = 0.0 + for k in keys: + root += math.sqrt(float(a.get(k, 0)) * float(c.get(k, 0))) + f = 0.0 + for k in keys: + f += coin_split(a.get(k, 0) + c.get(k, 0)) + s["distance"] = {"computed": True, "numerator": sum(abs(a.get(k, 0) - c.get(k, 0)) for k in keys), "denominator": 2 * shots, + "total_variation": sum(abs(a.get(k, 0) - c.get(k, 0)) for k in keys) / (2 * shots), + "hellinger_fidelity": root * root / (float(shots) * float(shots)), "sampling_tvd_bound": min(1.0, 0.5 * f / shots)} + add("shadow-width-other", edited(routed, shadow_width), ["shadow"], "a shadow whose outcomes are wider than the job's, its distance what they give") + add("route-mps-exact", edited(local, route("method:mps", lambda r: (r.update({"class": "exact", "outcome": "met"}), r.pop("rejected", None)))), ["planner_route", "planner_stable"], "the matrix product state's route stated exact, which a route of it never is") + + def registered(b): + rs = b["result"]["planner"]["routes"] + turbo = copy.deepcopy(next(r for r in rs if r["route"] == "method:exact")) + turbo.update({"route": "method:turbo", "method": "turbo"}) + rs.append(turbo) + add("route-registered-host-independent", edited(local, registered), ["planner_route", "planner_stable"], "a method the host registered, stated to depend on nothing of the host") + def host_failed(b): b["result"]["shadow"] = {"ran": False, "code": "failed", "why": "the host says it failed"} add("shadow-said-failed", edited(routed, host_failed), [], "a shadow planned and said to have failed: valid to read, and run again by --recheck") diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-cost-amount-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-cost-amount-other.json new file mode 100644 index 000000000..dce5ef63c --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-cost-amount-other.json @@ -0,0 +1,450 @@ +{ + "status": "done", + "method": "provider", + "why": "on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "providers": "allowed" + }, + "provider": "priced" + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "priced", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": false, + "estimate": { + "free": false, + "amount": "0.08", + "currency": "USD", + "unit": "shot", + "seconds": 0.0 + }, + "charged": { + "amount": "0.09", + "currency": "USD" + }, + "confirmed": true + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "named", + "named": "provider:priced", + "question": "counts", + "auto": null, + "host": { + "job_bytes": 17179869184, + "providers": [ + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + } + ], + "choice": "provider:priced", + "why": "the route the job names, which meets its contract (1 of 14 routes)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "42dab8b20f638eeb9c1d46fd7a0890b574c641a1e11d1306da2abc201ca84c5f", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": { + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": { + "amount": "0.09", + "currency": "USD" + }, + "kept": true + } + } + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "4a58d60b22d06875dc98bc95e3bca81ad6dc33e8d7b39114bf034db35bf1f4e0", + "signature": "a0e9c85f3347b634ce77bb2f9a2ebc9e565e8c930632e1becb315cfb40ca8833665ab23fcce9782e39e2b6df0ea3235ecf31271864c2f91babc06370c2466606" + } + }, + "id": "pj-e158396f1fd8f81d", + "submitted_ms": 1794033072602, + "finished_ms": 1794033072605 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-cost-route-free-run-paid.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-cost-route-free-run-paid.json new file mode 100644 index 000000000..9f8599e56 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-cost-route-free-run-paid.json @@ -0,0 +1,547 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": false, + "estimate": { + "free": false, + "amount": "50", + "currency": "USD", + "unit": "job", + "seconds": 0.0 + }, + "charged": null, + "confirmed": true + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "21b63e110f5db9eb78f8bbe8bc3e0cc5c27026294f99bf750ac02d45c7d2808e", + "signature": "e9f33fed626b427bc208a79724d44468bd425f86f7ac9f421a530cd0a02a08a4c533cd176a16b9be3ea5fac09a93a8d784a5d097b537a584d92d2e1180a51506" + } + }, + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-cost-route-paid-run-free.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-cost-route-paid-run-free.json new file mode 100644 index 000000000..6c25821c4 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-cost-route-paid-run-free.json @@ -0,0 +1,441 @@ +{ + "status": "done", + "method": "provider", + "why": "on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "providers": "allowed" + }, + "provider": "priced" + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "priced", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "named", + "named": "provider:priced", + "question": "counts", + "auto": null, + "host": { + "job_bytes": 17179869184, + "providers": [ + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + } + ], + "choice": "provider:priced", + "why": "the route the job names, which meets its contract (1 of 14 routes)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "42dab8b20f638eeb9c1d46fd7a0890b574c641a1e11d1306da2abc201ca84c5f", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": { + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "d954f8069ecd70a9cd634ffb35f78b8319bffeb84c62b1272e44b31cb019b4f3", + "signature": "849f782a2f4e28992635ff8c8104b8930efbaf105152d93d38f9cfda3ecbded6f45e29aa0ab495a182dd75d513316a5bf38510fd2c110d94130966598772e305" + } + }, + "id": "pj-e158396f1fd8f81d", + "submitted_ms": 1794033072602, + "finished_ms": 1794033072605 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-cost-unknown-run-free.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-cost-unknown-run-free.json new file mode 100644 index 000000000..a5f8c216f --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-cost-unknown-run-free.json @@ -0,0 +1,426 @@ +{ + "status": "done", + "method": "provider", + "why": "on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "providers": "allowed" + }, + "provider": "priced" + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "priced", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "named", + "named": "provider:priced", + "question": "counts", + "auto": null, + "host": { + "job_bytes": 17179869184, + "providers": [ + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "unknown": "the provider gives no estimate" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + } + ], + "choice": "provider:priced", + "why": "the route the job names, which meets its contract (1 of 14 routes)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "42dab8b20f638eeb9c1d46fd7a0890b574c641a1e11d1306da2abc201ca84c5f", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "dd3fb51c8a678abaddd96d5eaf2f2867ca13733416b9c4ff113b0de7b3e75014", + "signature": "cbd07c049bbd7edeeacfc935b7f679f406ac81eb2fa1b38d4c12c9a433a227b05bacfd2a961b141371e24aed8abc4a132e7811b6c4ddd17d790c0ecc3db5ff0e" + } + }, + "id": "pj-e158396f1fd8f81d", + "submitted_ms": 1794033072602, + "finished_ms": 1794033072605 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-device-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-device-other.json new file mode 100644 index 000000000..33e91dcc5 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-device-other.json @@ -0,0 +1,544 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-6", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "d82682124f0c714c884ff7a616a9190e21d2aa5a420a4b580bac57dc26e3ad5f", + "signature": "72fc4ee6b1fc959b81d35167e07c311c6b9c38b7cac830afe261081d0e1bb5973f73b5f36a091758d4620d0d1ee4e5eb4dcd90cdf49bb7dd338175e645fda709" + } + }, + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-mps-exact.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-mps-exact.json new file mode 100644 index 000000000..4cdb37f14 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-mps-exact.json @@ -0,0 +1,339 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "exact", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "bcd409cd099fa60358916a688c2174ff60ed947c6bd200f23c83c121f8821746", + "signature": "221ae0aecc89f0c939adf7c0ae55cdb7952a94d3cdbb6a4f81f372fb639230fcf6c4687aac5282ba139bf26ce2b9befd8ddb64760d3c293f71ce6869ee8d4506" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provenance-class.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provenance-class.json new file mode 100644 index 000000000..fa6deb70e --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-provenance-class.json @@ -0,0 +1,544 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "silicon", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "9dea6d0afa446cd297a4ab16999f47bcf4245b41f6cc95db12cf436116e256b7", + "signature": "bd7c45bdf52ee229a598e19006c14bcb2ee93fe10c3b9406f3e7ed6fafacf3820a863098ff3454cc3dce1a8aef5b68528f71a00f4b73b831365047d05e75a009" + } + }, + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-route-registered-host-independent.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-registered-host-independent.json new file mode 100644 index 000000000..1194d6e32 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-route-registered-host-independent.json @@ -0,0 +1,368 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "exact" + }, + "counts": { + "11": 505, + "00": 495 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "outcome_dimension": 1, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:turbo", + "kind": "local", + "method": "turbo", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "met" + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": true + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + } + } + }, + "energy": { + "unmetered": "the command line does not meter a run's energy" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "dd82cdedb5d5cbf9d3cde5c2d407ab831e5ecfc2832149a587c259e83d324725", + "signature": "a9c3bc551b1e3c0bfe9c9c15d496ab6892946da20e1c36a85d18ecce335c4ba2ece1bdcae972c720d7e9e2e9c8a98c190a7f7d16cd586a8360aea2c150770202" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-width-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-width-other.json new file mode 100644 index 000000000..f0c4dec49 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-shadow-width-other.json @@ -0,0 +1,544 @@ +{ + "status": "done", + "method": "provider", + "why": "on ref, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "exactness": "simulated", + "providers": "allowed" + } + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "ref", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "0a802ecd608fb5bca73c5a22ff65b5a08a408416501bb5472986f6540ff91ac0" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": true, + "estimate": { + "free": true, + "seconds": 0.0 + }, + "charged": null, + "confirmed": false + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [ + "ref", + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bit-exact, and the job wants simulated" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268442722, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 7.296e-08, + "basis": "nominal" + }, + "memory_bytes": 67128070, + "work": 608, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.010518528000000001, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 7012352, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and the job wants simulated" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4.05e-07, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 2700, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants simulated" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is exact, and the job wants simulated" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants simulated" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants simulated" + } + }, + { + "route": "provider:ref", + "kind": "provider", + "provider": "ref", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot" + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "rejected", + "rejected": { + "code": "cost_no_ceiling", + "why": "0.09 USD: it costs money or its cost is unknown, and the contract gives no ceiling to hold it to; give max_cost, or name the provider" + } + } + ], + "choice": "provider:ref", + "why": "the cheapest of the 1 of 15 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "e42e49d90e3f5015f93e050136dfb3c2633235039d89e9db50114125c0aced1a", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "000": 161, + "011": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 600, + "denominator": 600, + "total_variation": 1.0, + "hellinger_fidelity": 0.0, + "sampling_tvd_bound": 0.06521202331161233 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "5a907d30971e88ea738bc90e9b40706608717426530f29869c3efd4f075e97a5", + "signature": "bf5f5c993a9832ff147fb403ec1fefca7a5fe0d844a698bd54057748dcebf20ae4941f701f2c26c1a5a81a309dba4c833e4f72b4dadca584a879f0bdc649ee0e" + } + }, + "id": "pj-6059aefb7ace70bc", + "submitted_ms": 1794033072508, + "finished_ms": 1794033072511 +} diff --git a/wai/quantum-conformance/receipts/manifest.json b/wai/quantum-conformance/receipts/manifest.json index 89bbd5ff4..ad0d8a271 100644 --- a/wai/quantum-conformance/receipts/manifest.json +++ b/wai/quantum-conformance/receipts/manifest.json @@ -1868,6 +1868,80 @@ "made_by": "crafted", "what": "a bound on the distance the shots alone leave that is not what the counts give" }, + { + "file": "jobs/crafted-contract-cost-route-free-run-paid.json", + "reasons": [ + "planner_choice" + ], + "made_by": "crafted", + "what": "a run sealed at 50 USD on a route the reasoning calls free: not the route chosen" + }, + { + "file": "jobs/crafted-contract-cost-route-paid-run-free.json", + "reasons": [ + "planner_choice" + ], + "made_by": "crafted", + "what": "a paid route chosen, its run sealed as free and unconfirmed" + }, + { + "file": "jobs/crafted-contract-cost-amount-other.json", + "reasons": [ + "planner_choice" + ], + "made_by": "crafted", + "what": "a run sealed at another estimate than its route's" + }, + { + "file": "jobs/crafted-contract-cost-unknown-run-free.json", + "reasons": [ + "planner_choice" + ], + "made_by": "crafted", + "what": "a route whose cost is not known, its run sealed as free and unconfirmed" + }, + { + "file": "jobs/crafted-contract-route-device-other.json", + "reasons": [ + "planner_choice" + ], + "made_by": "crafted", + "what": "the route chosen names another device than the one that ran" + }, + { + "file": "jobs/crafted-contract-route-provenance-class.json", + "reasons": [ + "planner_route" + ], + "made_by": "crafted", + "what": "a provider's route whose class is not its provenance's" + }, + { + "file": "jobs/crafted-contract-shadow-width-other.json", + "reasons": [ + "shadow" + ], + "made_by": "crafted", + "what": "a shadow whose outcomes are wider than the job's, its distance what they give" + }, + { + "file": "jobs/crafted-contract-route-mps-exact.json", + "reasons": [ + "planner_route", + "planner_stable" + ], + "made_by": "crafted", + "what": "the matrix product state's route stated exact, which a route of it never is" + }, + { + "file": "jobs/crafted-contract-route-registered-host-independent.json", + "reasons": [ + "planner_route", + "planner_stable" + ], + "made_by": "crafted", + "what": "a method the host registered, stated to depend on nothing of the host" + }, { "file": "jobs/crafted-contract-shadow-said-failed.json", "reasons": [], diff --git a/wai/quantum-conformance/tools/receipt_verify.py b/wai/quantum-conformance/tools/receipt_verify.py index c1da4d6f5..fff80863f 100644 --- a/wai/quantum-conformance/tools/receipt_verify.py +++ b/wai/quantum-conformance/tools/receipt_verify.py @@ -1222,12 +1222,14 @@ def _states_itself(r, request): """§8.7: a built-in method has the class its table gives it on this request, and depends on the host only when it runs on a GPU; a provider's route depends on it.""" name = r["route"] + cls = r["class"] if not name.startswith("method:"): - return r["host_dependent"] is True + # A provider's route has the class its provenance gives. + given = read_class(r.get("provenance")) + return r["host_dependent"] is True and (given is None or cls == given) m = name[len("method:"):] if m not in METHOD_CLASSES: - return True - cls = r["class"] + return r["host_dependent"] is True # a method the host registered is its own code options = request.get("options") given = lambda k: isinstance(options, dict) and options.get(k) is not None if m == "stabilizer": @@ -1236,9 +1238,34 @@ def _states_itself(r, request): return False if m == "stabilizer_rank" and cls != ("estimate" if given("terms") or given("epsilon") else "exact"): return False + # Every other method but cut-rank (whose plan says which table fits) has the one + # class its table gives: the first each class it declares meets. + if m not in ("stabilizer", "stabilizer_rank", "cutrank"): + declared = METHOD_CLASSES[m] + worst = declared[0] if len(declared) == 1 else next((c for c in LADDER if all(meets(c, d) for d in declared)), None) + if cls != worst: + return False return cls in METHOD_CLASSES[m] and r["host_dependent"] is (m in _GPU_NAMES) +def _ran_as_routed(routes, choice, result): + """§8.7: the route chosen is what ran; for a provider's, the result's provider is the + device and provenance it names, where it names them, and the result's cost is its money.""" + r = next((x for x in routes if x["route"] == choice), None) + if r is None or r["kind"] != "provider": + return True + money = _member(r, "price", "money") + cost = result.get("cost") + provider = result.get("provider") + if not (isinstance(money, dict) and isinstance(cost, dict) and isinstance(provider, dict)): + return False + estimate = cost.get("estimate") if isinstance(cost.get("estimate"), dict) else {} + missing = object() + return (all(k not in r or r[k] == provider.get(k, missing) for k in ("device", "provenance")) + and _plain(cost.get("free", missing)) == _plain(money.get("free", missing)) + and all(_plain(estimate.get(k, missing)) == _plain(money.get(k, missing)) for k in ("amount", "currency", "unit", "at_least"))) + + def _planner_form(p): if not isinstance(p, dict) or p.get("format") != "wai.quantum.planner/1": return False @@ -1621,8 +1648,10 @@ def _shadow_holds(request, contract, p, result): return False if not (_whole(s.get("distinct_outcomes")) and s["distinct_outcomes"].value >= 0): return False - # Its outcomes are a counts' form: of 0 and 1, of one width; with none omitted, as said. - width = len(next(iter(counts), "")) + # Its outcomes are a counts' form: of 0 and 1, as wide as the job's where the + # provider's counts name one; with none omitted, as said. + theirs = result.get("counts") + width = len(next(iter(theirs), "")) if isinstance(theirs, dict) and theirs else len(next(iter(counts), "")) if any(len(k) != width or set(k) - {"0", "1"} for k in counts) or (omitted == 0 and s["distinct_outcomes"].value != len(counts)): return False d = s.get("distance") @@ -1725,7 +1754,8 @@ def check_contract(request, result, reasons): m = result.get("method") ran = "method:" + m if isinstance(m, str) else None if "choice-unchecked" not in PLANTS: # PLANT - if _picked(routes, auto, contract, lambda r: gate(r) is None) != planner["choice"] or ran != planner["choice"]: + if (_picked(routes, auto, contract, lambda r: gate(r) is None) != planner["choice"] or ran != planner["choice"] + or not _ran_as_routed(routes, planner["choice"], result)): reasons.add("planner_choice") if not _stable_holds(planner, routes, contract): reasons.add("planner_stable") @@ -2856,6 +2886,20 @@ def self_test(args): def local_body(contract, routes, choice, auto, stable_choice, kept, **kw): return _seal(seed, *_local_contract_job(contract, routes, choice, auto, stable_choice, kept, **kw)) + def contract_edited(edit): + request, text = _contract_job(seed=None, extra_routes=()) + body = {"request": json.loads(request), "result": json.loads(text)} + edit(body) + return _seal(seed, json.dumps(body["request"], separators=(",", ":")), json.dumps(body["result"], separators=(",", ":"))) + + def chosen(b): + return next(r for r in b["result"]["planner"]["routes"] if r["route"] == b["result"]["planner"]["choice"]) + + check("a run sealed at a cost its route does not state", reasons_of(contract_edited( + lambda b: b["result"]["cost"].update(free=False, confirmed=True, estimate={"free": False, "amount": "50", "currency": "USD"}))) == ["planner_choice"]) + check("the route chosen names another device than ran", reasons_of(contract_edited(lambda b: chosen(b).update(device="elsewhere"))) == ["planner_choice"]) + check("the route chosen names the device that ran", reasons_of(contract_edited(lambda b: chosen(b).update(device=b["result"]["provider"]["device"]))) == []) + def timed_by_host(kept): request, text = _local_contract_job({"exactness": "exact", "deadline_seconds": 60}, base(), "method:exact", "method:exact", True, kept) result = json.loads(text) @@ -2971,6 +3015,12 @@ def self_test(args): _lr("mps", "heuristic", 60, "rejected", "class", memory=4096)], "method:exact", "method:exact", True, {"deadline": {"seconds": 60, "elapsed_ms": 3, "kept": True}}), []), ("a deadline a host's timer kept, the result stating no time of its own", timed_by_host({"deadline": {"seconds": 60, "elapsed_ms": 3, "kept": True}}), []), + ("the matrix product state's route stated exact", local_body({"exactness": "exact", "deadline_seconds": 60}, base()[:3] + [_lr("mps", "exact", 60, "met", memory=4096)], + "method:exact", "method:exact", True, {"deadline": {"seconds": 60, "elapsed_ms": 3, "kept": True}}), ["planner_route"]), + ("a method the host registered, said not to depend on the host", local_body({"exactness": "exact", "deadline_seconds": 60}, base() + [_lr("turbo", "bit-exact", None, "met")], + "method:exact", "method:exact", True, {"deadline": {"seconds": 60, "elapsed_ms": 3, "kept": True}}), ["planner_route"]), + ("the same, said to depend on it", local_body({"exactness": "exact", "deadline_seconds": 60}, base() + [_lr("turbo", "bit-exact", None, "met", host_dependent=True)], + "method:exact", "method:exact", False, {"deadline": {"seconds": 60, "elapsed_ms": 3, "kept": True}}), []), ("a deadline's time that is not the result's", local_body({"exactness": "exact", "deadline_seconds": 60}, base(), "method:exact", "method:exact", True, {"deadline": {"seconds": 60, "elapsed_ms": 4, "kept": True}}), ["planner_kept"]), diff --git a/wai/wai-quantum-cli/README.md b/wai/wai-quantum-cli/README.md index 9e8057adf..c1bc9d013 100644 --- a/wai/wai-quantum-cli/README.md +++ b/wai/wai-quantum-cli/README.md @@ -109,7 +109,7 @@ wai-quantum run circuit.qasm --method statevector --fabric cpu --fabric cpu --sh wai-quantum run prog.qasm --fabric a-member-elsewhere # exits 1 ``` -**Under a contract.** `--exactness CLASS`, `--deadline SECONDS`, `--max-cost 0.50:USD`, `--max-joules J` and `--allow-providers` (or `--contract` with the JSON of [the provider protocol's section 8.7](../extensions/quantum-providers.md)) say what the answer must be. The planner then prices every route it can see: each method here, at its memory and the time its work predicts, and with `--allow-providers` each of your own providers, by its own estimate and what that leaves out (each is asked, and sent nothing). It rejects every route that cannot meet the contract, runs the cheapest of the rest, and seals its reasoning in the receipt. An unknown never passes: a time nobody states does not meet a deadline, nor an unknown cost a ceiling, nor an estimate that is only the least a job can come to. Nothing falls back, from exact to approximate or between a simulator and a device, and with no route left the job is refused with every route's reason (`J071`). A contract that names no class keeps the class `auto` would give, and a device's counts are reached only by asking for `measured` (or `any`). A provider's answer carries a classical method's counts beside it, with their distance, wherever a method here can reach them in the time the contract leaves, and the receipt says why where none can. Under a contract no provider is asked anything without `--allow-providers` and a class one could give (`--exactness measured`, `simulated` or `any`), and one you name is refused without them (`J070`). A ceiling bounds the estimate a route is chosen by, not what is charged after, and confirms nothing: a run on a provider you name that is not free still takes `--yes`, and one the planner routes to a provider that is not free takes `--confirm WORD`, the word its `--dry-run` prints for that route, that provider and device, that estimate and that program, and is refused if any of them has changed when it would be sent. A deadline holds a method's own run time here, and a provider's from its submission to its counts; the command line cancels a provider's job still waiting at it (`J074`), and a job ends there only on the provider's word that it was cancelled: a provider that cannot cancel says so in its price, and its job stays waiting. `wai-quantum plan` with the same options shows every route's price or reason and sends nothing; `wai-quantum verify --recheck` prices the routes again here and runs the shadow again; a run that kept less than its contract asked is still sealed, says so, and exits 4. +**Under a contract.** `--exactness CLASS`, `--deadline SECONDS`, `--max-cost 0.50:USD`, `--max-joules J` and `--allow-providers` (or `--contract` with the JSON of [the provider protocol's section 8.7](../extensions/quantum-providers.md)) say what the answer must be. The planner then prices every route it can see: each method here, at its memory and the time its work predicts, and with `--allow-providers` each of your own providers, by its own estimate and what that leaves out (each is asked, and sent nothing). It rejects every route that cannot meet the contract, runs the cheapest of the rest, and seals its reasoning in the receipt. An unknown never passes: a time nobody states does not meet a deadline, nor an unknown cost a ceiling, nor an estimate that is only the least a job can come to. Nothing falls back, from exact to approximate or between a simulator and a device, and with no route left the job is refused with every route's reason (`J071`). A contract that names no class keeps the class `auto` would give, and a device's counts are reached only by asking for `measured` (or `any`). A provider's answer carries a classical method's counts beside it, with their distance, wherever a method here can reach them in the time the contract leaves, and the receipt says why where none can. Under a contract no provider is asked anything without `--allow-providers` and a class one could give (`--exactness measured`, `simulated` or `any`), and one you name is refused without them (`J070`). A ceiling bounds the estimate a route is chosen by, not what is charged after, and confirms nothing: a run on a provider you name that is not free still takes `--yes`, and one the planner routes to a provider that is not free takes `--confirm WORD`, the word its `--dry-run` prints for that route, that provider and device, that estimate, that program and that contract, and is refused if any of them has changed when it would be sent; a word sends one run, and a dry run after it gives the word for the next. A deadline holds a method's own run time here, and a provider's from its submission to its counts; the command line cancels a provider's job still waiting at it (`J074`), and a job ends there only on the provider's word that it was cancelled: a provider that says it cannot cancel (the cloud-tasks kinds, or an open-protocol provider whose `describe` says `"cancels": false`) says so in its price, and its job stays waiting. `wai-quantum plan` with the same options shows every route's price or reason and sends nothing; `wai-quantum verify --recheck` prices the routes again here and runs the shadow again; a run that kept less than its contract asked is still sealed, says so, and exits 4. Each result names: diff --git a/wai/wai-quantum-cli/README.zh-CN.md b/wai/wai-quantum-cli/README.zh-CN.md index f8307d95a..29987a3c2 100644 --- a/wai/wai-quantum-cli/README.zh-CN.md +++ b/wai/wai-quantum-cli/README.zh-CN.md @@ -112,7 +112,7 @@ wai-quantum run circuit.qasm --method statevector --fabric cpu --fabric cpu --sh wai-quantum run prog.qasm --fabric a-member-elsewhere # exits 1:别处的成员,被拒绝 ``` -**在契约之下。** `--exactness CLASS`、`--deadline SECONDS`、`--max-cost 0.50:USD`、`--max-joules J` 和 `--allow-providers`(或用 `--contract` 给出 [提供方协议第 8.7 节](../extensions/quantum-providers.md) 的 JSON)说明答案必须满足什么。规划器随后为它能看到的每条路径定价:本机的每个方法,按其内存和其工作量所预示的时间;加上 `--allow-providers` 时,还有你自己的每个提供方,按其自身的估算以及该估算未包含的内容(每个都会被询问,但不会发送任何东西)。它拒绝每条无法满足契约的路径,运行其余路径中最便宜的一条,并把它的推理封入收据。未知量从不算作满足:无人说明的时间不满足截止时间,未知的费用不满足上限,只是作业最低可能费用的估算也不满足。不会回退:既不会从精确退到近似,也不会在模拟器与设备之间互换;没有路径剩下时,作业被拒绝,并列出每条路径的原因(`J071`)。未指明类别的契约保留 `auto` 会给出的类别;只有请求 `measured`(或 `any`)才会用到设备的计数。提供方的答案旁边附有经典方法的计数及两者的距离,只要本机有方法能在契约留下的时间内得到它们;没有方法能做到时,收据会说明原因。在契约之下,没有 `--allow-providers` 以及提供方能够给出的类别(`--exactness measured`、`simulated` 或 `any`)时,不会询问任何提供方,你指定的提供方也会被拒绝(`J070`)。上限约束的是选择路径所依据的估算,而不是之后实际收取的费用,它也不构成确认:在你指定的提供方上运行、且不免费时,仍需要 `--yes`;规划器选到的提供方不免费时,需要 `--confirm WORD`,即它的 `--dry-run` 为该路径、该提供方和设备、该估算和该程序打印的词,发送时只要其中任何一项已有变化就会被拒绝。截止时间约束本机方法自身的运行时间,以及提供方从提交到得出计数的时间;命令行会在截止时取消仍在等待的提供方作业(`J074`),且只有提供方确认已取消时作业才在此结束:无法取消的提供方会在其价格中说明,其作业继续等待。带相同选项的 `wai-quantum plan` 显示每条路径的价格或原因,不发送任何东西;`wai-quantum verify --recheck` 在本机重新为路径定价并重新运行影子运行;未能满足契约全部要求的运行仍会被封存,并如实说明,退出状态为 4。 +**在契约之下。** `--exactness CLASS`、`--deadline SECONDS`、`--max-cost 0.50:USD`、`--max-joules J` 和 `--allow-providers`(或用 `--contract` 给出 [提供方协议第 8.7 节](../extensions/quantum-providers.md) 的 JSON)说明答案必须满足什么。规划器随后为它能看到的每条路径定价:本机的每个方法,按其内存和其工作量所预示的时间;加上 `--allow-providers` 时,还有你自己的每个提供方,按其自身的估算以及该估算未包含的内容(每个都会被询问,但不会发送任何东西)。它拒绝每条无法满足契约的路径,运行其余路径中最便宜的一条,并把它的推理封入收据。未知量从不算作满足:无人说明的时间不满足截止时间,未知的费用不满足上限,只是作业最低可能费用的估算也不满足。不会回退:既不会从精确退到近似,也不会在模拟器与设备之间互换;没有路径剩下时,作业被拒绝,并列出每条路径的原因(`J071`)。未指明类别的契约保留 `auto` 会给出的类别;只有请求 `measured`(或 `any`)才会用到设备的计数。提供方的答案旁边附有经典方法的计数及两者的距离,只要本机有方法能在契约留下的时间内得到它们;没有方法能做到时,收据会说明原因。在契约之下,没有 `--allow-providers` 以及提供方能够给出的类别(`--exactness measured`、`simulated` 或 `any`)时,不会询问任何提供方,你指定的提供方也会被拒绝(`J070`)。上限约束的是选择路径所依据的估算,而不是之后实际收取的费用,它也不构成确认:在你指定的提供方上运行、且不免费时,仍需要 `--yes`;规划器选到的提供方不免费时,需要 `--confirm WORD`,即它的 `--dry-run` 为该路径、该提供方和设备、该估算、该程序和该契约打印的词,一个词只发送一次运行,之后的预演会给出下一次运行的词,发送时只要其中任何一项已有变化就会被拒绝。截止时间约束本机方法自身的运行时间,以及提供方从提交到得出计数的时间;命令行会在截止时取消仍在等待的提供方作业(`J074`),且只有提供方确认已取消时作业才在此结束:声明无法取消的提供方(cloud-tasks 各类,或 `describe` 中写明 `"cancels": false` 的开放协议提供方)会在其价格中说明,其作业继续等待。带相同选项的 `wai-quantum plan` 显示每条路径的价格或原因,不发送任何东西;`wai-quantum verify --recheck` 在本机重新为路径定价并重新运行影子运行;未能满足契约全部要求的运行仍会被封存,并如实说明,退出状态为 4。 每个结果都注明: diff --git a/wai/wai-quantum-cli/src/providers.rs b/wai/wai-quantum-cli/src/providers.rs index 4726df8da..3166bddf7 100644 --- a/wai/wai-quantum-cli/src/providers.rs +++ b/wai/wai-quantum-cli/src/providers.rs @@ -313,7 +313,7 @@ pub fn plan(job: &Job, as_json: bool) { let req = job_request(job).unwrap_or_else(|e| die(&e)); let (reg, stores) = load(); let (open, closed) = targets(®, &stores, job.memory_gb << 30); - let routed = pjob::route_with(&open, closed, &req, job.memory_gb << 30).unwrap_or_else(|e| die(&e.to_string())); + let routed = counted(pjob::route_with(&open, closed, &req, job.memory_gb << 30).unwrap_or_else(|e| die(&e.to_string()))); if as_json { println!("{}", routed.json()); } else { @@ -321,6 +321,14 @@ pub fn plan(job: &Job, as_json: bool) { } } +/// `routed`, its word the one for the next run of its job by the person's ledger. +fn counted(routed: pjob::Routed) -> pjob::Routed { + match Ledger::load_default() { + Ok(l) => routed.counted(&l), + Err(_) => routed, + } +} + /// A routed plan as a reader takes it in: the planner's reasoning, and, where the /// route chosen is not free, the word that confirms that route at that estimate. fn print_routed(routed: &pjob::Routed) { @@ -335,7 +343,7 @@ fn run_routed(job: &Job, out: &Output, key: &KeyArgs, args: &RunArgs) { let req = job_request(job).unwrap_or_else(|e| die(&e)); let (reg, stores) = load(); let (open, closed) = targets(®, &stores, job.memory_gb << 30); - let routed = pjob::route_with(&open, closed, &req, job.memory_gb << 30).unwrap_or_else(|e| die(&e.to_string())); + let routed = counted(pjob::route_with(&open, closed, &req, job.memory_gb << 30).unwrap_or_else(|e| die(&e.to_string()))); if args.dry_run { if out.json { println!("{}", routed.json()); @@ -869,7 +877,7 @@ pub fn mcp_call_with(name: &str, args: &Value, key: &SigningKey, reg: &Registry, "plan_routes" | "run_routed" => (|| { let req = mcp_routed(args)?; let (open, closed) = targets(reg, stores, crate::DEFAULT_MEMORY_GB << 30); - let routed = pjob::route_with(&open, closed, &req, crate::DEFAULT_MEMORY_GB << 30).map_err(|e| e.to_string())?; + let routed = pjob::route_with(&open, closed, &req, crate::DEFAULT_MEMORY_GB << 30).map_err(|e| e.to_string())?.counted(ledger); if name == "plan_routes" { return Ok(routed.json()); } diff --git a/wai/wai-quantum-cli/tests/providers.rs b/wai/wai-quantum-cli/tests/providers.rs index c9d4f813b..73407f488 100644 --- a/wai/wai-quantum-cli/tests/providers.rs +++ b/wai/wai-quantum-cli/tests/providers.rs @@ -420,14 +420,18 @@ fn an_agent_weighs_a_contract_and_runs_on_the_route_it_chooses() { fn with<'a>(base: &[&'a str], more: &[&'a str]) -> Vec<&'a str> { base.iter().chain(more).copied().collect() } + // The agent's word sent its run, so the dry run gives the next run's. let shown = h.ok(&with(&routed, &["--dry-run"]), ""); - assert!(shown.contains(&format!("--confirm {word}")), "{shown}"); + let next = shown.split("--confirm ").nth(1).and_then(|s| s.split_whitespace().next()).unwrap_or_else(|| panic!("{shown}")).to_string(); + assert!(next != word && shown.contains("sent once before"), "{shown}"); let sent = jobs(&h).len(); - let out = h.run(&with(&routed, &["--confirm", "0123456789abcdef"]), ""); - assert_eq!(out.status.code(), Some(3), "{}", String::from_utf8_lossy(&out.stderr)); - assert!(String::from_utf8_lossy(&out.stderr).contains("not what was confirmed"), "{}", String::from_utf8_lossy(&out.stderr)); - assert_eq!(jobs(&h).len(), sent, "a word for another route or estimate sends nothing"); - let body: Value = serde_json::from_str(&h.ok(&with(&routed, &["--confirm", &word, "--json"]), "")).unwrap(); + for (given, says) in [(word.as_str(), "already sent"), ("0123456789abcdef", "not what was confirmed")] { + let out = h.run(&with(&routed, &["--confirm", given]), ""); + assert_eq!(out.status.code(), Some(3), "{}", String::from_utf8_lossy(&out.stderr)); + assert!(String::from_utf8_lossy(&out.stderr).contains(says), "{}", String::from_utf8_lossy(&out.stderr)); + } + assert_eq!(jobs(&h).len(), sent, "a spent word, or one for another route or estimate, sends nothing"); + let body: Value = serde_json::from_str(&h.ok(&with(&routed, &["--confirm", &next, "--json"]), "")).unwrap(); assert_eq!((body["result"]["provider"]["name"].as_str(), body["result"]["cost"]["confirmed"].as_bool()), (Some("paid"), Some(true)), "{body}"); } diff --git a/wai/wai-quantum-qpu/src/job.rs b/wai/wai-quantum-qpu/src/job.rs index 83f0db0d2..91756a655 100644 --- a/wai/wai-quantum-qpu/src/job.rs +++ b/wai/wai-quantum-qpu/src/job.rs @@ -458,6 +458,16 @@ pub struct Routed { /// The route chosen, and its plan when it is one of the engine's methods. pub choice: planner::Choice, plans: Vec<(String, Plan)>, + /// The job's contract, which the word binds. + contract: Value, + /// How many runs of this job its word has sent before, as the ledger shows. + sent: usize, +} + +/// How many runs a ledger holds of a job whose word is `base`: each one recorded, +/// less those its provider refused, which were not sent. +fn sends_of(ledger: &Ledger, base: &str) -> usize { + ledger.list().0.iter().filter(|t| t.confirms() == Some(base) && t.state() != "failed").count() } impl Routed { @@ -478,7 +488,7 @@ impl Routed { "token": token, "route": format!("provider:{name}"), "money": money, - "says": self.says(name, &token), + "says": self.says(name, &token, self.sent), }); } } @@ -489,9 +499,14 @@ impl Routed { /// What a person reads of a routed run that is not free: what it costs, and /// the word, which is the one thing that confirms it. - fn says(&self, name: &str, token: &str) -> String { + fn says(&self, name: &str, token: &str, sent: usize) -> String { let cost = self.plans.iter().find(|(n, _)| n == name).map(|(_, p)| p.cost.clone()).unwrap_or_default(); - format!("{cost}; a ceiling confirms nothing. It runs only on the person's word for this route, this device, this estimate and this program: --confirm {token} on the command line, confirm: \"{token}\" for an agent") + let again = match sent { + 0 => String::new(), + 1 => " This job has been sent once before.".to_string(), + n => format!(" This job has been sent {n} times before."), + }; + format!("{cost}; a ceiling confirms nothing. It runs once, only on the person's word for this route, this device, this estimate, this program and this contract: --confirm {token} on the command line, confirm: \"{token}\" for an agent.{again}") } fn chosen_route(&self) -> &Value { @@ -508,19 +523,40 @@ impl Routed { /// saw it is not sent. `None` for a route that is free, or one of the /// engine's methods. pub fn confirmation(&self) -> Option { + self.word(self.sent) + } + + /// The word, taking the ledger's count of the runs of this job sent before: + /// a word confirms one run, so a dry run after one gives another word. + pub fn counted(mut self, ledger: &Ledger) -> Routed { + self.sent = self.base().map_or(0, |b| sends_of(ledger, &b)); + self + } + + fn said(&self) -> Option { let planner::Choice::Provider(name) = &self.choice else { return None }; let (_, p) = self.plans.iter().find(|(n, _)| n == name)?; if p.free { return None; } - let said = json!({ + Some(json!({ "route": format!("provider:{name}"), "money": self.chosen_route()["price"]["money"], "provider": p.json["provider"], "identity": p.identity, "program": compiled_json(&p.program)["program"], "shots": p.read.shots, - }); + "contract": self.contract, + })) + } + + fn base(&self) -> Option { + self.said().map(|s| blake3::hash(&receipt::canonical(&s)).to_hex()[..16].to_string()) + } + + fn word(&self, sent: usize) -> Option { + let mut said = self.said()?; + said["sent_before"] = json!(sent); Some(blake3::hash(&receipt::canonical(&said)).to_hex()[..16].to_string()) } @@ -569,7 +605,7 @@ pub fn route_with(targets: &[Target], also: Vec, request: &Value { p.reason_held(request, d.reasoning.clone(), name)?; } - Ok(Routed { reasoning: d.reasoning, choice: d.choice, plans }) + Ok(Routed { reasoning: d.reasoning, choice: d.choice, plans, contract: request.get("contract").cloned().unwrap_or(Value::Null), sent: 0 }) } /// A local route the planner chose ([`route`]) run here, its result carrying the @@ -595,22 +631,25 @@ pub fn start_routed(t: &Target, routed: &Routed, request: &Value, confirm: Optio if routed.provider() != Some(t.name.as_str()) { return Err(JobError::Failed(format!("the planner did not choose {}", t.name))); } - if let Some(token) = routed.confirmation() + let base = routed.base(); + let sent = base.as_deref().map_or(0, |b| sends_of(ledger, b)); + if let Some(token) = routed.word(sent) && confirm != Some(token.as_str()) { let seen = match confirm { + Some(c) if (0..sent).any(|k| routed.word(k).as_deref() == Some(c)) => "that word confirmed a run of this job already sent, and a word confirms one run: the word below confirms another. ", Some(_) => "the word given is not this route's at this estimate: what is chosen now, or what it costs, is not what was confirmed. ", None => "", }; // The provider's plan, as a run on a provider named is refused with, saying // what confirms this one. - let says = routed.says(&t.name, &token); + let says = routed.says(&t.name, &token, sent); let mut plan = p.json.clone(); plan["confirm"] = json!(says); plan["token"] = json!(token); return Err(JobError::Unconfirmed { plan, message: format!("{seen}this run on {}: {says}", t.name) }); } - start_planned(t, p, request, true, ledger) + start_planned(t, p, request, true, ledger, base.as_deref()) } /// The dry run: the plan for `request` on `t`, with nothing submitted. @@ -762,12 +801,15 @@ pub fn start(t: &Target, request: &Value, confirmed: bool, ledger: &Ledger) -> R allowed(t, request)?; let sampler = QpuSampler::new(&*t.provider).map_err(|e| t.fail(e))?; let p = plan_with(t, &sampler, request)?; - start_planned(t, &p, request, confirmed, ledger) + start_planned(t, &p, request, confirmed, ledger, None) } -fn start_planned(t: &Target, p: &Plan, request: &Value, confirmed: bool, ledger: &Ledger) -> Result { +fn start_planned(t: &Target, p: &Plan, request: &Value, confirmed: bool, ledger: &Ledger, confirms: Option<&str>) -> Result { refuse_unconfirmed(t, p, confirmed)?; let mut ticket = Ticket::recording(&t.name, request, &p.program, p.read.shots, p.read.seed, sealing_of(t, p, confirmed), p.names.as_ref()); + if let Some(base) = confirms { + ticket.confirming(base); + } ledger.put(&ticket).map_err(|e| JobError::Failed(format!("nothing was sent: the job could not be recorded first ({e})")))?; match t.provider.submit_seeded(&p.program, p.read.shots, p.read.seed) { Ok(id) => { @@ -1603,6 +1645,70 @@ mod tests { assert!(plan["confirm"].is_string() && plan["token"] == routed.confirmation().unwrap().as_str(), "{plan}"); } + /// A word confirms one run: the same word does not send the job again, and a dry + /// run after it gives the word for another run. It binds the contract it was + /// given under: a deadline dropped is not what was confirmed. + #[test] + fn a_word_confirms_one_run_and_binds_its_contract() { + let r = Arc::new(Reference::new(Config { price: Some(("0.001".into(), "USD".into(), Per::Shot)), ..Config::default() }).unwrap()); + let (t, ops, _) = watched(&r); + let want = json!({ "qasm": BELL, "shots": 1000, "seed": 2, "contract": { "providers": "allowed", "exactness": "simulated", "max_cost": { "amount": "5", "currency": "USD" }, "deadline_seconds": 600 } }); + let records = Records::new("word-once"); + let ledger = records.ledger(); + let routed = || route(std::slice::from_ref(&t), &want, 1 << 30).unwrap(); + let word = routed().counted(&ledger).confirmation().expect("not free"); + start_routed(&t, &routed(), &want, Some(&word), &ledger).unwrap(); + assert_eq!(count(&ops, "submit"), 1); + let Err(JobError::Unconfirmed { plan, message }) = start_routed(&t, &routed(), &want, Some(&word), &ledger) else { panic!("one word sent a second run") }; + assert_eq!(count(&ops, "submit"), 1, "nothing more was sent"); + assert!(message.contains("already sent") && message.contains("sent once before"), "{message}"); + let next = routed().counted(&ledger).confirmation().unwrap(); + assert!(next != word && plan["token"] == next.as_str(), "{plan}"); + start_routed(&t, &routed(), &want, Some(&next), &ledger).unwrap(); + assert_eq!(count(&ops, "submit"), 2); + // Under another contract the word is another. + let mut loose = want.clone(); + loose["contract"].as_object_mut().unwrap().remove("deadline_seconds"); + let elsewhere = Records::new("word-contract"); + let given = routed().counted(&elsewhere.ledger()).confirmation().unwrap(); + let other = route(std::slice::from_ref(&t), &loose, 1 << 30).unwrap(); + assert!(matches!(start_routed(&t, &other, &loose, Some(&given), &elsewhere.ledger()), Err(JobError::Unconfirmed { .. }))); + assert_eq!(count(&ops, "submit"), 2); + } + + /// An open-protocol provider says what its price leaves out: one whose describe + /// says it cannot cancel has `cancel` in its route's `leaves_out`, and an + /// estimate that is the least a job can come to meets no ceiling. + #[test] + fn an_open_provider_says_it_cannot_cancel_and_that_its_estimate_is_the_least() { + let r = Arc::new(Reference::new(Config { price: Some(("0.001".into(), "USD".into(), Per::Shot)), ..Config::default() }).unwrap()); + let edited = |edit: fn(&mut Value)| { + let r = Arc::clone(&r); + Target::new("lab", Kind::Process, Box::new(OpenProvider::new(Local(move |m: &Value| { + let mut a = r.handle(m, None); + edit(&mut a); + a + }))), None) + }; + let deadline = json!({ "qasm": BELL, "shots": 100, "contract": { "providers": "allowed", "exactness": "simulated", "deadline_seconds": 600, "max_cost": { "amount": "5", "currency": "USD" } } }); + let left = |t: Target| route(&[t], &deadline, 1 << 30).unwrap().reasoning["routes"].as_array().unwrap().iter().find(|x| x["route"] == "provider:lab").unwrap()["price"]["leaves_out"].clone(); + let cannot: fn(&mut Value) = |a| { + if a.get("protocol").is_some() { + a["cancels"] = json!(false); + } + }; + assert!(left(edited(cannot)).as_array().unwrap().contains(&json!("cancel"))); + assert!(!left(edited(|_| {})).as_array().unwrap().contains(&json!("cancel"))); + let least: fn(&mut Value) = |a| { + if a.get("amount").is_some() { + a["at_least"] = json!(true); + } + }; + let Err(refused) = route(&[edited(least)], &deadline, 1 << 30).map(|r| r.reasoning) else { panic!("an estimate that is the least met the ceiling") }; + let said = refused.to_string(); + assert!(said.contains("provider:lab: at least") && said.contains("the least it can come to"), "{said}"); + } + /// Only the provider's word ends a job past its deadline. A cancel it has not /// finished, or a status that does not read, leaves the job to be asked after, /// and if it finishes it is sealed, saying the deadline was missed. A client diff --git a/wai/wai-quantum-qpu/src/ledger.rs b/wai/wai-quantum-qpu/src/ledger.rs index 1d7c8270b..142c70634 100644 --- a/wai/wai-quantum-qpu/src/ledger.rs +++ b/wai/wai-quantum-qpu/src/ledger.rs @@ -213,6 +213,16 @@ impl Ticket { self.value["polls"].as_u64().unwrap_or(0) as u32 } + /// The word a routed run was confirmed by, less which run of it this is: the + /// same job confirmed again is told apart by how many were sent before. + pub(crate) fn confirms(&self) -> Option<&str> { + self.value["confirms"].as_str() + } + + pub(crate) fn confirming(&mut self, base: &str) { + self.value["confirms"] = json!(base); + } + pub(crate) fn polled(&mut self) { self.value["polls"] = json!(self.polls() + 1); } diff --git a/wai/wai-quantum-qpu/src/open_provider.rs b/wai/wai-quantum-qpu/src/open_provider.rs index 37e8d9ff3..b6085392b 100644 --- a/wai/wai-quantum-qpu/src/open_provider.rs +++ b/wai/wai-quantum-qpu/src/open_provider.rs @@ -420,7 +420,8 @@ pub fn estimate_of(a: &Value) -> Result { unit: a.get("unit").and_then(Value::as_str).map(String::from), seconds: a.get("seconds").and_then(Value::as_f64).filter(|s| s.is_finite() && *s >= 0.0), note: a.get("note").and_then(Value::as_str).map(|n| n.chars().take(400).collect()), - at_least: false, + // The least the job can come to, as a time-billed provider may only know (§5.2). + at_least: !free && a.get("at_least") == Some(&Value::Bool(true)), }) } @@ -706,8 +707,10 @@ impl Provider for OpenProvider { Ok((counts, info, Stated::counts(source).with_execution(execution))) } + /// What its `describe` says: a provider that cannot cancel says + /// `"cancels": false` (§5.1), and a price then says so. fn can_cancel(&self) -> bool { - true + self.describe().map_or(true, |d| d.get("cancels") != Some(&Value::Bool(false))) } fn cancel(&self, id: &str) -> Result<(), QpuError> { diff --git a/wai/wai-quantum/src/engine/planner.rs b/wai/wai-quantum/src/engine/planner.rs index 77b42e6e6..4e8753f16 100644 --- a/wai/wai-quantum/src/engine/planner.rs +++ b/wai/wai-quantum/src/engine/planner.rs @@ -1089,6 +1089,23 @@ pub fn own_check(v: &Value, result: &Value) -> Result<(), String> { /// with a result that says only that the provider ran. pub fn before_sending(v: &Value, reasoning: &Value, provider: &str, shots: u64) -> Result<(), String> { let mut r = json!({ "method": "provider", "provider": { "name": provider }, "shots": shots, "planner": reasoning, "shadow": { "ran": false, "code": "failed", "why": "not yet run" } }); + // What the run would seal of who ran it and what it costs: the route's own word. + let name = format!("provider:{provider}"); + if let Some(route) = reasoning["routes"].as_array().and_then(|a| a.iter().find(|x| x["route"] == name)) { + for k in ["device", "provenance"] { + if let Some(v) = route.get(k) { + r["provider"][k] = v.clone(); + } + } + let money = &route["price"]["money"]; + let mut estimate = json!({ "free": money["free"] }); + for k in ["amount", "currency", "unit", "at_least"] { + if let Some(v) = money.get(k) { + estimate[k] = v.clone(); + } + } + r["cost"] = json!({ "free": money["free"], "estimate": estimate }); + } if reasoning["shadow"]["route"].is_null() { r["shadow"]["code"] = reasoning["shadow"]["code"].clone(); } @@ -1517,7 +1534,7 @@ pub fn check(request: &Value, result: &Value) -> Vec<&'static str> { } let picked = pick(routes, auto.as_deref(), &held); let ran = if result["method"] == "provider" { result.pointer("/provider/name").and_then(Value::as_str).map(|n| format!("provider:{n}")) } else { result["method"].as_str().map(|m| format!("method:{m}")) }; - if picked.and_then(|r| r["route"].as_str()) != p["choice"].as_str() || ran.as_deref() != p["choice"].as_str() { + if picked.and_then(|r| r["route"].as_str()) != p["choice"].as_str() || ran.as_deref() != p["choice"].as_str() || !ran_as_routed(routes, p["choice"].as_str(), result) { out.push(PLANNER_CHOICE); } let want_stable = stable_of(routes, &p["host"]["job_bytes"], p["choice"].as_str(), &contract); @@ -1553,21 +1570,42 @@ fn class_of_method(method: &str, class: &str) -> bool { /// when it runs on a GPU; a provider's route depends on the host. fn states_itself(r: &Value, request: &Value) -> bool { let class = r["class"].as_str().unwrap_or(""); + // A provider's route has the class its provenance gives. let Some(m) = r["route"].as_str().and_then(|n| n.strip_prefix("method:")) else { + return r["host_dependent"] == true && r["provenance"].as_str().and_then(super::provider::class_of_provenance).is_none_or(|c| class == c); + }; + // A method the host registered is the host's own code. + let Some(builtin) = Registry::builtins().method(m) else { return r["host_dependent"] == true; }; - if Registry::builtins().method(m).is_none() { - return true; - } let given = |k: &str| request["options"].get(k).is_some_and(|x| !x.is_null()); let by_job = match m { "stabilizer" => class == if request.get("noise").is_some_and(|x| !x.is_null()) || crate::engine::targets::job::names_target(request) { "estimate" } else { "exact" }, "stabilizer_rank" => class == if given("terms") || given("epsilon") { "estimate" } else { "exact" }, - _ => true, + // Its plan says which table fits, and a route need not be priced. + "cutrank" => true, + // Every other method's route has the one class its table gives: the first + // each class it declares meets. + _ => class == class_of(builtin, None, None, false), }; by_job && class_of_method(m, class) && r["host_dependent"] == is_gpu(m) } +/// Whether the route chosen is what ran: for a provider's, the result's provider +/// is the device and provenance it names, where it names them, and the result's +/// cost is its money (free alike, and its amount, currency, unit and whether it +/// is the least it can come to). +fn ran_as_routed(routes: &[Value], choice: Option<&str>, result: &Value) -> bool { + let Some(r) = routes.iter().find(|r| r["route"].as_str() == choice) else { return true }; + if r["kind"] != "provider" { + return true; + } + let (money, cost) = (&r["price"]["money"], &result["cost"]); + ["device", "provenance"].iter().all(|k| r.get(*k).is_none_or(|v| *v == result["provider"][*k])) + && cost["free"] == money["free"] + && ["amount", "currency", "unit", "at_least"].iter().all(|k| cost["estimate"].get(*k) == money.get(*k)) +} + /// A `kept` member as its table gives it: true, false, or `null` where it is not /// known. Nothing else reads as `null`. fn kept_is(v: &Value, want: Option) -> bool { @@ -1670,9 +1708,10 @@ fn shadow_plan_holds(request: &Value, contract: &Contract, p: &Value, result: &V /// Whether a shadow's outcomes are of a counts' form: each a string of `0` and /// `1`, all of one width, and, with none omitted, as many as it says. -fn outcomes_hold(s: &Value, omitted: Option) -> bool { +fn outcomes_hold(s: &Value, omitted: Option, of: &Value) -> bool { let Some(counts) = s["counts"].as_object() else { return false }; - let width = counts.keys().next().map_or(0, String::len); + // As wide as the job's outcomes, where the provider's counts name one. + let width = of.as_object().and_then(|c| c.keys().next()).or_else(|| counts.keys().next()).map_or(0, String::len); counts.keys().all(|k| k.len() == width && k.bytes().all(|b| b == b'0' || b == b'1')) && (omitted != Some(0) || s["distinct_outcomes"].as_f64() == Some(counts.len() as f64)) } @@ -1698,7 +1737,7 @@ fn shadow_holds(request: &Value, contract: &Contract, p: &Value, result: &Value) (Some(l), Some(o), Some(n)) => l + u128::from(o) == u128::from(n), _ => false, } && is_whole(&s["distinct_outcomes"]) - && outcomes_hold(s, omitted); + && outcomes_hold(s, omitted, &result["counts"]); let whole_lists = result["omitted_shots"].as_f64() == Some(0.0) && s["omitted_shots"].as_f64() == Some(0.0); let distance_ok = match s["distance"]["computed"].as_bool() { Some(false) => s["distance"]["why"].is_string() && !whole_lists, @@ -1792,9 +1831,23 @@ pub fn recheck(reg: &Registry, job: &Value) -> Result { } else if replanned.is_some() { json!({ "checked": true, "same": true, "why": "no shadow could be planned, and none can here" }) } else { - json!({ "checked": false, "why": "no shadow could be planned, as the reasoning says why; another engine's plan is not held here" }) + // Sealed by another engine, whose version is its host's word: what this one + // plans is said, and the receipt is held neither way. + let here = plan.is_object().then(|| Contract::read(request).ok().flatten()).flatten().map(|c| { + let chosen = p["choice"].as_str().unwrap_or(""); + let a = shadow_plan(reg, request, &Host::new(job_bytes), &c, provider_seconds(&p["routes"], chosen)); + if a["route"].is_null() { a["code"].clone() } else { a["route"].clone() } + }); + json!({ "checked": false, "same": null, "why": format!("no shadow could be planned, the reasoning says, and it was sealed by another engine; this one plans {}, so the receipt is not held here either way", here.unwrap_or(Value::Null)) }) + }; + // Held only where everything that applies was checked here. + let holds = if priced["same"] == false || shadow["same"] == false { + json!(false) + } else if shadow.get("same") == Some(&Value::Null) { + Value::Null + } else { + json!(true) }; - let holds = priced["same"] != false && shadow["same"] != false; Ok(json!({ "holds": holds, "engine": { "sealed_by": engine, "this": super::schema::ENGINE_VERSION, "same": same_engine }, "priced": priced, "shadow": shadow })) } diff --git a/wai/wai-quantum/src/engine/planner/tests.rs b/wai/wai-quantum/src/engine/planner/tests.rs index e66c271a4..18e881cdd 100644 --- a/wai/wai-quantum/src/engine/planner/tests.rs +++ b/wai/wai-quantum/src/engine/planner/tests.rs @@ -672,13 +672,23 @@ fn provider_body_on(req: &Value, quotes: Vec, counts: Vec, provenanc let Choice::Provider(name) = d.choice else { panic!("a local route was chosen: {}", d.reasoning) }; let read = provider::read_named(req, Some(&name)).unwrap(); let text = "OPENQASM 3.0;\nbit[2] c;\ncz $0, $1;\n"; + // Who ran it and what it cost, as the route chosen says: what ran is what was chosen. + let chosen = route(&d.reasoning, &format!("provider:{name}")).clone(); + let money = &chosen["price"]["money"]; + let cost = if money["free"] == true { + json!({ "free": true, "estimate": { "free": true }, "charged": null, "confirmed": false }) + } else { + let mut estimate = money.clone(); + estimate.as_object_mut().unwrap().remove("unknown"); + json!({ "free": false, "estimate": estimate, "charged": { "amount": money["amount"], "currency": money["currency"] }, "confirmed": true }) + }; let m = provider::Measured { counts, - provider: json!({ "name": name, "kind": "process", "protocol": "wai.quantum.provider/1", "device": "lab:dev", "provenance": provenance, "qubits": 5, "basis": "rzsxxcz", "describe": "ab".repeat(32) }), + provider: json!({ "name": name, "kind": "process", "protocol": "wai.quantum.provider/1", "device": chosen["device"], "provenance": provenance, "qubits": 5, "basis": "rzsxxcz", "describe": "ab".repeat(32) }), calibration: Some("snap-1".into()), compiled: json!({ "basis": "rzsxxcz", "program": blake3::hash(text.as_bytes()).to_hex().to_string(), "qasm3": text, "native_gates": 9, "two_qubit_gates": 1, "swaps": 0, "layout": [0, 1], "final_layout": [0, 1], "checked": "checked here" }), job: json!({ "id": "j-1", "polls": 0 }), - cost: json!({ "free": false, "estimate": { "free": false, "amount": "0.3", "currency": "USD" }, "charged": { "amount": "0.3", "currency": "USD" }, "confirmed": true }), + cost, energy: json!({ "unmetered": "the work ran at the provider" }), }; let e = provider::provider_execution(&json!({ "mitigation": "none", "twirling": "none", "decoder": "none", "decoupling": "none", "remapping": "none", "optimisation": "none", "verbatim": true })); @@ -1386,6 +1396,15 @@ fn recheck_plans_the_shadow_again_and_leaves_the_host_s_routes_to_the_host() { }); assert_eq!((skipped["holds"].as_bool(), skipped["shadow"]["same"].as_bool()), (Some(false), Some(false)), "{skipped}"); assert!(skipped["shadow"]["why"].as_str().unwrap().contains("method:exact"), "{skipped}"); + // The same, said by another engine: its version is its host's word, so the + // receipt is held neither way, and never said to hold. + let elsewhere = edited(&|b| { + b["result"]["planner"]["shadow"] = json!({ "route": null, "code": "none", "why": "said so" }); + b["result"]["shadow"] = json!({ "ran": false, "code": "none", "why": "said so" }); + b["result"]["engine"]["version"] = json!("0.0.1"); + }); + assert!(elsewhere["holds"].is_null() && elsewhere["shadow"]["same"].is_null(), "{elsewhere}"); + assert!(elsewhere["shadow"]["why"].as_str().unwrap().contains("method:exact"), "{elsewhere}"); // A weaker method run where a stronger one reaches the counts. let weaker = edited(&|b| { for side in ["/result/planner/shadow", "/result/shadow"] { -- 2.54.0 (Apple Git-157) From 930630c3b86870f6211d177bcd6070082bd395d8 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sat, 7 Nov 2026 09:46:04 -0500 Subject: [PATCH 17/42] wai-quantum: clippy on the child run's test and the service's one test module The test of a run in its own process fails on a Mac rather than skipping, without a constant assertion; the service's meter test is in its one test module, the kernel's test gated to macOS within it. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/wai-quantum-service.yml | 2 +- wai/wai-quantum-cli/src/estimates.rs | 4 +++- wai/wai-quantum-service/src/energy.rs | 24 +++++++++++------------ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/wai-quantum-service.yml b/.github/workflows/wai-quantum-service.yml index b034ba83a..a6a2189ed 100644 --- a/.github/workflows/wai-quantum-service.yml +++ b/.github/workflows/wai-quantum-service.yml @@ -81,7 +81,7 @@ jobs: grep -qE '^test result: ok\. [1-9][0-9]* passed; 0 failed' "$RUNNER_TEMP/test.log" || { echo "::error::no test ran"; exit 1; } grep -q '^test the_service_gives_every_receipt_the_verdict_the_corpus_gives_it \.\.\. ok$' "$RUNNER_TEMP/test.log" || { echo "::error::the service was not held to the corpus of receipts"; exit 1; } grep -q '^test jobs::tests::a_route_s_figure_is_an_estimate_and_what_reads_the_run \.\.\. ok$' "$RUNNER_TEMP/test.log" || { echo "::error::the service's routes did not say what reads them"; exit 1; } - grep -q '^test energy::meter_tests::a_mac_whose_counter_reads_nothing_has_no_meter \.\.\. ok$' "$RUNNER_TEMP/test.log" || { echo "::error::a Mac that reads nothing was given a meter"; exit 1; } + grep -q '^test energy::tests::a_mac_whose_counter_reads_nothing_has_no_meter \.\.\. ok$' "$RUNNER_TEMP/test.log" || { echo "::error::a Mac that reads nothing was given a meter"; exit 1; } grep -q '^test a_job_is_stopped_at_its_energy_ceiling_and_its_receipt_says_so \.\.\. ok$' "$RUNNER_TEMP/test.log" || { echo "::error::the service did not stop a job at its ceiling"; exit 1; } # A job under a contract: met or refused with every route's reason, never routed to a # provider, stopped at its deadline, and its reasoning kept across a restart. diff --git a/wai/wai-quantum-cli/src/estimates.rs b/wai/wai-quantum-cli/src/estimates.rs index 84b061dcf..53b4b4831 100644 --- a/wai/wai-quantum-cli/src/estimates.rs +++ b/wai/wai-quantum-cli/src/estimates.rs @@ -698,7 +698,9 @@ mod tests { fn a_run_in_its_own_process_is_killed_at_its_ceiling_and_read_whole() { use std::os::unix::fs::PermissionsExt; if unmetered(true).is_some() { - assert!(!cfg!(target_os = "macos"), "a Mac reads a process's own energy, so this test may not pass by skipping"); + if cfg!(target_os = "macos") { + panic!("a Mac reads a process's own energy, so this test may not pass by skipping"); + } return; } let d = dir("own-process"); diff --git a/wai/wai-quantum-service/src/energy.rs b/wai/wai-quantum-service/src/energy.rs index 9002e0128..d5bd3a44f 100644 --- a/wai/wai-quantum-service/src/energy.rs +++ b/wai/wai-quantum-service/src/energy.rs @@ -79,17 +79,6 @@ fn mac_meter(reads: bool) -> Meter { } } -#[cfg(test)] -mod meter_tests { - /// A Mac whose counter reads nothing is no meter, so a contract's ceiling is - /// refused there rather than admitted and lost a second into the run. - #[test] - fn a_mac_whose_counter_reads_nothing_has_no_meter() { - assert!(matches!(super::mac_meter(false), super::Meter::Unmetered(_))); - assert!(matches!(super::mac_meter(true), super::Meter::Process)); - } -} - /// Whether child `pid` has exited, without reaping it: `Some(true)` once it /// has (it is then readable by [`read`] until reaped), `Some(false)` while it /// runs, `None` where this cannot be told (off macOS, or the wait failed), in @@ -122,13 +111,22 @@ pub fn exited_unreaped(_pid: u32) -> Option { None } -// The one test reads the kernel's counter, which only macOS has. -#[cfg(all(test, target_os = "macos"))] +#[cfg(test)] mod tests { use super::*; + /// A Mac whose counter reads nothing is no meter, so a contract's ceiling is + /// refused there rather than admitted and lost a second into the run. + #[test] + fn a_mac_whose_counter_reads_nothing_has_no_meter() { + assert!(matches!(mac_meter(false), Meter::Unmetered(_))); + assert!(matches!(mac_meter(true), Meter::Process)); + } + /// A child that burns CPU and exits reads a complete, non-zero count while /// it is unreaped, over a window that covers its run; once reaped, it is gone. + /// Only macOS's kernel has the counter. + #[cfg(target_os = "macos")] #[test] fn an_exited_worker_reads_its_whole_energy_before_it_is_reaped() { let mut child = std::process::Command::new("/bin/sh") -- 2.54.0 (Apple Git-157) From 533b9d3788dbbc9c51746e6b34dfc104e7952292 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sat, 7 Nov 2026 12:27:12 -0500 Subject: [PATCH 18/42] wai-quantum: the planner's fourth check: one comparison in both verifiers, the earlier form, a locked word - Both verifiers compare a route's money, device and provenance with what ran alike: numbers by value (7 and 7.0, -0 and 0), a boolean only to a boolean, null as an absent member. - Under a contract a provider's result of the earlier form is refused (contract_form), in both verifiers. - A recheck of a receipt sealed by another engine version gives holds null, and reads the job's memory as a number by value. - A routed word's count and its run's record are taken under one lock on the ledger, so two sends of one word do not both go; a run the provider took spends the word whatever became of it. - A job that names a provider, under a contract that allows one but wants a class no provider's counts have, is refused (J071) before it is described or asked for an estimate. - CI runs the receipt plants side by side: each runs the whole differential, and run one after another they took the job past its hour. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/wai-quantum-cli.yml | 9 ++- ...06-wai-quantum-planner-under-a-contract.md | 6 ++ wai/extensions/quantum-providers.md | 15 +++-- .../tools/receipt_verify.py | 24 ++++++-- wai/wai-quantum-qpu/src/job.rs | 60 ++++++++++++++++++- wai/wai-quantum/src/engine/planner.rs | 38 +++++++++--- wai/wai-quantum/src/engine/planner/tests.rs | 16 +++++ 7 files changed, 148 insertions(+), 20 deletions(-) diff --git a/.github/workflows/wai-quantum-cli.yml b/.github/workflows/wai-quantum-cli.yml index 85084847d..6467f2b8b 100644 --- a/.github/workflows/wai-quantum-cli.yml +++ b/.github/workflows/wai-quantum-cli.yml @@ -173,9 +173,12 @@ jobs: python3 -I wai/quantum-conformance/receipts/generate.py --self-test python3 -I wai/quantum-conformance/tools/receipt_verify.py --self-test wai/wai-quantum/src/engine/testdata/es-number-tostring.txt python3 -I wai/quantum-conformance/tools/receipt_differential.py --reference wai/wai-quantum-cli/target/release/wai-quantum - for plant in lenient-key no-alg last-duplicate no-inexact measured-simulator whole-cap lax-small-order-r no-canonical-spelling set-seal-only names-layout-only route-unchecked choice-unchecked distance-unchecked; do - python3 -I wai/quantum-conformance/tools/receipt_differential.py --reference wai/wai-quantum-cli/target/release/wai-quantum --plant "$plant" | tail -1 - done + # Each plant runs the whole differential with one verifier broken on purpose, a few + # minutes each: they run side by side, and every one must be caught. + printf '%s\n' lenient-key no-alg last-duplicate no-inexact measured-simulator whole-cap lax-small-order-r no-canonical-spelling set-seal-only names-layout-only route-unchecked choice-unchecked distance-unchecked \ + | xargs -P "$(nproc)" -I{} bash -c 'set -o pipefail; python3 -I wai/quantum-conformance/tools/receipt_differential.py --reference wai/wai-quantum-cli/target/release/wai-quantum --plant "{}" | tail -1' \ + | tee "$RUNNER_TEMP/plants.log" + test "$(grep -c ': caught' "$RUNNER_TEMP/plants.log")" -eq 13 || { echo "::error::not every plant was caught"; exit 1; } # The release binary, pinned by version and SHA-256, rather than a build from source. # Every WAI workflow that runs wasmtime pins this one version, and every run passes # -W nan-canonicalization=y -W relaxed-simd-deterministic=y: every NaN a float diff --git a/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md b/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md index 465842b5b..b8a3e3187 100644 --- a/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md +++ b/wai/changes/2026-11-06-wai-quantum-planner-under-a-contract.md @@ -60,6 +60,12 @@ say it holds. A routed run's word binds the contract too and sends one run. An open-protocol provider may say in `describe` that it cannot cancel (`cancels`), and in an estimate that its amount is the least the job can come to (`at_least`), and its price says so. +- **The fourth check.** Both verifiers compare a route and its result alike: numbers by value, a boolean only to a + boolean, `null` as absent. Under a contract a provider's result of the earlier form is refused (`contract_form`). A + recheck across engine versions gives `holds` `null`, and reads the job's memory by value. A word's count and its + run's record are taken under one lock, and a run the provider took spends the word whatever became of it. A job + that names a provider under a class no provider's counts have is refused (`J071`) before the provider is asked. + CI runs the verifier plants side by side. - **Every host seals only what its verifier accepts.** A result short of the class its reasoning wants gives no answer (`J072`), and each host checks a contract job's reasoning before it seals it. A run past its contract's deadline on the job service is stopped, and the command line cancels a provider's job still waiting at it (`J074`). A deadline holds diff --git a/wai/extensions/quantum-providers.md b/wai/extensions/quantum-providers.md index 9820cdaf9..e7158dea0 100644 --- a/wai/extensions/quantum-providers.md +++ b/wai/extensions/quantum-providers.md @@ -903,7 +903,12 @@ program and shots it would send, the job's `contract`, and how many runs of this the host has sent on such a word before, as a short digest, and sends the job only when the word it is given is that digest made again at send time; a route, a device, an estimate, a program or a contract that changed since is not sent, and a word sends -one run: the next run of the same job has another word. A host asks no provider +one run: the next run of the same job has another word. The count is read and the run +recorded under one lock, so two sends of one word do not both go; a run the provider +took is a run whatever became of it, and only one it refused before taking it leaves +the word unspent. A job that names a provider under a contract that allows one but +wants a class no provider's counts have is refused (`J071`) before the provider is +asked anything. A host asks no provider anything (an estimate's request carries the compiled program, and a description says a job is coming) where the contract does not allow one, or names no class a provider's counts are in: with none named the job keeps a classical class, which @@ -1032,11 +1037,11 @@ written, so that every verifier gets the same bits. | reason | when | |---|---| -| `contract_form` | the request's `contract` is not of its form. Of §8.7, reported alone | +| `contract_form` | the request's `contract` is not of its form (of §8.7, then reported alone); or, under a contract, a provider's result of the earlier form (§8.4), which states neither where its counts come from nor what was done to them | | `contract_provider` | the request names a `provider` and its contract's `providers` is not `allowed` | | `planner_form` | a contract job's result has no `planner`, or one not of the form above: `format`, `routes` and each route's members (a local route's `auto_rank`, its money free, every `seconds` and amount within its bounds), `named`, `auto` and `choice` each naming a route of `routes` or `null` (`choice` a route), `question`, `host`, `why`, `stable` and `kept` an object, each present; or `named`, `question`, a built-in method's `auto_rank`, `auto`, `wanted` or `wanted_from` is not what the request and the routes give. Or a result with no contract carries a `planner`. Reported alone of §8.7, beside `contract_provider` | | `planner_route` | a route's `rejected.code` is not what the rules above give it (or it is rejected when they let it through, or not when they do not), or the route `chosen` is not one and `choice` | -| `planner_choice` | `choice` is not the route the choice's rules pick from those the rules let through, whatever their `outcome` says; or it is not what ran: a method's result is of another method, and a provider's names another provider, or its `cost` is not its route's `money` (`free` alike, and `amount`, `currency`, `unit` and `at_least` in its `estimate` alike), or the route names a `device` or `provenance` that is not its provider's | +| `planner_choice` | `choice` is not the route the choice's rules pick from those the rules let through, whatever their `outcome` says; or it is not what ran: a method's result is of another method, and a provider's names another provider, or its `cost` is not its route's `money` (`free` alike, and `amount`, `currency`, `unit` and `at_least` in its `estimate` alike), or the route names a `device` or `provenance` that is not its provider's. Members are alike as numbers are by value (`7` and `7.0`, `-0` and `0`), a boolean only to a boolean, and `null` as an absent member | | `planner_stable` | `stable.routes`, `digest` or `choice` is not what the routes give | | `planner_kept` | `kept` does not hold exactly a member for each the contract gives, or any of those members is not what the table gives | | `contract_class` | the result's class does not meet `wanted` | @@ -1054,7 +1059,9 @@ shadow's counts and class to a run here; runs a shadow the host says failed; and on the same engine, plans the shadow again, so that which method ran, or that none could, is what this engine gives: a verifier without one takes those on the host's word. A receipt sealed by another engine whose shadow did not run is held neither -way: what this engine plans is said, and the recheck does not say it holds. +way: what this engine plans is said, and the recheck does not say it holds. So is any +receipt sealed by another engine version: a recheck there gives `holds` `null` unless +something differs. The free job service reaches no provider. It lists none among its routes, a contract that wants a device's class is refused there (`J071`), and a request that diff --git a/wai/quantum-conformance/tools/receipt_verify.py b/wai/quantum-conformance/tools/receipt_verify.py index fff80863f..8ec52c9fa 100644 --- a/wai/quantum-conformance/tools/receipt_verify.py +++ b/wai/quantum-conformance/tools/receipt_verify.py @@ -1260,10 +1260,19 @@ def _ran_as_routed(routes, choice, result): if not (isinstance(money, dict) and isinstance(cost, dict) and isinstance(provider, dict)): return False estimate = cost.get("estimate") if isinstance(cost.get("estimate"), dict) else {} - missing = object() - return (all(k not in r or r[k] == provider.get(k, missing) for k in ("device", "provenance")) - and _plain(cost.get("free", missing)) == _plain(money.get("free", missing)) - and all(_plain(estimate.get(k, missing)) == _plain(money.get(k, missing)) for k in ("amount", "currency", "unit", "at_least"))) + return (all(k not in r or _alike(r[k], provider.get(k)) for k in ("device", "provenance")) + and _alike(cost.get("free"), money.get("free")) + and all(_alike(estimate.get(k), money.get(k)) for k in ("amount", "currency", "unit", "at_least"))) + + +def _alike(a, b): + """§8.7: two members alike: numbers by value (7 and 7.0, -0 and 0), a boolean only + to a boolean, and null as an absent member.""" + if isinstance(a, Num) or isinstance(b, Num): + return isinstance(a, Num) and isinstance(b, Num) and float(a.value) == float(b.value) + if isinstance(a, bool) or isinstance(b, bool): + return isinstance(a, bool) and isinstance(b, bool) and a == b + return a == b def _planner_form(p): @@ -1767,6 +1776,9 @@ def check_contract(request, result, reasons): method = result.get("method") if short or (isinstance(method, str) and method != "provider" and not _class_of_method(method, cls)): reasons.add("contract_class") + # Under a contract a provider's result is of the current form. + if result.get("method") == "provider" and ("counts_source" not in result or "execution" not in result): + reasons.add("contract_form") is_provider = planner["choice"].startswith("provider:") if is_provider != ("shadow" in result) or is_provider != ("shadow" in planner) or (is_provider and not _shadow_holds(request, contract, planner, result)): reasons.add("shadow") @@ -2898,6 +2910,10 @@ def self_test(args): check("a run sealed at a cost its route does not state", reasons_of(contract_edited( lambda b: b["result"]["cost"].update(free=False, confirmed=True, estimate={"free": False, "amount": "50", "currency": "USD"}))) == ["planner_choice"]) check("the route chosen names another device than ran", reasons_of(contract_edited(lambda b: chosen(b).update(device="elsewhere"))) == ["planner_choice"]) + check("members alike by value: 7 and 7.0, -0 and 0", _alike(Num("7", 7.0), Num("7.0", 7.0)) and _alike(Num("-0", -0.0), Num("0", 0.0))) + check("a boolean is no number, and null is absent", not _alike(True, Num("1", 1.0)) and _alike(None, None) and not _alike("a", None)) + check("an earlier-form provider result under a contract", "contract_form" in reasons_of(contract_edited( + lambda b: [b["result"].pop(k) for k in ("counts_source", "execution")]))) check("the route chosen names the device that ran", reasons_of(contract_edited(lambda b: chosen(b).update(device=b["result"]["provider"]["device"]))) == []) def timed_by_host(kept): diff --git a/wai/wai-quantum-qpu/src/job.rs b/wai/wai-quantum-qpu/src/job.rs index 91756a655..37a30efa3 100644 --- a/wai/wai-quantum-qpu/src/job.rs +++ b/wai/wai-quantum-qpu/src/job.rs @@ -465,9 +465,35 @@ pub struct Routed { } /// How many runs a ledger holds of a job whose word is `base`: each one recorded, -/// less those its provider refused, which were not sent. +/// less those its provider refused before taking them, which were not sent. A run +/// the provider took is a run, whatever became of it after. fn sends_of(ledger: &Ledger, base: &str) -> usize { - ledger.list().0.iter().filter(|t| t.confirms() == Some(base) && t.state() != "failed").count() + ledger.list().0.iter().filter(|t| t.confirms() == Some(base) && (t.state() != "failed" || t.provider_id().is_some())).count() +} + +/// The ledger held by this process alone while a word is counted and its run is +/// recorded, so that two sends of one word cannot both find it unspent. Held until +/// dropped; where no lock can be taken, nothing is sent. +struct WordLock(#[allow(dead_code)] std::fs::File); + +fn lock_words(ledger: &Ledger) -> Result { + let path = ledger.dir().join(".words.lock"); + let _ = std::fs::create_dir_all(ledger.dir()); + let file = std::fs::OpenOptions::new().create(true).truncate(false).write(true).open(&path).map_err(|e| JobError::Failed(format!("nothing was sent: the ledger's lock could not be opened ({e})")))?; + #[cfg(unix)] + { + use std::os::unix::io::AsRawFd; + unsafe extern "C" { + fn flock(fd: i32, operation: i32) -> i32; + } + /// `LOCK_EX` in ``. + const LOCK_EX: i32 = 2; + // SAFETY: the descriptor is this open file's, for the call. + if unsafe { flock(file.as_raw_fd(), LOCK_EX) } != 0 { + return Err(JobError::Failed(format!("nothing was sent: the ledger could not be locked ({})", std::io::Error::last_os_error()))); + } + } + Ok(WordLock(file)) } impl Routed { @@ -632,6 +658,8 @@ pub fn start_routed(t: &Target, routed: &Routed, request: &Value, confirm: Optio return Err(JobError::Failed(format!("the planner did not choose {}", t.name))); } let base = routed.base(); + // Counted, and the run recorded before it is sent, under one lock. + let _held = if base.is_some() { Some(lock_words(ledger)?) } else { None }; let sent = base.as_deref().map_or(0, |b| sends_of(ledger, b)); if let Some(token) = routed.word(sent) && confirm != Some(token.as_str()) @@ -1598,6 +1626,13 @@ mod tests { assert!(ops.lock().unwrap().is_empty(), "{:?}", ops.lock().unwrap()); // Allowed with no class named, a job keeps a classical class no provider's // counts meet: none is asked for what could never be chosen. + // Named and allowed, under a class no provider's counts have: refused, and + // not described or asked for an estimate first. + let classical = json!({ "qasm": BELL, "shots": 100, "provider": "lab", "contract": { "providers": "allowed", "exactness": "exact" } }); + for refused in [plan(&t, &classical).map(|_| ()).unwrap_err(), start(&t, &classical, true, &records.ledger()).map(|_| ()).unwrap_err()] { + assert!(refused.to_string().ends_with("[J071]"), "{refused}"); + } + assert!(ops.lock().unwrap().is_empty(), "{:?}", ops.lock().unwrap()); let routed = route(&[t], &json!({ "qasm": BELL, "shots": 100, "contract": { "providers": "allowed" } }), 1 << 30).unwrap(); assert_eq!(routed.reasoning["host"]["providers"], json!([]), "{}", routed.reasoning); assert!(ops.lock().unwrap().is_empty(), "{:?}", ops.lock().unwrap()); @@ -1666,6 +1701,27 @@ mod tests { assert!(next != word && plan["token"] == next.as_str(), "{plan}"); start_routed(&t, &routed(), &want, Some(&next), &ledger).unwrap(); assert_eq!(count(&ops, "submit"), 2); + // Sent together, one word sends one run: the second waits for the first to + // be recorded, and finds the word spent. + let racing = Records::new("word-race"); + let word = routed().counted(&racing.ledger()).confirmation().unwrap(); + let go = std::sync::Barrier::new(4); + let sent: Vec = std::thread::scope(|s| { + let runs: Vec<_> = (0..4).map(|_| s.spawn(|| { + let ledger = racing.ledger(); + let (mine, _, _) = watched(&r); + let routed = route(std::slice::from_ref(&mine), &want, 1 << 30).unwrap(); + go.wait(); + start_routed(&mine, &routed, &want, Some(&word), &ledger).is_ok() + })).collect(); + runs.into_iter().map(|h| h.join().unwrap()).collect() + }); + assert_eq!(sent.iter().filter(|s| **s).count(), 1, "{sent:?}"); + // A run the provider took and then failed is a run: its word is spent. + let mut failed = racing.ledger().list().0.into_iter().find(|t| t.provider_id().is_some()).unwrap(); + failed.ended("failed", "the device failed it"); + racing.ledger().put(&failed).unwrap(); + assert!(matches!(start_routed(&t, &routed(), &want, Some(&word), &racing.ledger()), Err(JobError::Unconfirmed { .. }))); // Under another contract the word is another. let mut loose = want.clone(); loose["contract"].as_object_mut().unwrap().remove("deadline_seconds"); diff --git a/wai/wai-quantum/src/engine/planner.rs b/wai/wai-quantum/src/engine/planner.rs index 4e8753f16..6b6f7aa97 100644 --- a/wai/wai-quantum/src/engine/planner.rs +++ b/wai/wai-quantum/src/engine/planner.rs @@ -854,6 +854,10 @@ fn local_routes(reg: &Registry, v: &Value, host: &Host<'_>, q: Question) -> Resu /// the provider anything. pub fn provider_allowed(v: &Value) -> Result<(), String> { let Some(contract) = Contract::read(v)? else { return Ok(()) }; + // A class no provider's counts have: none is asked anything for it. + if v.get("provider").is_some_and(|p| !p.is_null()) && contract.providers == Some(true) && contract.exactness.as_deref().is_some_and(|w| !matches!(w, "measured" | "simulated" | "any")) { + return Err(tag(refusal::NOTHING_MEETS, format!("the job names a provider, and its contract wants {}: no provider's counts are of that class, so none is asked", contract.exactness.as_deref().unwrap_or("")))); + } if v.get("provider").is_some_and(|p| !p.is_null()) && contract.providers != Some(true) { return Err(tag(refusal::CONTRACT_FORM, "the job names a provider, and its contract does not allow one: under a contract a provider is used only with providers: allowed")); } @@ -1088,7 +1092,7 @@ pub fn own_check(v: &Value, result: &Value) -> Result<(), String> { /// receipt of this reasoning cannot give should cost nothing. The reasoning, /// with a result that says only that the provider ran. pub fn before_sending(v: &Value, reasoning: &Value, provider: &str, shots: u64) -> Result<(), String> { - let mut r = json!({ "method": "provider", "provider": { "name": provider }, "shots": shots, "planner": reasoning, "shadow": { "ran": false, "code": "failed", "why": "not yet run" } }); + let mut r = json!({ "method": "provider", "provider": { "name": provider }, "shots": shots, "counts_source": "shots", "execution": {}, "planner": reasoning, "shadow": { "ran": false, "code": "failed", "why": "not yet run" } }); // What the run would seal of who ran it and what it costs: the route's own word. let name = format!("provider:{provider}"); if let Some(route) = reasoning["routes"].as_array().and_then(|a| a.iter().find(|x| x["route"] == name)) { @@ -1552,6 +1556,11 @@ pub fn check(request: &Value, result: &Value) -> Vec<&'static str> { if short || foreign { out.push(CONTRACT_CLASS); } + // Under a contract a provider's result is of the current form: the earlier one + // states neither where its counts come from nor what was done to them. + if result["method"] == "provider" && (result.get("counts_source").is_none() || result.get("execution").is_none()) { + out.push(CONTRACT_FORM); + } let is_provider = p["choice"].as_str().is_some_and(|c| c.starts_with("provider:")); if is_provider != result.get("shadow").is_some() || is_provider != p.get("shadow").is_some() || (is_provider && !shadow_holds(request, &contract, p, result)) { out.push(SHADOW); @@ -1601,9 +1610,23 @@ fn ran_as_routed(routes: &[Value], choice: Option<&str>, result: &Value) -> bool return true; } let (money, cost) = (&r["price"]["money"], &result["cost"]); - ["device", "provenance"].iter().all(|k| r.get(*k).is_none_or(|v| *v == result["provider"][*k])) - && cost["free"] == money["free"] - && ["amount", "currency", "unit", "at_least"].iter().all(|k| cost["estimate"].get(*k) == money.get(*k)) + ["device", "provenance"].iter().all(|k| r.get(*k).is_none_or(|v| alike(Some(v), result["provider"].get(*k)))) + && alike(cost.get("free"), money.get("free")) + && ["amount", "currency", "unit", "at_least"].iter().all(|k| alike(cost["estimate"].get(*k), money.get(*k))) +} + +/// Two members alike as section 8.7 compares them: numbers by value (7 and 7.0, +/// -0 and 0 alike), a boolean only to a boolean, and `null` as an absent member. +fn alike(a: Option<&Value>, b: Option<&Value>) -> bool { + let a = a.filter(|v| !v.is_null()); + let b = b.filter(|v| !v.is_null()); + match (a, b) { + (None, None) => true, + (Some(Value::Number(x)), Some(Value::Number(y))) => x.as_f64() == y.as_f64(), + (Some(Value::Number(_)), _) | (_, Some(Value::Number(_))) => false, + (Some(x), Some(y)) => x == y, + _ => false, + } } /// A `kept` member as its table gives it: true, false, or `null` where it is not @@ -1786,7 +1809,7 @@ pub fn recheck(reg: &Registry, job: &Value) -> Result { let Some(p) = result.get("planner") else { return Err("this result carries no planner's reasoning".into()) }; let engine = result.pointer("/engine/version").and_then(Value::as_str); let same_engine = engine == Some(super::schema::ENGINE_VERSION); - let job_bytes = p["host"]["job_bytes"].as_u64().ok_or("the reasoning names no job memory")?; + let job_bytes = p["host"]["job_bytes"].as_f64().filter(|x| x.fract() == 0.0 && *x >= 0.0 && *x < 1.8446744073709552e19).map(|x| x as u64).ok_or("the reasoning names no job memory")?; let routes = p["routes"].as_array().map_or(&[][..], Vec::as_slice); let priced = if request.get("provider").is_some_and(|x| !x.is_null()) { json!({ "checked": false, "why": "the job names its provider, so no local route was priced" }) @@ -1840,10 +1863,11 @@ pub fn recheck(reg: &Registry, job: &Value) -> Result { }); json!({ "checked": false, "same": null, "why": format!("no shadow could be planned, the reasoning says, and it was sealed by another engine; this one plans {}, so the receipt is not held here either way", here.unwrap_or(Value::Null)) }) }; - // Held only where everything that applies was checked here. + // Held only where everything that applies was checked here, by this engine: a + // receipt sealed by another engine version is held neither way. let holds = if priced["same"] == false || shadow["same"] == false { json!(false) - } else if shadow.get("same") == Some(&Value::Null) { + } else if shadow.get("same") == Some(&Value::Null) || !same_engine { Value::Null } else { json!(true) diff --git a/wai/wai-quantum/src/engine/planner/tests.rs b/wai/wai-quantum/src/engine/planner/tests.rs index 18e881cdd..5bb501883 100644 --- a/wai/wai-quantum/src/engine/planner/tests.rs +++ b/wai/wai-quantum/src/engine/planner/tests.rs @@ -1361,6 +1361,9 @@ fn a_built_in_route_and_a_result_are_held_to_their_method_s_classes() { /// provider routes, and a shadow's outcomes are a counts' form. #[test] fn what_a_receipt_states_of_itself_is_of_its_form() { + // Members alike by value, as the second verifier compares them. + assert!(alike(Some(&json!(7)), Some(&json!(7.0))) && alike(Some(&json!(-0.0)), Some(&json!(0)))); + assert!(!alike(Some(&json!(true)), Some(&json!(1))) && alike(None, Some(&Value::Null)) && !alike(Some(&json!("a")), None)); let good = provider_body(&device_contract(), vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))], vec![450, 100, 0, 450]); assert_eq!(reasons(&good), Vec::<&str>::new()); cases(&good, vec![ @@ -1405,6 +1408,19 @@ fn recheck_plans_the_shadow_again_and_leaves_the_host_s_routes_to_the_host() { }); assert!(elsewhere["holds"].is_null() && elsewhere["shadow"]["same"].is_null(), "{elsewhere}"); assert!(elsewhere["shadow"]["why"].as_str().unwrap().contains("method:exact"), "{elsewhere}"); + // Any receipt sealed by another engine version is held neither way, a shadow + // that ran here alike as well. + let other = edited(&|b| b["result"]["engine"]["version"] = json!("0.0.1")); + assert!(other["holds"].is_null(), "{other}"); + // Its job memory read as a number by value, however it is spelled. + let respelled = edited(&|b| b["result"]["planner"]["host"]["job_bytes"] = json!(1073741824.0)); + assert_eq!(respelled["holds"], true, "{respelled}"); + // Under a contract a provider's result of the earlier form is refused. + let earlier = resealed(&good, |b| { + b["result"].as_object_mut().unwrap().remove("counts_source"); + b["result"].as_object_mut().unwrap().remove("execution"); + }); + assert!(reasons(&earlier).contains(&CONTRACT_FORM), "{:?}", reasons(&earlier)); // A weaker method run where a stronger one reaches the counts. let weaker = edited(&|b| { for side in ["/result/planner/shadow", "/result/shadow"] { -- 2.54.0 (Apple Git-157) From fa187b0c0c837944f79116b823c43552cde60dc3 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sun, 8 Nov 2026 08:10:59 -0500 Subject: [PATCH 19/42] wai-quantum: the fourth check of a ceiling: a run dies with its watcher, and its figure is added up - A run's process ends with the one that watches it: its standard input stays open while the command line lives, the run exits on its close, and on Linux the kernel kills it with its parent. A thread that cannot start kills the run. - A package's counter is added up read by read for the whole figure, on the command line and in the service, so a run past the counter's range is read in full; a whole figure below what stopped the run is no reading, and both verifiers hold a stopped receipt's figure and time to the decision's. - A counter that stands still while the run spends CPU time is frozen, and loses the run as silence does; the longest gap counts the time before the first read; a counter that reads nothing once is read again after a spin. - On macOS a worker leaves the core before it exits, and an exited read far below its CPU time is no reading. - SIGCHLD is set to its default before a run is waited for, and a reading kept nowhere is not taken. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/wai-quantum-cli.yml | 2 + .github/workflows/wai-quantum-service.yml | 2 + ...6-11-06-wai-quantum-cli-energy-estimate.md | 8 + wai/extensions/quantum-providers.md | 14 +- wai/quantum-conformance/receipts/generate.py | 4 + ...rafted-contract-stopped-elapsed-other.json | 355 ++++++++++++++++++ .../crafted-contract-stopped-whole-above.json | 355 ++++++++++++++++++ .../crafted-contract-stopped-whole-below.json | 355 ++++++++++++++++++ .../receipts/manifest.json | 22 ++ .../tools/receipt_verify.py | 4 +- wai/wai-quantum-cli/src/estimates.rs | 156 +++++--- wai/wai-quantum-cli/src/main.rs | 55 ++- wai/wai-quantum-cli/tests/estimates.rs | 51 +++ wai/wai-quantum-service/src/jobs.rs | 36 +- wai/wai-quantum-service/src/main.rs | 19 +- wai/wai-quantum/src/engine/energy.rs | 197 ++++++++-- wai/wai-quantum/src/engine/planner.rs | 4 + 17 files changed, 1532 insertions(+), 107 deletions(-) create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-elapsed-other.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-whole-above.json create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-whole-below.json diff --git a/.github/workflows/wai-quantum-cli.yml b/.github/workflows/wai-quantum-cli.yml index 88dc9ad1d..a0663145d 100644 --- a/.github/workflows/wai-quantum-cli.yml +++ b/.github/workflows/wai-quantum-cli.yml @@ -126,6 +126,8 @@ jobs: estimates::tests::a_route_nothing_can_read_or_stop_has_no_watch \ estimates::tests::a_run_in_its_own_process_is_killed_at_its_ceiling_and_read_whole \ estimates::tests::readings_are_kept_under_the_machine_reader_and_build \ + estimates::tests::a_counter_is_asked_twice_and_a_reading_kept_nowhere_is_not_taken \ + a_run_under_a_ceiling_ends_with_its_command_line \ keys::tests::processes_starting_together_share_one_whole_key \ estimates::tests::a_run_is_read_only_where_something_needs_the_reading \ estimates::tests::the_wait_for_a_counter_is_in_no_run_s_power \ diff --git a/.github/workflows/wai-quantum-service.yml b/.github/workflows/wai-quantum-service.yml index a6a2189ed..9d7b03fe6 100644 --- a/.github/workflows/wai-quantum-service.yml +++ b/.github/workflows/wai-quantum-service.yml @@ -111,6 +111,8 @@ jobs: engine::energy::tests::a_package_figure_names_its_scope_and_declares_its_edges \ engine::energy::tests::a_host_s_estimate_rests_on_its_own_runs_and_says_whose \ engine::energy::tests::a_live_reading_stops_at_the_ceiling_and_a_silent_second_loses_it \ + engine::energy::tests::an_exited_read_far_below_its_cpu_time_is_no_reading \ + engine::energy::tests::a_package_counter_added_up_read_by_read_keeps_every_range \ engine::energy::tests::a_counter_s_reading_is_trusted_only_within_one_wrap \ qasm::tests::a_bound_parameter_reads_as_the_program_written_with_its_value; do grep -q "^test $t \.\.\. ok$" "$RUNNER_TEMP/engine.log" || { echo "::error::$t did not run"; exit 1; } diff --git a/wai/changes/2026-11-06-wai-quantum-cli-energy-estimate.md b/wai/changes/2026-11-06-wai-quantum-cli-energy-estimate.md index ca0d5d1a4..42a9c61b1 100644 --- a/wai/changes/2026-11-06-wai-quantum-cli-energy-estimate.md +++ b/wai/changes/2026-11-06-wai-quantum-cli-energy-estimate.md @@ -30,6 +30,14 @@ - **What is read is read fairly.** The wait for a process's counter is in the energy and not in the time the power is taken over. A package counter is read over at least four of its updates, the step it can be short by added, and a reading past the time a counter can wrap twice is no reading. +- **The fourth check.** A run's process ends with the one that watches it (its standard input stays open, and on + Linux the kernel kills it with its parent), so a command line killed mid-run leaves nothing computing. A package's + counter is added up read by read for the whole figure, so a run past the counter's range is read in full; a whole + figure below what stopped a run is no reading, and both verifiers hold a stopped receipt's figure and time. A counter + that stands still while the run spends CPU time is frozen, and loses the run as silence does; the longest gap counts + the time before the first read. On macOS a worker leaves the core before it exits, and an exited read far below its + CPU time is no reading. SIGCHLD is set to its default before a run is waited for, and a reading kept nowhere is not + taken. - **Two processes making a key at once.** A new key was created empty and then written, so a process starting in that moment read an empty file and died, or found the file there and died; a test that discards standard error saw only silence. A key now appears whole or not at all, and the one that finds a key there reads it. diff --git a/wai/extensions/quantum-providers.md b/wai/extensions/quantum-providers.md index a58ddfd0c..61dc2b1a6 100644 --- a/wai/extensions/quantum-providers.md +++ b/wai/extensions/quantum-providers.md @@ -757,8 +757,12 @@ yet shown. A host that runs a job inside a process doing other work, or that rea nothing, gives no `watch`, nor does a provider's route: the route is refused under a ceiling (`energy_unwatched`). A counter that stops reading during a run leaves nothing holding the ceiling: the host stops the run after a second of time without a reading, -and seals nothing. A host reads the run's process whole when it ends, killed or not, -and seals that figure in `energy`, so a run that passed its ceiling between two reads +or with one that stood still while the run spent CPU time (a frozen counter is not a +live one), and seals nothing. The run's process ends with the process that watches +it, however that one ends. A host reads the run's process whole when it ends, killed or not (a package's +counter added up read by read, each step corrected for a wrap, so that a run passing +the counter's range is read in full; a process's read that is far below what its CPU +time implies is no reading), and seals that figure in `energy`, so a run that passed its ceiling between two reads and finished is sealed as having missed it. A run so stopped gave no answer. Its result has no member but `method`, `qubits`, @@ -767,8 +771,10 @@ and `receipt`, so no counts, expectations, amplitudes, verdict, outputs, mitigat distribution of any kind; its `accuracy.class` is `none`; and it has `stopped`, an object of exactly `at`, the string `max_joules`; `joules`, what the reading had come to, a number at or above the ceiling; `max_joules`, the contract's; -`elapsed_ms`, a whole number; and `read`, a sentence saying what read it and the -longest time between two reads. It is sealed like any result, `energy` the whole +`elapsed_ms`, a whole number and the result's `elapsed_ms`; and `read`, a sentence +saying what read it and the longest time between two reads, the first counted from +the start. Its `energy.joules_micro`, where it has one, is no less than `joules` × +10^6, less one for its rounding. It is sealed like any result, `energy` the whole figure of the process killed where the host could read it, its `kept.energy` says the ceiling was not kept, and a command line exits 4. A result whose energy was not read whole states `kept.energy.joules` `null`. diff --git a/wai/quantum-conformance/receipts/generate.py b/wai/quantum-conformance/receipts/generate.py index b59fd2a99..561a56a70 100644 --- a/wai/quantum-conformance/receipts/generate.py +++ b/wai/quantum-conformance/receipts/generate.py @@ -877,12 +877,16 @@ def contract_cases(run, at, drop): b["result"].pop(k, None) b["result"]["accuracy"] = {"class": "none", "note": "stopped at its ceiling"} b["result"]["stopped"] = {"at": "max_joules", "joules": 2.5, "max_joules": 2, "elapsed_ms": 0, "read": "a host's live reading"} + b["result"]["elapsed_ms"] = 0 b["result"]["energy"] = {"unmetered": "stopped"} b["result"]["planner"]["kept"]["energy"] = {"max_joules": 2, "joules": 2.5, "kept": False} add("stopped", edited(local, stopped), [], "a run stopped at its ceiling by a live reading: no answer, and a receipt that says so") add("stopped-kept-claimed", edited(local, both(stopped, at(P + ("kept", "energy", "kept"), True))), ["planner_kept"], "a stopped run said to have kept its ceiling") add("stopped-under", edited(local, both(stopped, at(R + ("stopped", "joules"), 1.5), at(P + ("kept", "energy", "joules"), 1.5))), ["stopped"], "a run said stopped under its ceiling") add("stopped-with-counts", edited(local, both(stopped, at(R + ("counts",), {"00": 100}))), ["stopped"], "a stopped run that gives an answer") + add("stopped-whole-below", edited(local, both(stopped, at(R + ("energy",), {"joules_micro": 1}))), ["stopped"], "a stopped run whose whole figure is less than what stopped it") + add("stopped-whole-above", edited(local, both(stopped, at(R + ("energy",), {"joules_micro": 2600000}))), [], "a stopped run whose whole figure is a little past what stopped it") + add("stopped-elapsed-other", edited(local, both(stopped, at(R + ("stopped", "elapsed_ms"), 99999))), ["stopped"], "a stop at another time than the result's") add("stopped-with-verdict", edited(local, both(stopped, at(R + ("verdict",), {"holds": True}))), ["stopped"], "a stopped run that gives a verdict, an answer by another name") add("stopped-with-outputs", edited(local, both(stopped, at(R + ("outputs",), {"x": 1}))), ["stopped"], "a stopped run that gives outputs") add("stopped-other-ceiling", edited(local, both(stopped, at(R + ("stopped", "max_joules"), 9))), ["stopped"], "a stop at a ceiling the contract does not give") diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-elapsed-other.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-elapsed-other.json new file mode 100644 index 000000000..33cee221d --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-elapsed-other.json @@ -0,0 +1,355 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0, + "max_joules": 2 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "none", + "note": "stopped at its ceiling" + }, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": false + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + }, + "energy": { + "max_joules": 2, + "joules": 2.5, + "kept": false + } + } + }, + "energy": { + "unmetered": "stopped" + }, + "stopped": { + "at": "max_joules", + "joules": 2.5, + "max_joules": 2, + "elapsed_ms": 99999, + "read": "a host's live reading" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "939b7ec25ab9ebd2ef6069538627d3ce4887926a04448f98311dea7f6e98bb4b", + "signature": "7ee9a2626a8e2a8121513b952ea91859065ffba544c0bd19404235e89f3a8aad1188edd0800e244f94e5f3debaa65a3b25724ac2f94a86158d456d994092c00f" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-whole-above.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-whole-above.json new file mode 100644 index 000000000..2b51dc1c2 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-whole-above.json @@ -0,0 +1,355 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0, + "max_joules": 2 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "none", + "note": "stopped at its ceiling" + }, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": false + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + }, + "energy": { + "max_joules": 2, + "joules": 2.5, + "kept": false + } + } + }, + "energy": { + "joules_micro": 2600000 + }, + "stopped": { + "at": "max_joules", + "joules": 2.5, + "max_joules": 2, + "elapsed_ms": 0, + "read": "a host's live reading" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "666018250f88cf1479b718fe6fbc77d0985d402c193cde448bb3ef75ba4ca947", + "signature": "f79c6bed73ad781d1ccebd791c606e85920f632573e9d85496d5f559685caa5ecf8bded8cde316b05428d939f3d51490dfb7a4676961d6bde5efb8fcd95c0a09" + } + } +} diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-whole-below.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-whole-below.json new file mode 100644 index 000000000..ae37cddcf --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-whole-below.json @@ -0,0 +1,355 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0, + "max_joules": 2 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "none", + "note": "stopped at its ceiling" + }, + "elapsed_ms": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": false + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 0, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + }, + "energy": { + "max_joules": 2, + "joules": 2.5, + "kept": false + } + } + }, + "energy": { + "joules_micro": 1 + }, + "stopped": { + "at": "max_joules", + "joules": 2.5, + "max_joules": 2, + "elapsed_ms": 0, + "read": "a host's live reading" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "901f3a321aa6e0be9b96ea6ed52b666563825e12ba6a2af7d3a94061e36b3e62", + "signature": "388e5f529ff4dede9abbf2f2e263d7fe0c32e03876b5d327ed2282094f0b2d710cb6af5fa134ab4ea4244798d30c5a73629a796be577cfffceff21391d5e2b02" + } + } +} diff --git a/wai/quantum-conformance/receipts/manifest.json b/wai/quantum-conformance/receipts/manifest.json index 772542d99..bc32caccf 100644 --- a/wai/quantum-conformance/receipts/manifest.json +++ b/wai/quantum-conformance/receipts/manifest.json @@ -1746,6 +1746,28 @@ "made_by": "crafted", "what": "a stopped run that gives an answer" }, + { + "file": "jobs/crafted-contract-stopped-whole-below.json", + "reasons": [ + "stopped" + ], + "made_by": "crafted", + "what": "a stopped run whose whole figure is less than what stopped it" + }, + { + "file": "jobs/crafted-contract-stopped-whole-above.json", + "reasons": [], + "made_by": "crafted", + "what": "a stopped run whose whole figure is a little past what stopped it" + }, + { + "file": "jobs/crafted-contract-stopped-elapsed-other.json", + "reasons": [ + "stopped" + ], + "made_by": "crafted", + "what": "a stop at another time than the result's" + }, { "file": "jobs/crafted-contract-stopped-with-verdict.json", "reasons": [ diff --git a/wai/quantum-conformance/tools/receipt_verify.py b/wai/quantum-conformance/tools/receipt_verify.py index 6bc6a4ae2..f79425db9 100644 --- a/wai/quantum-conformance/tools/receipt_verify.py +++ b/wai/quantum-conformance/tools/receipt_verify.py @@ -1697,7 +1697,9 @@ def _stopped_holds(contract, result): return (s.get("at") == "max_joules" and _value_of(s.get("max_joules")) == j and x is not None and x >= j and _whole(s.get("elapsed_ms")) and s["elapsed_ms"].value >= 0 and isinstance(s.get("read"), str) and result.get("method") != "provider" and _member(result, "accuracy", "class") == "none" - and all(k in STOPPED_MEMBERS for k in result)) + and all(k in STOPPED_MEMBERS for k in result) + and (_value_of(_member(result, "energy", "joules_micro")) is None or _value_of(_member(result, "energy", "joules_micro")) >= x * 1e6 - 1.0) + and _value_of(result.get("elapsed_ms")) == _value_of(s.get("elapsed_ms"))) def check_contract(request, result, reasons): diff --git a/wai/wai-quantum-cli/src/estimates.rs b/wai/wai-quantum-cli/src/estimates.rs index 53b4b4831..a3c2f3250 100644 --- a/wai/wai-quantum-cli/src/estimates.rs +++ b/wai/wai-quantum-cli/src/estimates.rs @@ -242,7 +242,13 @@ pub fn ceiling(request: &Value) -> Option { /// would run with too few runs read to estimate from. A counter costs a run time, and /// on Linux its first read costs a third of a second. pub fn wanted(book: &Book, request: &Value, job_bytes: u64) -> bool { - !cfg!(target_family = "wasm") && (ceiling(request).is_some() || wai_quantum::engine::catalog::plan(request, job_bytes).is_ok_and(|p| book.wants(&p.method))) + wanted_keeping(book, request, job_bytes, path().is_some()) +} + +/// [`wanted`], where `keeping` says whether what is read is kept: a reading kept +/// nowhere is not worth a counter's probe. +fn wanted_keeping(book: &Book, request: &Value, job_bytes: u64, keeping: bool) -> bool { + !cfg!(target_family = "wasm") && (ceiling(request).is_some() || (keeping && wai_quantum::engine::catalog::plan(request, job_bytes).is_ok_and(|p| book.wants(&p.method)))) } /// Why this command line reads no energy counter here, where it reads none. @@ -252,7 +258,7 @@ pub fn unmetered(live: bool) -> Option { return Some("a wasm build reads no energy counter".to_string()); } if cfg!(target_os = "macos") { - return energy::own().is_none().then(|| "this process's CPU energy counter does not read here".to_string()); + return (!own_reads()).then(|| "this process's CPU energy counter does not read here".to_string()); } if cfg!(target_os = "linux") { return match energy::access_in(Path::new("/sys/class/powercap")) { @@ -377,35 +383,68 @@ pub enum Ended { } /// What reads a run in its own process: on macOS that process's CPU energy, on -/// Linux the processor packages' since it began. None where nothing reads. -enum Meter { +/// Linux the processor packages' since it began, added up read by read. +enum Meter<'a> { Process, - Packages(&'static energy::Packages, energy::PackageSnapshot), + Packages(energy::Accumulated<'a>), +} + +/// Whether this process's own counter reads here: a read of nothing is taken again +/// after a short spin, since an idle process can read nothing on a live counter. +pub fn own_reads() -> bool { + reads_after(|| energy::own().is_some(), || { + let until = Instant::now() + Duration::from_millis(20); + while Instant::now() < until { + std::hint::spin_loop(); + } + }) +} + +/// `read`, and where it gives nothing, `spend` and `read` again. +fn reads_after(mut read: impl FnMut() -> bool, spend: impl FnOnce()) -> bool { + read() || { + spend(); + read() + } } /// `input` run by `exe WORKER` in its own process under `ceiling` joules: read every /// [`energy::WATCH_MS`] as the host schedules this one, and killed at once at the /// ceiling, so the work stops there; its whole figure is read after it ends, killed -/// or not, and sealed. A counter silent for a second stops it too ([`energy::Watcher`]). +/// or not, and sealed. A counter silent, or frozen, for a second stops it too +/// ([`energy::Watcher`]). Its standard input stays open while this process lives, +/// so that it ends with this one however this one ends. pub fn run_watched(exe: &Path, input: &Value, ceiling: f64) -> Result { use std::io::{Read as _, Write as _}; use std::process::{Command, Stdio}; raise_watch(); - let meter = if cfg!(target_os = "macos") { - energy::own().ok_or("this process's CPU energy counter does not read here")?; + default_sigchld(); + let mut meter = if cfg!(target_os = "macos") { + if !own_reads() { + return Err("this process's CPU energy counter does not read here".into()); + } Meter::Process } else { let p = packages().as_ref().map_err(String::clone)?; - Meter::Packages(p, p.read().ok_or("the processor packages' counter did not read")?) + Meter::Packages(energy::Accumulated::new(p, p.read().ok_or("the processor packages' counter did not read")?)) }; let began = Instant::now(); let mut child = Command::new(exe).arg(WORKER).stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn().map_err(|e| format!("the run's process did not start: {e}"))?; let pid = child.id(); - if let Some(mut stdin) = child.stdin.take() { - let _ = stdin.write_all(input.to_string().as_bytes()); + let fail = |child: &mut std::process::Child, why: String| { + let _ = child.kill(); + let _ = child.wait(); + why + }; + // The job on one line; the pipe then stays open until this process is done with it. + let mut held = child.stdin.take(); + if let Some(stdin) = held.as_mut() + && let Err(e) = stdin.write_all(format!("{input}\n").as_bytes()).and_then(|_| stdin.flush()) + { + return Err(fail(&mut child, format!("the job did not reach the run's process: {e}"))); } let drain = |r: Option>| { - std::thread::spawn(move || { + std::thread::Builder::new().spawn(move || { let mut out = Vec::new(); if let Some(mut r) = r { let _ = r.read_to_end(&mut out); @@ -413,41 +452,32 @@ pub fn run_watched(exe: &Path, input: &Value, ceiling: f64) -> Result)); - let err = drain(child.stderr.take().map(|e| Box::new(e) as Box)); - let mut since = match &meter { - Meter::Packages(p, before) => Some(p.since(before.clone())), - Meter::Process => None, + let out = match drain(child.stdout.take().map(|o| Box::new(o) as Box)) { + Ok(t) => t, + Err(e) => return Err(fail(&mut child, format!("no thread could read the run: {e}"))), + }; + let err = match drain(child.stderr.take().map(|e| Box::new(e) as Box)) { + Ok(t) => t, + Err(e) => return Err(fail(&mut child, format!("no thread could read the run: {e}"))), }; let mut watcher = energy::Watcher::new(ceiling); - let whole = |reading: Option, after: Option| match &meter { - Meter::Process => (energy::figure(reading.as_ref(), false, "the run's process could not be read when it ended"), reading.map(|r| r.joules())), - Meter::Packages(p, before) => { - let r = after.and_then(|a| p.between(before, &a, 0)); - (energy::package_figure(r.as_ref(), "the processor packages' counter did not read when the run ended"), r.map(|r| r.energy_uj as f64 / 1e6)) - } - }; let ended = loop { // Ended: read whole, then reaped (on macOS a process is readable whole // between its exit and its reaping). let exited = match &meter { Meter::Process => energy::read(pid).map(Some), - Meter::Packages(..) => child.try_wait().map_err(|e| format!("the run's process could not be watched: {e}"))?.map(|_| None), + Meter::Packages(_) => child.try_wait().map_err(|e| format!("the run's process could not be watched: {e}"))?.map(|_| None), }; if let Some(reading) = exited { - let after = match &meter { - Meter::Packages(p, _) => p.read(), - Meter::Process => None, - }; let status = child.wait().map_err(|e| format!("the run's process could not be reaped: {e}"))?; - let (figure, joules) = whole(reading, after); + let (figure, joules) = whole(&mut meter, reading); break Ended::Finished { out: Vec::new(), err: Vec::new(), status, figure, read: Read::over(began.elapsed(), joules) }; } - let now = match &meter { - Meter::Process => energy::running(pid).map(|r| r.joules()), - Meter::Packages(..) => since.as_mut().and_then(|read| read()), + let (now, cpu) = match &mut meter { + Meter::Process => energy::running(pid).map_or((None, None), |r| (Some(r.joules()), Some(r.cpu_ns))), + Meter::Packages(added) => (added.read(), None), }; - match watcher.take(now) { + match watcher.take_with(now, cpu) { Some(energy::Watched::Reached(joules)) => { let _ = child.kill(); let elapsed_ms = u64::try_from(began.elapsed().as_millis()).unwrap_or(u64::MAX); @@ -456,24 +486,25 @@ pub fn run_watched(exe: &Path, input: &Value, ceiling: f64) -> Result None, + Meter::Packages(_) => None, }; let _ = child.wait(); - let after = match &meter { - Meter::Packages(p, _) => p.read(), - Meter::Process => None, - }; - let (figure, _) = whole(reading, after); + let (mut figure, _) = whole(&mut meter, reading); + // A whole figure below what stopped the run is no reading of it. + if figure["joules_micro"].as_u64().is_some_and(|u| (u as f64) < joules * 1e6 - 1.0) { + figure = json!({ "unmetered": "the run's whole reading came to less than the reading that stopped it, so it is no reading" }); + } break Ended::Stopped { stopped: planner::Stopped { joules, elapsed_ms, read: watcher.said(&scope()) }, figure }; } Some(energy::Watched::Lost) => { let _ = child.kill(); let _ = child.wait(); - return Err("the counter holding this run's energy ceiling stopped reading, so the run was stopped: nothing is sealed".into()); + return Err("the counter holding this run's energy ceiling stopped reading, or stood still while the run worked, so the run was stopped: nothing is sealed".into()); } None => std::thread::sleep(Duration::from_millis(energy::WATCH_MS)), } }; + drop(held); let (o, e) = (out.join().unwrap_or_default(), err.join().unwrap_or_default()); Ok(match ended { Ended::Finished { status, figure, read, .. } => Ended::Finished { out: o, err: e, status, figure, read }, @@ -481,6 +512,34 @@ pub fn run_watched(exe: &Path, input: &Value, ceiling: f64) -> Result, reading: Option) -> (Value, Option) { + match meter { + Meter::Process => (energy::figure(reading.as_ref(), false, "the run's process could not be read when it ended"), reading.map(|r| r.joules())), + Meter::Packages(added) => { + let total = added.read(); + let r = added.reading(0); + (energy::package_figure(total.map(|_| &r), "the processor packages' counter did not read when the run ended"), total) + } + } +} + +/// SIGCHLD as the system has it, whatever this process was started with: a parent +/// that ignores it cannot wait for its child. +fn default_sigchld() { + #[cfg(unix)] + { + unsafe extern "C" { + fn signal(sig: i32, handler: usize) -> usize; + } + /// `SIGCHLD` in ``. + const SIGCHLD: i32 = if cfg!(target_os = "macos") { 20 } else { 17 }; + // SAFETY: SIG_DFL (0) for SIGCHLD changes no memory of this process. + let _ = unsafe { signal(SIGCHLD, 0) }; + } +} + /// On macOS, this thread's reads at the quality of service of work a person waits /// on, so that the host does not put them off as it does a background thread's. fn raise_watch() { @@ -690,6 +749,19 @@ mod tests { let _ = std::fs::remove_dir_all(&d); } + /// A counter that reads nothing once is read again after a spin, not called dead; + /// and a run whose reading is kept nowhere is not read for an estimate. + #[test] + fn a_counter_is_asked_twice_and_a_reading_kept_nowhere_is_not_taken() { + let mut reads = [false, true].into_iter(); + assert!(reads_after(|| reads.next().unwrap(), || {})); + assert!(!reads_after(|| false, || {})); + let b = Book::default(); + let req = json!({ "qasm": "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\nh q[0];\nc = measure q;\n", "shots": 10 }); + assert!(!wanted_keeping(&b, &req, 1 << 30, false)); + assert_eq!(wanted_keeping(&b, &req, 1 << 30, true), !cfg!(target_family = "wasm")); + } + /// A run under a ceiling is a process of its own: at the ceiling it is killed at /// once and read whole, the receipt saying the longest time between reads; one /// that finishes is read whole too; one that fails ends the watch, whatever its @@ -718,7 +790,7 @@ mod tests { assert!(whole.is_some_and(|w| w >= stopped.joules), "read whole after the kill, and no less than what stopped it: {figure} {stopped:?}"); let Ended::Finished { status, .. } = run_watched(&script("fails", "exit 101"), &json!({}), 1e9).unwrap() else { panic!("a failed run said stopped") }; assert_eq!(status.code(), Some(101)); - let Ended::Finished { out, status, figure, .. } = run_watched(&script("quick", "cat > /dev/null; echo done"), &json!({ "x": 1 }), 1e9).unwrap() else { panic!("a quick run said stopped") }; + let Ended::Finished { out, status, figure, .. } = run_watched(&script("quick", "read job; echo done"), &json!({ "x": 1 }), 1e9).unwrap() else { panic!("a quick run said stopped") }; assert!(status.success() && out == b"done\n" && figure.is_object(), "{figure}"); let _ = std::fs::remove_dir_all(&d); } diff --git a/wai/wai-quantum-cli/src/main.rs b/wai/wai-quantum-cli/src/main.rs index e65835295..4cf10b301 100644 --- a/wai/wai-quantum-cli/src/main.rs +++ b/wai/wai-quantum-cli/src/main.rs @@ -1010,13 +1010,25 @@ pub(crate) fn run_under_ceiling(req: &Value, plan: &catalog::Plan, reasoning: &V } /// A run under a ceiling, in the process [`run_under_ceiling`] started for it: the -/// request, the plan and the reasoning on standard input, the result, or -/// `{"error"}`, on standard output. +/// request, the plan and the reasoning on the first line of standard input, the +/// result, or `{"error"}`, on standard output. It ends with the process that +/// watches it: when that one's end of the pipe closes, however it ended, this one +/// exits (and on Linux the kernel kills it when its parent dies). fn worker() { - use std::io::Read as _; + use std::io::{BufRead as _, Read as _}; use wai_quantum::engine::{planner, registry::Registry}; - let mut input = String::new(); - let out = match std::io::stdin().read_to_string(&mut input).map_err(|e| e.to_string()).and_then(|_| serde_json::from_str::(&input).map_err(|e| e.to_string())) { + die_with_parent(); + let mut stdin = std::io::BufReader::new(std::io::stdin()); + let mut line = String::new(); + let read = stdin.read_line(&mut line); + // The watcher's end of the pipe stays open while it watches: its close is the + // end of this run. + let _ = std::thread::Builder::new().spawn(move || { + let mut rest = [0u8; 64]; + while matches!(stdin.read(&mut rest), Ok(n) if n > 0) {} + std::process::exit(3); + }); + let out = match read.map_err(|e| e.to_string()).and_then(|_| serde_json::from_str::(&line).map_err(|e| e.to_string())) { Ok(v) => match serde_json::from_value::(v["plan"].clone()) { Ok(plan) => planner::run_chosen(Registry::builtins(), &v["request"], &plan, &v["reasoning"]).unwrap_or_else(|e| json!({ "error": e })), Err(e) => json!({ "error": format!("the job's plan does not read: {e}") }), @@ -1024,6 +1036,39 @@ fn worker() { Err(e) => json!({ "error": format!("the job did not arrive: {e}") }), }; println!("{out}"); + // Off the core before it exits, so that the counter takes in its last stretch + // (on Apple silicon a thread's energy is added as it leaves a core). + std::thread::sleep(std::time::Duration::from_millis(5)); +} + +/// This process killed with its parent: on Linux by the kernel, and on any Unix by +/// noticing the parent changed, within half a second. +fn die_with_parent() { + #[cfg(unix)] + { + let parent = std::os::unix::process::parent_id(); + #[cfg(target_os = "linux")] + { + unsafe extern "C" { + fn prctl(option: i32, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> i32; + } + /// `PR_SET_PDEATHSIG` and `SIGKILL`. + const PR_SET_PDEATHSIG: i32 = 1; + // SAFETY: it sets this process's own death signal. + let _ = unsafe { prctl(PR_SET_PDEATHSIG, 9, 0, 0, 0) }; + } + if std::os::unix::process::parent_id() != parent || parent == 1 { + std::process::exit(3); + } + let _ = std::thread::Builder::new().spawn(move || { + loop { + std::thread::sleep(std::time::Duration::from_millis(100)); + if std::os::unix::process::parent_id() != parent { + std::process::exit(3); + } + } + }); + } } /// The `run` command's job, this process's one run: under a ceiling, in a process of diff --git a/wai/wai-quantum-cli/tests/estimates.rs b/wai/wai-quantum-cli/tests/estimates.rs index 6a262d2db..f8a4a6afe 100644 --- a/wai/wai-quantum-cli/tests/estimates.rs +++ b/wai/wai-quantum-cli/tests/estimates.rs @@ -115,6 +115,57 @@ fn a_run_is_stopped_at_its_ceiling_by_a_live_reading_and_its_receipt_says_so() { assert!(kept["machines"].as_object().unwrap().values().next().unwrap().as_object().is_some_and(|m| !m.is_empty()), "{kept}"); } +/// The run's process ends with the command line, however that ends: a SIGTERM or a +/// SIGKILL to it mid-run leaves nothing computing. One started with SIGCHLD ignored +/// still waits for its run. +#[test] +fn a_run_under_a_ceiling_ends_with_its_command_line() { + let h = Home::new("orphans"); + if !reads_here(&h) { + if cfg!(target_os = "macos") { + panic!("a Mac reads a process's own energy, so this test may not pass by skipping"); + } + return; + } + std::fs::write(h.0.join("busy.qasm"), BUSY).unwrap(); + let alive = |pid: &str| Command::new("kill").args(["-0", pid]).stderr(Stdio::null()).status().is_ok_and(|s| s.success()); + for signal in ["-TERM", "-KILL"] { + let mut cli = h.cmd().args(["run", "busy.qasm", "--method", "statevector", "--shots", "1000000", "--max-joules", "100000", "--demo-key"]).stdout(Stdio::null()).stderr(Stdio::null()).spawn().unwrap(); + let parent = cli.id().to_string(); + let child = (0..400) + .find_map(|_| { + let out = Command::new("pgrep").args(["-P", &parent]).output().ok()?; + let found = String::from_utf8_lossy(&out.stdout).split_whitespace().next().map(str::to_string); + if found.is_none() { + std::thread::sleep(std::time::Duration::from_millis(25)); + } + found + }) + .expect("the run's process started"); + assert!(Command::new("kill").args([signal, &parent]).status().unwrap().success()); + let _ = cli.wait(); + let gone = (0..80).any(|_| { + let still = alive(&child); + if still { + std::thread::sleep(std::time::Duration::from_millis(25)); + } + !still + }); + assert!(gone, "{signal}: the run's process {child} outlived its command line"); + } + // SIGCHLD ignored, as a parent can leave it: the run is waited for all the same. + let out = Command::new("sh") + .arg("-c") + .arg(format!("trap '' CHLD; exec '{}' run bell.qasm --shots 100 --exactness exact --max-joules 1000 --demo-key --json", env!("CARGO_BIN_EXE_wai-quantum"))) + .current_dir(&h.0) + .env("HOME", &h.0) + .env("XDG_CONFIG_HOME", h.0.join("config")) + .env("WAI_QUANTUM_TIMINGS", h.timings()) + .output() + .unwrap(); + assert_eq!(out.status.code(), Some(0), "{}", String::from_utf8_lossy(&out.stderr)); +} + /// Where nothing can stop a run the route is refused under a ceiling, with why: a /// server's run, in a process with other work in it, on every tool that weighs a /// route. `plan` shows what a run would be held by, and sends and runs nothing. diff --git a/wai/wai-quantum-service/src/jobs.rs b/wai/wai-quantum-service/src/jobs.rs index e3c0b74e2..ac1ef7172 100644 --- a/wai/wai-quantum-service/src/jobs.rs +++ b/wai/wai-quantum-service/src/jobs.rs @@ -1190,8 +1190,10 @@ impl Service { // A contract's energy ceiling, held by a live reading of the worker: a // package's counter is added up as it is read, so that it can wrap. let ceiling = planner::Contract::read(&input["request"]).ok().flatten().and_then(|c| c.max_joules); + // The packages' counter added up read by read, every look: what the job + // took in all, however many ranges it passes. let mut packages = match meter { - energy::Meter::Packages(p) => before.clone().map(|b| p.since(b)), + energy::Meter::Packages(p) => before.clone().map(|b| wai_quantum::engine::energy::Accumulated::new(p, b)), _ => None, }; let mut watcher = ceiling.map(wai_quantum::engine::energy::Watcher::new); @@ -1199,7 +1201,7 @@ impl Service { let mut stopped_figure = Value::Null; let mut peak = 0u64; let mut reading = None; - let mut after = None; + let mut ended_at: Option<()> = None; let why = loop { // The worker's energy is readable only between its exit and its // reaping, so it is reaped only once it has been seen to exit and @@ -1212,8 +1214,9 @@ impl Service { if exited != Some(false) { match child.try_wait() { Ok(Some(status)) => { - if let energy::Meter::Packages(p) = meter { - after = p.read(); + // The packages read once more, at the exit, and added up. + if let Some(added) = packages.as_mut() { + ended_at = added.read().map(|_| ()); } break status.success().then_some(()).ok_or(format!("the worker ended: {status}")); } @@ -1229,13 +1232,14 @@ impl Service { break Err(format!("the job used {} MiB, over the {} MiB it was admitted with; it was stopped", rss >> 20, mib)); } } + let looked = packages.as_mut().and_then(|added| added.read()); if let Some(w) = &mut watcher { - let now = match meter { - energy::Meter::Process => wai_quantum::engine::energy::running(pid).map(|r| r.joules()), - energy::Meter::Packages(_) => packages.as_mut().and_then(|read| read()), - energy::Meter::Unmetered(_) => None, + let (now, cpu) = match meter { + energy::Meter::Process => wai_quantum::engine::energy::running(pid).map_or((None, None), |r| (Some(r.joules()), Some(r.cpu_ns))), + energy::Meter::Packages(_) => (looked, None), + energy::Meter::Unmetered(_) => (None, None), }; - match w.take(now) { + match w.take_with(now, cpu) { Some(wai_quantum::engine::energy::Watched::Reached(joules)) => { kill(pid); let elapsed_ms = began.elapsed().as_millis() as u64; @@ -1254,9 +1258,10 @@ impl Service { let _ = child.wait().await; energy::figure(whole.as_ref(), gpu, "the worker could not be read after it was stopped") } - energy::Meter::Packages(p) => { + energy::Meter::Packages(_) => { let _ = child.wait().await; - let r = before.as_ref().zip(p.read()).and_then(|(b, a)| p.between(b, &a, others + self.starts.load(Ordering::SeqCst).saturating_sub(start))); + let concurrent = others + self.starts.load(Ordering::SeqCst).saturating_sub(start); + let r = packages.as_mut().and_then(|added| added.read().map(|_| added.reading(concurrent))); energy::package_figure(r.as_ref(), "the processor packages' counter did not read when the worker was stopped") } energy::Meter::Unmetered(why) => { @@ -1294,8 +1299,9 @@ impl Service { if exited.is_none() { match tokio::time::timeout(step, child.wait()).await { Ok(Ok(status)) => { - if let energy::Meter::Packages(p) = meter { - after = p.read(); + // The packages read once more, at the exit, and added up. + if let Some(added) = packages.as_mut() { + ended_at = added.read().map(|_| ()); } break status.success().then_some(()).ok_or(format!("the worker ended: {status}")); } @@ -1325,8 +1331,8 @@ impl Service { let concurrent = others + self.starts.load(Ordering::SeqCst).saturating_sub(start); let figure = match meter { energy::Meter::Process => energy::figure(reading.as_ref(), gpu, energy::UNMETERED_HERE), - energy::Meter::Packages(p) => { - let r = before.as_ref().zip(after.as_ref()).and_then(|(b, a)| p.between(b, a, concurrent)); + energy::Meter::Packages(_) => { + let r = ended_at.and(packages.as_ref()).map(|added| added.reading(concurrent)); energy::package_figure(r.as_ref(), "the processor packages' counter did not read at the job's start or end") } energy::Meter::Unmetered(why) => json!({ "unmetered": why }), diff --git a/wai/wai-quantum-service/src/main.rs b/wai/wai-quantum-service/src/main.rs index ce3b2ff7b..491224150 100644 --- a/wai/wai-quantum-service/src/main.rs +++ b/wai/wai-quantum-service/src/main.rs @@ -74,9 +74,23 @@ fn watch_parent() { #[cfg(unix)] { let parent = std::os::unix::process::parent_id(); + // On Linux the kernel kills a worker whose service has died. + #[cfg(target_os = "linux")] + { + unsafe extern "C" { + fn prctl(option: i32, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> i32; + } + /// `PR_SET_PDEATHSIG` and `SIGKILL`. + const PR_SET_PDEATHSIG: i32 = 1; + // SAFETY: it sets this process's own death signal. + let _ = unsafe { prctl(PR_SET_PDEATHSIG, 9, 0, 0, 0) }; + } + if std::os::unix::process::parent_id() != parent || parent == 1 { + std::process::exit(3); + } std::thread::spawn(move || { loop { - std::thread::sleep(std::time::Duration::from_millis(500)); + std::thread::sleep(std::time::Duration::from_millis(100)); if std::os::unix::process::parent_id() != parent { std::process::exit(3); } @@ -114,6 +128,9 @@ fn worker() { Err(e) => serde_json::json!({ "error": format!("the job is not JSON: {e}") }), }; println!("{out}"); + // Off the core before it exits, so that the counter takes in its last stretch + // (on Apple silicon a thread's energy is added as it leaves a core). + std::thread::sleep(std::time::Duration::from_millis(5)); } /// The host a result's provenance names. diff --git a/wai/wai-quantum/src/engine/energy.rs b/wai/wai-quantum/src/engine/energy.rs index 9e772c5fd..38d97dd98 100644 --- a/wai/wai-quantum/src/engine/energy.rs +++ b/wai/wai-quantum/src/engine/energy.rs @@ -116,14 +116,21 @@ pub enum Watched { Lost, } +/// The least power, in watts (nanojoules a nanosecond), an exited process's read +/// must show over its CPU time to be a reading of it at all. +pub const EXITED_FLOOR_W: f64 = 0.05; + /// A run under a ceiling, read by read: what ends it, and the longest time the -/// host let pass between two reads, which is what the ceiling is held to. +/// host let pass between two reads (from the start of the watch), which is what +/// the ceiling is held to. A counter that keeps one value while the run spends CPU +/// time is frozen, not live: a second of that loses the run, as silence does. #[derive(Debug)] pub struct Watcher { ceiling: f64, read_at: std::time::Instant, - taken_at: Option, - /// The longest time between two reads so far. + taken_at: std::time::Instant, + last: Option<(f64, Option)>, + /// The longest time between two reads so far, the first counted from the start. pub longest_gap: std::time::Duration, } @@ -133,27 +140,41 @@ impl Watcher { } pub fn new_at(ceiling: f64, at: std::time::Instant) -> Watcher { - Watcher { ceiling, read_at: at, taken_at: None, longest_gap: std::time::Duration::ZERO } + Watcher { ceiling, read_at: at, taken_at: at, last: None, longest_gap: std::time::Duration::ZERO } } /// One read now, or one that did not read: what ends the run, where it does. pub fn take(&mut self, read: Option) -> Option { - self.take_at(read, std::time::Instant::now()) + self.take_at(read, None, std::time::Instant::now()) } - /// [`Watcher::take`], read at `at`. - pub fn take_at(&mut self, read: Option, at: std::time::Instant) -> Option { - if let Some(before) = self.taken_at { - self.longest_gap = self.longest_gap.max(at.saturating_duration_since(before)); - } - self.taken_at = Some(at); + /// [`Watcher::take`], with the run's CPU time so far where it is known. + pub fn take_with(&mut self, read: Option, cpu_ns: Option) -> Option { + self.take_at(read, cpu_ns, std::time::Instant::now()) + } + + /// A read at `at`, with the run's CPU time then where it is known: a reading + /// counts as live only when it moved, or when the run spent no CPU time since. + pub fn take_at(&mut self, read: Option, cpu_ns: Option, at: std::time::Instant) -> Option { + self.longest_gap = self.longest_gap.max(at.saturating_duration_since(self.taken_at)); + self.taken_at = at; + let lost = |w: &Watcher| (at.saturating_duration_since(w.read_at) >= std::time::Duration::from_millis(WATCH_LOST_MS)).then_some(Watched::Lost); match read { Some(j) if j >= self.ceiling => Some(Watched::Reached(j)), - Some(_) => { - self.read_at = at; - None + Some(j) => { + let moved = match self.last { + None => true, + Some((before, cpu_before)) => j != before || matches!((cpu_before, cpu_ns), (Some(b), Some(a)) if a <= b), + }; + self.last = Some((j, cpu_ns)); + if moved { + self.read_at = at; + None + } else { + lost(self) + } } - None => (at.saturating_duration_since(self.read_at) >= std::time::Duration::from_millis(WATCH_LOST_MS)).then_some(Watched::Lost), + None => lost(self), } } @@ -276,6 +297,12 @@ pub fn figure(reading: Option<&Reading>, gpu: bool, unmetered_why: &str) -> Valu // here; that is no reading, not a reading of zero. return json!({ "unmetered": "the worker's energy counter did not advance: it is not live on this host" }); } + // An exited process read far below what its CPU time implies (under 50 mW over + // it) missed its last stretch on a core: on Apple silicon a thread's energy is + // added when it leaves a core, and one that exits on it leaves that out. + if (r.energy_nj as f64) < r.cpu_ns as f64 * EXITED_FLOOR_W { + return json!({ "unmetered": "the worker's counter read far below what its CPU time implies: the read missed its last stretch on a core, so it is no reading" }); + } let total_nj = r.energy_nj.saturating_add(r.billed_nj).saturating_sub(r.serviced_nj); let joules_micro = total_nj.saturating_add(500) / 1000; if joules_micro == 0 { @@ -605,14 +632,54 @@ impl Packages { /// What the packages have taken since `before`, read by read: added up as it /// goes, so that a counter that wraps during a long run loses nothing. pub fn since(&self, before: PackageSnapshot) -> impl FnMut() -> Option + Send + '_ { - let (mut last, mut total) = (before, 0.0); - move || { - let now = self.read()?; - total += self.between(&last, &now, 0)?.energy_uj as f64 / 1e6; - last = now; - Some(total) - } + let mut added = Accumulated::new(self, before); + move || added.read() } +} + +/// The packages' energy since a first read, added up read by read, each read's step +/// corrected for a wrap: what a run took in all, however many ranges it passes, so +/// long as no two reads are a wrap apart. +#[derive(Debug)] +pub struct Accumulated<'a> { + packages: &'a Packages, + first: PackageSnapshot, + last: PackageSnapshot, + total_uj: u64, +} + +impl<'a> Accumulated<'a> { + pub fn new(packages: &'a Packages, first: PackageSnapshot) -> Accumulated<'a> { + Accumulated { packages, last: first.clone(), first, total_uj: 0 } + } + + /// A read now, its step added: the total so far in joules, or none where a + /// package did not read. + pub fn read(&mut self) -> Option { + let now = self.packages.read()?; + self.total_uj = self.total_uj.saturating_add(self.packages.between(&self.last, &now, 0)?.energy_uj); + self.last = now; + Some(self.total_uj as f64 / 1e6) + } + + /// What was added up, as one reading from the first read to the last, with + /// `concurrent` other jobs on the host. + pub fn reading(&self, concurrent: u64) -> PackageReading { + let mut r = self.packages.between(&self.first, &self.first, concurrent).unwrap_or(PackageReading { + energy_uj: 0, + window_ns: 0, + packages: self.packages.zones.len() as u32, + update_ns: self.packages.probe.update_ns, + step_uj: self.packages.probe.step_uj, + concurrent, + }); + r.energy_uj = self.total_uj; + r.window_ns = self.last.at.saturating_duration_since(self.first.at).as_nanos() as u64; + r + } +} + +impl Packages { /// The longest a reading between two reads can be trusted ([`wrap_seconds`]). pub fn wrap_seconds(&self) -> Option { @@ -829,12 +896,13 @@ mod tests { const WHY: &str = "this host has no per-process energy counter"; fn reading(energy_nj: u64) -> Reading { - Reading { energy_nj, billed_nj: 0, serviced_nj: 0, cpu_ns: 250_000_000, window_ns: 300_000_000 } + // CPU time short enough that no size here is below the exited-read floor. + Reading { energy_nj, billed_nj: 0, serviced_nj: 0, cpu_ns: 1_000, window_ns: 300_000_000 } } #[test] fn a_figure_is_a_counter_reading_with_its_declared_uncertainty() { - let f = figure(Some(&reading(812_345_678)), false, WHY); + let f = figure(Some(&Reading { cpu_ns: 250_000_000, ..reading(812_345_678) }), false, WHY); assert_eq!(f["joules_micro"], 812_346); assert_eq!(f["energy_provenance"], "OnChipCounter"); assert_eq!(f["energy_counter_filtering"], "Unknown"); @@ -1075,31 +1143,82 @@ mod tests { /// A run is stopped by the first reading at or past its ceiling. A read that /// fails is passed over, as a counter's lag is; a counter silent for a second - /// of time loses the run its ceiling, however few reads the host allowed in it; - /// and the longest time between two reads is kept, to be said. + /// of time loses the run its ceiling, however few reads the host allowed in it, + /// and so does one that keeps one value while the run spends CPU time. The + /// longest time between two reads is kept, the first counted from the start. #[test] fn a_live_reading_stops_at_the_ceiling_and_a_silent_second_loses_it() { use std::time::{Duration, Instant}; let t0 = Instant::now(); let ms = |n: u64| t0 + Duration::from_millis(n); let mut w = Watcher::new_at(2.0, t0); - assert_eq!(w.take_at(Some(0.5), ms(10)), None); - assert_eq!(w.take_at(None, ms(20)), None); - assert_eq!(w.take_at(Some(1.5), ms(250)), None); - assert_eq!(w.take_at(Some(2.0), ms(260)), Some(Watched::Reached(2.0)), "at the ceiling, not only past it"); + assert_eq!(w.take_at(Some(0.5), None, ms(40)), None); + assert_eq!(w.longest_gap, Duration::from_millis(40), "the time before the first read is a gap"); + assert_eq!(w.take_at(None, None, ms(50)), None); + assert_eq!(w.take_at(Some(1.5), None, ms(280)), None); + assert_eq!(w.take_at(Some(2.0), None, ms(290)), Some(Watched::Reached(2.0)), "at the ceiling, not only past it"); assert_eq!(w.longest_gap, Duration::from_millis(230)); assert!(w.said("a counter").ends_with("the longest time between two reads was 230 ms")); - // Silent: two late reads a second apart lose it, where a hundred quick ones did not. + // Silent: two late reads a second apart lose it. let mut w = Watcher::new_at(2.0, t0); - assert_eq!(w.take_at(Some(1.0), ms(10)), None); - assert_eq!(w.take_at(None, ms(500)), None); - assert_eq!(w.take_at(None, ms(1010)), Some(Watched::Lost)); - // A read between keeps it. + assert_eq!(w.take_at(Some(1.0), None, ms(10)), None); + assert_eq!(w.take_at(None, None, ms(500)), None); + assert_eq!(w.take_at(None, None, ms(1010)), Some(Watched::Lost)); + // A read that moved keeps it. let mut w = Watcher::new_at(2.0, t0); - assert_eq!(w.take_at(None, ms(900)), None); - assert_eq!(w.take_at(Some(1.0), ms(950)), None); - assert_eq!(w.take_at(None, ms(1900)), None); - assert_eq!(w.take_at(None, ms(1950)), Some(Watched::Lost)); + assert_eq!(w.take_at(None, None, ms(900)), None); + assert_eq!(w.take_at(Some(1.0), None, ms(950)), None); + assert_eq!(w.take_at(None, None, ms(1900)), None); + assert_eq!(w.take_at(None, None, ms(1950)), Some(Watched::Lost)); + // Frozen: one value for a second while the run spends CPU time is no reading. + let mut w = Watcher::new_at(2.0, t0); + assert_eq!(w.take_at(Some(1.0), Some(10), ms(10)), None); + assert_eq!(w.take_at(Some(1.0), Some(500_000_000), ms(500)), None); + assert_eq!(w.take_at(Some(1.0), Some(1_000_000_000), ms(1010)), Some(Watched::Lost)); + // One value while the run spends none is a run waiting, not a frozen counter. + let mut w = Watcher::new_at(2.0, t0); + assert_eq!(w.take_at(Some(1.0), Some(10), ms(10)), None); + assert_eq!(w.take_at(Some(1.0), Some(10), ms(1500)), None); + // A package counter, whose CPU time is not known, that stops moving is frozen. + let mut w = Watcher::new_at(2.0, t0); + assert_eq!(w.take_at(Some(1.0), None, ms(10)), None); + assert_eq!(w.take_at(Some(1.0), None, ms(1010)), Some(Watched::Lost)); + } + + /// An exited read far below what its CPU time implies missed its last stretch + /// on a core, and is no reading; one in proportion is. + #[test] + fn an_exited_read_far_below_its_cpu_time_is_no_reading() { + let r = |energy_nj: u64, cpu_ns: u64| Reading { energy_nj, billed_nj: 0, serviced_nj: 0, cpu_ns, window_ns: cpu_ns }; + assert!(figure(Some(&r(7_094, 4_500_000)), false, "x")["unmetered"].as_str().unwrap().contains("last stretch on a core")); + assert!(figure(Some(&r(3_000_000, 4_500_000)), false, "x")["joules_micro"].is_number()); + } + + /// Added up read by read, a package counter's steps make what the run took in + /// all though the counter wraps twice: one delta from first to last loses each + /// whole range. + #[test] + fn a_package_counter_added_up_read_by_read_keeps_every_range() { + let d = std::env::temp_dir().join(format!("wai-energy-ranges-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&d); + let zone = d.join("intel-rapl:0"); + std::fs::create_dir_all(&zone).unwrap(); + std::fs::write(zone.join("name"), "package-0\n").unwrap(); + std::fs::write(zone.join("max_energy_range_uj"), "1000\n").unwrap(); + let file = zone.join("energy_uj"); + std::fs::write(&file, "0\n").unwrap(); + let zones = zones_in(&d, &|p| std::fs::read_to_string(p)).unwrap(); + let p = Packages { zones, probe: Probe { update_ns: 1_000_000, step_uj: 1 } }; + let mut added = Accumulated::new(&p, p.read().unwrap()); + let first = p.read().unwrap(); + // 400 µJ a read, ten reads: 4000 µJ, four times the range. + for k in 1..=10u64 { + std::fs::write(&file, format!("{}\n", (k * 400) % 1000)).unwrap(); + added.read().unwrap(); + } + assert_eq!(added.reading(0).energy_uj, 4000); + assert!(p.between(&first, &p.read().unwrap(), 0).unwrap().energy_uj < 1000, "one delta keeps less than a range"); + let _ = std::fs::remove_dir_all(&d); } /// A reading past the time a counter can wrap twice is not to be trusted: at the diff --git a/wai/wai-quantum/src/engine/planner.rs b/wai/wai-quantum/src/engine/planner.rs index 79607e747..78e304c41 100644 --- a/wai/wai-quantum/src/engine/planner.rs +++ b/wai/wai-quantum/src/engine/planner.rs @@ -1660,6 +1660,10 @@ fn stopped_holds(c: &Contract, result: &Value) -> bool { && result["method"] != "provider" && result.pointer("/accuracy/class").and_then(Value::as_str) == Some(STOPPED_CLASS) && result.as_object().is_some_and(|o| o.keys().all(|k| STOPPED_MEMBERS.contains(&k.as_str()))) + // Its whole figure, where it has one, is no less than what stopped it, and + // its time is the result's. + && result.pointer("/energy/joules_micro").and_then(Value::as_f64).is_none_or(|u| s["joules"].as_f64().is_some_and(|j| u >= j * 1e6 - 1.0)) + && result["elapsed_ms"].as_f64() == s["elapsed_ms"].as_f64() } /// Whether the route chosen is what ran: for a provider's, the result's provider -- 2.54.0 (Apple Git-157) From 3214e99918ce67348a9162490e3ea9038a70a7d2 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sun, 8 Nov 2026 08:11:49 -0500 Subject: [PATCH 20/42] wai-quantum: the corpus's stop on a provider's run is of the earlier form too Co-Authored-By: Claude Opus 5.5 --- wai/quantum-conformance/receipts/generate.py | 2 +- wai/quantum-conformance/receipts/manifest.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/wai/quantum-conformance/receipts/generate.py b/wai/quantum-conformance/receipts/generate.py index 561a56a70..0a4782e60 100644 --- a/wai/quantum-conformance/receipts/generate.py +++ b/wai/quantum-conformance/receipts/generate.py @@ -892,7 +892,7 @@ def contract_cases(run, at, drop): add("stopped-other-ceiling", edited(local, both(stopped, at(R + ("stopped", "max_joules"), 9))), ["stopped"], "a stop at a ceiling the contract does not give") add("stopped-at-ceiling", edited(local, both(stopped, at(R + ("stopped", "joules"), 2), at(P + ("kept", "energy", "joules"), 2))), [], "a reading exactly at the ceiling stops a run") add("stopped-class", edited(local, both(stopped, at(R + ("accuracy", "class"), "exact"))), ["stopped"], "a stopped run that claims a class") - add("stopped-on-provider", edited(local, both(stopped, at(R + ("method",), "provider"))), ["counts", "planner_choice", "provider_class", "request_provider", "request_shots", "stopped"], "a stop on a provider's run, which nothing here reads: and a local job's request and route, which no provider's result can have") + add("stopped-on-provider", edited(local, both(stopped, at(R + ("method",), "provider"))), ["contract_form", "counts", "planner_choice", "provider_class", "request_provider", "request_shots", "stopped"], "a stop on a provider's run, which nothing here reads: and a local job's request and route, which no provider's result can have, in the earlier form") add("stopped-read-form", edited(local, both(stopped, at(R + ("stopped", "read"), 7))), ["stopped"], "a stop that does not say what read it") add("stopped-elapsed-form", edited(local, both(stopped, at(R + ("stopped", "elapsed_ms"), 1.5))), ["stopped"], "a stop at a time that is no whole number") add("stopped-extra-member", edited(local, both(stopped, at(R + ("stopped", "note"), "more"))), ["stopped"], "a stop with a member its form does not have") diff --git a/wai/quantum-conformance/receipts/manifest.json b/wai/quantum-conformance/receipts/manifest.json index bc32caccf..51d2ddb47 100644 --- a/wai/quantum-conformance/receipts/manifest.json +++ b/wai/quantum-conformance/receipts/manifest.json @@ -1809,6 +1809,7 @@ { "file": "jobs/crafted-contract-stopped-on-provider.json", "reasons": [ + "contract_form", "counts", "planner_choice", "provider_class", @@ -1817,7 +1818,7 @@ "stopped" ], "made_by": "crafted", - "what": "a stop on a provider's run, which nothing here reads: and a local job's request and route, which no provider's result can have" + "what": "a stop on a provider's run, which nothing here reads: and a local job's request and route, which no provider's result can have, in the earlier form" }, { "file": "jobs/crafted-contract-stopped-read-form.json", -- 2.54.0 (Apple Git-157) From cce7fd5717d4fdd124e875ec550492d89c013218 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sun, 8 Nov 2026 08:16:27 -0500 Subject: [PATCH 21/42] wai-quantum: the tests' plans have 0.9.0's metered member Co-Authored-By: Claude Opus 5.5 --- wai/wai-quantum-cli/src/estimates.rs | 2 +- wai/wai-quantum-service/src/jobs.rs | 2 +- wai/wai-quantum/src/engine/energy.rs | 2 +- wai/wai-quantum/src/engine/planner/tests.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/wai/wai-quantum-cli/src/estimates.rs b/wai/wai-quantum-cli/src/estimates.rs index a3c2f3250..fc1f3edc4 100644 --- a/wai/wai-quantum-cli/src/estimates.rs +++ b/wai/wai-quantum-cli/src/estimates.rs @@ -653,7 +653,7 @@ mod tests { use std::sync::atomic::AtomicBool; fn plan(method: &str, work: u64) -> Plan { - Plan { method: method.into(), why: String::new(), memory_bytes: 1, work, qubits: 2, target: None } + Plan { method: method.into(), why: String::new(), memory_bytes: 1, work, qubits: 2, target: None, metered: false } } fn timing(work: u64, window_us: u64, watts: f64) -> Timing { diff --git a/wai/wai-quantum-service/src/jobs.rs b/wai/wai-quantum-service/src/jobs.rs index 130b96def..1ec754acb 100644 --- a/wai/wai-quantum-service/src/jobs.rs +++ b/wai/wai-quantum-service/src/jobs.rs @@ -1970,7 +1970,7 @@ mod tests { #[test] fn a_route_s_figure_is_an_estimate_and_what_reads_the_run() { let s = Service::new(config()); - let p = Plan { method: "statevector".into(), why: "".into(), memory_bytes: 1, work: 2_000_000_000, qubits: 20, target: None }; + let p = Plan { method: "statevector".into(), why: "".into(), memory_bytes: 1, work: 2_000_000_000, qubits: 20, target: None, metered: false }; let job = |coverage: &str| Job { id: job_id(), client: "x".into(), request: json!({}), plan: Plan { work: 1_000_000_000, ..p.clone() }, work: Work::One, status: Status::Done, submitted_ms: 0, started_ms: None, finished_ms: Some(1), result: Some(json!({ "elapsed_ms": 500, "energy": { "joules_micro": 5_000_000, "coverage": coverage, "energy_uncertainty": { "window_us": 500_000 } } })), error: None, peak_rss: 0, digests: Digests::default(), key: None, interruptions: Vec::new(), child: None }; assert!(s.figure(&p).estimate.is_err()); for _ in 0..3 { diff --git a/wai/wai-quantum/src/engine/energy.rs b/wai/wai-quantum/src/engine/energy.rs index 38d97dd98..79f770d51 100644 --- a/wai/wai-quantum/src/engine/energy.rs +++ b/wai/wai-quantum/src/engine/energy.rs @@ -1110,7 +1110,7 @@ mod tests { } fn plan(method: &str, work: u64) -> super::super::catalog::Plan { - super::super::catalog::Plan { method: method.into(), why: String::new(), memory_bytes: 1, work, qubits: 2, target: None } + super::super::catalog::Plan { method: method.into(), why: String::new(), memory_bytes: 1, work, qubits: 2, target: None, metered: false } } /// One estimate for every host: its words name whose runs it rests on, and they diff --git a/wai/wai-quantum/src/engine/planner/tests.rs b/wai/wai-quantum/src/engine/planner/tests.rs index 0b8c299a8..eada91039 100644 --- a/wai/wai-quantum/src/engine/planner/tests.rs +++ b/wai/wai-quantum/src/engine/planner/tests.rs @@ -1009,7 +1009,7 @@ impl Method for TwoWays { } fn plan(&self, job: &Job<'_>) -> Result { let r = job.request()?; - Ok(Plan { method: "two_ways".into(), why: "a test's method".into(), memory_bytes: 1 << 20, work: 1, qubits: r.program.n_qubits, target: None }) + Ok(Plan { method: "two_ways".into(), why: "a test's method".into(), memory_bytes: 1 << 20, work: 1, qubits: r.program.n_qubits, target: None, metered: false }) } fn run(&self, job: &Job<'_>, _: &Plan, out: &mut Value) -> Result<(), String> { let r = job.request()?; -- 2.54.0 (Apple Git-157) From 1bf4fc4ce3d1e2360b00a020e4c35c459d5526c4 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sun, 8 Nov 2026 08:16:27 -0500 Subject: [PATCH 22/42] wai-quantum: a test's plan has 0.9.0's metered member Co-Authored-By: Claude Opus 5.5 --- wai/wai-quantum/src/engine/planner/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wai/wai-quantum/src/engine/planner/tests.rs b/wai/wai-quantum/src/engine/planner/tests.rs index 5bb501883..ea7fe90c1 100644 --- a/wai/wai-quantum/src/engine/planner/tests.rs +++ b/wai/wai-quantum/src/engine/planner/tests.rs @@ -956,7 +956,7 @@ impl Method for TwoWays { } fn plan(&self, job: &Job<'_>) -> Result { let r = job.request()?; - Ok(Plan { method: "two_ways".into(), why: "a test's method".into(), memory_bytes: 1 << 20, work: 1, qubits: r.program.n_qubits, target: None }) + Ok(Plan { method: "two_ways".into(), why: "a test's method".into(), memory_bytes: 1 << 20, work: 1, qubits: r.program.n_qubits, target: None, metered: false }) } fn run(&self, job: &Job<'_>, _: &Plan, out: &mut Value) -> Result<(), String> { let r = job.request()?; -- 2.54.0 (Apple Git-157) From e6efed7819f99a23151ec74018614843600a5b7f Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sun, 8 Nov 2026 08:27:38 -0500 Subject: [PATCH 23/42] wai-quantum: the routes' digests pinned again on 0.9.0's prices Main's 0.9.0 changes what four of the five pinned jobs' routes cost; the fifth is unchanged. The new digests were read on macOS arm64 and held on Linux. Co-Authored-By: Claude Opus 5.5 --- wai/wai-quantum/src/engine/planner/tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wai/wai-quantum/src/engine/planner/tests.rs b/wai/wai-quantum/src/engine/planner/tests.rs index ea7fe90c1..cc451b675 100644 --- a/wai/wai-quantum/src/engine/planner/tests.rs +++ b/wai/wai-quantum/src/engine/planner/tests.rs @@ -892,10 +892,10 @@ fn what_the_routes_cost_is_the_same_bytes_on_every_host() { } const PINNED_DIGESTS: [&str; 5] = [ - "2ff3b387677fc4860b0aeba26585eea08f41b2693b8d8cd26dbf927006e8a9b6", - "74e00ef788c2493e610521d4fbd79af43e2e0558aa1535a5f6955186e10cf2ad", - "28339eda6fb7659e124649aff6db9f8717da721f7a98d3a33c17879cb9ba43c8", - "23ab02c8b0e119f25db1adc71857da76e67be851ea8c53b71a6f1f86fb838fa4", + "9e40eeb50e1fd3cea81119ec7c5d4ee1517c46aa35acf13270658e745058dc92", + "221e18db5ede946e533ef17725a1cb2551ed53120cf2b52a874cfa043e9c0aba", + "967b86c71cc874b2e9b1850df12b7e6d2db87c71a2e60af6514a459c05c59088", + "c8876fea57d73b89744656a66b09b78558a50f08581eb2b2b8cac6331e121c8d", "8189fad98f54c33e6956f82c5d4f7d9bd2c46a7ad49ebb08f0bdbf003cb1d323", ]; -- 2.54.0 (Apple Git-157) From 208482963728be0e6a384e5e63f01ac0240a08fe Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sun, 8 Nov 2026 08:28:51 -0500 Subject: [PATCH 24/42] wai-quantum: the tool lists blessed on the merged tree; a test of what is read keeps its reading Co-Authored-By: Claude Opus 5.5 --- wai/wai-quantum-cli/docs/local-mcp.json | 20257 +++++++++++++++++++- wai/wai-quantum-cli/docs/service-mcp.json | 520 + wai/wai-quantum-cli/src/estimates.rs | 4 +- 3 files changed, 20762 insertions(+), 19 deletions(-) diff --git a/wai/wai-quantum-cli/docs/local-mcp.json b/wai/wai-quantum-cli/docs/local-mcp.json index b4c691083..991eeec2b 100644 --- a/wai/wai-quantum-cli/docs/local-mcp.json +++ b/wai/wai-quantum-cli/docs/local-mcp.json @@ -4,7 +4,7 @@ { "name": "run_quantum_circuit", "title": "Run a quantum program here", - "description": "Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more.", + "description": "Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `contract` (the class wanted, a deadline) and the planner prices every method here, runs the cheapest that meets it, seals its reasoning under `planner`, and refuses (J071) rather than fall back to less; this tool reaches no provider, and plan_routes and run_routed do. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more.", "inputSchema": { "type": "object", "anyOf": [ @@ -531,6 +531,78 @@ "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, held by a live reading while it runs: at the ceiling the run is stopped, gives no answer, and its receipt says so. A route nothing here can read and stop does not meet it, so on a host that reads none every route is rejected. An estimate can refuse a job clearly past it, and promises nothing.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -1358,6 +1430,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, held by a live reading while it runs: at the ceiling the run is stopped, gives no answer, and its receipt says so. A route nothing here can read and stop does not meet it, so on a host that reads none every route is rejected. An estimate can refuse a job clearly past it, and promises nothing.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -1476,9 +1620,10 @@ "estimate", "heuristic", "measured", - "simulated" + "simulated", + "none" ], - "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance. none: the run was stopped at its contract's energy ceiling and gave no answer." }, "approximate": { "const": true, @@ -4194,6 +4339,984 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unwatched" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "stopped": { + "type": "object", + "description": "A run stopped at its contract's max_joules by a live reading: it gave no answer, and accuracy.class is none (wai/extensions/quantum-providers.md section 8.7).", + "required": [ + "at", + "joules", + "max_joules", + "elapsed_ms", + "read" + ], + "properties": { + "at": { + "const": "max_joules" + }, + "joules": { + "type": "number", + "description": "What the reading had come to, at or past the ceiling." + }, + "max_joules": { + "type": "number" + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "read": { + "type": "string", + "description": "What read the run, and what that covers." + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "none" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance. none: the run was stopped at its contract's energy ceiling and gave no answer." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -5204,6 +6327,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, held by a live reading while it runs: at the ceiling the run is stopped, gives no answer, and its receipt says so. A route nothing here can read and stop does not meet it, so on a host that reads none every route is rejected. An estimate can refuse a job clearly past it, and promises nothing.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -5320,9 +6515,10 @@ "estimate", "heuristic", "measured", - "simulated" + "simulated", + "none" ], - "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance. none: the run was stopped at its contract's energy ceiling and gave no answer." }, "approximate": { "const": true, @@ -8038,6 +9234,984 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unwatched" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "stopped": { + "type": "object", + "description": "A run stopped at its contract's max_joules by a live reading: it gave no answer, and accuracy.class is none (wai/extensions/quantum-providers.md section 8.7).", + "required": [ + "at", + "joules", + "max_joules", + "elapsed_ms", + "read" + ], + "properties": { + "at": { + "const": "max_joules" + }, + "joules": { + "type": "number", + "description": "What the reading had come to, at or past the ceiling." + }, + "max_joules": { + "type": "number" + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "read": { + "type": "string", + "description": "What read the run, and what that covers." + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "none" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance. none: the run was stopped at its contract's energy ceiling and gave no answer." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -8898,7 +11072,7 @@ { "name": "plan_quantum_circuit", "title": "Plan a quantum program", - "description": "The method a program would run on and why, the memory and work it would take, without running it.", + "description": "The method a program would run on and why, the memory and work it would take, without running it. With a contract, every route's price or reason for rejection under planner, or the refusal (J071) when no route meets it.", "inputSchema": { "type": "object", "anyOf": [ @@ -9425,17 +11599,89 @@ "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, held by a live reading while it runs: at the ceiling the run is stopped, gives no answer, and its receipt says so. A route nothing here can read and stop does not meet it, so on a host that reads none every route is rejected. An estimate can refuse a job clearly past it, and promises nothing.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, "outputSchema": { "$id": "wai-quantum://schemas/plan_quantum_circuit/1", "type": "object", - "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it.", + "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it. A job with a contract carries the planner's reasoning.", "anyOf": [ { "title": "wai.quantum.plan/1", - "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it.", + "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it. A job with a contract carries the planner's reasoning.", "type": "object", "required": [ "method", @@ -9513,6 +11759,677 @@ } } }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unwatched" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, "metered": { "type": "boolean", "description": "True when a job naming method mps would pass one job's work at the bond it asks for: it runs under a meter of the bonds it reaches, may take far less than `work`, and stops with J011 if it passes `work`." @@ -21538,7 +24455,7 @@ { "name": "verify_quantum_result", "title": "Check a result's receipt", - "description": "Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and every rule of its form holds (`reasons` names what does not), and which key signed it.", + "description": "Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and every rule of its form holds (`reasons` names what does not), and which key signed it; for a job under a contract, every route's outcome and the choice recomputed from what it states, and with recheck its routes priced again and its shadow run again.", "inputSchema": { "type": "object", "required": [ @@ -21551,6 +24468,10 @@ "string" ], "description": "The job's text as it was given (preferred: read as the protocol reads it, so a member named twice or a number past what a parsed job keeps is seen), or the job: {\"request\": ..., \"result\": ...}, the result carrying its receipt." + }, + "recheck": { + "type": "boolean", + "description": "For a job under a contract: its routes priced again at the job's memory, held to the digest it sealed, and its shadow run again, held to its counts bit for bit." } } }, @@ -21604,6 +24525,28 @@ "null" ], "description": "That key as a did:key." + }, + "planner": { + "type": "object", + "description": "For a job under a contract, what its reasoning says: the route chosen, the class wanted and given, whether the choice depends on the host, what was kept, and the shadow." + }, + "recheck": { + "type": "object", + "description": "With recheck: whether the routes priced again and the shadow run again are what the job sealed.", + "properties": { + "holds": { + "type": "boolean" + }, + "engine": { + "type": "object" + }, + "priced": { + "type": "object" + }, + "shadow": { + "type": "object" + } + } } } }, @@ -30865,6 +33808,78 @@ "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, held by a live reading while it runs: at the ceiling the run is stopped, gives no answer, and its receipt says so. A route nothing here can read and stop does not meet it, so on a host that reads none every route is rejected. An estimate can refuse a job clearly past it, and promises nothing.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } }, "required": [ @@ -31695,6 +34710,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, held by a live reading while it runs: at the ceiling the run is stopped, gives no answer, and its receipt says so. A route nothing here can read and stop does not meet it, so on a host that reads none every route is rejected. An estimate can refuse a job clearly past it, and promises nothing.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -31813,9 +34900,10 @@ "estimate", "heuristic", "measured", - "simulated" + "simulated", + "none" ], - "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance. none: the run was stopped at its contract's energy ceiling and gave no answer." }, "approximate": { "const": true, @@ -34531,6 +37619,984 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unwatched" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "stopped": { + "type": "object", + "description": "A run stopped at its contract's max_joules by a live reading: it gave no answer, and accuracy.class is none (wai/extensions/quantum-providers.md section 8.7).", + "required": [ + "at", + "joules", + "max_joules", + "elapsed_ms", + "read" + ], + "properties": { + "at": { + "const": "max_joules" + }, + "joules": { + "type": "number", + "description": "What the reading had come to, at or past the ceiling." + }, + "max_joules": { + "type": "number" + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "read": { + "type": "string", + "description": "What read the run, and what that covers." + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "none" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance. none: the run was stopped at its contract's energy ceiling and gave no answer." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -35541,6 +39607,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, held by a live reading while it runs: at the ceiling the run is stopped, gives no answer, and its receipt says so. A route nothing here can read and stop does not meet it, so on a host that reads none every route is rejected. An estimate can refuse a job clearly past it, and promises nothing.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -35657,9 +39795,10 @@ "estimate", "heuristic", "measured", - "simulated" + "simulated", + "none" ], - "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance. none: the run was stopped at its contract's energy ceiling and gave no answer." }, "approximate": { "const": true, @@ -38375,6 +42514,984 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unwatched" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "stopped": { + "type": "object", + "description": "A run stopped at its contract's max_joules by a live reading: it gave no answer, and accuracy.class is none (wai/extensions/quantum-providers.md section 8.7).", + "required": [ + "at", + "joules", + "max_joules", + "elapsed_ms", + "read" + ], + "properties": { + "at": { + "const": "max_joules" + }, + "joules": { + "type": "number", + "description": "What the reading had come to, at or past the ceiling." + }, + "max_joules": { + "type": "number" + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "read": { + "type": "string", + "description": "What read the run, and what that covers." + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "none" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance. none: the run was stopped at its contract's energy ceiling and gave no answer." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -50779,6 +55896,78 @@ "type": "integer", "minimum": 0, "description": "A seed, for a provider that is a seeded simulator; a device ignores it." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, held by a live reading while it runs: at the ceiling the run is stopped, gives no answer, and its receipt says so. A route nothing here can read and stop does not meet it, so on a host that reads none every route is rejected. An estimate can refuse a job clearly past it, and promises nothing.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -50826,6 +56015,677 @@ "confirm": { "type": "string", "description": "What the person reads before confirming a run that is not free." + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unwatched" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } } } }, @@ -50911,6 +56771,78 @@ "minimum": 0, "description": "A seed, for a provider that is a seeded simulator; a device ignores it." }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, held by a live reading while it runs: at the ceiling the run is stopped, gives no answer, and its receipt says so. A route nothing here can read and stop does not meet it, so on a host that reads none every route is rejected. An estimate can refuse a job clearly past it, and promises nothing.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } + }, "confirm_cost": { "type": "boolean", "description": "true only when the person has agreed to this run's cost. A run that is not free is refused without it." @@ -51744,6 +57676,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, held by a live reading while it runs: at the ceiling the run is stopped, gives no answer, and its receipt says so. A route nothing here can read and stop does not meet it, so on a host that reads none every route is rejected. An estimate can refuse a job clearly past it, and promises nothing.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -51862,9 +57866,10 @@ "estimate", "heuristic", "measured", - "simulated" + "simulated", + "none" ], - "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance. none: the run was stopped at its contract's energy ceiling and gave no answer." }, "approximate": { "const": true, @@ -54580,6 +60585,984 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unwatched" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "stopped": { + "type": "object", + "description": "A run stopped at its contract's max_joules by a live reading: it gave no answer, and accuracy.class is none (wai/extensions/quantum-providers.md section 8.7).", + "required": [ + "at", + "joules", + "max_joules", + "elapsed_ms", + "read" + ], + "properties": { + "at": { + "const": "max_joules" + }, + "joules": { + "type": "number", + "description": "What the reading had come to, at or past the ceiling." + }, + "max_joules": { + "type": "number" + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "read": { + "type": "string", + "description": "What read the run, and what that covers." + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "none" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance. none: the run was stopped at its contract's energy ceiling and gave no answer." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -55590,6 +62573,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, held by a live reading while it runs: at the ceiling the run is stopped, gives no answer, and its receipt says so. A route nothing here can read and stop does not meet it, so on a host that reads none every route is rejected. An estimate can refuse a job clearly past it, and promises nothing.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -55706,9 +62761,10 @@ "estimate", "heuristic", "measured", - "simulated" + "simulated", + "none" ], - "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance. none: the run was stopped at its contract's energy ceiling and gave no answer." }, "approximate": { "const": true, @@ -58424,6 +65480,13173 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unwatched" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "stopped": { + "type": "object", + "description": "A run stopped at its contract's max_joules by a live reading: it gave no answer, and accuracy.class is none (wai/extensions/quantum-providers.md section 8.7).", + "required": [ + "at", + "joules", + "max_joules", + "elapsed_ms", + "read" + ], + "properties": { + "at": { + "const": "max_joules" + }, + "joules": { + "type": "number", + "description": "What the reading had come to, at or past the ceiling." + }, + "max_joules": { + "type": "number" + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "read": { + "type": "string", + "description": "What read the run, and what that covers." + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "none" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance. none: the run was stopped at its contract's energy ceiling and gave no answer." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + }, + "error": { + "type": "string" + }, + "code": { + "type": "string", + "description": "A failed item's refusal code (engine::refusal)." + }, + "path": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The item's leaf's sibling digests up to the root, in hex." + } + } + } + } + } + } + ] + }, + "error": { + "type": "string", + "description": "Why a job failed, or why it was interrupted." + }, + "interruptions": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "The job service: each time it stopped while the job ran, in milliseconds since 1970. A job that was running when the service stopped is queued again, once, to run from its stored request." + }, + "submitted_ms": { + "type": "integer", + "description": "The job service: when it was submitted, in milliseconds since 1970." + }, + "started_ms": { + "type": "integer" + }, + "finished_ms": { + "type": "integer" + }, + "peak_rss_bytes": { + "type": "integer", + "description": "The job service: the most memory the job's process held." + }, + "digests": { + "type": "object", + "description": "The job service: the BLAKE3 digests its store keeps the job's objects under (the request, each program, the result and the receipt).", + "properties": { + "algorithm": { + "const": "blake3" + }, + "request": { + "type": [ + "string", + "null" + ] + }, + "programs": { + "type": "array", + "items": { + "type": "string" + } + }, + "result": { + "type": "string" + }, + "receipt": { + "type": "string" + } + } + } + } + }, + { + "type": "object", + "description": "A refusal as data: the message, every code in it (the last is the code), its outcome and meaning as the code's table gives them. A host that refuses for its own reasons gives the error alone.", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + } + ] + } + }, + { + "name": "plan_routes", + "title": "Weigh a contract against every route", + "description": "Every route a job could take under its contract: the methods on this machine and each of the person's own providers, each with its price or why it was rejected, what a provider's estimate leaves out, and the route the planner would choose: the cheapest that meets the contract, or the refusal (J071) with every route's reason. Each provider is asked to describe its device and estimate the job. Nothing is submitted and nothing is spent. A device is chosen only when exactness asks for measured or any.", + "inputSchema": { + "type": "object", + "required": [ + "qasm", + "contract" + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why." + }, + "inputs": { + "type": "object", + "additionalProperties": { + "type": "integer" + }, + "description": "A generator's inputs' values, as {\"n\": 5}." + }, + "shots": { + "type": "integer", + "minimum": 1, + "description": "Shots (default 1024)." + }, + "seed": { + "type": "integer", + "minimum": 0, + "description": "A seed." + }, + "observables": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Pauli observables: a provider's job answers counts, so a method here answers these." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, held by a live reading while it runs: at the ceiling the run is stopped, gives no answer, and its receipt says so. A route nothing here can read and stop does not meet it, so on a host that reads none every route is rejected. An estimate can refuse a job clearly past it, and promises nothing.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } + } + } + }, + "outputSchema": { + "$id": "wai-quantum://schemas/plan_routes/1", + "type": "object", + "description": "Every route a job could take under its contract, each with its price or why it was rejected, and the route chosen: nothing submitted, nothing spent.", + "anyOf": [ + { + "type": "object", + "description": "Every route a job could take under its contract, each with its price or why it was rejected, and the route chosen: nothing submitted, nothing spent.", + "required": [ + "dry_run", + "planner" + ], + "properties": { + "dry_run": { + "const": true + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unwatched" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "plan": { + "title": "wai.quantum.plan/1", + "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it. A job with a contract carries the planner's reasoning.", + "type": "object", + "required": [ + "method", + "why", + "memory_bytes", + "work", + "qubits" + ], + "properties": { + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0, + "description": "The method's own unit: an upper bound on what the run takes where the method's cost is known beforehand, and with `metered` what the meter holds it to." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "target": { + "type": "object", + "description": "A run on a device target: which target (its hash, as its receipt binds it), its calibration snapshot, where the program was placed and why, and the noise derived from the target.", + "required": [ + "name", + "hash" + ], + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "hash_is": { + "type": "string" + }, + "calibration": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "source": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "note": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "description": "The native gate set, the layout and routes chosen, the swaps, the expected success beside the fewest-swaps layout's, and the check of the compiled program." + }, + "noise": { + "type": "object", + "description": "The noise model derived from the target's calibration: its channels, durations and idling, and each qubit's readout." + } + } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unwatched" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "metered": { + "type": "boolean", + "description": "True when a job naming method mps would pass one job's work at the bond it asks for: it runs under a meter of the bonds it reaches, may take far less than `work`, and stops with J011 if it passes `work`." + } + } + }, + "provider_plan": { + "type": "object", + "description": "The dry run of a job on a provider: nothing submitted, nothing spent.", + "required": [ + "dry_run", + "provider", + "plan", + "estimate", + "free", + "confirm" + ], + "properties": { + "dry_run": { + "const": true + }, + "provider": { + "type": "object" + }, + "calibration": { + "type": [ + "string", + "null" + ] + }, + "billing": { + "type": "object" + }, + "plan": { + "type": "object" + }, + "estimate": { + "type": "object" + }, + "free": { + "type": "boolean" + }, + "confirm": { + "type": "string", + "description": "What the person reads before confirming a run that is not free." + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unwatched" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + } + } + }, + "confirm": { + "type": "object", + "description": "Where the route chosen is a provider's and not free: what a person confirms it by. token is a digest of the route, its estimate's money and the program and shots it would send; a run is sent only when given that token made again at send time.", + "required": [ + "token", + "route", + "money", + "says" + ], + "properties": { + "token": { + "type": "string" + }, + "route": { + "type": "string" + }, + "money": { + "type": "object" + }, + "says": { + "type": "string" + } + } + } + } + }, + { + "type": "object", + "description": "A refusal as data: the message, every code in it (the last is the code), its outcome and meaning as the code's table gives them. A host that refuses for its own reasons gives the error alone.", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + } + ] + } + }, + { + "name": "run_routed", + "title": "Run a job on the route its contract chooses (can spend the person's money)", + "description": "Runs a job on the route plan_routes chooses: a method on this machine, or one of the person's own providers. THIS CAN SPEND THE PERSON'S MONEY OR QUOTA, when the contract allows a provider and one is chosen. A cost ceiling confirms nothing: a run that is not free is refused unless confirm is the word plan_routes gave for that route, its estimate and its program (its confirm.token), set only after the person has seen them and agreed to that run; if the route or its estimate changed since, it is refused with the new word. The answer is a job in the service's form, its result carrying the planner's reasoning under planner; a provider's result also carries a classical method's counts and their distance under shadow, or why no classical method could reach them. If the job has not finished within this call the answer has status running and an id, and get_provider_job collects it later. Do not run it again to find out: that is a second job, and it can be a second bill.", + "inputSchema": { + "type": "object", + "required": [ + "qasm", + "contract" + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why." + }, + "inputs": { + "type": "object", + "additionalProperties": { + "type": "integer" + }, + "description": "A generator's inputs' values, as {\"n\": 5}." + }, + "shots": { + "type": "integer", + "minimum": 1, + "description": "Shots (default 1024)." + }, + "seed": { + "type": "integer", + "minimum": 0, + "description": "A seed." + }, + "observables": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Pauli observables: a provider's job answers counts, so a method here answers these." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, held by a live reading while it runs: at the ceiling the run is stopped, gives no answer, and its receipt says so. A route nothing here can read and stop does not meet it, so on a host that reads none every route is rejected. An estimate can refuse a job clearly past it, and promises nothing.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } + }, + "confirm": { + "type": "string", + "description": "The word plan_routes gave (confirm.token) for the route, the estimate and the program the person agreed to. A run that is not free is refused without it, whatever the contract's ceiling, and refused if what is chosen now is not what that word names." + } + } + }, + "outputSchema": { + "$id": "wai-quantum://schemas/run_routed/1", + "type": "object", + "description": "A job as a host returns it: its status, the method its plan chose and why, the request as submitted, and, once it is done, the result with its receipt: a job's result, or for a set (a request with programs or a sweep, its method set) the set's result. The command line's run --json, the local MCP server's run_quantum_circuit and a run on the person's own provider give a finished job; the job service also gives its id and times, and a job still queued or running, or failed with its error. A job's receipt verifies from this document alone: request and result.", + "anyOf": [ + { + "title": "wai.quantum.job/1", + "description": "A job as a host returns it: its status, the method its plan chose and why, the request as submitted, and, once it is done, the result with its receipt: a job's result, or for a set (a request with programs or a sweep, its method set) the set's result. The command line's run --json, the local MCP server's run_quantum_circuit and a run on the person's own provider give a finished job; the job service also gives its id and times, and a job still queued or running, or failed with its error. A job's receipt verifies from this document alone: request and result.", + "type": "object", + "required": [ + "status", + "request" + ], + "properties": { + "id": { + "type": "string", + "description": "The job service's id for the job." + }, + "status": { + "enum": [ + "queued", + "running", + "done", + "failed", + "cancelled", + "interrupted" + ], + "description": "interrupted: the job service stopped while the job ran, after it had run it again once from its request, so it has no result; error says so." + }, + "method": { + "type": "string", + "description": "The method the plan chose; set for a set." + }, + "why": { + "type": "string", + "description": "Why the plan chose the method." + }, + "estimate": { + "type": "object", + "description": "What the plan admitted the job with.", + "required": [ + "memory_bytes", + "work" + ], + "properties": { + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0, + "description": "In the method's own unit." + } + } + }, + "request": { + "title": "wai.quantum.job-request/1", + "description": "A job as a client submits it: a program and what is asked of it, or a set: many programs (programs), or one over a grid of its inputs (sweep), run as one job. The command line, both MCP servers, the job service, the desktop app and the Studio read it alike, and a receipt seals it as it was given. A member the engine does not read is ignored, and sealed with the rest.", + "type": "object", + "anyOf": [ + { + "required": [ + "qasm" + ] + }, + { + "required": [ + "programs" + ] + }, + { + "required": [ + "source" + ] + } + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, in OpenQASM 3 or the OpenQASM 2 forms in common use." + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "description": "The program in another format, in place of qasm (engine::formats::expand): read to the job's qasm before the job is read, the request keeping its source.", + "properties": { + "format": { + "enum": [ + "qasm", + "qir", + "jeff" + ] + }, + "program": { + "type": "string", + "description": "The program's text (OpenQASM, QIR)." + }, + "program_base64": { + "type": "string", + "description": "The program's bytes as base64 (jeff)." + } + } + }, + "shots": { + "type": "integer", + "minimum": 0, + "maximum": 1000000, + "description": "Measurement shots; 1024 when no observables or amplitudes are asked for, otherwise 0." + }, + "seed": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991, + "description": "The sampling seed (1 when not given): the same job and seed give the same counts." + }, + "method": { + "type": "string", + "description": "auto (the default: the strongest method the program admits), or a method by its name as the methods list names it; pulse runs a pulse program (OpenPulse calibrations) under the pulse options." + }, + "observables": { + "type": "array", + "maxItems": 256, + "description": "Pauli observables to take the expectation values of.", + "items": { + "anyOf": [ + { + "type": "string", + "description": "A Pauli string, as \"Z0 Z1\"; qubits count from 0." + }, + { + "type": "object", + "required": [ + "pauli" + ], + "properties": { + "pauli": { + "type": "string", + "description": "A Pauli string, as \"X3\"." + }, + "coeff": { + "type": "number", + "description": "Its coefficient (1 when not given)." + } + } + } + ] + } + }, + "amplitudes": { + "type": "array", + "maxItems": 64, + "description": "Basis states whose amplitudes to return: one 0 or 1 per qubit, qubit n-1 first.", + "items": { + "type": "string" + } + }, + "noise": { + "type": "object", + "description": "A noise model, each channel a probability. A channel not listed here is refused.", + "additionalProperties": false, + "properties": { + "depolarizing_1q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "depolarizing_2q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "amplitude_damping": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "dephasing": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "readout": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + } + }, + "options": { + "type": "object", + "description": "Options of the method that runs the job, as the methods list names them (max_bond, cutoff, fusion, trajectories, threshold, max_weight, ladder, max_terms, path_restarts, controls), and memory_gb.", + "additionalProperties": true, + "properties": { + "controls": { + "enum": [ + "whole", + "standard" + ], + "description": "A gate whose standard gates would double (x, y, z or h under three or more controls; s, sdg, t, tdg, p, rx, ry, rz, u, sx or sxdg under two or more) runs as one on statevector and in standard gates on exact. \"standard\" runs standard gates on statevector too, which reproduces a result made that way bit for bit. \"whole\" holds the gate whole on exact too, which gives other bits than its default, and is refused (J003) on a job that runs standard gates: another method named, a compile, noise, mitigation, a device target or a named place on the fabric. Any other value is refused." + } + } + }, + "compile": { + "type": "object", + "description": "What a compile is asked for, each optional: the most the output may differ from the program (epsilon, in the operator norm up to a global phase), the level (0 lowers and approximates; 1 also rewrites and folds phases; 2 also resynthesises), the basis, the gate set it writes the program in (clifford_t: every rotation off the multiples of π/4 a Clifford+T word; standard: nothing approximated), whether to give the circuit after each pass (stages), and the twirl and dd passes, last (twirl, with its seed; dd, with its sequence).", + "properties": { + "epsilon": { + "type": "number", + "exclusiveMinimum": 0 + }, + "level": { + "type": "integer", + "minimum": 0, + "maximum": 2 + }, + "basis": { + "enum": [ + "clifford_t", + "standard" + ] + }, + "stages": { + "type": "boolean" + }, + "twirl": { + "description": "Twirl each two-qubit Clifford gate with Paulis drawn from a seeded stream: true (seed 1), or {\"seed\": N}. One seed is one instance, checked to be the same circuit.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "required": [ + "seed" + ], + "properties": { + "seed": { + "type": "integer", + "minimum": 0 + } + } + } + ] + }, + "dd": { + "description": "Dynamical decoupling in each window where a qubit idles long enough: xx or xy4 (or {\"sequence\": …}), checked to change nothing without noise.", + "anyOf": [ + { + "enum": [ + "xx", + "xy4" + ] + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "sequence": { + "enum": [ + "xx", + "xy4" + ] + } + } + } + ] + } + } + }, + "intent": { + "description": "What the program must do, checked with the run: one intent or a list. The result's verdict says how far it was checked.", + "anyOf": [ + { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + } + ] + }, + "verdict": { + "type": "boolean", + "description": "true: the result carries a verdict even with no intent." + }, + "target": { + "description": "A device target: a built-in target's name, or a target document. The program is compiled to it, placed and simulated under its noise; noise may not be given beside it.", + "anyOf": [ + { + "type": "string" + }, + { + "title": "wai.quantum.target/1", + "description": "A device target: its qubits, the pairs it couples, its native gates with their errors and durations, and the calibration snapshot they come from. A value not known is left out, never written as zero. Every field but format, name, source, qubits, gates and coupling is optional, and a field the format does not name is refused, so a misspelt one never reads as absent. Its canonical text is its RFC 8785 form, and the BLAKE3 of that text, the target's hash, names the snapshot in a receipt.", + "type": "object", + "required": [ + "format", + "name", + "source", + "qubits", + "gates", + "coupling" + ], + "additionalProperties": false, + "properties": { + "format": { + "const": "wai.quantum.target/1" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "additionalProperties": false, + "properties": { + "format": { + "type": "string", + "description": "The format the target was read from (wai-quantum targets import --help lists them)." + }, + "note": { + "type": "string", + "maxLength": 400 + } + } + }, + "calibration": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "maxLength": 400, + "description": "The calibration snapshot's id, as the source names it, or a content id of the snapshot read." + }, + "timestamp": { + "type": "string", + "maxLength": 400, + "description": "When the snapshot was taken, as the source writes it." + } + } + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2048, + "description": "Every qubit, in order.", + "items": { + "type": "object", + "required": [ + "qubit" + ], + "additionalProperties": false, + "properties": { + "qubit": { + "type": "integer", + "minimum": 0, + "description": "Its index: its place in the list." + }, + "label": { + "type": "string", + "description": "The source's own name for it, when that is not its index." + }, + "t1_us": { + "type": "number", + "minimum": 0, + "description": "T1, microseconds." + }, + "t2_us": { + "type": "number", + "minimum": 0, + "description": "T2 (the echo or Ramsey time the source reports), microseconds." + }, + "frequency_ghz": { + "type": "number", + "minimum": 0, + "description": "Its frequency, gigahertz." + }, + "readout": { + "type": "object", + "required": [ + "p01", + "p10" + ], + "additionalProperties": false, + "properties": { + "p01": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 1 | holds 0)." + }, + "p10": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 0 | holds 1)." + } + } + }, + "measure_ns": { + "type": "number", + "minimum": 0, + "description": "The measurement's duration, nanoseconds." + } + } + } + }, + "gates": { + "type": "array", + "maxItems": 262144, + "description": "Each native gate where the device runs it, sorted by gate then qubits.", + "items": { + "type": "object", + "required": [ + "gate", + "qubits" + ], + "additionalProperties": false, + "properties": { + "gate": { + "type": "string", + "pattern": "^[a-z0-9_]{1,40}$" + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + }, + "error": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "The average gate infidelity." + }, + "duration_ns": { + "type": "number", + "minimum": 0, + "description": "Nanoseconds." + } + } + } + }, + "coupling": { + "type": "array", + "description": "The pairs a two-qubit gate may act on, each once, the lower qubit first, sorted.", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + ] + }, + "fabric": { + "description": "Where the statevector method's state runs: auto (the default: on a member only where the committed measurements show it faster than this host's CPU for the job's size and fusion width, otherwise on the CPU), cpu, accelerator (the first accelerator member certified bit-exact here that holds the state, falling back to the next if it fails during the run), a member's id or key (wai-quantum fabric lists them), or a list of members, a power of two of them, the state split by its top qubits into one partition on each (cpu is a member, and a member may be named more than once). A member certified bit-exact gives the CPU's bits. A placement this host cannot honour is refused (J013), never made elsewhere.", + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "array", + "minItems": 2, + "maxItems": 64, + "items": { + "type": "string", + "minLength": 1 + } + } + ] + }, + "repair": { + "description": "Repair the program first on its flagged lines: true, or the choices.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "max_iterations": { + "type": "integer", + "minimum": 1 + }, + "dyadic_bits": { + "type": "integer", + "minimum": 1, + "maximum": 32 + }, + "sizes": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + } + } + } + ] + }, + "history": { + "type": "object", + "description": "The program's history's account of the version the job runs: its digest, and the gates and lines in each hand. The receipt binds it; a history recomputes and checks it." + }, + "provider": { + "type": "string", + "description": "The person's own provider to run on, by the name their registry gives it. Only a host that holds their credentials runs such a job; every other host refuses it." + }, + "programs": { + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "type": "string", + "description": "A program's text." + }, + { + "type": "object", + "required": [ + "qasm" + ], + "description": "A job of its own, read as a job request is (no programs or sweep in it); each item of the set's result holds its request in full." + } + ] + }, + "description": "A set (engine::sets): the programs to run as one job, each a program's text or a job of its own; the request's other fields apply to every item that does not set them itself." + }, + "sweep": { + "type": "object", + "additionalProperties": { + "type": "array", + "minItems": 1, + "items": { + "type": "number" + } + }, + "description": "A set over the request's own qasm: values for each of the program's inputs (integer, float or angle), every combination run, the names in sorted order and the first varying slowest." + }, + "params": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "A value for each of the program's parameters (`input float theta;`, `input angle phi;`), bound exactly before the program is read: it runs as if each were written as a `const` at that double. A parameter left without a value is refused (Q114, J050). In a sweep, the parameters it fixes, each bound at every point." + }, + "dry_run": { + "type": "boolean", + "description": "With true: what the host would do with the job or set, running nothing." + }, + "mitigate": { + "description": "Mitigate the job's expectation values (or, for readout, its counts) under its noise (engine::mitigate): zne, pea, pec, cdr, vd or readout, or {\"method\", …} with its options. The result's mitigation gives each value raw and mitigated.", + "anyOf": [ + { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + { + "type": "object", + "required": [ + "method" + ] + } + ] + }, + "pulse": { + "type": "object", + "description": "A pulse run's options (method \"pulse\"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0.", + "additionalProperties": false, + "properties": { + "dt_ns": { + "type": "number", + "exclusiveMinimum": 0, + "maximum": 1000, + "description": "The sample period, ns (default 0.5)." + }, + "levels": { + "type": "integer", + "enum": [ + 2, + 3 + ], + "description": "Levels kept per qubit (default 2; 3 shows leakage)." + }, + "tolerance": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1, + "description": "The most the stated error may be (default 1e-6): a run whose bound and rounding estimate pass it is refused, naming the steps that would meet it." + }, + "substeps": { + "type": "integer", + "minimum": 1, + "maximum": 4096, + "description": "Steps per sample (default: chosen so each step times the generator's norm is at most 0.5)." + }, + "qubits": { + "type": "object", + "description": "Each qubit's parameters by its index, over the target's and the defaults.", + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "frequency_ghz": { + "type": "number", + "description": "Its frequency, GHz." + }, + "rabi_mhz": { + "type": "number", + "description": "Its Rabi frequency at full amplitude, MHz." + }, + "anharmonicity_mhz": { + "type": "number", + "description": "Its anharmonicity, MHz." + }, + "t1_us": { + "type": "number", + "description": "Its relaxation time, µs." + }, + "t2_us": { + "type": "number", + "description": "Its coherence time, µs (at most 2·T1)." + } + } + } + }, + "couplings": { + "type": "array", + "description": "Static ZZ couplings.", + "items": { + "type": "object", + "required": [ + "qubits", + "zz_khz" + ], + "additionalProperties": false, + "properties": { + "qubits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + }, + "minItems": 2, + "maxItems": 2 + }, + "zz_khz": { + "type": "number", + "description": "The coupling's rate, kHz." + } + } + } + }, + "ports": { + "type": "object", + "description": "Ports by name: what each is for and the qubit it reaches.", + "additionalProperties": { + "type": "object", + "required": [ + "kind", + "qubit" + ], + "additionalProperties": false, + "properties": { + "kind": { + "enum": [ + "drive", + "measure", + "acquire" + ] + }, + "qubit": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, held by a live reading while it runs: at the ceiling the run is stopped, gives no answer, and its receipt says so. A route nothing here can read and stop does not meet it, so on a host that reads none every route is rejected. An estimate can refuse a job clearly past it, and promises nothing.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } + } + } + }, + "result": { + "anyOf": [ + { + "title": "wai.quantum.job-result/1", + "description": "A job's result as the engine gives it, on every host: what was asked of the program, computed by the method its plan chose, with that method's accuracy class. The receipt seals the result without its receipt member, beside the request. A result names the engine that made it and this schema (engine and schema); results made before results carried them have neither and follow this schema all the same.", + "type": "object", + "required": [ + "method", + "qubits", + "gates", + "accuracy" + ], + "properties": { + "engine": { + "type": "object", + "description": "The engine that made the result: the wai-quantum crate's name and version.", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "const": "wai-quantum" + }, + "version": { + "type": "string", + "description": "Its semantic version, as MAJOR.MINOR.PATCH." + } + } + }, + "schema": { + "const": "wai.quantum.job-result/1", + "description": "The schema the result follows." + }, + "components": { + "type": "array", + "description": "The identity of every component that made the result, when a registered one took part (engine::registry): its program's format, the passes its compile ran, the noise channels it names, its method; each registered one marked so. Sealed by the receipt with the rest.", + "items": { + "type": "object", + "description": "One component that made the result (engine::registry): its kind, name and version, the BLAKE3 digest of its descriptor, and whether it is built in. A result carries these only when a registered component took part; one made by built-ins alone names them as it always has (its method, its compile's passes, its noise's channels and the engine's version), the digests of that version listed by the components list.", + "required": [ + "kind", + "name", + "version", + "digest", + "origin" + ], + "properties": { + "kind": { + "enum": [ + "method", + "pass", + "channel", + "front_end" + ] + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "digest": { + "type": "string", + "pattern": "^[0-9a-f]{64}$", + "description": "BLAKE3 of the component's descriptor in its canonical JSON (engine::registry::digest_of)." + }, + "origin": { + "enum": [ + "built-in", + "registered" + ], + "description": "built-in: the engine's own; registered: a host's own, added in its process, not part of the engine." + }, + "certified": { + "const": false, + "description": "Beside a registered component: the engine does not certify it." + } + } + } + }, + "method": { + "type": "string", + "description": "The method that ran the job (provider for a run on the person's own provider)." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": "integer", + "minimum": 0, + "description": "The program's gates, in standard gates (at most 2^53 - 1), however the method ran them." + }, + "operations": { + "type": "integer", + "minimum": 0, + "description": "When the method held a gate under many controls as one (statevector, and exact asked for it): the operations it ran." + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "none" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance. none: the run was stopped at its contract's energy ceiling and gave no answer." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "state_hash": { + "type": "string", + "description": "The bit-exact method's statevector hash (BLAKE3, hex): the same on every machine." + }, + "counts": { + "type": "object", + "description": "Outcomes and their counts, keyed by the program's classical bits, the highest bit first. At most 65536 outcomes are listed; omitted_shots holds the rest.", + "additionalProperties": { + "type": "integer", + "minimum": 0 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "outcome_dimension": { + "type": "integer", + "minimum": 0, + "description": "The stabilizer method: the dimension of the measured outcomes' affine space." + }, + "shots": { + "type": "integer", + "minimum": 0, + "description": "The shots, where the method names them in the result (trajectories, provider)." + }, + "expectations": { + "type": "array", + "items": { + "type": "object", + "required": [ + "observable", + "coeff", + "value" + ], + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "value": { + "type": "number", + "description": "The coefficient times the expectation value." + }, + "stderr": { + "type": "number", + "description": "The standard error, for an estimate." + }, + "bound": { + "type": "number", + "description": "A bound on |exact − value|: rigorous for the bounded class; with confidence beside it, holding with that probability." + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + }, + "max_terms": { + "type": "integer" + }, + "ladder": { + "type": "array", + "description": "The value at thresholds a decade apart, the asked one last.", + "items": { + "type": "object", + "required": [ + "threshold", + "value", + "bound" + ], + "properties": { + "threshold": { + "type": "number" + }, + "value": { + "type": "number" + }, + "bound": { + "type": "number" + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + } + } + } + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds, for a bound that holds with a stated probability (stabilizer_rank's sampled mode)." + } + } + } + }, + "amplitudes": { + "type": "array", + "items": { + "type": "object", + "required": [ + "bits", + "re", + "im" + ], + "properties": { + "bits": { + "type": "string", + "description": "One 0 or 1 per qubit, qubit n-1 first." + }, + "re": { + "type": "number" + }, + "im": { + "type": "number" + }, + "bound": { + "type": "number", + "minimum": 0, + "description": "A bound on |exact − value| of the amplitude, holding with the probability confidence states (stabilizer_rank's sampled mode)." + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds." + } + } + } + }, + "global_phase": { + "type": "string", + "description": "Why the amplitudes' global phase is not fixed, when it is not." + }, + "warning": { + "type": "string" + }, + "contraction_flops": { + "type": "number", + "description": "The tensor network's contraction cost." + }, + "dynamic": { + "type": "object", + "description": "A program that measures in the middle, resets or branches on a measured bit: how it ran.", + "properties": { + "measurements_and_resets": { + "type": "integer", + "minimum": 0 + }, + "branches_run": { + "type": "integer", + "minimum": 0 + }, + "states_at_once": { + "type": "integer", + "minimum": 0 + }, + "branches_weighed": { + "type": "integer", + "minimum": 0 + } + } + }, + "outputs": { + "type": "array", + "description": "The program's output declarations: each its name and type, and its value, or the places of its bits in each outcome.", + "items": { + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "bits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + } + }, + "value": { + "description": "A number, a boolean, a bit string, a duration's text, {\"re\", \"im\"}, or an array of them." + } + } + } + }, + "timing": { + "type": "object", + "description": "A program that states durations (delay, box, stretch) the method does not apply: said so, with the reader's code.", + "required": [ + "applied", + "why" + ], + "properties": { + "applied": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "diagnostics": { + "type": "array", + "description": "The reader's warnings and notes on the program, each with its code.", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "compiled": { + "description": "How the program was compiled before it ran: on the person's own provider, to the device's gates; or, asked with compile, to a basis within a budget. Either way, basis is the gate set it was compiled to.", + "anyOf": [ + { + "type": "object", + "description": "A provider job: the program sent, compiled exactly to the device's own gates: its basis (the device's gate set), its OpenQASM 3 text (qasm3) and that text's BLAKE3 (program), its counts of gates and swaps, its layouts, and the check it passed before it was sent. Results sealed before qasm3 carry the hash alone.", + "required": [ + "basis", + "program" + ], + "properties": { + "basis": { + "type": "string" + }, + "program": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "qasm3": { + "type": "string", + "description": "The program sent, as OpenQASM 3, $i being index i of the coupling map the provider described; program is the BLAKE3 of its UTF-8 bytes." + }, + "qubit_names": { + "type": "object", + "additionalProperties": { + "type": "string", + "minLength": 1 + }, + "description": "The device's own name for each index the program uses, as it was when the job was sent, where a client sends it under those names." + }, + "native_gates": { + "type": "integer" + }, + "two_qubit_gates": { + "type": "integer" + }, + "swaps": { + "type": "integer" + }, + "layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "final_layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "checked": { + "type": "string" + }, + "placement": { + "type": "object", + "description": "Where the program was placed on the device's qubits, and why." + } + } + }, + { + "type": "object", + "description": "A job asked to compile its program first: what ran is the compiled circuit, within distance of the program in the operator norm up to a global phase.", + "required": [ + "basis", + "verdict" + ], + "properties": { + "basis": { + "enum": [ + "clifford_t", + "standard" + ], + "description": "The gate set the program was compiled to." + }, + "level": { + "type": "integer", + "minimum": 0 + }, + "epsilon": { + "type": "number", + "description": "The budget asked for." + }, + "distance": { + "type": [ + "number", + "null" + ], + "description": "The bound the passes' distances add to." + }, + "verdict": { + "type": "string" + }, + "source": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "output": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ], + "description": "The BLAKE3 of the compile certificate's RFC 8785 text, in hex." + }, + "note": { + "type": "string" + } + } + } + ] + }, + "verdict": { + "title": "wai.quantum.verdict/1", + "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", + "type": "object", + "required": [ + "schema", + "level", + "rank", + "holds", + "statement", + "parsed", + "executed", + "intent", + "critique", + "repairs" + ], + "properties": { + "schema": { + "const": "wai.quantum.verdict/1" + }, + "level": { + "enum": [ + "refused", + "parsed", + "executed", + "evidence", + "proof" + ] + }, + "rank": { + "type": "integer", + "minimum": 0, + "maximum": 4, + "description": "The level's place on the ladder, from 0 (refused) to 4 (proof)." + }, + "holds": { + "type": [ + "boolean", + "null" + ] + }, + "statement": { + "type": "string", + "description": "The level in one plain line." + }, + "parsed": { + "type": "object", + "description": "Whether the reader took the program, and its warnings and notes with their codes, or its refusal.", + "required": [ + "ok" + ], + "properties": { + "ok": { + "type": "boolean" + }, + "diagnostics": { + "type": "array", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + }, + "text": { + "type": "string", + "description": "The refusal as the reader wrote it, with its line and code." + } + } + }, + "executed": { + "type": [ + "object", + "null" + ], + "description": "The method that ran and its accuracy class, and the distance a compile put between the program and what ran.", + "properties": { + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "compiled_distance": { + "type": [ + "number", + "null" + ] + } + } + }, + "intent": { + "type": "array", + "items": { + "type": "object", + "description": "One intent's check: what it asked, whether it held, how strong the check was and how it was made.", + "required": [ + "kind", + "outcome", + "strength", + "how" + ], + "properties": { + "kind": { + "enum": [ + "distribution", + "equivalent", + "prepares", + "sampled", + "compiled" + ] + }, + "outcome": { + "enum": [ + "holds", + "fails", + "unchecked" + ] + }, + "strength": { + "enum": [ + "proof", + "evidence", + "none" + ] + }, + "how": { + "type": "string" + }, + "why": { + "type": "string" + }, + "distance": { + "type": "number" + }, + "tolerance": { + "type": "number" + }, + "outcomes": { + "type": "integer", + "description": "The outcomes the distribution holds, or the samples' distinct outcomes." + }, + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The program's distribution, when its outcomes are few enough to list." + }, + "largest_gaps": { + "type": "array", + "items": { + "type": "object", + "properties": { + "outcome": { + "type": "string" + }, + "program": { + "type": "number" + }, + "intent": { + "type": "number" + } + } + } + }, + "global_phase": { + "type": [ + "number", + "null" + ] + }, + "method": { + "type": "string", + "description": "A sampled intent: the method the samples were run by." + }, + "seed": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "alpha": { + "type": "number" + }, + "fit": { + "type": "object", + "description": "A sampled intent: the test, its statistic, degrees of freedom and p-value, the level, and whether it rejected.", + "properties": { + "test": { + "type": "string" + }, + "statistic": { + "type": "number" + }, + "dof": { + "type": "integer" + }, + "p_value": { + "type": "number" + }, + "alpha": { + "type": "number" + }, + "shots": { + "type": "integer" + }, + "rejected": { + "type": "boolean" + }, + "smallest_expected": { + "type": [ + "number", + "null" + ] + }, + "impossible": { + "type": [ + "integer", + "array", + "boolean" + ] + }, + "note": { + "type": "string" + } + } + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "name": { + "type": "string" + }, + "note": { + "type": "string" + } + } + } + }, + "critique": { + "type": "array", + "description": "The program's smells, each with its lines.", + "items": { + "type": "object" + } + }, + "repairs": { + "type": "array", + "description": "Each edit a repair made, with the code it answered and the lines it changed.", + "items": { + "type": "object" + } + }, + "refusal": { + "type": "object", + "description": "For a refused job: its message and its codes.", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + }, + "sealed": { + "type": "boolean" + } + } + }, + "target": { + "type": "object", + "description": "A run on a device target: which target (its hash, as its receipt binds it), its calibration snapshot, where the program was placed and why, and the noise derived from the target.", + "required": [ + "name", + "hash" + ], + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "hash_is": { + "type": "string" + }, + "calibration": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "source": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "note": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "description": "The native gate set, the layout and routes chosen, the swaps, the expected success beside the fewest-swaps layout's, and the check of the compiled program." + }, + "noise": { + "type": "object", + "description": "The noise model derived from the target's calibration: its channels, durations and idling, and each qubit's readout." + } + } + }, + "fabric": { + "type": "object", + "description": "Where the state vector, or the pauli method's sum of terms, ran: the kernel, the placement the job asked for, the member that ran it (or each partition's), each with its certificate, and the energy. Present when the job asked for a placement, or when auto placed the state on a member by measurement (`auto`); a job auto leaves on the CPU names nothing; the receipt seals it with the rest of the result. Every member placed is certified bit-exact, so the answers are the CPU's, byte for byte.", + "required": [ + "kernel", + "asked", + "parity", + "energy" + ], + "properties": { + "kernel": { + "type": "string" + }, + "asked": { + "description": "The placement the job asked for, as it gave it.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "partitions": { + "type": "array", + "description": "Each partition's member, by the value of the state's top qubits: partition i holds the amplitudes whose top bits read i.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "partition_qubits": { + "type": "integer", + "minimum": 0 + }, + "local_qubits": { + "type": "integer", + "minimum": 0 + }, + "segments": { + "type": "integer", + "minimum": 0, + "description": "Runs of gates the partitions took in turn, between exchanges." + }, + "exchanges": { + "type": "integer", + "minimum": 0, + "description": "Partition qubits exchanged with local ones through the host's copy of the state." + }, + "fell_back_from": { + "type": "array", + "description": "An accelerator request whose member failed during the run: each member that failed, in turn, with how; the member named above ran the job.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "auto": { + "type": "object", + "description": "Why auto placed the state where it ran: the rule (a member is placed only where the committed measurements show it faster than this host's CPU for the job's size and fusion width) and the measured row it rests on, with the host, the day and the load it was measured under. Present only when auto placed a state on a member.", + "required": [ + "rule", + "host", + "fusion", + "from_qubits", + "to_qubits" + ], + "properties": { + "rule": { + "type": "string" + }, + "host": { + "type": "string", + "description": "The host's processor as the measurements name it (cpu--)." + }, + "measured": { + "type": "string", + "description": "The day the host was measured (UTC)." + }, + "about": { + "type": "string" + }, + "load": { + "type": "string" + }, + "discovery_ms": { + "type": "number", + "description": "What discovering and certifying the host's members took, once per process, as measured." + }, + "fusion": { + "type": "integer", + "minimum": 1 + }, + "from_qubits": { + "type": "integer", + "minimum": 0 + }, + "to_qubits": { + "type": "integer", + "minimum": 0 + }, + "min_launches": { + "type": "integer", + "minimum": 0 + }, + "basis": { + "type": "object", + "description": "The measured row the job is judged by: the largest measured size at or below its own, the launches of its plan, the runs of each, and the spread of the CPU's and the member's times in milliseconds.", + "required": [ + "qubits", + "launches", + "runs", + "cpu_ms", + "member_ms" + ], + "properties": { + "qubits": { + "type": "integer", + "minimum": 0 + }, + "launches": { + "type": "integer", + "minimum": 0 + }, + "runs": { + "type": "integer", + "minimum": 0 + }, + "cpu_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + }, + "member_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + } + } + } + } + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "why": { + "type": "string" + } + } + }, + "repaired": { + "type": "object", + "description": "A job asked to repair its program first: the program that ran, each repair, and what needs a person.", + "properties": { + "qasm": { + "type": "string" + }, + "repairs": { + "type": "array", + "items": { + "type": "object", + "required": [ + "code", + "by", + "edits" + ], + "properties": { + "code": { + "type": "string" + }, + "rule": { + "type": "string" + }, + "by": { + "enum": [ + "engine", + "proposal" + ] + }, + "flagged": { + "type": "array", + "items": { + "type": "integer" + } + }, + "edits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "line": { + "type": "integer" + }, + "before": { + "type": [ + "string", + "null" + ] + }, + "after": { + "type": [ + "string", + "null" + ] + } + } + } + } + } + } + }, + "needs_person": { + "type": "array", + "items": { + "type": "object" + } + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0, + "description": "Wall time of the run, where the host has a clock (not in a browser tab)." + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "receipt": { + "anyOf": [ + { + "title": "wai.quantum.receipt/2", + "description": "A result's receipt: an Ed25519 signature, by the key it names, over digest = BLAKE3(\"wai:quantum-service-receipt\\x02\" ‖ len ‖ request ‖ len ‖ result), each of request and result in its RFC 8785 canonical text (the result without its receipt member), each length 8 bytes big-endian. Whatever members the request and the result hold are sealed, the result's engine and schema among them. The first receipts (no canon member, $defs/first) sealed their writer's compact text under the domain ending \\x01; they still verify. wai/extensions/quantum-providers.md section 8.2 states the seal in full, and section 8.4 what a verifier checks.", + "type": "object", + "required": [ + "alg", + "canon", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "canon": { + "const": "rfc8785", + "description": "The canonical form the digest is taken over." + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The signing key, 32 bytes in lower-case hex." + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The digest signed, 32 bytes in lower-case hex." + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$", + "description": "The signature, 64 bytes in lower-case hex." + } + } + }, + { + "description": "The first form, before canon: the digest is over the compact text its writer wrote of each, members in the document's order (section 8.2 of wai/extensions/quantum-providers.md), under the domain ending \\x01. Never written now; still verified.", + "type": "object", + "required": [ + "alg", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$" + } + } + } + ] + }, + "provider": { + "type": "object", + "description": "A provider job: the provider's name, kind and protocol, the device, its provenance, and the hash of its description." + }, + "counts_source": { + "enum": [ + "shots", + "vendor_counts", + "probabilities" + ], + "description": "A provider job: where its counts come from (wai/extensions/quantum-providers.md section 8.3): tallied from one record a shot (shots), the provider's own counts (vendor_counts), or rebuilt from the probabilities it returned by largest remainders, derived and not shot records (probabilities). Results sealed before it carry neither it nor execution." + }, + "execution": { + "type": "object", + "description": "A provider job: how the device was asked to run the program (section 8.3): who states it (stated_by: client, provider or nobody); what the client sent (sent: the request's members and the settings among them); each of mitigation, twirling, decoupling, remapping and optimisation (off, on, default when the request sets nothing for it, none when the device has no such step, unknown when nobody states it); whether the gates were to run as written (verbatim); and a note.", + "required": [ + "stated_by", + "mitigation", + "twirling", + "decoupling", + "remapping", + "optimisation", + "verbatim" + ], + "properties": { + "stated_by": { + "enum": [ + "client", + "provider", + "nobody" + ] + }, + "sent": { + "type": "object", + "required": [ + "fields", + "settings" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "settings": { + "type": "object" + } + }, + "additionalProperties": false + }, + "mitigation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "twirling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "decoupling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "remapping": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "optimisation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "verbatim": { + "type": [ + "boolean", + "null" + ] + }, + "note": { + "type": "string" + } + }, + "additionalProperties": false + }, + "calibration": { + "type": [ + "string", + "null" + ], + "description": "A provider job: the calibration snapshot it ran under." + }, + "job": { + "type": "object", + "description": "A provider job: the provider's job id and its status checks." + }, + "ideal": { + "description": "A provider job: the circuit's exact distribution set beside the measured counts.", + "anyOf": [ + { + "type": "object", + "required": [ + "computed", + "total_variation_distance", + "hellinger_fidelity" + ], + "properties": { + "computed": { + "const": true + }, + "method": { + "type": "string" + }, + "total_variation_distance": { + "type": "number" + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number" + }, + "ideal_outcomes": { + "type": "integer" + }, + "note": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "computed", + "why" + ], + "properties": { + "computed": { + "const": false + }, + "why": { + "type": "string" + } + } + } + ] + }, + "cost": { + "type": "object", + "description": "A provider job: the estimate shown before it was sent, what the provider says it charged, and whether the person confirmed a run that was not free." + }, + "provenance": { + "title": "wai.quantum.provenance/1", + "description": "What a result came from, under the five categories cross-platform provenance surveys use: the circuit, the computer, the compilation, the execution and the software. A host adds it to the results it seals (the job service does, and each item of a set); a result without it reads as it always did. wai-quantum-service/docs/provenance.md maps every field to where it is and whether the receipt seals it.", + "type": "object", + "required": [ + "schema", + "circuit", + "computer", + "compilation", + "execution", + "software" + ], + "properties": { + "schema": { + "const": "wai.quantum.provenance/1" + }, + "circuit": { + "type": "object", + "description": "The program: the BLAKE3 digest of its text as given, its qubits and its gates.", + "required": [ + "program" + ], + "properties": { + "program": { + "type": "string", + "description": "BLAKE3 of the program's text, in hex." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": [ + "integer", + "null" + ] + } + } + }, + "computer": { + "type": "object", + "description": "What ran it: a classical simulator, the method and its accuracy class, a device target's hash when the job named one, and the fabric's members when the result names where its state ran.", + "required": [ + "kind", + "method" + ], + "properties": { + "kind": { + "const": "simulator" + }, + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "target": { + "type": "string", + "description": "The device target's hash; its layout, routes and noise are in the result's own target." + }, + "fabric": { + "type": "object", + "description": "The kernel and the member that ran the state, or each partition's, as the result's fabric names them.", + "properties": { + "kernel": { + "type": "string" + }, + "members": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "compilation": { + "type": "object", + "description": "Whether the job asked to be compiled; if it did, each pass in order with its check's verdict, the certificate's digest, the gate set compiled to (its basis), the level, the ε budget and the distance the result carries, and that no pass draws a random number.", + "required": [ + "asked" + ], + "properties": { + "asked": { + "type": "boolean" + }, + "passes": { + "type": [ + "array", + "null" + ], + "items": { + "type": "object", + "properties": { + "pass": { + "type": "string" + }, + "verdict": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ] + }, + "basis": { + "type": [ + "string", + "null" + ], + "description": "The gate set compiled to: clifford_t or standard." + }, + "level": { + "type": [ + "integer", + "null" + ] + }, + "epsilon": { + "type": [ + "number", + "null" + ] + }, + "distance": { + "type": [ + "number", + "null" + ] + }, + "seeded": { + "const": false + }, + "device": { + "type": "string", + "description": "A job on a device target, compiled exactly to its gates: where its layout and routes are." + }, + "status": { + "const": "not-applicable" + }, + "why": { + "type": "string" + } + } + }, + "execution": { + "type": "object", + "description": "The shots, the seed and the plan the job ran under; its identifier and times are the host's, outside the result.", + "required": [ + "plan" + ], + "properties": { + "shots": { + "type": [ + "integer", + "null" + ] + }, + "seed": { + "type": [ + "integer", + "null" + ] + }, + "plan": { + "type": "object", + "properties": { + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0 + } + } + } + } + }, + "software": { + "type": "object", + "description": "The engine's name and version, and the host's.", + "required": [ + "engine", + "host" + ], + "properties": { + "engine": { + "type": "string" + }, + "host": { + "type": "string" + } + } + } + } + }, + "mitigation": { + "title": "wai.quantum.mitigation/1", + "description": "A job's mitigation (its request's mitigate, engine::mitigate), in its result: the method and the options it ran with, its bias and variance assumptions, each observable raw and mitigated with a standard error each and the ideal value (or, for readout, the counts inverted as a quasi-distribution), the method's own details and what it spent. docs/qec.md describes each method.", + "type": "object", + "required": [ + "method", + "options", + "assumptions" + ], + "properties": { + "method": { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + "options": { + "type": "object", + "description": "The options it ran with, the defaults filled in.", + "properties": { + "method": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "factors": { + "type": "array", + "items": { + "type": "number" + } + }, + "extrapolation": { + "enum": [ + "richardson", + "linear", + "exponential" + ] + }, + "samples": { + "type": "integer" + }, + "training": { + "type": "integer" + }, + "keep": { + "type": "integer" + }, + "learn_shots": { + "type": "integer" + } + } + }, + "assumptions": { + "type": "object", + "properties": { + "bias": { + "type": "string" + }, + "variance": { + "type": "string" + } + } + }, + "noise": { + "type": "string", + "description": "How the job's noise model is read for the method." + }, + "note": { + "type": "string" + }, + "observables": { + "type": "array", + "items": { + "type": "object", + "description": "One observable: its raw value and the mitigated one, each with its standard error, and the ideal value a simulation knows.", + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "raw": { + "type": "number" + }, + "raw_stderr": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + }, + "ideal": { + "type": "number" + } + } + } + }, + "distribution": { + "type": "array", + "description": "readout: each outcome's raw share and its mitigated quasi-probability, with its standard error.", + "items": { + "type": "object", + "properties": { + "bits": { + "type": "string" + }, + "raw": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + } + } + } + }, + "details": { + "type": "object", + "description": "The method's own: the folded scales and the folding check (zne), the learned model and the amplified values (pea), the quasi-probability and the value it converges to (pec), the training fits (cdr), the purity (vd), the flip and its amplification (readout).", + "additionalProperties": true + }, + "cost": { + "type": "object", + "description": "The circuits and shots it spent beyond the job's own.", + "properties": { + "circuits": { + "type": "integer", + "minimum": 0 + }, + "shots": { + "type": "integer", + "minimum": 0 + }, + "note": { + "type": "string" + } + } + } + } + }, + "pulse": { + "type": "object", + "description": "A pulse run (method pulse, engine::pulse): what was read and its distribution, the final populations, each capture's reading, the final density matrix's digest, the schedule's length, the integrator and its step, the device and where each parameter came from, and what the receipt binds (calibration).", + "required": [ + "read", + "outcome_bits", + "populations", + "simulated_qubits", + "density_hash", + "integrator", + "device", + "calibration" + ], + "properties": { + "read": { + "type": "string", + "description": "What the distribution reads: the captures together (into the program's bits when each writes one), or the final state." + }, + "outcome_bits": { + "type": "array", + "items": { + "type": "string" + }, + "description": "What each character of an outcome is, left to right: a program bit (c[0]) or a qubit ($0)." + }, + "distribution": { + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "number" + }, + "description": "The probability of each outcome, which the counts sample; null when the captures start at different samples." + }, + "populations": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The final state read on every simulated qubit, the highest qubit first, a level above 0 read as 1." + }, + "simulated_qubits": { + "type": "array", + "items": { + "type": "integer" + } + }, + "captures": { + "type": "array", + "items": { + "type": "object", + "properties": { + "frame": { + "type": "string" + }, + "qubit": { + "type": "integer" + }, + "start": { + "type": "integer" + }, + "start_ns": { + "type": "number" + }, + "bit": { + "type": [ + "string", + "null" + ] + }, + "p1": { + "type": "number" + }, + "p2": { + "type": "number" + } + } + } + }, + "leakage": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "p2": { + "type": "number" + } + } + }, + "description": "With three levels: each qubit's final probability of level 2." + }, + "trace": { + "type": "number" + }, + "density_hash": { + "type": "string", + "description": "The BLAKE3 of the final density matrix's bits: the same on every platform." + }, + "duration": { + "type": "integer" + }, + "duration_ns": { + "type": "number" + }, + "integrator": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "order": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "substeps": { + "type": "integer" + }, + "step_ns": { + "type": "number" + }, + "steps": { + "type": "integer" + }, + "norm_max": { + "type": "number" + }, + "frame": { + "type": "string" + } + } + }, + "device": { + "type": "object", + "properties": { + "levels": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "qubits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "frequency_hz": { + "type": "number" + }, + "rabi_hz": { + "type": "number" + }, + "anharmonicity_hz": { + "type": "number" + }, + "t1_ns": { + "type": "number" + }, + "t2_ns": { + "type": "number" + }, + "from": { + "type": "object", + "additionalProperties": { + "enum": [ + "pulse", + "target", + "default", + "none" + ] + } + } + } + } + }, + "couplings": { + "type": "array" + }, + "model": { + "type": "string" + } + } + }, + "calibration": { + "type": "object", + "description": "What the receipt binds: the program's, its calibrations', the schedule's and the device's digests, and the target snapshot.", + "properties": { + "program": { + "type": "string" + }, + "calibrations": { + "type": "string" + }, + "schedule": { + "type": "string" + }, + "device": { + "type": "string" + }, + "target": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "calibration": { + "type": "object" + } + } + } + } + }, + "not_modelled": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unwatched" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "stopped": { + "type": "object", + "description": "A run stopped at its contract's max_joules by a live reading: it gave no answer, and accuracy.class is none (wai/extensions/quantum-providers.md section 8.7).", + "required": [ + "at", + "joules", + "max_joules", + "elapsed_ms", + "read" + ], + "properties": { + "at": { + "const": "max_joules" + }, + "joules": { + "type": "number", + "description": "What the reading had come to, at or past the ceiling." + }, + "max_joules": { + "type": "number" + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "read": { + "type": "string", + "description": "What read the run, and what that covers." + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "none" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance. none: the run was stopped at its contract's energy ceiling and gave no answer." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + }, + { + "title": "wai.quantum.set/1", + "description": "A set's result: many programs, or one program over a grid of its inputs, run as one job (engine::sets). Its head holds the count, how many items finished and failed, the Merkle root over the items' leaves, the set's energy and time; the set's receipt seals the set's request and its head. Each item is a plain job with its own receipt, its index, its point in a sweep, and its path to the root, so it is shown sealed by the set alone. A result names the engine that made it and this schema (engine and schema).", + "type": "object", + "required": [ + "format", + "count", + "done", + "failed", + "root", + "items" + ], + "properties": { + "engine": { + "type": "object", + "description": "The engine that made the result: the wai-quantum crate's name and version.", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "const": "wai-quantum" + }, + "version": { + "type": "string" + } + } + }, + "schema": { + "const": "wai.quantum.set/1" + }, + "format": { + "const": "wai.quantum.set/1" + }, + "count": { + "type": "integer", + "minimum": 1 + }, + "done": { + "type": "integer", + "minimum": 0 + }, + "failed": { + "type": "integer", + "minimum": 0 + }, + "root": { + "type": "string", + "description": "The Merkle root of the items' leaves, in hex (domains moq-jwp:merkle-leaf and moq-jwp:merkle-node, version 1)." + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "receipt": { + "title": "wai.quantum.receipt/2", + "description": "A result's receipt: an Ed25519 signature, by the key it names, over digest = BLAKE3(\"wai:quantum-service-receipt\\x02\" ‖ len ‖ request ‖ len ‖ result), each of request and result in its RFC 8785 canonical text (the result without its receipt member), each length 8 bytes big-endian. Whatever members the request and the result hold are sealed, the result's engine and schema among them. The first receipts (no canon member, $defs/first) sealed their writer's compact text under the domain ending \\x01; they still verify. wai/extensions/quantum-providers.md section 8.2 states the seal in full, and section 8.4 what a verifier checks.", + "type": "object", + "required": [ + "alg", + "canon", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "canon": { + "const": "rfc8785", + "description": "The canonical form the digest is taken over." + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The signing key, 32 bytes in lower-case hex." + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The digest signed, 32 bytes in lower-case hex." + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$", + "description": "The signature, 64 bytes in lower-case hex." + } + } + }, + "items": { + "type": "array", + "items": { + "type": "object", + "description": "One item: its index, its point in a sweep, its request (a plain job, complete in itself), and its result with its own receipt, or why it failed; and its path to the set's root.", + "required": [ + "index", + "request", + "status", + "path" + ], + "properties": { + "index": { + "type": "integer", + "minimum": 0 + }, + "point": { + "type": "object", + "description": "A sweep's item: the value of each input it was run at." + }, + "status": { + "enum": [ + "done", + "failed" + ] + }, + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "request": { + "title": "wai.quantum.job-request/1", + "description": "A job as a client submits it: a program and what is asked of it, or a set: many programs (programs), or one over a grid of its inputs (sweep), run as one job. The command line, both MCP servers, the job service, the desktop app and the Studio read it alike, and a receipt seals it as it was given. A member the engine does not read is ignored, and sealed with the rest.", + "type": "object", + "anyOf": [ + { + "required": [ + "qasm" + ] + }, + { + "required": [ + "programs" + ] + }, + { + "required": [ + "source" + ] + } + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, in OpenQASM 3 or the OpenQASM 2 forms in common use." + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "description": "The program in another format, in place of qasm (engine::formats::expand): read to the job's qasm before the job is read, the request keeping its source.", + "properties": { + "format": { + "enum": [ + "qasm", + "qir", + "jeff" + ] + }, + "program": { + "type": "string", + "description": "The program's text (OpenQASM, QIR)." + }, + "program_base64": { + "type": "string", + "description": "The program's bytes as base64 (jeff)." + } + } + }, + "shots": { + "type": "integer", + "minimum": 0, + "maximum": 1000000, + "description": "Measurement shots; 1024 when no observables or amplitudes are asked for, otherwise 0." + }, + "seed": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991, + "description": "The sampling seed (1 when not given): the same job and seed give the same counts." + }, + "method": { + "type": "string", + "description": "auto (the default: the strongest method the program admits), or a method by its name as the methods list names it; pulse runs a pulse program (OpenPulse calibrations) under the pulse options." + }, + "observables": { + "type": "array", + "maxItems": 256, + "description": "Pauli observables to take the expectation values of.", + "items": { + "anyOf": [ + { + "type": "string", + "description": "A Pauli string, as \"Z0 Z1\"; qubits count from 0." + }, + { + "type": "object", + "required": [ + "pauli" + ], + "properties": { + "pauli": { + "type": "string", + "description": "A Pauli string, as \"X3\"." + }, + "coeff": { + "type": "number", + "description": "Its coefficient (1 when not given)." + } + } + } + ] + } + }, + "amplitudes": { + "type": "array", + "maxItems": 64, + "description": "Basis states whose amplitudes to return: one 0 or 1 per qubit, qubit n-1 first.", + "items": { + "type": "string" + } + }, + "noise": { + "type": "object", + "description": "A noise model, each channel a probability. A channel not listed here is refused.", + "additionalProperties": false, + "properties": { + "depolarizing_1q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "depolarizing_2q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "amplitude_damping": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "dephasing": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "readout": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + } + }, + "options": { + "type": "object", + "description": "Options of the method that runs the job, as the methods list names them (max_bond, cutoff, fusion, trajectories, threshold, max_weight, ladder, max_terms, path_restarts, controls), and memory_gb.", + "additionalProperties": true, + "properties": { + "controls": { + "enum": [ + "whole", + "standard" + ], + "description": "A gate whose standard gates would double (x, y, z or h under three or more controls; s, sdg, t, tdg, p, rx, ry, rz, u, sx or sxdg under two or more) runs as one on statevector and in standard gates on exact. \"standard\" runs standard gates on statevector too, which reproduces a result made that way bit for bit. \"whole\" holds the gate whole on exact too, which gives other bits than its default, and is refused (J003) on a job that runs standard gates: another method named, a compile, noise, mitigation, a device target or a named place on the fabric. Any other value is refused." + } + } + }, + "compile": { + "type": "object", + "description": "What a compile is asked for, each optional: the most the output may differ from the program (epsilon, in the operator norm up to a global phase), the level (0 lowers and approximates; 1 also rewrites and folds phases; 2 also resynthesises), the basis, the gate set it writes the program in (clifford_t: every rotation off the multiples of π/4 a Clifford+T word; standard: nothing approximated), whether to give the circuit after each pass (stages), and the twirl and dd passes, last (twirl, with its seed; dd, with its sequence).", + "properties": { + "epsilon": { + "type": "number", + "exclusiveMinimum": 0 + }, + "level": { + "type": "integer", + "minimum": 0, + "maximum": 2 + }, + "basis": { + "enum": [ + "clifford_t", + "standard" + ] + }, + "stages": { + "type": "boolean" + }, + "twirl": { + "description": "Twirl each two-qubit Clifford gate with Paulis drawn from a seeded stream: true (seed 1), or {\"seed\": N}. One seed is one instance, checked to be the same circuit.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "required": [ + "seed" + ], + "properties": { + "seed": { + "type": "integer", + "minimum": 0 + } + } + } + ] + }, + "dd": { + "description": "Dynamical decoupling in each window where a qubit idles long enough: xx or xy4 (or {\"sequence\": …}), checked to change nothing without noise.", + "anyOf": [ + { + "enum": [ + "xx", + "xy4" + ] + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "sequence": { + "enum": [ + "xx", + "xy4" + ] + } + } + } + ] + } + } + }, + "intent": { + "description": "What the program must do, checked with the run: one intent or a list. The result's verdict says how far it was checked.", + "anyOf": [ + { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + } + ] + }, + "verdict": { + "type": "boolean", + "description": "true: the result carries a verdict even with no intent." + }, + "target": { + "description": "A device target: a built-in target's name, or a target document. The program is compiled to it, placed and simulated under its noise; noise may not be given beside it.", + "anyOf": [ + { + "type": "string" + }, + { + "title": "wai.quantum.target/1", + "description": "A device target: its qubits, the pairs it couples, its native gates with their errors and durations, and the calibration snapshot they come from. A value not known is left out, never written as zero. Every field but format, name, source, qubits, gates and coupling is optional, and a field the format does not name is refused, so a misspelt one never reads as absent. Its canonical text is its RFC 8785 form, and the BLAKE3 of that text, the target's hash, names the snapshot in a receipt.", + "type": "object", + "required": [ + "format", + "name", + "source", + "qubits", + "gates", + "coupling" + ], + "additionalProperties": false, + "properties": { + "format": { + "const": "wai.quantum.target/1" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "additionalProperties": false, + "properties": { + "format": { + "type": "string", + "description": "The format the target was read from (wai-quantum targets import --help lists them)." + }, + "note": { + "type": "string", + "maxLength": 400 + } + } + }, + "calibration": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "maxLength": 400, + "description": "The calibration snapshot's id, as the source names it, or a content id of the snapshot read." + }, + "timestamp": { + "type": "string", + "maxLength": 400, + "description": "When the snapshot was taken, as the source writes it." + } + } + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2048, + "description": "Every qubit, in order.", + "items": { + "type": "object", + "required": [ + "qubit" + ], + "additionalProperties": false, + "properties": { + "qubit": { + "type": "integer", + "minimum": 0, + "description": "Its index: its place in the list." + }, + "label": { + "type": "string", + "description": "The source's own name for it, when that is not its index." + }, + "t1_us": { + "type": "number", + "minimum": 0, + "description": "T1, microseconds." + }, + "t2_us": { + "type": "number", + "minimum": 0, + "description": "T2 (the echo or Ramsey time the source reports), microseconds." + }, + "frequency_ghz": { + "type": "number", + "minimum": 0, + "description": "Its frequency, gigahertz." + }, + "readout": { + "type": "object", + "required": [ + "p01", + "p10" + ], + "additionalProperties": false, + "properties": { + "p01": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 1 | holds 0)." + }, + "p10": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 0 | holds 1)." + } + } + }, + "measure_ns": { + "type": "number", + "minimum": 0, + "description": "The measurement's duration, nanoseconds." + } + } + } + }, + "gates": { + "type": "array", + "maxItems": 262144, + "description": "Each native gate where the device runs it, sorted by gate then qubits.", + "items": { + "type": "object", + "required": [ + "gate", + "qubits" + ], + "additionalProperties": false, + "properties": { + "gate": { + "type": "string", + "pattern": "^[a-z0-9_]{1,40}$" + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + }, + "error": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "The average gate infidelity." + }, + "duration_ns": { + "type": "number", + "minimum": 0, + "description": "Nanoseconds." + } + } + } + }, + "coupling": { + "type": "array", + "description": "The pairs a two-qubit gate may act on, each once, the lower qubit first, sorted.", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + ] + }, + "fabric": { + "description": "Where the statevector method's state runs: auto (the default: on a member only where the committed measurements show it faster than this host's CPU for the job's size and fusion width, otherwise on the CPU), cpu, accelerator (the first accelerator member certified bit-exact here that holds the state, falling back to the next if it fails during the run), a member's id or key (wai-quantum fabric lists them), or a list of members, a power of two of them, the state split by its top qubits into one partition on each (cpu is a member, and a member may be named more than once). A member certified bit-exact gives the CPU's bits. A placement this host cannot honour is refused (J013), never made elsewhere.", + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "array", + "minItems": 2, + "maxItems": 64, + "items": { + "type": "string", + "minLength": 1 + } + } + ] + }, + "repair": { + "description": "Repair the program first on its flagged lines: true, or the choices.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "max_iterations": { + "type": "integer", + "minimum": 1 + }, + "dyadic_bits": { + "type": "integer", + "minimum": 1, + "maximum": 32 + }, + "sizes": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + } + } + } + ] + }, + "history": { + "type": "object", + "description": "The program's history's account of the version the job runs: its digest, and the gates and lines in each hand. The receipt binds it; a history recomputes and checks it." + }, + "provider": { + "type": "string", + "description": "The person's own provider to run on, by the name their registry gives it. Only a host that holds their credentials runs such a job; every other host refuses it." + }, + "programs": { + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "type": "string", + "description": "A program's text." + }, + { + "type": "object", + "required": [ + "qasm" + ], + "description": "A job of its own, read as a job request is (no programs or sweep in it); each item of the set's result holds its request in full." + } + ] + }, + "description": "A set (engine::sets): the programs to run as one job, each a program's text or a job of its own; the request's other fields apply to every item that does not set them itself." + }, + "sweep": { + "type": "object", + "additionalProperties": { + "type": "array", + "minItems": 1, + "items": { + "type": "number" + } + }, + "description": "A set over the request's own qasm: values for each of the program's inputs (integer, float or angle), every combination run, the names in sorted order and the first varying slowest." + }, + "params": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "A value for each of the program's parameters (`input float theta;`, `input angle phi;`), bound exactly before the program is read: it runs as if each were written as a `const` at that double. A parameter left without a value is refused (Q114, J050). In a sweep, the parameters it fixes, each bound at every point." + }, + "dry_run": { + "type": "boolean", + "description": "With true: what the host would do with the job or set, running nothing." + }, + "mitigate": { + "description": "Mitigate the job's expectation values (or, for readout, its counts) under its noise (engine::mitigate): zne, pea, pec, cdr, vd or readout, or {\"method\", …} with its options. The result's mitigation gives each value raw and mitigated.", + "anyOf": [ + { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + { + "type": "object", + "required": [ + "method" + ] + } + ] + }, + "pulse": { + "type": "object", + "description": "A pulse run's options (method \"pulse\"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0.", + "additionalProperties": false, + "properties": { + "dt_ns": { + "type": "number", + "exclusiveMinimum": 0, + "maximum": 1000, + "description": "The sample period, ns (default 0.5)." + }, + "levels": { + "type": "integer", + "enum": [ + 2, + 3 + ], + "description": "Levels kept per qubit (default 2; 3 shows leakage)." + }, + "tolerance": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1, + "description": "The most the stated error may be (default 1e-6): a run whose bound and rounding estimate pass it is refused, naming the steps that would meet it." + }, + "substeps": { + "type": "integer", + "minimum": 1, + "maximum": 4096, + "description": "Steps per sample (default: chosen so each step times the generator's norm is at most 0.5)." + }, + "qubits": { + "type": "object", + "description": "Each qubit's parameters by its index, over the target's and the defaults.", + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "frequency_ghz": { + "type": "number", + "description": "Its frequency, GHz." + }, + "rabi_mhz": { + "type": "number", + "description": "Its Rabi frequency at full amplitude, MHz." + }, + "anharmonicity_mhz": { + "type": "number", + "description": "Its anharmonicity, MHz." + }, + "t1_us": { + "type": "number", + "description": "Its relaxation time, µs." + }, + "t2_us": { + "type": "number", + "description": "Its coherence time, µs (at most 2·T1)." + } + } + } + }, + "couplings": { + "type": "array", + "description": "Static ZZ couplings.", + "items": { + "type": "object", + "required": [ + "qubits", + "zz_khz" + ], + "additionalProperties": false, + "properties": { + "qubits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + }, + "minItems": 2, + "maxItems": 2 + }, + "zz_khz": { + "type": "number", + "description": "The coupling's rate, kHz." + } + } + } + }, + "ports": { + "type": "object", + "description": "Ports by name: what each is for and the qubit it reaches.", + "additionalProperties": { + "type": "object", + "required": [ + "kind", + "qubit" + ], + "additionalProperties": false, + "properties": { + "kind": { + "enum": [ + "drive", + "measure", + "acquire" + ] + }, + "qubit": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, held by a live reading while it runs: at the ceiling the run is stopped, gives no answer, and its receipt says so. A route nothing here can read and stop does not meet it, so on a host that reads none every route is rejected. An estimate can refuse a job clearly past it, and promises nothing.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } + } + } + }, + "result": { + "title": "wai.quantum.job-result/1", + "description": "A job's result as the engine gives it, on every host: what was asked of the program, computed by the method its plan chose, with that method's accuracy class. The receipt seals the result without its receipt member, beside the request. A result names the engine that made it and this schema (engine and schema); results made before results carried them have neither and follow this schema all the same.", + "type": "object", + "required": [ + "method", + "qubits", + "gates", + "accuracy" + ], + "properties": { + "engine": { + "type": "object", + "description": "The engine that made the result: the wai-quantum crate's name and version.", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "const": "wai-quantum" + }, + "version": { + "type": "string", + "description": "Its semantic version, as MAJOR.MINOR.PATCH." + } + } + }, + "schema": { + "const": "wai.quantum.job-result/1", + "description": "The schema the result follows." + }, + "components": { + "type": "array", + "description": "The identity of every component that made the result, when a registered one took part (engine::registry): its program's format, the passes its compile ran, the noise channels it names, its method; each registered one marked so. Sealed by the receipt with the rest.", + "items": { + "type": "object", + "description": "One component that made the result (engine::registry): its kind, name and version, the BLAKE3 digest of its descriptor, and whether it is built in. A result carries these only when a registered component took part; one made by built-ins alone names them as it always has (its method, its compile's passes, its noise's channels and the engine's version), the digests of that version listed by the components list.", + "required": [ + "kind", + "name", + "version", + "digest", + "origin" + ], + "properties": { + "kind": { + "enum": [ + "method", + "pass", + "channel", + "front_end" + ] + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "digest": { + "type": "string", + "pattern": "^[0-9a-f]{64}$", + "description": "BLAKE3 of the component's descriptor in its canonical JSON (engine::registry::digest_of)." + }, + "origin": { + "enum": [ + "built-in", + "registered" + ], + "description": "built-in: the engine's own; registered: a host's own, added in its process, not part of the engine." + }, + "certified": { + "const": false, + "description": "Beside a registered component: the engine does not certify it." + } + } + } + }, + "method": { + "type": "string", + "description": "The method that ran the job (provider for a run on the person's own provider)." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": "integer", + "minimum": 0, + "description": "The program's gates, in standard gates (at most 2^53 - 1), however the method ran them." + }, + "operations": { + "type": "integer", + "minimum": 0, + "description": "When the method held a gate under many controls as one (statevector, and exact asked for it): the operations it ran." + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "none" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance. none: the run was stopped at its contract's energy ceiling and gave no answer." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "state_hash": { + "type": "string", + "description": "The bit-exact method's statevector hash (BLAKE3, hex): the same on every machine." + }, + "counts": { + "type": "object", + "description": "Outcomes and their counts, keyed by the program's classical bits, the highest bit first. At most 65536 outcomes are listed; omitted_shots holds the rest.", + "additionalProperties": { + "type": "integer", + "minimum": 0 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "outcome_dimension": { + "type": "integer", + "minimum": 0, + "description": "The stabilizer method: the dimension of the measured outcomes' affine space." + }, + "shots": { + "type": "integer", + "minimum": 0, + "description": "The shots, where the method names them in the result (trajectories, provider)." + }, + "expectations": { + "type": "array", + "items": { + "type": "object", + "required": [ + "observable", + "coeff", + "value" + ], + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "value": { + "type": "number", + "description": "The coefficient times the expectation value." + }, + "stderr": { + "type": "number", + "description": "The standard error, for an estimate." + }, + "bound": { + "type": "number", + "description": "A bound on |exact − value|: rigorous for the bounded class; with confidence beside it, holding with that probability." + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + }, + "max_terms": { + "type": "integer" + }, + "ladder": { + "type": "array", + "description": "The value at thresholds a decade apart, the asked one last.", + "items": { + "type": "object", + "required": [ + "threshold", + "value", + "bound" + ], + "properties": { + "threshold": { + "type": "number" + }, + "value": { + "type": "number" + }, + "bound": { + "type": "number" + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + } + } + } + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds, for a bound that holds with a stated probability (stabilizer_rank's sampled mode)." + } + } + } + }, + "amplitudes": { + "type": "array", + "items": { + "type": "object", + "required": [ + "bits", + "re", + "im" + ], + "properties": { + "bits": { + "type": "string", + "description": "One 0 or 1 per qubit, qubit n-1 first." + }, + "re": { + "type": "number" + }, + "im": { + "type": "number" + }, + "bound": { + "type": "number", + "minimum": 0, + "description": "A bound on |exact − value| of the amplitude, holding with the probability confidence states (stabilizer_rank's sampled mode)." + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds." + } + } + } + }, + "global_phase": { + "type": "string", + "description": "Why the amplitudes' global phase is not fixed, when it is not." + }, + "warning": { + "type": "string" + }, + "contraction_flops": { + "type": "number", + "description": "The tensor network's contraction cost." + }, + "dynamic": { + "type": "object", + "description": "A program that measures in the middle, resets or branches on a measured bit: how it ran.", + "properties": { + "measurements_and_resets": { + "type": "integer", + "minimum": 0 + }, + "branches_run": { + "type": "integer", + "minimum": 0 + }, + "states_at_once": { + "type": "integer", + "minimum": 0 + }, + "branches_weighed": { + "type": "integer", + "minimum": 0 + } + } + }, + "outputs": { + "type": "array", + "description": "The program's output declarations: each its name and type, and its value, or the places of its bits in each outcome.", + "items": { + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "bits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + } + }, + "value": { + "description": "A number, a boolean, a bit string, a duration's text, {\"re\", \"im\"}, or an array of them." + } + } + } + }, + "timing": { + "type": "object", + "description": "A program that states durations (delay, box, stretch) the method does not apply: said so, with the reader's code.", + "required": [ + "applied", + "why" + ], + "properties": { + "applied": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "diagnostics": { + "type": "array", + "description": "The reader's warnings and notes on the program, each with its code.", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "compiled": { + "description": "How the program was compiled before it ran: on the person's own provider, to the device's gates; or, asked with compile, to a basis within a budget. Either way, basis is the gate set it was compiled to.", + "anyOf": [ + { + "type": "object", + "description": "A provider job: the program sent, compiled exactly to the device's own gates: its basis (the device's gate set), its OpenQASM 3 text (qasm3) and that text's BLAKE3 (program), its counts of gates and swaps, its layouts, and the check it passed before it was sent. Results sealed before qasm3 carry the hash alone.", + "required": [ + "basis", + "program" + ], + "properties": { + "basis": { + "type": "string" + }, + "program": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "qasm3": { + "type": "string", + "description": "The program sent, as OpenQASM 3, $i being index i of the coupling map the provider described; program is the BLAKE3 of its UTF-8 bytes." + }, + "qubit_names": { + "type": "object", + "additionalProperties": { + "type": "string", + "minLength": 1 + }, + "description": "The device's own name for each index the program uses, as it was when the job was sent, where a client sends it under those names." + }, + "native_gates": { + "type": "integer" + }, + "two_qubit_gates": { + "type": "integer" + }, + "swaps": { + "type": "integer" + }, + "layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "final_layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "checked": { + "type": "string" + }, + "placement": { + "type": "object", + "description": "Where the program was placed on the device's qubits, and why." + } + } + }, + { + "type": "object", + "description": "A job asked to compile its program first: what ran is the compiled circuit, within distance of the program in the operator norm up to a global phase.", + "required": [ + "basis", + "verdict" + ], + "properties": { + "basis": { + "enum": [ + "clifford_t", + "standard" + ], + "description": "The gate set the program was compiled to." + }, + "level": { + "type": "integer", + "minimum": 0 + }, + "epsilon": { + "type": "number", + "description": "The budget asked for." + }, + "distance": { + "type": [ + "number", + "null" + ], + "description": "The bound the passes' distances add to." + }, + "verdict": { + "type": "string" + }, + "source": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "output": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ], + "description": "The BLAKE3 of the compile certificate's RFC 8785 text, in hex." + }, + "note": { + "type": "string" + } + } + } + ] + }, + "verdict": { + "title": "wai.quantum.verdict/1", + "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", + "type": "object", + "required": [ + "schema", + "level", + "rank", + "holds", + "statement", + "parsed", + "executed", + "intent", + "critique", + "repairs" + ], + "properties": { + "schema": { + "const": "wai.quantum.verdict/1" + }, + "level": { + "enum": [ + "refused", + "parsed", + "executed", + "evidence", + "proof" + ] + }, + "rank": { + "type": "integer", + "minimum": 0, + "maximum": 4, + "description": "The level's place on the ladder, from 0 (refused) to 4 (proof)." + }, + "holds": { + "type": [ + "boolean", + "null" + ] + }, + "statement": { + "type": "string", + "description": "The level in one plain line." + }, + "parsed": { + "type": "object", + "description": "Whether the reader took the program, and its warnings and notes with their codes, or its refusal.", + "required": [ + "ok" + ], + "properties": { + "ok": { + "type": "boolean" + }, + "diagnostics": { + "type": "array", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + }, + "text": { + "type": "string", + "description": "The refusal as the reader wrote it, with its line and code." + } + } + }, + "executed": { + "type": [ + "object", + "null" + ], + "description": "The method that ran and its accuracy class, and the distance a compile put between the program and what ran.", + "properties": { + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "compiled_distance": { + "type": [ + "number", + "null" + ] + } + } + }, + "intent": { + "type": "array", + "items": { + "type": "object", + "description": "One intent's check: what it asked, whether it held, how strong the check was and how it was made.", + "required": [ + "kind", + "outcome", + "strength", + "how" + ], + "properties": { + "kind": { + "enum": [ + "distribution", + "equivalent", + "prepares", + "sampled", + "compiled" + ] + }, + "outcome": { + "enum": [ + "holds", + "fails", + "unchecked" + ] + }, + "strength": { + "enum": [ + "proof", + "evidence", + "none" + ] + }, + "how": { + "type": "string" + }, + "why": { + "type": "string" + }, + "distance": { + "type": "number" + }, + "tolerance": { + "type": "number" + }, + "outcomes": { + "type": "integer", + "description": "The outcomes the distribution holds, or the samples' distinct outcomes." + }, + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The program's distribution, when its outcomes are few enough to list." + }, + "largest_gaps": { + "type": "array", + "items": { + "type": "object", + "properties": { + "outcome": { + "type": "string" + }, + "program": { + "type": "number" + }, + "intent": { + "type": "number" + } + } + } + }, + "global_phase": { + "type": [ + "number", + "null" + ] + }, + "method": { + "type": "string", + "description": "A sampled intent: the method the samples were run by." + }, + "seed": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "alpha": { + "type": "number" + }, + "fit": { + "type": "object", + "description": "A sampled intent: the test, its statistic, degrees of freedom and p-value, the level, and whether it rejected.", + "properties": { + "test": { + "type": "string" + }, + "statistic": { + "type": "number" + }, + "dof": { + "type": "integer" + }, + "p_value": { + "type": "number" + }, + "alpha": { + "type": "number" + }, + "shots": { + "type": "integer" + }, + "rejected": { + "type": "boolean" + }, + "smallest_expected": { + "type": [ + "number", + "null" + ] + }, + "impossible": { + "type": [ + "integer", + "array", + "boolean" + ] + }, + "note": { + "type": "string" + } + } + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "name": { + "type": "string" + }, + "note": { + "type": "string" + } + } + } + }, + "critique": { + "type": "array", + "description": "The program's smells, each with its lines.", + "items": { + "type": "object" + } + }, + "repairs": { + "type": "array", + "description": "Each edit a repair made, with the code it answered and the lines it changed.", + "items": { + "type": "object" + } + }, + "refusal": { + "type": "object", + "description": "For a refused job: its message and its codes.", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + }, + "sealed": { + "type": "boolean" + } + } + }, + "target": { + "type": "object", + "description": "A run on a device target: which target (its hash, as its receipt binds it), its calibration snapshot, where the program was placed and why, and the noise derived from the target.", + "required": [ + "name", + "hash" + ], + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "hash_is": { + "type": "string" + }, + "calibration": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "source": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "note": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "description": "The native gate set, the layout and routes chosen, the swaps, the expected success beside the fewest-swaps layout's, and the check of the compiled program." + }, + "noise": { + "type": "object", + "description": "The noise model derived from the target's calibration: its channels, durations and idling, and each qubit's readout." + } + } + }, + "fabric": { + "type": "object", + "description": "Where the state vector, or the pauli method's sum of terms, ran: the kernel, the placement the job asked for, the member that ran it (or each partition's), each with its certificate, and the energy. Present when the job asked for a placement, or when auto placed the state on a member by measurement (`auto`); a job auto leaves on the CPU names nothing; the receipt seals it with the rest of the result. Every member placed is certified bit-exact, so the answers are the CPU's, byte for byte.", + "required": [ + "kernel", + "asked", + "parity", + "energy" + ], + "properties": { + "kernel": { + "type": "string" + }, + "asked": { + "description": "The placement the job asked for, as it gave it.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "partitions": { + "type": "array", + "description": "Each partition's member, by the value of the state's top qubits: partition i holds the amplitudes whose top bits read i.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "partition_qubits": { + "type": "integer", + "minimum": 0 + }, + "local_qubits": { + "type": "integer", + "minimum": 0 + }, + "segments": { + "type": "integer", + "minimum": 0, + "description": "Runs of gates the partitions took in turn, between exchanges." + }, + "exchanges": { + "type": "integer", + "minimum": 0, + "description": "Partition qubits exchanged with local ones through the host's copy of the state." + }, + "fell_back_from": { + "type": "array", + "description": "An accelerator request whose member failed during the run: each member that failed, in turn, with how; the member named above ran the job.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "auto": { + "type": "object", + "description": "Why auto placed the state where it ran: the rule (a member is placed only where the committed measurements show it faster than this host's CPU for the job's size and fusion width) and the measured row it rests on, with the host, the day and the load it was measured under. Present only when auto placed a state on a member.", + "required": [ + "rule", + "host", + "fusion", + "from_qubits", + "to_qubits" + ], + "properties": { + "rule": { + "type": "string" + }, + "host": { + "type": "string", + "description": "The host's processor as the measurements name it (cpu--)." + }, + "measured": { + "type": "string", + "description": "The day the host was measured (UTC)." + }, + "about": { + "type": "string" + }, + "load": { + "type": "string" + }, + "discovery_ms": { + "type": "number", + "description": "What discovering and certifying the host's members took, once per process, as measured." + }, + "fusion": { + "type": "integer", + "minimum": 1 + }, + "from_qubits": { + "type": "integer", + "minimum": 0 + }, + "to_qubits": { + "type": "integer", + "minimum": 0 + }, + "min_launches": { + "type": "integer", + "minimum": 0 + }, + "basis": { + "type": "object", + "description": "The measured row the job is judged by: the largest measured size at or below its own, the launches of its plan, the runs of each, and the spread of the CPU's and the member's times in milliseconds.", + "required": [ + "qubits", + "launches", + "runs", + "cpu_ms", + "member_ms" + ], + "properties": { + "qubits": { + "type": "integer", + "minimum": 0 + }, + "launches": { + "type": "integer", + "minimum": 0 + }, + "runs": { + "type": "integer", + "minimum": 0 + }, + "cpu_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + }, + "member_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + } + } + } + } + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "why": { + "type": "string" + } + } + }, + "repaired": { + "type": "object", + "description": "A job asked to repair its program first: the program that ran, each repair, and what needs a person.", + "properties": { + "qasm": { + "type": "string" + }, + "repairs": { + "type": "array", + "items": { + "type": "object", + "required": [ + "code", + "by", + "edits" + ], + "properties": { + "code": { + "type": "string" + }, + "rule": { + "type": "string" + }, + "by": { + "enum": [ + "engine", + "proposal" + ] + }, + "flagged": { + "type": "array", + "items": { + "type": "integer" + } + }, + "edits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "line": { + "type": "integer" + }, + "before": { + "type": [ + "string", + "null" + ] + }, + "after": { + "type": [ + "string", + "null" + ] + } + } + } + } + } + } + }, + "needs_person": { + "type": "array", + "items": { + "type": "object" + } + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0, + "description": "Wall time of the run, where the host has a clock (not in a browser tab)." + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "receipt": { + "anyOf": [ + { + "title": "wai.quantum.receipt/2", + "description": "A result's receipt: an Ed25519 signature, by the key it names, over digest = BLAKE3(\"wai:quantum-service-receipt\\x02\" ‖ len ‖ request ‖ len ‖ result), each of request and result in its RFC 8785 canonical text (the result without its receipt member), each length 8 bytes big-endian. Whatever members the request and the result hold are sealed, the result's engine and schema among them. The first receipts (no canon member, $defs/first) sealed their writer's compact text under the domain ending \\x01; they still verify. wai/extensions/quantum-providers.md section 8.2 states the seal in full, and section 8.4 what a verifier checks.", + "type": "object", + "required": [ + "alg", + "canon", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "canon": { + "const": "rfc8785", + "description": "The canonical form the digest is taken over." + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The signing key, 32 bytes in lower-case hex." + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The digest signed, 32 bytes in lower-case hex." + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$", + "description": "The signature, 64 bytes in lower-case hex." + } + } + }, + { + "description": "The first form, before canon: the digest is over the compact text its writer wrote of each, members in the document's order (section 8.2 of wai/extensions/quantum-providers.md), under the domain ending \\x01. Never written now; still verified.", + "type": "object", + "required": [ + "alg", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$" + } + } + } + ] + }, + "provider": { + "type": "object", + "description": "A provider job: the provider's name, kind and protocol, the device, its provenance, and the hash of its description." + }, + "counts_source": { + "enum": [ + "shots", + "vendor_counts", + "probabilities" + ], + "description": "A provider job: where its counts come from (wai/extensions/quantum-providers.md section 8.3): tallied from one record a shot (shots), the provider's own counts (vendor_counts), or rebuilt from the probabilities it returned by largest remainders, derived and not shot records (probabilities). Results sealed before it carry neither it nor execution." + }, + "execution": { + "type": "object", + "description": "A provider job: how the device was asked to run the program (section 8.3): who states it (stated_by: client, provider or nobody); what the client sent (sent: the request's members and the settings among them); each of mitigation, twirling, decoupling, remapping and optimisation (off, on, default when the request sets nothing for it, none when the device has no such step, unknown when nobody states it); whether the gates were to run as written (verbatim); and a note.", + "required": [ + "stated_by", + "mitigation", + "twirling", + "decoupling", + "remapping", + "optimisation", + "verbatim" + ], + "properties": { + "stated_by": { + "enum": [ + "client", + "provider", + "nobody" + ] + }, + "sent": { + "type": "object", + "required": [ + "fields", + "settings" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "settings": { + "type": "object" + } + }, + "additionalProperties": false + }, + "mitigation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "twirling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "decoupling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "remapping": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "optimisation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "verbatim": { + "type": [ + "boolean", + "null" + ] + }, + "note": { + "type": "string" + } + }, + "additionalProperties": false + }, + "calibration": { + "type": [ + "string", + "null" + ], + "description": "A provider job: the calibration snapshot it ran under." + }, + "job": { + "type": "object", + "description": "A provider job: the provider's job id and its status checks." + }, + "ideal": { + "description": "A provider job: the circuit's exact distribution set beside the measured counts.", + "anyOf": [ + { + "type": "object", + "required": [ + "computed", + "total_variation_distance", + "hellinger_fidelity" + ], + "properties": { + "computed": { + "const": true + }, + "method": { + "type": "string" + }, + "total_variation_distance": { + "type": "number" + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number" + }, + "ideal_outcomes": { + "type": "integer" + }, + "note": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "computed", + "why" + ], + "properties": { + "computed": { + "const": false + }, + "why": { + "type": "string" + } + } + } + ] + }, + "cost": { + "type": "object", + "description": "A provider job: the estimate shown before it was sent, what the provider says it charged, and whether the person confirmed a run that was not free." + }, + "provenance": { + "title": "wai.quantum.provenance/1", + "description": "What a result came from, under the five categories cross-platform provenance surveys use: the circuit, the computer, the compilation, the execution and the software. A host adds it to the results it seals (the job service does, and each item of a set); a result without it reads as it always did. wai-quantum-service/docs/provenance.md maps every field to where it is and whether the receipt seals it.", + "type": "object", + "required": [ + "schema", + "circuit", + "computer", + "compilation", + "execution", + "software" + ], + "properties": { + "schema": { + "const": "wai.quantum.provenance/1" + }, + "circuit": { + "type": "object", + "description": "The program: the BLAKE3 digest of its text as given, its qubits and its gates.", + "required": [ + "program" + ], + "properties": { + "program": { + "type": "string", + "description": "BLAKE3 of the program's text, in hex." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": [ + "integer", + "null" + ] + } + } + }, + "computer": { + "type": "object", + "description": "What ran it: a classical simulator, the method and its accuracy class, a device target's hash when the job named one, and the fabric's members when the result names where its state ran.", + "required": [ + "kind", + "method" + ], + "properties": { + "kind": { + "const": "simulator" + }, + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "target": { + "type": "string", + "description": "The device target's hash; its layout, routes and noise are in the result's own target." + }, + "fabric": { + "type": "object", + "description": "The kernel and the member that ran the state, or each partition's, as the result's fabric names them.", + "properties": { + "kernel": { + "type": "string" + }, + "members": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "compilation": { + "type": "object", + "description": "Whether the job asked to be compiled; if it did, each pass in order with its check's verdict, the certificate's digest, the gate set compiled to (its basis), the level, the ε budget and the distance the result carries, and that no pass draws a random number.", + "required": [ + "asked" + ], + "properties": { + "asked": { + "type": "boolean" + }, + "passes": { + "type": [ + "array", + "null" + ], + "items": { + "type": "object", + "properties": { + "pass": { + "type": "string" + }, + "verdict": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ] + }, + "basis": { + "type": [ + "string", + "null" + ], + "description": "The gate set compiled to: clifford_t or standard." + }, + "level": { + "type": [ + "integer", + "null" + ] + }, + "epsilon": { + "type": [ + "number", + "null" + ] + }, + "distance": { + "type": [ + "number", + "null" + ] + }, + "seeded": { + "const": false + }, + "device": { + "type": "string", + "description": "A job on a device target, compiled exactly to its gates: where its layout and routes are." + }, + "status": { + "const": "not-applicable" + }, + "why": { + "type": "string" + } + } + }, + "execution": { + "type": "object", + "description": "The shots, the seed and the plan the job ran under; its identifier and times are the host's, outside the result.", + "required": [ + "plan" + ], + "properties": { + "shots": { + "type": [ + "integer", + "null" + ] + }, + "seed": { + "type": [ + "integer", + "null" + ] + }, + "plan": { + "type": "object", + "properties": { + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0 + } + } + } + } + }, + "software": { + "type": "object", + "description": "The engine's name and version, and the host's.", + "required": [ + "engine", + "host" + ], + "properties": { + "engine": { + "type": "string" + }, + "host": { + "type": "string" + } + } + } + } + }, + "mitigation": { + "title": "wai.quantum.mitigation/1", + "description": "A job's mitigation (its request's mitigate, engine::mitigate), in its result: the method and the options it ran with, its bias and variance assumptions, each observable raw and mitigated with a standard error each and the ideal value (or, for readout, the counts inverted as a quasi-distribution), the method's own details and what it spent. docs/qec.md describes each method.", + "type": "object", + "required": [ + "method", + "options", + "assumptions" + ], + "properties": { + "method": { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + "options": { + "type": "object", + "description": "The options it ran with, the defaults filled in.", + "properties": { + "method": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "factors": { + "type": "array", + "items": { + "type": "number" + } + }, + "extrapolation": { + "enum": [ + "richardson", + "linear", + "exponential" + ] + }, + "samples": { + "type": "integer" + }, + "training": { + "type": "integer" + }, + "keep": { + "type": "integer" + }, + "learn_shots": { + "type": "integer" + } + } + }, + "assumptions": { + "type": "object", + "properties": { + "bias": { + "type": "string" + }, + "variance": { + "type": "string" + } + } + }, + "noise": { + "type": "string", + "description": "How the job's noise model is read for the method." + }, + "note": { + "type": "string" + }, + "observables": { + "type": "array", + "items": { + "type": "object", + "description": "One observable: its raw value and the mitigated one, each with its standard error, and the ideal value a simulation knows.", + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "raw": { + "type": "number" + }, + "raw_stderr": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + }, + "ideal": { + "type": "number" + } + } + } + }, + "distribution": { + "type": "array", + "description": "readout: each outcome's raw share and its mitigated quasi-probability, with its standard error.", + "items": { + "type": "object", + "properties": { + "bits": { + "type": "string" + }, + "raw": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + } + } + } + }, + "details": { + "type": "object", + "description": "The method's own: the folded scales and the folding check (zne), the learned model and the amplified values (pea), the quasi-probability and the value it converges to (pec), the training fits (cdr), the purity (vd), the flip and its amplification (readout).", + "additionalProperties": true + }, + "cost": { + "type": "object", + "description": "The circuits and shots it spent beyond the job's own.", + "properties": { + "circuits": { + "type": "integer", + "minimum": 0 + }, + "shots": { + "type": "integer", + "minimum": 0 + }, + "note": { + "type": "string" + } + } + } + } + }, + "pulse": { + "type": "object", + "description": "A pulse run (method pulse, engine::pulse): what was read and its distribution, the final populations, each capture's reading, the final density matrix's digest, the schedule's length, the integrator and its step, the device and where each parameter came from, and what the receipt binds (calibration).", + "required": [ + "read", + "outcome_bits", + "populations", + "simulated_qubits", + "density_hash", + "integrator", + "device", + "calibration" + ], + "properties": { + "read": { + "type": "string", + "description": "What the distribution reads: the captures together (into the program's bits when each writes one), or the final state." + }, + "outcome_bits": { + "type": "array", + "items": { + "type": "string" + }, + "description": "What each character of an outcome is, left to right: a program bit (c[0]) or a qubit ($0)." + }, + "distribution": { + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "number" + }, + "description": "The probability of each outcome, which the counts sample; null when the captures start at different samples." + }, + "populations": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The final state read on every simulated qubit, the highest qubit first, a level above 0 read as 1." + }, + "simulated_qubits": { + "type": "array", + "items": { + "type": "integer" + } + }, + "captures": { + "type": "array", + "items": { + "type": "object", + "properties": { + "frame": { + "type": "string" + }, + "qubit": { + "type": "integer" + }, + "start": { + "type": "integer" + }, + "start_ns": { + "type": "number" + }, + "bit": { + "type": [ + "string", + "null" + ] + }, + "p1": { + "type": "number" + }, + "p2": { + "type": "number" + } + } + } + }, + "leakage": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "p2": { + "type": "number" + } + } + }, + "description": "With three levels: each qubit's final probability of level 2." + }, + "trace": { + "type": "number" + }, + "density_hash": { + "type": "string", + "description": "The BLAKE3 of the final density matrix's bits: the same on every platform." + }, + "duration": { + "type": "integer" + }, + "duration_ns": { + "type": "number" + }, + "integrator": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "order": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "substeps": { + "type": "integer" + }, + "step_ns": { + "type": "number" + }, + "steps": { + "type": "integer" + }, + "norm_max": { + "type": "number" + }, + "frame": { + "type": "string" + } + } + }, + "device": { + "type": "object", + "properties": { + "levels": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "qubits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "frequency_hz": { + "type": "number" + }, + "rabi_hz": { + "type": "number" + }, + "anharmonicity_hz": { + "type": "number" + }, + "t1_ns": { + "type": "number" + }, + "t2_ns": { + "type": "number" + }, + "from": { + "type": "object", + "additionalProperties": { + "enum": [ + "pulse", + "target", + "default", + "none" + ] + } + } + } + } + }, + "couplings": { + "type": "array" + }, + "model": { + "type": "string" + } + } + }, + "calibration": { + "type": "object", + "description": "What the receipt binds: the program's, its calibrations', the schedule's and the device's digests, and the target snapshot.", + "properties": { + "program": { + "type": "string" + }, + "calibrations": { + "type": "string" + }, + "schedule": { + "type": "string" + }, + "device": { + "type": "string" + }, + "target": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "calibration": { + "type": "object" + } + } + } + } + }, + "not_modelled": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unwatched" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "An estimate of what the run takes, from past runs, never a promise. A contract's max_joules is enforced by a live reading while the run goes; an estimate can only refuse a job clearly past a ceiling." + }, + "watch": { + "type": "string", + "description": "What reads the run while it runs, and what that covers: what stops it at a contract's max_joules." + }, + "unwatched": { + "type": "string", + "description": "Why nothing can read the run while it runs; under a ceiling the route is refused (energy_unwatched)." + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "stopped": { + "type": "object", + "description": "A run stopped at its contract's max_joules by a live reading: it gave no answer, and accuracy.class is none (wai/extensions/quantum-providers.md section 8.7).", + "required": [ + "at", + "joules", + "max_joules", + "elapsed_ms", + "read" + ], + "properties": { + "at": { + "const": "max_joules" + }, + "joules": { + "type": "number", + "description": "What the reading had come to, at or past the ceiling." + }, + "max_joules": { + "type": "number" + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "read": { + "type": "string", + "description": "What read the run, and what that covers." + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "none" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance. none: the run was stopped at its contract's energy ceiling and gave no answer." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, diff --git a/wai/wai-quantum-cli/docs/service-mcp.json b/wai/wai-quantum-cli/docs/service-mcp.json index 211edfc31..36cba2b3e 100644 --- a/wai/wai-quantum-cli/docs/service-mcp.json +++ b/wai/wai-quantum-cli/docs/service-mcp.json @@ -5099,6 +5099,71 @@ "note": { "type": "string" }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, "fusion": { "type": "integer" }, @@ -9929,6 +9994,71 @@ "note": { "type": "string" }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, "fusion": { "type": "integer" }, @@ -18000,6 +18130,71 @@ "note": { "type": "string" }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, "fusion": { "type": "integer" }, @@ -22830,6 +23025,71 @@ "note": { "type": "string" }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, "fusion": { "type": "integer" }, @@ -32664,6 +32924,71 @@ "note": { "type": "string" }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, "fusion": { "type": "integer" }, @@ -37494,6 +37819,71 @@ "note": { "type": "string" }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, "fusion": { "type": "integer" }, @@ -58277,6 +58667,71 @@ "note": { "type": "string" }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, "fusion": { "type": "integer" }, @@ -63107,6 +63562,71 @@ "note": { "type": "string" }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, "fusion": { "type": "integer" }, diff --git a/wai/wai-quantum-cli/src/estimates.rs b/wai/wai-quantum-cli/src/estimates.rs index fc1f3edc4..65c79d78f 100644 --- a/wai/wai-quantum-cli/src/estimates.rs +++ b/wai/wai-quantum-cli/src/estimates.rs @@ -801,9 +801,9 @@ mod tests { let bell = "OPENQASM 3.0;\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n"; let req = json!({ "qasm": bell, "shots": 10, "method": "stabilizer" }); let mut b = Book::default(); - assert!(wanted(&b, &req, 1 << 30), "a method with no runs read"); + assert!(wanted_keeping(&b, &req, 1 << 30, true), "a method with no runs read"); b.runs.insert("stabilizer".into(), vec![timing(9, 1000, 1.0); 3]); - assert!(!wanted(&b, &req, 1 << 30), "a method with enough, and no ceiling"); + assert!(!wanted_keeping(&b, &req, 1 << 30, true), "a method with enough, and no ceiling"); assert!(wanted(&b, &json!({ "qasm": bell, "shots": 10, "method": "stabilizer", "contract": { "max_joules": 1 } }), 1 << 30)); assert_eq!(ceiling(&json!({ "contract": { "max_joules": 2.5 } })), Some(2.5)); // Nothing read, nothing kept: the store is not written for a run with no reading. -- 2.54.0 (Apple Git-157) From ba774db6bda555fd16a5ce3948e0cf62bc18b588 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sun, 8 Nov 2026 08:40:59 -0500 Subject: [PATCH 25/42] wai-quantum: the tool lists blessed on 0.9.0, and the qpu library's pin at 94 Main's 0.9.0 adds a test to the qpu library; with this branch's it holds 94. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/wai-quantum-qpu.yml | 4 +- wai/wai-quantum-cli/docs/local-mcp.json | 19735 +++++++++++++++++++- wai/wai-quantum-cli/docs/service-mcp.json | 520 + 3 files changed, 20252 insertions(+), 7 deletions(-) diff --git a/.github/workflows/wai-quantum-qpu.yml b/.github/workflows/wai-quantum-qpu.yml index 6dbfbcd8e..e358e32ee 100644 --- a/.github/workflows/wai-quantum-qpu.yml +++ b/.github/workflows/wai-quantum-qpu.yml @@ -79,10 +79,10 @@ jobs: # tests never touch one but the macOS leg's own. export WAI_QUANTUM_CREDENTIALS=file cargo test --locked 2>&1 | tee "$RUNNER_TEMP/test.log" - # The library (93, the cloud-tasks client's and a job under a contract's among + # The library (94, the cloud-tasks client's and a job under a contract's among # them), the clients against their contracts (17), and the providers # end to end (12), each binary's count pinned. - for n in 93 17 12; do + for n in 94 17 12; do grep -qE "^test result: ok\. $n passed; 0 failed" "$RUNNER_TEMP/test.log" || { echo "::error::a test binary did not pass all $n of its tests"; exit 1; } done for t in curl_carries_a_request_to_a_server_and_back every_operation_over_http every_operation_over_a_local_process \ diff --git a/wai/wai-quantum-cli/docs/local-mcp.json b/wai/wai-quantum-cli/docs/local-mcp.json index b4c691083..4869a4e40 100644 --- a/wai/wai-quantum-cli/docs/local-mcp.json +++ b/wai/wai-quantum-cli/docs/local-mcp.json @@ -4,7 +4,7 @@ { "name": "run_quantum_circuit", "title": "Run a quantum program here", - "description": "Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more.", + "description": "Run an OpenQASM program on this machine, planned as the quantum job service plans it: measurement counts, Pauli expectation values and/or amplitudes, the method chosen and why, its accuracy class, and a receipt signed with this user's key. Give `contract` (the class wanted, a deadline) and the planner prices every method here, runs the cheapest that meets it, seals its reasoning under `planner`, and refuses (J071) rather than fall back to less; this tool reaches no provider, and plan_routes and run_routed do. Give `intent` (an exact distribution, or a reference program it must equal or whose state it must prepare) and the engine checks it with the run. Every answer carries `verdict`: the level the engine checked to (proof, evidence, executed, parsed, refused), whether the intent holds and a plain statement, sealed in the receipt. Quote the verdict and the numbers; do not estimate them or claim more.", "inputSchema": { "type": "object", "anyOf": [ @@ -531,6 +531,78 @@ "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -1358,6 +1430,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -4194,6 +4338,934 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -5204,6 +6276,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -8038,6 +9182,934 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -8898,7 +10970,7 @@ { "name": "plan_quantum_circuit", "title": "Plan a quantum program", - "description": "The method a program would run on and why, the memory and work it would take, without running it.", + "description": "The method a program would run on and why, the memory and work it would take, without running it. With a contract, every route's price or reason for rejection under planner, or the refusal (J071) when no route meets it.", "inputSchema": { "type": "object", "anyOf": [ @@ -9425,17 +11497,89 @@ "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, "outputSchema": { "$id": "wai-quantum://schemas/plan_quantum_circuit/1", "type": "object", - "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it.", + "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it. A job with a contract carries the planner's reasoning.", "anyOf": [ { "title": "wai.quantum.plan/1", - "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it.", + "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it. A job with a contract carries the planner's reasoning.", "type": "object", "required": [ "method", @@ -9513,6 +11657,659 @@ } } }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, "metered": { "type": "boolean", "description": "True when a job naming method mps would pass one job's work at the bond it asks for: it runs under a meter of the bonds it reaches, may take far less than `work`, and stops with J011 if it passes `work`." @@ -21538,7 +24335,7 @@ { "name": "verify_quantum_result", "title": "Check a result's receipt", - "description": "Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and every rule of its form holds (`reasons` names what does not), and which key signed it.", + "description": "Whether a job's receipt seals its request and its result, as run_quantum_circuit or the job service returns them, and every rule of its form holds (`reasons` names what does not), and which key signed it; for a job under a contract, every route's outcome and the choice recomputed from what it states, and with recheck its routes priced again and its shadow run again.", "inputSchema": { "type": "object", "required": [ @@ -21551,6 +24348,10 @@ "string" ], "description": "The job's text as it was given (preferred: read as the protocol reads it, so a member named twice or a number past what a parsed job keeps is seen), or the job: {\"request\": ..., \"result\": ...}, the result carrying its receipt." + }, + "recheck": { + "type": "boolean", + "description": "For a job under a contract: its routes priced again at the job's memory, held to the digest it sealed, and its shadow run again, held to its counts bit for bit." } } }, @@ -21604,6 +24405,28 @@ "null" ], "description": "That key as a did:key." + }, + "planner": { + "type": "object", + "description": "For a job under a contract, what its reasoning says: the route chosen, the class wanted and given, whether the choice depends on the host, what was kept, and the shadow." + }, + "recheck": { + "type": "object", + "description": "With recheck: whether the routes priced again and the shadow run again are what the job sealed.", + "properties": { + "holds": { + "type": "boolean" + }, + "engine": { + "type": "object" + }, + "priced": { + "type": "object" + }, + "shadow": { + "type": "object" + } + } } } }, @@ -30865,6 +33688,78 @@ "type": "number" }, "description": "A value for each of the program's parameters (input float theta;, input angle phi;), as {\"theta\": 0.3}: bound exactly before the program is read. A parameter left without one is refused (J050)." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } }, "required": [ @@ -31695,6 +34590,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -34531,6 +37498,934 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -35541,6 +39436,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -38375,6 +42342,934 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -50779,6 +55674,78 @@ "type": "integer", "minimum": 0, "description": "A seed, for a provider that is a seeded simulator; a device ignores it." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -50826,6 +55793,659 @@ "confirm": { "type": "string", "description": "What the person reads before confirming a run that is not free." + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } } } }, @@ -50911,6 +56531,78 @@ "minimum": 0, "description": "A seed, for a provider that is a seeded simulator; a device ignores it." }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } + }, "confirm_cost": { "type": "boolean", "description": "true only when the person has agreed to this run's cost. A run that is not free is refused without it." @@ -51744,6 +57436,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -54580,6 +60344,934 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, @@ -55590,6 +62282,78 @@ } } } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } } } }, @@ -58424,6 +65188,12967 @@ } } } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + }, + "error": { + "type": "string" + }, + "code": { + "type": "string", + "description": "A failed item's refusal code (engine::refusal)." + }, + "path": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The item's leaf's sibling digests up to the root, in hex." + } + } + } + } + } + } + ] + }, + "error": { + "type": "string", + "description": "Why a job failed, or why it was interrupted." + }, + "interruptions": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "The job service: each time it stopped while the job ran, in milliseconds since 1970. A job that was running when the service stopped is queued again, once, to run from its stored request." + }, + "submitted_ms": { + "type": "integer", + "description": "The job service: when it was submitted, in milliseconds since 1970." + }, + "started_ms": { + "type": "integer" + }, + "finished_ms": { + "type": "integer" + }, + "peak_rss_bytes": { + "type": "integer", + "description": "The job service: the most memory the job's process held." + }, + "digests": { + "type": "object", + "description": "The job service: the BLAKE3 digests its store keeps the job's objects under (the request, each program, the result and the receipt).", + "properties": { + "algorithm": { + "const": "blake3" + }, + "request": { + "type": [ + "string", + "null" + ] + }, + "programs": { + "type": "array", + "items": { + "type": "string" + } + }, + "result": { + "type": "string" + }, + "receipt": { + "type": "string" + } + } + } + } + }, + { + "type": "object", + "description": "A refusal as data: the message, every code in it (the last is the code), its outcome and meaning as the code's table gives them. A host that refuses for its own reasons gives the error alone.", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + } + ] + } + }, + { + "name": "plan_routes", + "title": "Weigh a contract against every route", + "description": "Every route a job could take under its contract: the methods on this machine and each of the person's own providers, each with its price or why it was rejected, what a provider's estimate leaves out, and the route the planner would choose: the cheapest that meets the contract, or the refusal (J071) with every route's reason. Each provider is asked to describe its device and estimate the job. Nothing is submitted and nothing is spent. A device is chosen only when exactness asks for measured or any.", + "inputSchema": { + "type": "object", + "required": [ + "qasm", + "contract" + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why." + }, + "inputs": { + "type": "object", + "additionalProperties": { + "type": "integer" + }, + "description": "A generator's inputs' values, as {\"n\": 5}." + }, + "shots": { + "type": "integer", + "minimum": 1, + "description": "Shots (default 1024)." + }, + "seed": { + "type": "integer", + "minimum": 0, + "description": "A seed." + }, + "observables": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Pauli observables: a provider's job answers counts, so a method here answers these." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } + } + } + }, + "outputSchema": { + "$id": "wai-quantum://schemas/plan_routes/1", + "type": "object", + "description": "Every route a job could take under its contract, each with its price or why it was rejected, and the route chosen: nothing submitted, nothing spent.", + "anyOf": [ + { + "type": "object", + "description": "Every route a job could take under its contract, each with its price or why it was rejected, and the route chosen: nothing submitted, nothing spent.", + "required": [ + "dry_run", + "planner" + ], + "properties": { + "dry_run": { + "const": true + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "plan": { + "title": "wai.quantum.plan/1", + "description": "What a job will run, before it runs: the method the planner chose and why, the memory the job is admitted with (an upper estimate) and its work in the method's own unit. The command line's plan --json and both servers' plan tools give it. A job with a contract carries the planner's reasoning.", + "type": "object", + "required": [ + "method", + "why", + "memory_bytes", + "work", + "qubits" + ], + "properties": { + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0, + "description": "The method's own unit: an upper bound on what the run takes where the method's cost is known beforehand, and with `metered` what the meter holds it to." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "target": { + "type": "object", + "description": "A run on a device target: which target (its hash, as its receipt binds it), its calibration snapshot, where the program was placed and why, and the noise derived from the target.", + "required": [ + "name", + "hash" + ], + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "hash_is": { + "type": "string" + }, + "calibration": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "source": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "note": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "description": "The native gate set, the layout and routes chosen, the swaps, the expected success beside the fewest-swaps layout's, and the check of the compiled program." + }, + "noise": { + "type": "object", + "description": "The noise model derived from the target's calibration: its channels, durations and idling, and each qubit's readout." + } + } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "metered": { + "type": "boolean", + "description": "True when a job naming method mps would pass one job's work at the bond it asks for: it runs under a meter of the bonds it reaches, may take far less than `work`, and stops with J011 if it passes `work`." + } + } + }, + "provider_plan": { + "type": "object", + "description": "The dry run of a job on a provider: nothing submitted, nothing spent.", + "required": [ + "dry_run", + "provider", + "plan", + "estimate", + "free", + "confirm" + ], + "properties": { + "dry_run": { + "const": true + }, + "provider": { + "type": "object" + }, + "calibration": { + "type": [ + "string", + "null" + ] + }, + "billing": { + "type": "object" + }, + "plan": { + "type": "object" + }, + "estimate": { + "type": "object" + }, + "free": { + "type": "boolean" + }, + "confirm": { + "type": "string", + "description": "What the person reads before confirming a run that is not free." + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + } + } + }, + "confirm": { + "type": "object", + "description": "Where the route chosen is a provider's and not free: what a person confirms it by. token is a digest of the route, its estimate's money and the program and shots it would send; a run is sent only when given that token made again at send time.", + "required": [ + "token", + "route", + "money", + "says" + ], + "properties": { + "token": { + "type": "string" + }, + "route": { + "type": "string" + }, + "money": { + "type": "object" + }, + "says": { + "type": "string" + } + } + } + } + }, + { + "type": "object", + "description": "A refusal as data: the message, every code in it (the last is the code), its outcome and meaning as the code's table gives them. A host that refuses for its own reasons gives the error alone.", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + } + ] + } + }, + { + "name": "run_routed", + "title": "Run a job on the route its contract chooses (can spend the person's money)", + "description": "Runs a job on the route plan_routes chooses: a method on this machine, or one of the person's own providers. THIS CAN SPEND THE PERSON'S MONEY OR QUOTA, when the contract allows a provider and one is chosen. A cost ceiling confirms nothing: a run that is not free is refused unless confirm is the word plan_routes gave for that route, its estimate and its program (its confirm.token), set only after the person has seen them and agreed to that run; if the route or its estimate changed since, it is refused with the new word. The answer is a job in the service's form, its result carrying the planner's reasoning under planner; a provider's result also carries a classical method's counts and their distance under shadow, or why no classical method could reach them. If the job has not finished within this call the answer has status running and an id, and get_provider_job collects it later. Do not run it again to find out: that is a second job, and it can be a second bill.", + "inputSchema": { + "type": "object", + "required": [ + "qasm", + "contract" + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, OpenQASM 3. A provider takes one whose measurements all come at the end and whose every angle is a dyadic multiple of 2π; one it cannot take is a route with why." + }, + "inputs": { + "type": "object", + "additionalProperties": { + "type": "integer" + }, + "description": "A generator's inputs' values, as {\"n\": 5}." + }, + "shots": { + "type": "integer", + "minimum": 1, + "description": "Shots (default 1024)." + }, + "seed": { + "type": "integer", + "minimum": 0, + "description": "A seed." + }, + "observables": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Pauli observables: a provider's job answers counts, so a method here answers these." + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } + }, + "confirm": { + "type": "string", + "description": "The word plan_routes gave (confirm.token) for the route, the estimate and the program the person agreed to. A run that is not free is refused without it, whatever the contract's ceiling, and refused if what is chosen now is not what that word names." + } + } + }, + "outputSchema": { + "$id": "wai-quantum://schemas/run_routed/1", + "type": "object", + "description": "A job as a host returns it: its status, the method its plan chose and why, the request as submitted, and, once it is done, the result with its receipt: a job's result, or for a set (a request with programs or a sweep, its method set) the set's result. The command line's run --json, the local MCP server's run_quantum_circuit and a run on the person's own provider give a finished job; the job service also gives its id and times, and a job still queued or running, or failed with its error. A job's receipt verifies from this document alone: request and result.", + "anyOf": [ + { + "title": "wai.quantum.job/1", + "description": "A job as a host returns it: its status, the method its plan chose and why, the request as submitted, and, once it is done, the result with its receipt: a job's result, or for a set (a request with programs or a sweep, its method set) the set's result. The command line's run --json, the local MCP server's run_quantum_circuit and a run on the person's own provider give a finished job; the job service also gives its id and times, and a job still queued or running, or failed with its error. A job's receipt verifies from this document alone: request and result.", + "type": "object", + "required": [ + "status", + "request" + ], + "properties": { + "id": { + "type": "string", + "description": "The job service's id for the job." + }, + "status": { + "enum": [ + "queued", + "running", + "done", + "failed", + "cancelled", + "interrupted" + ], + "description": "interrupted: the job service stopped while the job ran, after it had run it again once from its request, so it has no result; error says so." + }, + "method": { + "type": "string", + "description": "The method the plan chose; set for a set." + }, + "why": { + "type": "string", + "description": "Why the plan chose the method." + }, + "estimate": { + "type": "object", + "description": "What the plan admitted the job with.", + "required": [ + "memory_bytes", + "work" + ], + "properties": { + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0, + "description": "In the method's own unit." + } + } + }, + "request": { + "title": "wai.quantum.job-request/1", + "description": "A job as a client submits it: a program and what is asked of it, or a set: many programs (programs), or one over a grid of its inputs (sweep), run as one job. The command line, both MCP servers, the job service, the desktop app and the Studio read it alike, and a receipt seals it as it was given. A member the engine does not read is ignored, and sealed with the rest.", + "type": "object", + "anyOf": [ + { + "required": [ + "qasm" + ] + }, + { + "required": [ + "programs" + ] + }, + { + "required": [ + "source" + ] + } + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, in OpenQASM 3 or the OpenQASM 2 forms in common use." + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "description": "The program in another format, in place of qasm (engine::formats::expand): read to the job's qasm before the job is read, the request keeping its source.", + "properties": { + "format": { + "enum": [ + "qasm", + "qir", + "jeff" + ] + }, + "program": { + "type": "string", + "description": "The program's text (OpenQASM, QIR)." + }, + "program_base64": { + "type": "string", + "description": "The program's bytes as base64 (jeff)." + } + } + }, + "shots": { + "type": "integer", + "minimum": 0, + "maximum": 1000000, + "description": "Measurement shots; 1024 when no observables or amplitudes are asked for, otherwise 0." + }, + "seed": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991, + "description": "The sampling seed (1 when not given): the same job and seed give the same counts." + }, + "method": { + "type": "string", + "description": "auto (the default: the strongest method the program admits), or a method by its name as the methods list names it; pulse runs a pulse program (OpenPulse calibrations) under the pulse options." + }, + "observables": { + "type": "array", + "maxItems": 256, + "description": "Pauli observables to take the expectation values of.", + "items": { + "anyOf": [ + { + "type": "string", + "description": "A Pauli string, as \"Z0 Z1\"; qubits count from 0." + }, + { + "type": "object", + "required": [ + "pauli" + ], + "properties": { + "pauli": { + "type": "string", + "description": "A Pauli string, as \"X3\"." + }, + "coeff": { + "type": "number", + "description": "Its coefficient (1 when not given)." + } + } + } + ] + } + }, + "amplitudes": { + "type": "array", + "maxItems": 64, + "description": "Basis states whose amplitudes to return: one 0 or 1 per qubit, qubit n-1 first.", + "items": { + "type": "string" + } + }, + "noise": { + "type": "object", + "description": "A noise model, each channel a probability. A channel not listed here is refused.", + "additionalProperties": false, + "properties": { + "depolarizing_1q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "depolarizing_2q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "amplitude_damping": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "dephasing": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "readout": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + } + }, + "options": { + "type": "object", + "description": "Options of the method that runs the job, as the methods list names them (max_bond, cutoff, fusion, trajectories, threshold, max_weight, ladder, max_terms, path_restarts, controls), and memory_gb.", + "additionalProperties": true, + "properties": { + "controls": { + "enum": [ + "whole", + "standard" + ], + "description": "A gate whose standard gates would double (x, y, z or h under three or more controls; s, sdg, t, tdg, p, rx, ry, rz, u, sx or sxdg under two or more) runs as one on statevector and in standard gates on exact. \"standard\" runs standard gates on statevector too, which reproduces a result made that way bit for bit. \"whole\" holds the gate whole on exact too, which gives other bits than its default, and is refused (J003) on a job that runs standard gates: another method named, a compile, noise, mitigation, a device target or a named place on the fabric. Any other value is refused." + } + } + }, + "compile": { + "type": "object", + "description": "What a compile is asked for, each optional: the most the output may differ from the program (epsilon, in the operator norm up to a global phase), the level (0 lowers and approximates; 1 also rewrites and folds phases; 2 also resynthesises), the basis, the gate set it writes the program in (clifford_t: every rotation off the multiples of π/4 a Clifford+T word; standard: nothing approximated), whether to give the circuit after each pass (stages), and the twirl and dd passes, last (twirl, with its seed; dd, with its sequence).", + "properties": { + "epsilon": { + "type": "number", + "exclusiveMinimum": 0 + }, + "level": { + "type": "integer", + "minimum": 0, + "maximum": 2 + }, + "basis": { + "enum": [ + "clifford_t", + "standard" + ] + }, + "stages": { + "type": "boolean" + }, + "twirl": { + "description": "Twirl each two-qubit Clifford gate with Paulis drawn from a seeded stream: true (seed 1), or {\"seed\": N}. One seed is one instance, checked to be the same circuit.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "required": [ + "seed" + ], + "properties": { + "seed": { + "type": "integer", + "minimum": 0 + } + } + } + ] + }, + "dd": { + "description": "Dynamical decoupling in each window where a qubit idles long enough: xx or xy4 (or {\"sequence\": …}), checked to change nothing without noise.", + "anyOf": [ + { + "enum": [ + "xx", + "xy4" + ] + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "sequence": { + "enum": [ + "xx", + "xy4" + ] + } + } + } + ] + } + } + }, + "intent": { + "description": "What the program must do, checked with the run: one intent or a list. The result's verdict says how far it was checked.", + "anyOf": [ + { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + } + ] + }, + "verdict": { + "type": "boolean", + "description": "true: the result carries a verdict even with no intent." + }, + "target": { + "description": "A device target: a built-in target's name, or a target document. The program is compiled to it, placed and simulated under its noise; noise may not be given beside it.", + "anyOf": [ + { + "type": "string" + }, + { + "title": "wai.quantum.target/1", + "description": "A device target: its qubits, the pairs it couples, its native gates with their errors and durations, and the calibration snapshot they come from. A value not known is left out, never written as zero. Every field but format, name, source, qubits, gates and coupling is optional, and a field the format does not name is refused, so a misspelt one never reads as absent. Its canonical text is its RFC 8785 form, and the BLAKE3 of that text, the target's hash, names the snapshot in a receipt.", + "type": "object", + "required": [ + "format", + "name", + "source", + "qubits", + "gates", + "coupling" + ], + "additionalProperties": false, + "properties": { + "format": { + "const": "wai.quantum.target/1" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "additionalProperties": false, + "properties": { + "format": { + "type": "string", + "description": "The format the target was read from (wai-quantum targets import --help lists them)." + }, + "note": { + "type": "string", + "maxLength": 400 + } + } + }, + "calibration": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "maxLength": 400, + "description": "The calibration snapshot's id, as the source names it, or a content id of the snapshot read." + }, + "timestamp": { + "type": "string", + "maxLength": 400, + "description": "When the snapshot was taken, as the source writes it." + } + } + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2048, + "description": "Every qubit, in order.", + "items": { + "type": "object", + "required": [ + "qubit" + ], + "additionalProperties": false, + "properties": { + "qubit": { + "type": "integer", + "minimum": 0, + "description": "Its index: its place in the list." + }, + "label": { + "type": "string", + "description": "The source's own name for it, when that is not its index." + }, + "t1_us": { + "type": "number", + "minimum": 0, + "description": "T1, microseconds." + }, + "t2_us": { + "type": "number", + "minimum": 0, + "description": "T2 (the echo or Ramsey time the source reports), microseconds." + }, + "frequency_ghz": { + "type": "number", + "minimum": 0, + "description": "Its frequency, gigahertz." + }, + "readout": { + "type": "object", + "required": [ + "p01", + "p10" + ], + "additionalProperties": false, + "properties": { + "p01": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 1 | holds 0)." + }, + "p10": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 0 | holds 1)." + } + } + }, + "measure_ns": { + "type": "number", + "minimum": 0, + "description": "The measurement's duration, nanoseconds." + } + } + } + }, + "gates": { + "type": "array", + "maxItems": 262144, + "description": "Each native gate where the device runs it, sorted by gate then qubits.", + "items": { + "type": "object", + "required": [ + "gate", + "qubits" + ], + "additionalProperties": false, + "properties": { + "gate": { + "type": "string", + "pattern": "^[a-z0-9_]{1,40}$" + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + }, + "error": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "The average gate infidelity." + }, + "duration_ns": { + "type": "number", + "minimum": 0, + "description": "Nanoseconds." + } + } + } + }, + "coupling": { + "type": "array", + "description": "The pairs a two-qubit gate may act on, each once, the lower qubit first, sorted.", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + ] + }, + "fabric": { + "description": "Where the statevector method's state runs: auto (the default: on a member only where the committed measurements show it faster than this host's CPU for the job's size and fusion width, otherwise on the CPU), cpu, accelerator (the first accelerator member certified bit-exact here that holds the state, falling back to the next if it fails during the run), a member's id or key (wai-quantum fabric lists them), or a list of members, a power of two of them, the state split by its top qubits into one partition on each (cpu is a member, and a member may be named more than once). A member certified bit-exact gives the CPU's bits. A placement this host cannot honour is refused (J013), never made elsewhere.", + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "array", + "minItems": 2, + "maxItems": 64, + "items": { + "type": "string", + "minLength": 1 + } + } + ] + }, + "repair": { + "description": "Repair the program first on its flagged lines: true, or the choices.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "max_iterations": { + "type": "integer", + "minimum": 1 + }, + "dyadic_bits": { + "type": "integer", + "minimum": 1, + "maximum": 32 + }, + "sizes": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + } + } + } + ] + }, + "history": { + "type": "object", + "description": "The program's history's account of the version the job runs: its digest, and the gates and lines in each hand. The receipt binds it; a history recomputes and checks it." + }, + "provider": { + "type": "string", + "description": "The person's own provider to run on, by the name their registry gives it. Only a host that holds their credentials runs such a job; every other host refuses it." + }, + "programs": { + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "type": "string", + "description": "A program's text." + }, + { + "type": "object", + "required": [ + "qasm" + ], + "description": "A job of its own, read as a job request is (no programs or sweep in it); each item of the set's result holds its request in full." + } + ] + }, + "description": "A set (engine::sets): the programs to run as one job, each a program's text or a job of its own; the request's other fields apply to every item that does not set them itself." + }, + "sweep": { + "type": "object", + "additionalProperties": { + "type": "array", + "minItems": 1, + "items": { + "type": "number" + } + }, + "description": "A set over the request's own qasm: values for each of the program's inputs (integer, float or angle), every combination run, the names in sorted order and the first varying slowest." + }, + "params": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "A value for each of the program's parameters (`input float theta;`, `input angle phi;`), bound exactly before the program is read: it runs as if each were written as a `const` at that double. A parameter left without a value is refused (Q114, J050). In a sweep, the parameters it fixes, each bound at every point." + }, + "dry_run": { + "type": "boolean", + "description": "With true: what the host would do with the job or set, running nothing." + }, + "mitigate": { + "description": "Mitigate the job's expectation values (or, for readout, its counts) under its noise (engine::mitigate): zne, pea, pec, cdr, vd or readout, or {\"method\", …} with its options. The result's mitigation gives each value raw and mitigated.", + "anyOf": [ + { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + { + "type": "object", + "required": [ + "method" + ] + } + ] + }, + "pulse": { + "type": "object", + "description": "A pulse run's options (method \"pulse\"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0.", + "additionalProperties": false, + "properties": { + "dt_ns": { + "type": "number", + "exclusiveMinimum": 0, + "maximum": 1000, + "description": "The sample period, ns (default 0.5)." + }, + "levels": { + "type": "integer", + "enum": [ + 2, + 3 + ], + "description": "Levels kept per qubit (default 2; 3 shows leakage)." + }, + "tolerance": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1, + "description": "The most the stated error may be (default 1e-6): a run whose bound and rounding estimate pass it is refused, naming the steps that would meet it." + }, + "substeps": { + "type": "integer", + "minimum": 1, + "maximum": 4096, + "description": "Steps per sample (default: chosen so each step times the generator's norm is at most 0.5)." + }, + "qubits": { + "type": "object", + "description": "Each qubit's parameters by its index, over the target's and the defaults.", + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "frequency_ghz": { + "type": "number", + "description": "Its frequency, GHz." + }, + "rabi_mhz": { + "type": "number", + "description": "Its Rabi frequency at full amplitude, MHz." + }, + "anharmonicity_mhz": { + "type": "number", + "description": "Its anharmonicity, MHz." + }, + "t1_us": { + "type": "number", + "description": "Its relaxation time, µs." + }, + "t2_us": { + "type": "number", + "description": "Its coherence time, µs (at most 2·T1)." + } + } + } + }, + "couplings": { + "type": "array", + "description": "Static ZZ couplings.", + "items": { + "type": "object", + "required": [ + "qubits", + "zz_khz" + ], + "additionalProperties": false, + "properties": { + "qubits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + }, + "minItems": 2, + "maxItems": 2 + }, + "zz_khz": { + "type": "number", + "description": "The coupling's rate, kHz." + } + } + } + }, + "ports": { + "type": "object", + "description": "Ports by name: what each is for and the qubit it reaches.", + "additionalProperties": { + "type": "object", + "required": [ + "kind", + "qubit" + ], + "additionalProperties": false, + "properties": { + "kind": { + "enum": [ + "drive", + "measure", + "acquire" + ] + }, + "qubit": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } + } + } + }, + "result": { + "anyOf": [ + { + "title": "wai.quantum.job-result/1", + "description": "A job's result as the engine gives it, on every host: what was asked of the program, computed by the method its plan chose, with that method's accuracy class. The receipt seals the result without its receipt member, beside the request. A result names the engine that made it and this schema (engine and schema); results made before results carried them have neither and follow this schema all the same.", + "type": "object", + "required": [ + "method", + "qubits", + "gates", + "accuracy" + ], + "properties": { + "engine": { + "type": "object", + "description": "The engine that made the result: the wai-quantum crate's name and version.", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "const": "wai-quantum" + }, + "version": { + "type": "string", + "description": "Its semantic version, as MAJOR.MINOR.PATCH." + } + } + }, + "schema": { + "const": "wai.quantum.job-result/1", + "description": "The schema the result follows." + }, + "components": { + "type": "array", + "description": "The identity of every component that made the result, when a registered one took part (engine::registry): its program's format, the passes its compile ran, the noise channels it names, its method; each registered one marked so. Sealed by the receipt with the rest.", + "items": { + "type": "object", + "description": "One component that made the result (engine::registry): its kind, name and version, the BLAKE3 digest of its descriptor, and whether it is built in. A result carries these only when a registered component took part; one made by built-ins alone names them as it always has (its method, its compile's passes, its noise's channels and the engine's version), the digests of that version listed by the components list.", + "required": [ + "kind", + "name", + "version", + "digest", + "origin" + ], + "properties": { + "kind": { + "enum": [ + "method", + "pass", + "channel", + "front_end" + ] + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "digest": { + "type": "string", + "pattern": "^[0-9a-f]{64}$", + "description": "BLAKE3 of the component's descriptor in its canonical JSON (engine::registry::digest_of)." + }, + "origin": { + "enum": [ + "built-in", + "registered" + ], + "description": "built-in: the engine's own; registered: a host's own, added in its process, not part of the engine." + }, + "certified": { + "const": false, + "description": "Beside a registered component: the engine does not certify it." + } + } + } + }, + "method": { + "type": "string", + "description": "The method that ran the job (provider for a run on the person's own provider)." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": "integer", + "minimum": 0, + "description": "The program's gates, in standard gates (at most 2^53 - 1), however the method ran them." + }, + "operations": { + "type": "integer", + "minimum": 0, + "description": "When the method held a gate under many controls as one (statevector, and exact asked for it): the operations it ran." + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "state_hash": { + "type": "string", + "description": "The bit-exact method's statevector hash (BLAKE3, hex): the same on every machine." + }, + "counts": { + "type": "object", + "description": "Outcomes and their counts, keyed by the program's classical bits, the highest bit first. At most 65536 outcomes are listed; omitted_shots holds the rest.", + "additionalProperties": { + "type": "integer", + "minimum": 0 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "outcome_dimension": { + "type": "integer", + "minimum": 0, + "description": "The stabilizer method: the dimension of the measured outcomes' affine space." + }, + "shots": { + "type": "integer", + "minimum": 0, + "description": "The shots, where the method names them in the result (trajectories, provider)." + }, + "expectations": { + "type": "array", + "items": { + "type": "object", + "required": [ + "observable", + "coeff", + "value" + ], + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "value": { + "type": "number", + "description": "The coefficient times the expectation value." + }, + "stderr": { + "type": "number", + "description": "The standard error, for an estimate." + }, + "bound": { + "type": "number", + "description": "A bound on |exact − value|: rigorous for the bounded class; with confidence beside it, holding with that probability." + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + }, + "max_terms": { + "type": "integer" + }, + "ladder": { + "type": "array", + "description": "The value at thresholds a decade apart, the asked one last.", + "items": { + "type": "object", + "required": [ + "threshold", + "value", + "bound" + ], + "properties": { + "threshold": { + "type": "number" + }, + "value": { + "type": "number" + }, + "bound": { + "type": "number" + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + } + } + } + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds, for a bound that holds with a stated probability (stabilizer_rank's sampled mode)." + } + } + } + }, + "amplitudes": { + "type": "array", + "items": { + "type": "object", + "required": [ + "bits", + "re", + "im" + ], + "properties": { + "bits": { + "type": "string", + "description": "One 0 or 1 per qubit, qubit n-1 first." + }, + "re": { + "type": "number" + }, + "im": { + "type": "number" + }, + "bound": { + "type": "number", + "minimum": 0, + "description": "A bound on |exact − value| of the amplitude, holding with the probability confidence states (stabilizer_rank's sampled mode)." + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds." + } + } + } + }, + "global_phase": { + "type": "string", + "description": "Why the amplitudes' global phase is not fixed, when it is not." + }, + "warning": { + "type": "string" + }, + "contraction_flops": { + "type": "number", + "description": "The tensor network's contraction cost." + }, + "dynamic": { + "type": "object", + "description": "A program that measures in the middle, resets or branches on a measured bit: how it ran.", + "properties": { + "measurements_and_resets": { + "type": "integer", + "minimum": 0 + }, + "branches_run": { + "type": "integer", + "minimum": 0 + }, + "states_at_once": { + "type": "integer", + "minimum": 0 + }, + "branches_weighed": { + "type": "integer", + "minimum": 0 + } + } + }, + "outputs": { + "type": "array", + "description": "The program's output declarations: each its name and type, and its value, or the places of its bits in each outcome.", + "items": { + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "bits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + } + }, + "value": { + "description": "A number, a boolean, a bit string, a duration's text, {\"re\", \"im\"}, or an array of them." + } + } + } + }, + "timing": { + "type": "object", + "description": "A program that states durations (delay, box, stretch) the method does not apply: said so, with the reader's code.", + "required": [ + "applied", + "why" + ], + "properties": { + "applied": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "diagnostics": { + "type": "array", + "description": "The reader's warnings and notes on the program, each with its code.", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "compiled": { + "description": "How the program was compiled before it ran: on the person's own provider, to the device's gates; or, asked with compile, to a basis within a budget. Either way, basis is the gate set it was compiled to.", + "anyOf": [ + { + "type": "object", + "description": "A provider job: the program sent, compiled exactly to the device's own gates: its basis (the device's gate set), its OpenQASM 3 text (qasm3) and that text's BLAKE3 (program), its counts of gates and swaps, its layouts, and the check it passed before it was sent. Results sealed before qasm3 carry the hash alone.", + "required": [ + "basis", + "program" + ], + "properties": { + "basis": { + "type": "string" + }, + "program": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "qasm3": { + "type": "string", + "description": "The program sent, as OpenQASM 3, $i being index i of the coupling map the provider described; program is the BLAKE3 of its UTF-8 bytes." + }, + "qubit_names": { + "type": "object", + "additionalProperties": { + "type": "string", + "minLength": 1 + }, + "description": "The device's own name for each index the program uses, as it was when the job was sent, where a client sends it under those names." + }, + "native_gates": { + "type": "integer" + }, + "two_qubit_gates": { + "type": "integer" + }, + "swaps": { + "type": "integer" + }, + "layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "final_layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "checked": { + "type": "string" + }, + "placement": { + "type": "object", + "description": "Where the program was placed on the device's qubits, and why." + } + } + }, + { + "type": "object", + "description": "A job asked to compile its program first: what ran is the compiled circuit, within distance of the program in the operator norm up to a global phase.", + "required": [ + "basis", + "verdict" + ], + "properties": { + "basis": { + "enum": [ + "clifford_t", + "standard" + ], + "description": "The gate set the program was compiled to." + }, + "level": { + "type": "integer", + "minimum": 0 + }, + "epsilon": { + "type": "number", + "description": "The budget asked for." + }, + "distance": { + "type": [ + "number", + "null" + ], + "description": "The bound the passes' distances add to." + }, + "verdict": { + "type": "string" + }, + "source": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "output": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ], + "description": "The BLAKE3 of the compile certificate's RFC 8785 text, in hex." + }, + "note": { + "type": "string" + } + } + } + ] + }, + "verdict": { + "title": "wai.quantum.verdict/1", + "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", + "type": "object", + "required": [ + "schema", + "level", + "rank", + "holds", + "statement", + "parsed", + "executed", + "intent", + "critique", + "repairs" + ], + "properties": { + "schema": { + "const": "wai.quantum.verdict/1" + }, + "level": { + "enum": [ + "refused", + "parsed", + "executed", + "evidence", + "proof" + ] + }, + "rank": { + "type": "integer", + "minimum": 0, + "maximum": 4, + "description": "The level's place on the ladder, from 0 (refused) to 4 (proof)." + }, + "holds": { + "type": [ + "boolean", + "null" + ] + }, + "statement": { + "type": "string", + "description": "The level in one plain line." + }, + "parsed": { + "type": "object", + "description": "Whether the reader took the program, and its warnings and notes with their codes, or its refusal.", + "required": [ + "ok" + ], + "properties": { + "ok": { + "type": "boolean" + }, + "diagnostics": { + "type": "array", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + }, + "text": { + "type": "string", + "description": "The refusal as the reader wrote it, with its line and code." + } + } + }, + "executed": { + "type": [ + "object", + "null" + ], + "description": "The method that ran and its accuracy class, and the distance a compile put between the program and what ran.", + "properties": { + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "compiled_distance": { + "type": [ + "number", + "null" + ] + } + } + }, + "intent": { + "type": "array", + "items": { + "type": "object", + "description": "One intent's check: what it asked, whether it held, how strong the check was and how it was made.", + "required": [ + "kind", + "outcome", + "strength", + "how" + ], + "properties": { + "kind": { + "enum": [ + "distribution", + "equivalent", + "prepares", + "sampled", + "compiled" + ] + }, + "outcome": { + "enum": [ + "holds", + "fails", + "unchecked" + ] + }, + "strength": { + "enum": [ + "proof", + "evidence", + "none" + ] + }, + "how": { + "type": "string" + }, + "why": { + "type": "string" + }, + "distance": { + "type": "number" + }, + "tolerance": { + "type": "number" + }, + "outcomes": { + "type": "integer", + "description": "The outcomes the distribution holds, or the samples' distinct outcomes." + }, + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The program's distribution, when its outcomes are few enough to list." + }, + "largest_gaps": { + "type": "array", + "items": { + "type": "object", + "properties": { + "outcome": { + "type": "string" + }, + "program": { + "type": "number" + }, + "intent": { + "type": "number" + } + } + } + }, + "global_phase": { + "type": [ + "number", + "null" + ] + }, + "method": { + "type": "string", + "description": "A sampled intent: the method the samples were run by." + }, + "seed": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "alpha": { + "type": "number" + }, + "fit": { + "type": "object", + "description": "A sampled intent: the test, its statistic, degrees of freedom and p-value, the level, and whether it rejected.", + "properties": { + "test": { + "type": "string" + }, + "statistic": { + "type": "number" + }, + "dof": { + "type": "integer" + }, + "p_value": { + "type": "number" + }, + "alpha": { + "type": "number" + }, + "shots": { + "type": "integer" + }, + "rejected": { + "type": "boolean" + }, + "smallest_expected": { + "type": [ + "number", + "null" + ] + }, + "impossible": { + "type": [ + "integer", + "array", + "boolean" + ] + }, + "note": { + "type": "string" + } + } + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "name": { + "type": "string" + }, + "note": { + "type": "string" + } + } + } + }, + "critique": { + "type": "array", + "description": "The program's smells, each with its lines.", + "items": { + "type": "object" + } + }, + "repairs": { + "type": "array", + "description": "Each edit a repair made, with the code it answered and the lines it changed.", + "items": { + "type": "object" + } + }, + "refusal": { + "type": "object", + "description": "For a refused job: its message and its codes.", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + }, + "sealed": { + "type": "boolean" + } + } + }, + "target": { + "type": "object", + "description": "A run on a device target: which target (its hash, as its receipt binds it), its calibration snapshot, where the program was placed and why, and the noise derived from the target.", + "required": [ + "name", + "hash" + ], + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "hash_is": { + "type": "string" + }, + "calibration": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "source": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "note": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "description": "The native gate set, the layout and routes chosen, the swaps, the expected success beside the fewest-swaps layout's, and the check of the compiled program." + }, + "noise": { + "type": "object", + "description": "The noise model derived from the target's calibration: its channels, durations and idling, and each qubit's readout." + } + } + }, + "fabric": { + "type": "object", + "description": "Where the state vector, or the pauli method's sum of terms, ran: the kernel, the placement the job asked for, the member that ran it (or each partition's), each with its certificate, and the energy. Present when the job asked for a placement, or when auto placed the state on a member by measurement (`auto`); a job auto leaves on the CPU names nothing; the receipt seals it with the rest of the result. Every member placed is certified bit-exact, so the answers are the CPU's, byte for byte.", + "required": [ + "kernel", + "asked", + "parity", + "energy" + ], + "properties": { + "kernel": { + "type": "string" + }, + "asked": { + "description": "The placement the job asked for, as it gave it.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "partitions": { + "type": "array", + "description": "Each partition's member, by the value of the state's top qubits: partition i holds the amplitudes whose top bits read i.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "partition_qubits": { + "type": "integer", + "minimum": 0 + }, + "local_qubits": { + "type": "integer", + "minimum": 0 + }, + "segments": { + "type": "integer", + "minimum": 0, + "description": "Runs of gates the partitions took in turn, between exchanges." + }, + "exchanges": { + "type": "integer", + "minimum": 0, + "description": "Partition qubits exchanged with local ones through the host's copy of the state." + }, + "fell_back_from": { + "type": "array", + "description": "An accelerator request whose member failed during the run: each member that failed, in turn, with how; the member named above ran the job.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "auto": { + "type": "object", + "description": "Why auto placed the state where it ran: the rule (a member is placed only where the committed measurements show it faster than this host's CPU for the job's size and fusion width) and the measured row it rests on, with the host, the day and the load it was measured under. Present only when auto placed a state on a member.", + "required": [ + "rule", + "host", + "fusion", + "from_qubits", + "to_qubits" + ], + "properties": { + "rule": { + "type": "string" + }, + "host": { + "type": "string", + "description": "The host's processor as the measurements name it (cpu--)." + }, + "measured": { + "type": "string", + "description": "The day the host was measured (UTC)." + }, + "about": { + "type": "string" + }, + "load": { + "type": "string" + }, + "discovery_ms": { + "type": "number", + "description": "What discovering and certifying the host's members took, once per process, as measured." + }, + "fusion": { + "type": "integer", + "minimum": 1 + }, + "from_qubits": { + "type": "integer", + "minimum": 0 + }, + "to_qubits": { + "type": "integer", + "minimum": 0 + }, + "min_launches": { + "type": "integer", + "minimum": 0 + }, + "basis": { + "type": "object", + "description": "The measured row the job is judged by: the largest measured size at or below its own, the launches of its plan, the runs of each, and the spread of the CPU's and the member's times in milliseconds.", + "required": [ + "qubits", + "launches", + "runs", + "cpu_ms", + "member_ms" + ], + "properties": { + "qubits": { + "type": "integer", + "minimum": 0 + }, + "launches": { + "type": "integer", + "minimum": 0 + }, + "runs": { + "type": "integer", + "minimum": 0 + }, + "cpu_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + }, + "member_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + } + } + } + } + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "why": { + "type": "string" + } + } + }, + "repaired": { + "type": "object", + "description": "A job asked to repair its program first: the program that ran, each repair, and what needs a person.", + "properties": { + "qasm": { + "type": "string" + }, + "repairs": { + "type": "array", + "items": { + "type": "object", + "required": [ + "code", + "by", + "edits" + ], + "properties": { + "code": { + "type": "string" + }, + "rule": { + "type": "string" + }, + "by": { + "enum": [ + "engine", + "proposal" + ] + }, + "flagged": { + "type": "array", + "items": { + "type": "integer" + } + }, + "edits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "line": { + "type": "integer" + }, + "before": { + "type": [ + "string", + "null" + ] + }, + "after": { + "type": [ + "string", + "null" + ] + } + } + } + } + } + } + }, + "needs_person": { + "type": "array", + "items": { + "type": "object" + } + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0, + "description": "Wall time of the run, where the host has a clock (not in a browser tab)." + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "receipt": { + "anyOf": [ + { + "title": "wai.quantum.receipt/2", + "description": "A result's receipt: an Ed25519 signature, by the key it names, over digest = BLAKE3(\"wai:quantum-service-receipt\\x02\" ‖ len ‖ request ‖ len ‖ result), each of request and result in its RFC 8785 canonical text (the result without its receipt member), each length 8 bytes big-endian. Whatever members the request and the result hold are sealed, the result's engine and schema among them. The first receipts (no canon member, $defs/first) sealed their writer's compact text under the domain ending \\x01; they still verify. wai/extensions/quantum-providers.md section 8.2 states the seal in full, and section 8.4 what a verifier checks.", + "type": "object", + "required": [ + "alg", + "canon", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "canon": { + "const": "rfc8785", + "description": "The canonical form the digest is taken over." + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The signing key, 32 bytes in lower-case hex." + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The digest signed, 32 bytes in lower-case hex." + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$", + "description": "The signature, 64 bytes in lower-case hex." + } + } + }, + { + "description": "The first form, before canon: the digest is over the compact text its writer wrote of each, members in the document's order (section 8.2 of wai/extensions/quantum-providers.md), under the domain ending \\x01. Never written now; still verified.", + "type": "object", + "required": [ + "alg", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$" + } + } + } + ] + }, + "provider": { + "type": "object", + "description": "A provider job: the provider's name, kind and protocol, the device, its provenance, and the hash of its description." + }, + "counts_source": { + "enum": [ + "shots", + "vendor_counts", + "probabilities" + ], + "description": "A provider job: where its counts come from (wai/extensions/quantum-providers.md section 8.3): tallied from one record a shot (shots), the provider's own counts (vendor_counts), or rebuilt from the probabilities it returned by largest remainders, derived and not shot records (probabilities). Results sealed before it carry neither it nor execution." + }, + "execution": { + "type": "object", + "description": "A provider job: how the device was asked to run the program (section 8.3): who states it (stated_by: client, provider or nobody); what the client sent (sent: the request's members and the settings among them); each of mitigation, twirling, decoupling, remapping and optimisation (off, on, default when the request sets nothing for it, none when the device has no such step, unknown when nobody states it); whether the gates were to run as written (verbatim); and a note.", + "required": [ + "stated_by", + "mitigation", + "twirling", + "decoupling", + "remapping", + "optimisation", + "verbatim" + ], + "properties": { + "stated_by": { + "enum": [ + "client", + "provider", + "nobody" + ] + }, + "sent": { + "type": "object", + "required": [ + "fields", + "settings" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "settings": { + "type": "object" + } + }, + "additionalProperties": false + }, + "mitigation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "twirling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "decoupling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "remapping": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "optimisation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "verbatim": { + "type": [ + "boolean", + "null" + ] + }, + "note": { + "type": "string" + } + }, + "additionalProperties": false + }, + "calibration": { + "type": [ + "string", + "null" + ], + "description": "A provider job: the calibration snapshot it ran under." + }, + "job": { + "type": "object", + "description": "A provider job: the provider's job id and its status checks." + }, + "ideal": { + "description": "A provider job: the circuit's exact distribution set beside the measured counts.", + "anyOf": [ + { + "type": "object", + "required": [ + "computed", + "total_variation_distance", + "hellinger_fidelity" + ], + "properties": { + "computed": { + "const": true + }, + "method": { + "type": "string" + }, + "total_variation_distance": { + "type": "number" + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number" + }, + "ideal_outcomes": { + "type": "integer" + }, + "note": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "computed", + "why" + ], + "properties": { + "computed": { + "const": false + }, + "why": { + "type": "string" + } + } + } + ] + }, + "cost": { + "type": "object", + "description": "A provider job: the estimate shown before it was sent, what the provider says it charged, and whether the person confirmed a run that was not free." + }, + "provenance": { + "title": "wai.quantum.provenance/1", + "description": "What a result came from, under the five categories cross-platform provenance surveys use: the circuit, the computer, the compilation, the execution and the software. A host adds it to the results it seals (the job service does, and each item of a set); a result without it reads as it always did. wai-quantum-service/docs/provenance.md maps every field to where it is and whether the receipt seals it.", + "type": "object", + "required": [ + "schema", + "circuit", + "computer", + "compilation", + "execution", + "software" + ], + "properties": { + "schema": { + "const": "wai.quantum.provenance/1" + }, + "circuit": { + "type": "object", + "description": "The program: the BLAKE3 digest of its text as given, its qubits and its gates.", + "required": [ + "program" + ], + "properties": { + "program": { + "type": "string", + "description": "BLAKE3 of the program's text, in hex." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": [ + "integer", + "null" + ] + } + } + }, + "computer": { + "type": "object", + "description": "What ran it: a classical simulator, the method and its accuracy class, a device target's hash when the job named one, and the fabric's members when the result names where its state ran.", + "required": [ + "kind", + "method" + ], + "properties": { + "kind": { + "const": "simulator" + }, + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "target": { + "type": "string", + "description": "The device target's hash; its layout, routes and noise are in the result's own target." + }, + "fabric": { + "type": "object", + "description": "The kernel and the member that ran the state, or each partition's, as the result's fabric names them.", + "properties": { + "kernel": { + "type": "string" + }, + "members": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "compilation": { + "type": "object", + "description": "Whether the job asked to be compiled; if it did, each pass in order with its check's verdict, the certificate's digest, the gate set compiled to (its basis), the level, the ε budget and the distance the result carries, and that no pass draws a random number.", + "required": [ + "asked" + ], + "properties": { + "asked": { + "type": "boolean" + }, + "passes": { + "type": [ + "array", + "null" + ], + "items": { + "type": "object", + "properties": { + "pass": { + "type": "string" + }, + "verdict": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ] + }, + "basis": { + "type": [ + "string", + "null" + ], + "description": "The gate set compiled to: clifford_t or standard." + }, + "level": { + "type": [ + "integer", + "null" + ] + }, + "epsilon": { + "type": [ + "number", + "null" + ] + }, + "distance": { + "type": [ + "number", + "null" + ] + }, + "seeded": { + "const": false + }, + "device": { + "type": "string", + "description": "A job on a device target, compiled exactly to its gates: where its layout and routes are." + }, + "status": { + "const": "not-applicable" + }, + "why": { + "type": "string" + } + } + }, + "execution": { + "type": "object", + "description": "The shots, the seed and the plan the job ran under; its identifier and times are the host's, outside the result.", + "required": [ + "plan" + ], + "properties": { + "shots": { + "type": [ + "integer", + "null" + ] + }, + "seed": { + "type": [ + "integer", + "null" + ] + }, + "plan": { + "type": "object", + "properties": { + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0 + } + } + } + } + }, + "software": { + "type": "object", + "description": "The engine's name and version, and the host's.", + "required": [ + "engine", + "host" + ], + "properties": { + "engine": { + "type": "string" + }, + "host": { + "type": "string" + } + } + } + } + }, + "mitigation": { + "title": "wai.quantum.mitigation/1", + "description": "A job's mitigation (its request's mitigate, engine::mitigate), in its result: the method and the options it ran with, its bias and variance assumptions, each observable raw and mitigated with a standard error each and the ideal value (or, for readout, the counts inverted as a quasi-distribution), the method's own details and what it spent. docs/qec.md describes each method.", + "type": "object", + "required": [ + "method", + "options", + "assumptions" + ], + "properties": { + "method": { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + "options": { + "type": "object", + "description": "The options it ran with, the defaults filled in.", + "properties": { + "method": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "factors": { + "type": "array", + "items": { + "type": "number" + } + }, + "extrapolation": { + "enum": [ + "richardson", + "linear", + "exponential" + ] + }, + "samples": { + "type": "integer" + }, + "training": { + "type": "integer" + }, + "keep": { + "type": "integer" + }, + "learn_shots": { + "type": "integer" + } + } + }, + "assumptions": { + "type": "object", + "properties": { + "bias": { + "type": "string" + }, + "variance": { + "type": "string" + } + } + }, + "noise": { + "type": "string", + "description": "How the job's noise model is read for the method." + }, + "note": { + "type": "string" + }, + "observables": { + "type": "array", + "items": { + "type": "object", + "description": "One observable: its raw value and the mitigated one, each with its standard error, and the ideal value a simulation knows.", + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "raw": { + "type": "number" + }, + "raw_stderr": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + }, + "ideal": { + "type": "number" + } + } + } + }, + "distribution": { + "type": "array", + "description": "readout: each outcome's raw share and its mitigated quasi-probability, with its standard error.", + "items": { + "type": "object", + "properties": { + "bits": { + "type": "string" + }, + "raw": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + } + } + } + }, + "details": { + "type": "object", + "description": "The method's own: the folded scales and the folding check (zne), the learned model and the amplified values (pea), the quasi-probability and the value it converges to (pec), the training fits (cdr), the purity (vd), the flip and its amplification (readout).", + "additionalProperties": true + }, + "cost": { + "type": "object", + "description": "The circuits and shots it spent beyond the job's own.", + "properties": { + "circuits": { + "type": "integer", + "minimum": 0 + }, + "shots": { + "type": "integer", + "minimum": 0 + }, + "note": { + "type": "string" + } + } + } + } + }, + "pulse": { + "type": "object", + "description": "A pulse run (method pulse, engine::pulse): what was read and its distribution, the final populations, each capture's reading, the final density matrix's digest, the schedule's length, the integrator and its step, the device and where each parameter came from, and what the receipt binds (calibration).", + "required": [ + "read", + "outcome_bits", + "populations", + "simulated_qubits", + "density_hash", + "integrator", + "device", + "calibration" + ], + "properties": { + "read": { + "type": "string", + "description": "What the distribution reads: the captures together (into the program's bits when each writes one), or the final state." + }, + "outcome_bits": { + "type": "array", + "items": { + "type": "string" + }, + "description": "What each character of an outcome is, left to right: a program bit (c[0]) or a qubit ($0)." + }, + "distribution": { + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "number" + }, + "description": "The probability of each outcome, which the counts sample; null when the captures start at different samples." + }, + "populations": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The final state read on every simulated qubit, the highest qubit first, a level above 0 read as 1." + }, + "simulated_qubits": { + "type": "array", + "items": { + "type": "integer" + } + }, + "captures": { + "type": "array", + "items": { + "type": "object", + "properties": { + "frame": { + "type": "string" + }, + "qubit": { + "type": "integer" + }, + "start": { + "type": "integer" + }, + "start_ns": { + "type": "number" + }, + "bit": { + "type": [ + "string", + "null" + ] + }, + "p1": { + "type": "number" + }, + "p2": { + "type": "number" + } + } + } + }, + "leakage": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "p2": { + "type": "number" + } + } + }, + "description": "With three levels: each qubit's final probability of level 2." + }, + "trace": { + "type": "number" + }, + "density_hash": { + "type": "string", + "description": "The BLAKE3 of the final density matrix's bits: the same on every platform." + }, + "duration": { + "type": "integer" + }, + "duration_ns": { + "type": "number" + }, + "integrator": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "order": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "substeps": { + "type": "integer" + }, + "step_ns": { + "type": "number" + }, + "steps": { + "type": "integer" + }, + "norm_max": { + "type": "number" + }, + "frame": { + "type": "string" + } + } + }, + "device": { + "type": "object", + "properties": { + "levels": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "qubits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "frequency_hz": { + "type": "number" + }, + "rabi_hz": { + "type": "number" + }, + "anharmonicity_hz": { + "type": "number" + }, + "t1_ns": { + "type": "number" + }, + "t2_ns": { + "type": "number" + }, + "from": { + "type": "object", + "additionalProperties": { + "enum": [ + "pulse", + "target", + "default", + "none" + ] + } + } + } + } + }, + "couplings": { + "type": "array" + }, + "model": { + "type": "string" + } + } + }, + "calibration": { + "type": "object", + "description": "What the receipt binds: the program's, its calibrations', the schedule's and the device's digests, and the target snapshot.", + "properties": { + "program": { + "type": "string" + }, + "calibrations": { + "type": "string" + }, + "schedule": { + "type": "string" + }, + "device": { + "type": "string" + }, + "target": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "calibration": { + "type": "object" + } + } + } + } + }, + "not_modelled": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + }, + { + "title": "wai.quantum.set/1", + "description": "A set's result: many programs, or one program over a grid of its inputs, run as one job (engine::sets). Its head holds the count, how many items finished and failed, the Merkle root over the items' leaves, the set's energy and time; the set's receipt seals the set's request and its head. Each item is a plain job with its own receipt, its index, its point in a sweep, and its path to the root, so it is shown sealed by the set alone. A result names the engine that made it and this schema (engine and schema).", + "type": "object", + "required": [ + "format", + "count", + "done", + "failed", + "root", + "items" + ], + "properties": { + "engine": { + "type": "object", + "description": "The engine that made the result: the wai-quantum crate's name and version.", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "const": "wai-quantum" + }, + "version": { + "type": "string" + } + } + }, + "schema": { + "const": "wai.quantum.set/1" + }, + "format": { + "const": "wai.quantum.set/1" + }, + "count": { + "type": "integer", + "minimum": 1 + }, + "done": { + "type": "integer", + "minimum": 0 + }, + "failed": { + "type": "integer", + "minimum": 0 + }, + "root": { + "type": "string", + "description": "The Merkle root of the items' leaves, in hex (domains moq-jwp:merkle-leaf and moq-jwp:merkle-node, version 1)." + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "receipt": { + "title": "wai.quantum.receipt/2", + "description": "A result's receipt: an Ed25519 signature, by the key it names, over digest = BLAKE3(\"wai:quantum-service-receipt\\x02\" ‖ len ‖ request ‖ len ‖ result), each of request and result in its RFC 8785 canonical text (the result without its receipt member), each length 8 bytes big-endian. Whatever members the request and the result hold are sealed, the result's engine and schema among them. The first receipts (no canon member, $defs/first) sealed their writer's compact text under the domain ending \\x01; they still verify. wai/extensions/quantum-providers.md section 8.2 states the seal in full, and section 8.4 what a verifier checks.", + "type": "object", + "required": [ + "alg", + "canon", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "canon": { + "const": "rfc8785", + "description": "The canonical form the digest is taken over." + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The signing key, 32 bytes in lower-case hex." + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The digest signed, 32 bytes in lower-case hex." + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$", + "description": "The signature, 64 bytes in lower-case hex." + } + } + }, + "items": { + "type": "array", + "items": { + "type": "object", + "description": "One item: its index, its point in a sweep, its request (a plain job, complete in itself), and its result with its own receipt, or why it failed; and its path to the set's root.", + "required": [ + "index", + "request", + "status", + "path" + ], + "properties": { + "index": { + "type": "integer", + "minimum": 0 + }, + "point": { + "type": "object", + "description": "A sweep's item: the value of each input it was run at." + }, + "status": { + "enum": [ + "done", + "failed" + ] + }, + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "request": { + "title": "wai.quantum.job-request/1", + "description": "A job as a client submits it: a program and what is asked of it, or a set: many programs (programs), or one over a grid of its inputs (sweep), run as one job. The command line, both MCP servers, the job service, the desktop app and the Studio read it alike, and a receipt seals it as it was given. A member the engine does not read is ignored, and sealed with the rest.", + "type": "object", + "anyOf": [ + { + "required": [ + "qasm" + ] + }, + { + "required": [ + "programs" + ] + }, + { + "required": [ + "source" + ] + } + ], + "properties": { + "qasm": { + "type": "string", + "description": "The program, in OpenQASM 3 or the OpenQASM 2 forms in common use." + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "description": "The program in another format, in place of qasm (engine::formats::expand): read to the job's qasm before the job is read, the request keeping its source.", + "properties": { + "format": { + "enum": [ + "qasm", + "qir", + "jeff" + ] + }, + "program": { + "type": "string", + "description": "The program's text (OpenQASM, QIR)." + }, + "program_base64": { + "type": "string", + "description": "The program's bytes as base64 (jeff)." + } + } + }, + "shots": { + "type": "integer", + "minimum": 0, + "maximum": 1000000, + "description": "Measurement shots; 1024 when no observables or amplitudes are asked for, otherwise 0." + }, + "seed": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991, + "description": "The sampling seed (1 when not given): the same job and seed give the same counts." + }, + "method": { + "type": "string", + "description": "auto (the default: the strongest method the program admits), or a method by its name as the methods list names it; pulse runs a pulse program (OpenPulse calibrations) under the pulse options." + }, + "observables": { + "type": "array", + "maxItems": 256, + "description": "Pauli observables to take the expectation values of.", + "items": { + "anyOf": [ + { + "type": "string", + "description": "A Pauli string, as \"Z0 Z1\"; qubits count from 0." + }, + { + "type": "object", + "required": [ + "pauli" + ], + "properties": { + "pauli": { + "type": "string", + "description": "A Pauli string, as \"X3\"." + }, + "coeff": { + "type": "number", + "description": "Its coefficient (1 when not given)." + } + } + } + ] + } + }, + "amplitudes": { + "type": "array", + "maxItems": 64, + "description": "Basis states whose amplitudes to return: one 0 or 1 per qubit, qubit n-1 first.", + "items": { + "type": "string" + } + }, + "noise": { + "type": "object", + "description": "A noise model, each channel a probability. A channel not listed here is refused.", + "additionalProperties": false, + "properties": { + "depolarizing_1q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "depolarizing_2q": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "amplitude_damping": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "dephasing": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "readout": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + } + }, + "options": { + "type": "object", + "description": "Options of the method that runs the job, as the methods list names them (max_bond, cutoff, fusion, trajectories, threshold, max_weight, ladder, max_terms, path_restarts, controls), and memory_gb.", + "additionalProperties": true, + "properties": { + "controls": { + "enum": [ + "whole", + "standard" + ], + "description": "A gate whose standard gates would double (x, y, z or h under three or more controls; s, sdg, t, tdg, p, rx, ry, rz, u, sx or sxdg under two or more) runs as one on statevector and in standard gates on exact. \"standard\" runs standard gates on statevector too, which reproduces a result made that way bit for bit. \"whole\" holds the gate whole on exact too, which gives other bits than its default, and is refused (J003) on a job that runs standard gates: another method named, a compile, noise, mitigation, a device target or a named place on the fabric. Any other value is refused." + } + } + }, + "compile": { + "type": "object", + "description": "What a compile is asked for, each optional: the most the output may differ from the program (epsilon, in the operator norm up to a global phase), the level (0 lowers and approximates; 1 also rewrites and folds phases; 2 also resynthesises), the basis, the gate set it writes the program in (clifford_t: every rotation off the multiples of π/4 a Clifford+T word; standard: nothing approximated), whether to give the circuit after each pass (stages), and the twirl and dd passes, last (twirl, with its seed; dd, with its sequence).", + "properties": { + "epsilon": { + "type": "number", + "exclusiveMinimum": 0 + }, + "level": { + "type": "integer", + "minimum": 0, + "maximum": 2 + }, + "basis": { + "enum": [ + "clifford_t", + "standard" + ] + }, + "stages": { + "type": "boolean" + }, + "twirl": { + "description": "Twirl each two-qubit Clifford gate with Paulis drawn from a seeded stream: true (seed 1), or {\"seed\": N}. One seed is one instance, checked to be the same circuit.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "required": [ + "seed" + ], + "properties": { + "seed": { + "type": "integer", + "minimum": 0 + } + } + } + ] + }, + "dd": { + "description": "Dynamical decoupling in each window where a qubit idles long enough: xx or xy4 (or {\"sequence\": …}), checked to change nothing without noise.", + "anyOf": [ + { + "enum": [ + "xx", + "xy4" + ] + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "sequence": { + "enum": [ + "xx", + "xy4" + ] + } + } + } + ] + } + } + }, + "intent": { + "description": "What the program must do, checked with the run: one intent or a list. The result's verdict says how far it was checked.", + "anyOf": [ + { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "description": "One of distribution, equivalent, prepares or sampled, with its options.", + "properties": { + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "tolerance": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "equivalent": { + "type": "string" + }, + "prepares": { + "type": "string" + }, + "sampled": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "test": { + "enum": [ + "chi_squared", + "g_test" + ] + }, + "alpha": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1 + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "seed": { + "type": "integer", + "minimum": 0 + }, + "require": { + "const": "proof" + }, + "note": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + } + ] + }, + "verdict": { + "type": "boolean", + "description": "true: the result carries a verdict even with no intent." + }, + "target": { + "description": "A device target: a built-in target's name, or a target document. The program is compiled to it, placed and simulated under its noise; noise may not be given beside it.", + "anyOf": [ + { + "type": "string" + }, + { + "title": "wai.quantum.target/1", + "description": "A device target: its qubits, the pairs it couples, its native gates with their errors and durations, and the calibration snapshot they come from. A value not known is left out, never written as zero. Every field but format, name, source, qubits, gates and coupling is optional, and a field the format does not name is refused, so a misspelt one never reads as absent. Its canonical text is its RFC 8785 form, and the BLAKE3 of that text, the target's hash, names the snapshot in a receipt.", + "type": "object", + "required": [ + "format", + "name", + "source", + "qubits", + "gates", + "coupling" + ], + "additionalProperties": false, + "properties": { + "format": { + "const": "wai.quantum.target/1" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "source": { + "type": "object", + "required": [ + "format" + ], + "additionalProperties": false, + "properties": { + "format": { + "type": "string", + "description": "The format the target was read from (wai-quantum targets import --help lists them)." + }, + "note": { + "type": "string", + "maxLength": 400 + } + } + }, + "calibration": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "maxLength": 400, + "description": "The calibration snapshot's id, as the source names it, or a content id of the snapshot read." + }, + "timestamp": { + "type": "string", + "maxLength": 400, + "description": "When the snapshot was taken, as the source writes it." + } + } + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2048, + "description": "Every qubit, in order.", + "items": { + "type": "object", + "required": [ + "qubit" + ], + "additionalProperties": false, + "properties": { + "qubit": { + "type": "integer", + "minimum": 0, + "description": "Its index: its place in the list." + }, + "label": { + "type": "string", + "description": "The source's own name for it, when that is not its index." + }, + "t1_us": { + "type": "number", + "minimum": 0, + "description": "T1, microseconds." + }, + "t2_us": { + "type": "number", + "minimum": 0, + "description": "T2 (the echo or Ramsey time the source reports), microseconds." + }, + "frequency_ghz": { + "type": "number", + "minimum": 0, + "description": "Its frequency, gigahertz." + }, + "readout": { + "type": "object", + "required": [ + "p01", + "p10" + ], + "additionalProperties": false, + "properties": { + "p01": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 1 | holds 0)." + }, + "p10": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "P(reads 0 | holds 1)." + } + } + }, + "measure_ns": { + "type": "number", + "minimum": 0, + "description": "The measurement's duration, nanoseconds." + } + } + } + }, + "gates": { + "type": "array", + "maxItems": 262144, + "description": "Each native gate where the device runs it, sorted by gate then qubits.", + "items": { + "type": "object", + "required": [ + "gate", + "qubits" + ], + "additionalProperties": false, + "properties": { + "gate": { + "type": "string", + "pattern": "^[a-z0-9_]{1,40}$" + }, + "qubits": { + "type": "array", + "minItems": 1, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + }, + "error": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "The average gate infidelity." + }, + "duration_ns": { + "type": "number", + "minimum": 0, + "description": "Nanoseconds." + } + } + } + }, + "coupling": { + "type": "array", + "description": "The pairs a two-qubit gate may act on, each once, the lower qubit first, sorted.", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + ] + }, + "fabric": { + "description": "Where the statevector method's state runs: auto (the default: on a member only where the committed measurements show it faster than this host's CPU for the job's size and fusion width, otherwise on the CPU), cpu, accelerator (the first accelerator member certified bit-exact here that holds the state, falling back to the next if it fails during the run), a member's id or key (wai-quantum fabric lists them), or a list of members, a power of two of them, the state split by its top qubits into one partition on each (cpu is a member, and a member may be named more than once). A member certified bit-exact gives the CPU's bits. A placement this host cannot honour is refused (J013), never made elsewhere.", + "anyOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "array", + "minItems": 2, + "maxItems": 64, + "items": { + "type": "string", + "minLength": 1 + } + } + ] + }, + "repair": { + "description": "Repair the program first on its flagged lines: true, or the choices.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "max_iterations": { + "type": "integer", + "minimum": 1 + }, + "dyadic_bits": { + "type": "integer", + "minimum": 1, + "maximum": 32 + }, + "sizes": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + } + } + } + ] + }, + "history": { + "type": "object", + "description": "The program's history's account of the version the job runs: its digest, and the gates and lines in each hand. The receipt binds it; a history recomputes and checks it." + }, + "provider": { + "type": "string", + "description": "The person's own provider to run on, by the name their registry gives it. Only a host that holds their credentials runs such a job; every other host refuses it." + }, + "programs": { + "type": "array", + "minItems": 1, + "items": { + "anyOf": [ + { + "type": "string", + "description": "A program's text." + }, + { + "type": "object", + "required": [ + "qasm" + ], + "description": "A job of its own, read as a job request is (no programs or sweep in it); each item of the set's result holds its request in full." + } + ] + }, + "description": "A set (engine::sets): the programs to run as one job, each a program's text or a job of its own; the request's other fields apply to every item that does not set them itself." + }, + "sweep": { + "type": "object", + "additionalProperties": { + "type": "array", + "minItems": 1, + "items": { + "type": "number" + } + }, + "description": "A set over the request's own qasm: values for each of the program's inputs (integer, float or angle), every combination run, the names in sorted order and the first varying slowest." + }, + "params": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "A value for each of the program's parameters (`input float theta;`, `input angle phi;`), bound exactly before the program is read: it runs as if each were written as a `const` at that double. A parameter left without a value is refused (Q114, J050). In a sweep, the parameters it fixes, each bound at every point." + }, + "dry_run": { + "type": "boolean", + "description": "With true: what the host would do with the job or set, running nothing." + }, + "mitigate": { + "description": "Mitigate the job's expectation values (or, for readout, its counts) under its noise (engine::mitigate): zne, pea, pec, cdr, vd or readout, or {\"method\", …} with its options. The result's mitigation gives each value raw and mitigated.", + "anyOf": [ + { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + { + "type": "object", + "required": [ + "method" + ] + } + ] + }, + "pulse": { + "type": "object", + "description": "A pulse run's options (method \"pulse\"): the sample period, the levels kept, the tolerance on the stated error, the steps a sample is divided into, each qubit's parameters, static couplings, and ports beyond the names d0, m0, a0.", + "additionalProperties": false, + "properties": { + "dt_ns": { + "type": "number", + "exclusiveMinimum": 0, + "maximum": 1000, + "description": "The sample period, ns (default 0.5)." + }, + "levels": { + "type": "integer", + "enum": [ + 2, + 3 + ], + "description": "Levels kept per qubit (default 2; 3 shows leakage)." + }, + "tolerance": { + "type": "number", + "exclusiveMinimum": 0, + "exclusiveMaximum": 1, + "description": "The most the stated error may be (default 1e-6): a run whose bound and rounding estimate pass it is refused, naming the steps that would meet it." + }, + "substeps": { + "type": "integer", + "minimum": 1, + "maximum": 4096, + "description": "Steps per sample (default: chosen so each step times the generator's norm is at most 0.5)." + }, + "qubits": { + "type": "object", + "description": "Each qubit's parameters by its index, over the target's and the defaults.", + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "frequency_ghz": { + "type": "number", + "description": "Its frequency, GHz." + }, + "rabi_mhz": { + "type": "number", + "description": "Its Rabi frequency at full amplitude, MHz." + }, + "anharmonicity_mhz": { + "type": "number", + "description": "Its anharmonicity, MHz." + }, + "t1_us": { + "type": "number", + "description": "Its relaxation time, µs." + }, + "t2_us": { + "type": "number", + "description": "Its coherence time, µs (at most 2·T1)." + } + } + } + }, + "couplings": { + "type": "array", + "description": "Static ZZ couplings.", + "items": { + "type": "object", + "required": [ + "qubits", + "zz_khz" + ], + "additionalProperties": false, + "properties": { + "qubits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + }, + "minItems": 2, + "maxItems": 2 + }, + "zz_khz": { + "type": "number", + "description": "The coupling's rate, kHz." + } + } + } + }, + "ports": { + "type": "object", + "description": "Ports by name: what each is for and the qubit it reaches.", + "additionalProperties": { + "type": "object", + "required": [ + "kind", + "qubit" + ], + "additionalProperties": false, + "properties": { + "kind": { + "enum": [ + "drive", + "measure", + "acquire" + ] + }, + "qubit": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + }, + "contract": { + "description": "What the job wants of an answer (wai/extensions/quantum-providers.md section 8.7). Every route the host can see is priced with what is really known, those that cannot meet this are rejected, the cheapest of the rest runs, and the reasoning is sealed in the result as `planner`. Nothing falls back in silence, and a job no route can meet is refused (J071). A job without it plans as it always has, byte for byte. Refused on a set (J073).", + "type": [ + "object", + "null" + ], + "additionalProperties": false, + "properties": { + "exactness": { + "description": "The class wanted. Without it, the job keeps the class auto would give: auto's pick stands while it meets the rest of the contract, and only a route at least as exact may take its place. A device's counts are in no classical class: measured wants a processor's, simulated a provider's simulator's that its provider does not state is approximate, and any takes every route.", + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated", + "any", + null + ] + }, + "max_cost": { + "description": "The most a provider's estimate of the run may come to, before it runs: it bounds the estimate, not the charge, which is stated after the run beside it (kept.cost). A route with an unknown cost, an estimate that is only the least it can come to, or a price in another currency does not meet it: nothing is converted.", + "type": [ + "object", + "null" + ], + "required": [ + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "amount": { + "type": "string", + "description": "An amount in decimals: digits, and optionally a point and digits, at most 64 characters.", + "maxLength": 64 + }, + "currency": { + "type": "string", + "minLength": 1 + } + } + }, + "deadline_seconds": { + "description": "When it must be done by, in seconds from when it starts. A route whose time is not known does not meet it. A host that can stop a run stops it there (J074); otherwise the result says whether it was kept.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "max_joules": { + "description": "The most energy it may take, where a host estimates a job's energy before it runs. A route whose energy is not known does not meet it, so on a host that estimates none every route is rejected.", + "type": [ + "number", + "null" + ], + "exclusiveMinimum": 0 + }, + "providers": { + "description": "Whether a route may be one of the person's providers. never is the default, given or not: a job that names a provider under a contract that does not allow one is refused (J070), and a host asks no provider anything under it. A host that reaches none (the job service) lists none. A provider that costs money is chosen only under max_cost, or when the job names it, and still runs only on the person's word for that route and its estimate.", + "enum": [ + "never", + "allowed", + null + ] + } + } + } + } + }, + "result": { + "title": "wai.quantum.job-result/1", + "description": "A job's result as the engine gives it, on every host: what was asked of the program, computed by the method its plan chose, with that method's accuracy class. The receipt seals the result without its receipt member, beside the request. A result names the engine that made it and this schema (engine and schema); results made before results carried them have neither and follow this schema all the same.", + "type": "object", + "required": [ + "method", + "qubits", + "gates", + "accuracy" + ], + "properties": { + "engine": { + "type": "object", + "description": "The engine that made the result: the wai-quantum crate's name and version.", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "const": "wai-quantum" + }, + "version": { + "type": "string", + "description": "Its semantic version, as MAJOR.MINOR.PATCH." + } + } + }, + "schema": { + "const": "wai.quantum.job-result/1", + "description": "The schema the result follows." + }, + "components": { + "type": "array", + "description": "The identity of every component that made the result, when a registered one took part (engine::registry): its program's format, the passes its compile ran, the noise channels it names, its method; each registered one marked so. Sealed by the receipt with the rest.", + "items": { + "type": "object", + "description": "One component that made the result (engine::registry): its kind, name and version, the BLAKE3 digest of its descriptor, and whether it is built in. A result carries these only when a registered component took part; one made by built-ins alone names them as it always has (its method, its compile's passes, its noise's channels and the engine's version), the digests of that version listed by the components list.", + "required": [ + "kind", + "name", + "version", + "digest", + "origin" + ], + "properties": { + "kind": { + "enum": [ + "method", + "pass", + "channel", + "front_end" + ] + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "digest": { + "type": "string", + "pattern": "^[0-9a-f]{64}$", + "description": "BLAKE3 of the component's descriptor in its canonical JSON (engine::registry::digest_of)." + }, + "origin": { + "enum": [ + "built-in", + "registered" + ], + "description": "built-in: the engine's own; registered: a host's own, added in its process, not part of the engine." + }, + "certified": { + "const": false, + "description": "Beside a registered component: the engine does not certify it." + } + } + } + }, + "method": { + "type": "string", + "description": "The method that ran the job (provider for a run on the person's own provider)." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": "integer", + "minimum": 0, + "description": "The program's gates, in standard gates (at most 2^53 - 1), however the method ran them." + }, + "operations": { + "type": "integer", + "minimum": 0, + "description": "When the method held a gate under many controls as one (statevector, and exact asked for it): the operations it ran." + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "state_hash": { + "type": "string", + "description": "The bit-exact method's statevector hash (BLAKE3, hex): the same on every machine." + }, + "counts": { + "type": "object", + "description": "Outcomes and their counts, keyed by the program's classical bits, the highest bit first. At most 65536 outcomes are listed; omitted_shots holds the rest.", + "additionalProperties": { + "type": "integer", + "minimum": 0 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "outcome_dimension": { + "type": "integer", + "minimum": 0, + "description": "The stabilizer method: the dimension of the measured outcomes' affine space." + }, + "shots": { + "type": "integer", + "minimum": 0, + "description": "The shots, where the method names them in the result (trajectories, provider)." + }, + "expectations": { + "type": "array", + "items": { + "type": "object", + "required": [ + "observable", + "coeff", + "value" + ], + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "value": { + "type": "number", + "description": "The coefficient times the expectation value." + }, + "stderr": { + "type": "number", + "description": "The standard error, for an estimate." + }, + "bound": { + "type": "number", + "description": "A bound on |exact − value|: rigorous for the bounded class; with confidence beside it, holding with that probability." + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + }, + "max_terms": { + "type": "integer" + }, + "ladder": { + "type": "array", + "description": "The value at thresholds a decade apart, the asked one last.", + "items": { + "type": "object", + "required": [ + "threshold", + "value", + "bound" + ], + "properties": { + "threshold": { + "type": "number" + }, + "value": { + "type": "number" + }, + "bound": { + "type": "number" + }, + "peak_terms": { + "type": "integer" + }, + "threshold_reached": { + "type": "number" + } + } + } + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds, for a bound that holds with a stated probability (stabilizer_rank's sampled mode)." + } + } + } + }, + "amplitudes": { + "type": "array", + "items": { + "type": "object", + "required": [ + "bits", + "re", + "im" + ], + "properties": { + "bits": { + "type": "string", + "description": "One 0 or 1 per qubit, qubit n-1 first." + }, + "re": { + "type": "number" + }, + "im": { + "type": "number" + }, + "bound": { + "type": "number", + "minimum": 0, + "description": "A bound on |exact − value| of the amplitude, holding with the probability confidence states (stabilizer_rank's sampled mode)." + }, + "confidence": { + "type": "number", + "description": "The probability the bound holds." + } + } + } + }, + "global_phase": { + "type": "string", + "description": "Why the amplitudes' global phase is not fixed, when it is not." + }, + "warning": { + "type": "string" + }, + "contraction_flops": { + "type": "number", + "description": "The tensor network's contraction cost." + }, + "dynamic": { + "type": "object", + "description": "A program that measures in the middle, resets or branches on a measured bit: how it ran.", + "properties": { + "measurements_and_resets": { + "type": "integer", + "minimum": 0 + }, + "branches_run": { + "type": "integer", + "minimum": 0 + }, + "states_at_once": { + "type": "integer", + "minimum": 0 + }, + "branches_weighed": { + "type": "integer", + "minimum": 0 + } + } + }, + "outputs": { + "type": "array", + "description": "The program's output declarations: each its name and type, and its value, or the places of its bits in each outcome.", + "items": { + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "bits": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + } + }, + "value": { + "description": "A number, a boolean, a bit string, a duration's text, {\"re\", \"im\"}, or an array of them." + } + } + } + }, + "timing": { + "type": "object", + "description": "A program that states durations (delay, box, stretch) the method does not apply: said so, with the reader's code.", + "required": [ + "applied", + "why" + ], + "properties": { + "applied": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "diagnostics": { + "type": "array", + "description": "The reader's warnings and notes on the program, each with its code.", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "compiled": { + "description": "How the program was compiled before it ran: on the person's own provider, to the device's gates; or, asked with compile, to a basis within a budget. Either way, basis is the gate set it was compiled to.", + "anyOf": [ + { + "type": "object", + "description": "A provider job: the program sent, compiled exactly to the device's own gates: its basis (the device's gate set), its OpenQASM 3 text (qasm3) and that text's BLAKE3 (program), its counts of gates and swaps, its layouts, and the check it passed before it was sent. Results sealed before qasm3 carry the hash alone.", + "required": [ + "basis", + "program" + ], + "properties": { + "basis": { + "type": "string" + }, + "program": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "qasm3": { + "type": "string", + "description": "The program sent, as OpenQASM 3, $i being index i of the coupling map the provider described; program is the BLAKE3 of its UTF-8 bytes." + }, + "qubit_names": { + "type": "object", + "additionalProperties": { + "type": "string", + "minLength": 1 + }, + "description": "The device's own name for each index the program uses, as it was when the job was sent, where a client sends it under those names." + }, + "native_gates": { + "type": "integer" + }, + "two_qubit_gates": { + "type": "integer" + }, + "swaps": { + "type": "integer" + }, + "layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "final_layout": { + "type": "array", + "items": { + "type": "integer" + } + }, + "checked": { + "type": "string" + }, + "placement": { + "type": "object", + "description": "Where the program was placed on the device's qubits, and why." + } + } + }, + { + "type": "object", + "description": "A job asked to compile its program first: what ran is the compiled circuit, within distance of the program in the operator norm up to a global phase.", + "required": [ + "basis", + "verdict" + ], + "properties": { + "basis": { + "enum": [ + "clifford_t", + "standard" + ], + "description": "The gate set the program was compiled to." + }, + "level": { + "type": "integer", + "minimum": 0 + }, + "epsilon": { + "type": "number", + "description": "The budget asked for." + }, + "distance": { + "type": [ + "number", + "null" + ], + "description": "The bound the passes' distances add to." + }, + "verdict": { + "type": "string" + }, + "source": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "output": { + "type": "object", + "description": "A circuit's counts, as the compiler counts them.", + "properties": { + "gates": { + "type": "integer", + "minimum": 0 + }, + "one_qubit": { + "type": "integer", + "minimum": 0 + }, + "two_qubit": { + "type": "integer", + "minimum": 0 + }, + "three_qubit": { + "type": "integer", + "minimum": 0 + }, + "cnots": { + "type": "integer", + "minimum": 0 + }, + "t_count": { + "type": "integer", + "minimum": 0 + }, + "rotations": { + "type": "integer", + "minimum": 0 + }, + "depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ], + "description": "The BLAKE3 of the compile certificate's RFC 8785 text, in hex." + }, + "note": { + "type": "string" + } + } + } + ] + }, + "verdict": { + "title": "wai.quantum.verdict/1", + "description": "How far the engine checked an answer about a program, as one level of an ordered ladder (wai-quantum://docs/verdicts): refused, parsed, executed, evidence, proof. A level says how far the engine checked, not that the answer is good: holds says whether the intents held (true, false, or null when none was decided). A job's result carries one under verdict when the job gives an intent or asks for one, and the receipt seals it; both MCP servers state one beside every answer about a program.", + "type": "object", + "required": [ + "schema", + "level", + "rank", + "holds", + "statement", + "parsed", + "executed", + "intent", + "critique", + "repairs" + ], + "properties": { + "schema": { + "const": "wai.quantum.verdict/1" + }, + "level": { + "enum": [ + "refused", + "parsed", + "executed", + "evidence", + "proof" + ] + }, + "rank": { + "type": "integer", + "minimum": 0, + "maximum": 4, + "description": "The level's place on the ladder, from 0 (refused) to 4 (proof)." + }, + "holds": { + "type": [ + "boolean", + "null" + ] + }, + "statement": { + "type": "string", + "description": "The level in one plain line." + }, + "parsed": { + "type": "object", + "description": "Whether the reader took the program, and its warnings and notes with their codes, or its refusal.", + "required": [ + "ok" + ], + "properties": { + "ok": { + "type": "boolean" + }, + "diagnostics": { + "type": "array", + "items": { + "type": "object", + "description": "One of the reader's diagnostics: its code, what happens to the construct it is about, its message (without the line or the code), and where it stands.", + "required": [ + "code", + "outcome", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "lowered", + "carried", + "preserved", + "warned" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "code": { + "type": "string" + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "message": { + "type": "string" + }, + "line": { + "type": "integer", + "minimum": 1 + }, + "column": { + "type": "integer", + "minimum": 1 + }, + "length": { + "type": "integer", + "minimum": 0 + }, + "text": { + "type": "string", + "description": "The refusal as the reader wrote it, with its line and code." + } + } + }, + "executed": { + "type": [ + "object", + "null" + ], + "description": "The method that ran and its accuracy class, and the distance a compile put between the program and what ran.", + "properties": { + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "compiled_distance": { + "type": [ + "number", + "null" + ] + } + } + }, + "intent": { + "type": "array", + "items": { + "type": "object", + "description": "One intent's check: what it asked, whether it held, how strong the check was and how it was made.", + "required": [ + "kind", + "outcome", + "strength", + "how" + ], + "properties": { + "kind": { + "enum": [ + "distribution", + "equivalent", + "prepares", + "sampled", + "compiled" + ] + }, + "outcome": { + "enum": [ + "holds", + "fails", + "unchecked" + ] + }, + "strength": { + "enum": [ + "proof", + "evidence", + "none" + ] + }, + "how": { + "type": "string" + }, + "why": { + "type": "string" + }, + "distance": { + "type": "number" + }, + "tolerance": { + "type": "number" + }, + "outcomes": { + "type": "integer", + "description": "The outcomes the distribution holds, or the samples' distinct outcomes." + }, + "distribution": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The program's distribution, when its outcomes are few enough to list." + }, + "largest_gaps": { + "type": "array", + "items": { + "type": "object", + "properties": { + "outcome": { + "type": "string" + }, + "program": { + "type": "number" + }, + "intent": { + "type": "number" + } + } + } + }, + "global_phase": { + "type": [ + "number", + "null" + ] + }, + "method": { + "type": "string", + "description": "A sampled intent: the method the samples were run by." + }, + "seed": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "alpha": { + "type": "number" + }, + "fit": { + "type": "object", + "description": "A sampled intent: the test, its statistic, degrees of freedom and p-value, the level, and whether it rejected.", + "properties": { + "test": { + "type": "string" + }, + "statistic": { + "type": "number" + }, + "dof": { + "type": "integer" + }, + "p_value": { + "type": "number" + }, + "alpha": { + "type": "number" + }, + "shots": { + "type": "integer" + }, + "rejected": { + "type": "boolean" + }, + "smallest_expected": { + "type": [ + "number", + "null" + ] + }, + "impossible": { + "type": [ + "integer", + "array", + "boolean" + ] + }, + "note": { + "type": "string" + } + } + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "name": { + "type": "string" + }, + "note": { + "type": "string" + } + } + } + }, + "critique": { + "type": "array", + "description": "The program's smells, each with its lines.", + "items": { + "type": "object" + } + }, + "repairs": { + "type": "array", + "description": "Each edit a repair made, with the code it answered and the lines it changed.", + "items": { + "type": "object" + } + }, + "refusal": { + "type": "object", + "description": "For a refused job: its message and its codes.", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": [ + "string", + "null" + ] + }, + "codes": { + "type": "array", + "items": { + "type": "string" + } + }, + "outcome": { + "enum": [ + "refused", + "retry", + "failed", + "lowered", + "carried", + "preserved", + "warned", + "dropped", + "defaulted" + ] + }, + "meaning": { + "type": "string" + } + } + }, + "sealed": { + "type": "boolean" + } + } + }, + "target": { + "type": "object", + "description": "A run on a device target: which target (its hash, as its receipt binds it), its calibration snapshot, where the program was placed and why, and the noise derived from the target.", + "required": [ + "name", + "hash" + ], + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "hash_is": { + "type": "string" + }, + "calibration": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "source": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "note": { + "type": "string" + } + } + }, + "placement": { + "type": "object", + "description": "The native gate set, the layout and routes chosen, the swaps, the expected success beside the fewest-swaps layout's, and the check of the compiled program." + }, + "noise": { + "type": "object", + "description": "The noise model derived from the target's calibration: its channels, durations and idling, and each qubit's readout." + } + } + }, + "fabric": { + "type": "object", + "description": "Where the state vector, or the pauli method's sum of terms, ran: the kernel, the placement the job asked for, the member that ran it (or each partition's), each with its certificate, and the energy. Present when the job asked for a placement, or when auto placed the state on a member by measurement (`auto`); a job auto leaves on the CPU names nothing; the receipt seals it with the rest of the result. Every member placed is certified bit-exact, so the answers are the CPU's, byte for byte.", + "required": [ + "kernel", + "asked", + "parity", + "energy" + ], + "properties": { + "kernel": { + "type": "string" + }, + "asked": { + "description": "The placement the job asked for, as it gave it.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "partitions": { + "type": "array", + "description": "Each partition's member, by the value of the state's top qubits: partition i holds the amplitudes whose top bits read i.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "partition_qubits": { + "type": "integer", + "minimum": 0 + }, + "local_qubits": { + "type": "integer", + "minimum": 0 + }, + "segments": { + "type": "integer", + "minimum": 0, + "description": "Runs of gates the partitions took in turn, between exchanges." + }, + "exchanges": { + "type": "integer", + "minimum": 0, + "description": "Partition qubits exchanged with local ones through the host's copy of the state." + }, + "fell_back_from": { + "type": "array", + "description": "An accelerator request whose member failed during the run: each member that failed, in turn, with how; the member named above ran the job.", + "items": { + "type": "object", + "description": "A member of the fabric and its certificate for the kernel: its id (which binds the device), its key, its class, the implementation, the parity tier, the certificate's digest (BLAKE3, hex), and the corpus it was earned on (its digest, generator and cases; the CPU reference's own standing has none).", + "required": [ + "member", + "implementation", + "parity", + "certificate" + ], + "properties": { + "member": { + "type": "string" + }, + "key": { + "type": "string" + }, + "class": { + "type": "string" + }, + "implementation": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "wide": { + "type": "object", + "description": "A member's certificate for gates on more than three qubits at once (wai.quantum.sv/run-wide): a fusion width of 4 to 6, or a wider gate, runs kernels the pinned corpus does not reach, certified on a corpus of their own (sv64-wide-v1). A member is placed for such a job only when this certificate is bit-exact; one that is not, or has none, says why and runs only gates on up to three qubits at once.", + "required": [ + "parity" + ], + "properties": { + "kernel": { + "type": "string" + }, + "parity": { + "type": "object", + "description": "A certificate's standing against the CPU reference: bit-exact, within a bound (max_ulp, max_abs), statistical (fidelity over shots) or uncertified. Only bit-exact members are placed.", + "required": [ + "tier" + ], + "properties": { + "tier": { + "enum": [ + "bit-exact", + "within", + "statistical", + "uncertified" + ] + }, + "max_ulp": { + "type": "integer", + "minimum": 0 + }, + "max_abs": { + "type": "number" + }, + "fidelity": { + "type": "number" + }, + "shots": { + "type": "integer", + "minimum": 0 + } + } + }, + "certificate": { + "type": "string" + }, + "corpus": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "cases": { + "type": "integer", + "minimum": 0 + }, + "why": { + "type": "string" + } + } + }, + "why": { + "type": "string", + "description": "For a member the job fell back from: how it failed." + } + } + } + }, + "auto": { + "type": "object", + "description": "Why auto placed the state where it ran: the rule (a member is placed only where the committed measurements show it faster than this host's CPU for the job's size and fusion width) and the measured row it rests on, with the host, the day and the load it was measured under. Present only when auto placed a state on a member.", + "required": [ + "rule", + "host", + "fusion", + "from_qubits", + "to_qubits" + ], + "properties": { + "rule": { + "type": "string" + }, + "host": { + "type": "string", + "description": "The host's processor as the measurements name it (cpu--)." + }, + "measured": { + "type": "string", + "description": "The day the host was measured (UTC)." + }, + "about": { + "type": "string" + }, + "load": { + "type": "string" + }, + "discovery_ms": { + "type": "number", + "description": "What discovering and certifying the host's members took, once per process, as measured." + }, + "fusion": { + "type": "integer", + "minimum": 1 + }, + "from_qubits": { + "type": "integer", + "minimum": 0 + }, + "to_qubits": { + "type": "integer", + "minimum": 0 + }, + "min_launches": { + "type": "integer", + "minimum": 0 + }, + "basis": { + "type": "object", + "description": "The measured row the job is judged by: the largest measured size at or below its own, the launches of its plan, the runs of each, and the spread of the CPU's and the member's times in milliseconds.", + "required": [ + "qubits", + "launches", + "runs", + "cpu_ms", + "member_ms" + ], + "properties": { + "qubits": { + "type": "integer", + "minimum": 0 + }, + "launches": { + "type": "integer", + "minimum": 0 + }, + "runs": { + "type": "integer", + "minimum": 0 + }, + "cpu_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + }, + "member_ms": { + "type": "object", + "description": "The least, the median and the most of a measured row's runs, in milliseconds.", + "required": [ + "min", + "median", + "max" + ], + "properties": { + "min": { + "type": "number" + }, + "median": { + "type": "number" + }, + "max": { + "type": "number" + } + } + } + } + } + } + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "why": { + "type": "string" + } + } + }, + "repaired": { + "type": "object", + "description": "A job asked to repair its program first: the program that ran, each repair, and what needs a person.", + "properties": { + "qasm": { + "type": "string" + }, + "repairs": { + "type": "array", + "items": { + "type": "object", + "required": [ + "code", + "by", + "edits" + ], + "properties": { + "code": { + "type": "string" + }, + "rule": { + "type": "string" + }, + "by": { + "enum": [ + "engine", + "proposal" + ] + }, + "flagged": { + "type": "array", + "items": { + "type": "integer" + } + }, + "edits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "line": { + "type": "integer" + }, + "before": { + "type": [ + "string", + "null" + ] + }, + "after": { + "type": [ + "string", + "null" + ] + } + } + } + } + } + } + }, + "needs_person": { + "type": "array", + "items": { + "type": "object" + } + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0, + "description": "Wall time of the run, where the host has a clock (not in a browser tab)." + }, + "energy": { + "description": "The CPU energy of the job's process as the kernel counts it, with its uncertainty and what it leaves out, or unmetered with the reason.", + "anyOf": [ + { + "type": "object", + "required": [ + "unmetered" + ], + "properties": { + "unmetered": { + "type": "string" + }, + "service_kwh": { + "type": "number", + "description": "A provider job: the provider's own figure." + }, + "service_kwh_is": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "joules_micro", + "energy_provenance", + "coverage" + ], + "properties": { + "joules_micro": { + "type": "integer", + "minimum": 1 + }, + "energy_provenance": { + "type": "string" + }, + "energy_uncertainty": { + "type": "object", + "properties": { + "relative_ppm": { + "type": "integer" + }, + "window_us": { + "type": "integer" + } + } + }, + "energy_counter_filtering": { + "type": "string" + }, + "coverage": { + "enum": [ + "whole", + "partial" + ] + }, + "covers": { + "type": "string" + }, + "excludes": { + "type": "array", + "items": { + "type": "string" + } + }, + "cpu_ms": { + "type": "integer" + }, + "source": { + "type": "string" + }, + "attribution": { + "enum": [ + "process", + "none" + ], + "description": "Whose energy it is: the job's worker process, or none (the processor packages' over the job's window, every process on the host in it)." + }, + "packages": { + "type": "integer", + "minimum": 1, + "description": "The processor packages read." + }, + "concurrent_jobs": { + "type": "integer", + "minimum": 0, + "description": "Other jobs that ran on the host during the window." + }, + "counter": { + "type": "object", + "description": "The package counter as seen: the longest it went between updates, and the smallest step it took.", + "properties": { + "update_us": { + "type": "integer", + "minimum": 0 + }, + "step_uj": { + "type": "integer", + "minimum": 0 + } + } + }, + "declared": { + "type": "string", + "description": "What the stated uncertainty covers, and what it does not." + } + } + } + ] + }, + "receipt": { + "anyOf": [ + { + "title": "wai.quantum.receipt/2", + "description": "A result's receipt: an Ed25519 signature, by the key it names, over digest = BLAKE3(\"wai:quantum-service-receipt\\x02\" ‖ len ‖ request ‖ len ‖ result), each of request and result in its RFC 8785 canonical text (the result without its receipt member), each length 8 bytes big-endian. Whatever members the request and the result hold are sealed, the result's engine and schema among them. The first receipts (no canon member, $defs/first) sealed their writer's compact text under the domain ending \\x01; they still verify. wai/extensions/quantum-providers.md section 8.2 states the seal in full, and section 8.4 what a verifier checks.", + "type": "object", + "required": [ + "alg", + "canon", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "canon": { + "const": "rfc8785", + "description": "The canonical form the digest is taken over." + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The signing key, 32 bytes in lower-case hex." + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$", + "description": "The digest signed, 32 bytes in lower-case hex." + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$", + "description": "The signature, 64 bytes in lower-case hex." + } + } + }, + { + "description": "The first form, before canon: the digest is over the compact text its writer wrote of each, members in the document's order (section 8.2 of wai/extensions/quantum-providers.md), under the domain ending \\x01. Never written now; still verified.", + "type": "object", + "required": [ + "alg", + "key", + "digest", + "signature" + ], + "properties": { + "alg": { + "const": "ed25519" + }, + "key": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "digest": { + "type": "string", + "minLength": 64, + "maxLength": 64, + "pattern": "^[0-9a-f]{64}$" + }, + "signature": { + "type": "string", + "minLength": 128, + "maxLength": 128, + "pattern": "^[0-9a-f]{128}$" + } + } + } + ] + }, + "provider": { + "type": "object", + "description": "A provider job: the provider's name, kind and protocol, the device, its provenance, and the hash of its description." + }, + "counts_source": { + "enum": [ + "shots", + "vendor_counts", + "probabilities" + ], + "description": "A provider job: where its counts come from (wai/extensions/quantum-providers.md section 8.3): tallied from one record a shot (shots), the provider's own counts (vendor_counts), or rebuilt from the probabilities it returned by largest remainders, derived and not shot records (probabilities). Results sealed before it carry neither it nor execution." + }, + "execution": { + "type": "object", + "description": "A provider job: how the device was asked to run the program (section 8.3): who states it (stated_by: client, provider or nobody); what the client sent (sent: the request's members and the settings among them); each of mitigation, twirling, decoupling, remapping and optimisation (off, on, default when the request sets nothing for it, none when the device has no such step, unknown when nobody states it); whether the gates were to run as written (verbatim); and a note.", + "required": [ + "stated_by", + "mitigation", + "twirling", + "decoupling", + "remapping", + "optimisation", + "verbatim" + ], + "properties": { + "stated_by": { + "enum": [ + "client", + "provider", + "nobody" + ] + }, + "sent": { + "type": "object", + "required": [ + "fields", + "settings" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "settings": { + "type": "object" + } + }, + "additionalProperties": false + }, + "mitigation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "twirling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "decoupling": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "remapping": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "optimisation": { + "enum": [ + "off", + "on", + "default", + "none", + "unknown" + ], + "description": "What happened to one step: off or on (by a setting the client sent, or as the provider states), default (the request sets nothing for it, so the provider's default stands), none (the device has no such step), unknown (nobody states it)." + }, + "verbatim": { + "type": [ + "boolean", + "null" + ] + }, + "note": { + "type": "string" + } + }, + "additionalProperties": false + }, + "calibration": { + "type": [ + "string", + "null" + ], + "description": "A provider job: the calibration snapshot it ran under." + }, + "job": { + "type": "object", + "description": "A provider job: the provider's job id and its status checks." + }, + "ideal": { + "description": "A provider job: the circuit's exact distribution set beside the measured counts.", + "anyOf": [ + { + "type": "object", + "required": [ + "computed", + "total_variation_distance", + "hellinger_fidelity" + ], + "properties": { + "computed": { + "const": true + }, + "method": { + "type": "string" + }, + "total_variation_distance": { + "type": "number" + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_expected": { + "type": "number" + }, + "ideal_outcomes": { + "type": "integer" + }, + "note": { + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "computed", + "why" + ], + "properties": { + "computed": { + "const": false + }, + "why": { + "type": "string" + } + } + } + ] + }, + "cost": { + "type": "object", + "description": "A provider job: the estimate shown before it was sent, what the provider says it charged, and whether the person confirmed a run that was not free." + }, + "provenance": { + "title": "wai.quantum.provenance/1", + "description": "What a result came from, under the five categories cross-platform provenance surveys use: the circuit, the computer, the compilation, the execution and the software. A host adds it to the results it seals (the job service does, and each item of a set); a result without it reads as it always did. wai-quantum-service/docs/provenance.md maps every field to where it is and whether the receipt seals it.", + "type": "object", + "required": [ + "schema", + "circuit", + "computer", + "compilation", + "execution", + "software" + ], + "properties": { + "schema": { + "const": "wai.quantum.provenance/1" + }, + "circuit": { + "type": "object", + "description": "The program: the BLAKE3 digest of its text as given, its qubits and its gates.", + "required": [ + "program" + ], + "properties": { + "program": { + "type": "string", + "description": "BLAKE3 of the program's text, in hex." + }, + "qubits": { + "type": "integer", + "minimum": 0 + }, + "gates": { + "type": [ + "integer", + "null" + ] + } + } + }, + "computer": { + "type": "object", + "description": "What ran it: a classical simulator, the method and its accuracy class, a device target's hash when the job named one, and the fabric's members when the result names where its state ran.", + "required": [ + "kind", + "method" + ], + "properties": { + "kind": { + "const": "simulator" + }, + "method": { + "type": "string" + }, + "accuracy": { + "type": [ + "string", + "null" + ] + }, + "target": { + "type": "string", + "description": "The device target's hash; its layout, routes and noise are in the result's own target." + }, + "fabric": { + "type": "object", + "description": "The kernel and the member that ran the state, or each partition's, as the result's fabric names them.", + "properties": { + "kernel": { + "type": "string" + }, + "members": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "compilation": { + "type": "object", + "description": "Whether the job asked to be compiled; if it did, each pass in order with its check's verdict, the certificate's digest, the gate set compiled to (its basis), the level, the ε budget and the distance the result carries, and that no pass draws a random number.", + "required": [ + "asked" + ], + "properties": { + "asked": { + "type": "boolean" + }, + "passes": { + "type": [ + "array", + "null" + ], + "items": { + "type": "object", + "properties": { + "pass": { + "type": "string" + }, + "verdict": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "certificate": { + "type": [ + "string", + "null" + ] + }, + "basis": { + "type": [ + "string", + "null" + ], + "description": "The gate set compiled to: clifford_t or standard." + }, + "level": { + "type": [ + "integer", + "null" + ] + }, + "epsilon": { + "type": [ + "number", + "null" + ] + }, + "distance": { + "type": [ + "number", + "null" + ] + }, + "seeded": { + "const": false + }, + "device": { + "type": "string", + "description": "A job on a device target, compiled exactly to its gates: where its layout and routes are." + }, + "status": { + "const": "not-applicable" + }, + "why": { + "type": "string" + } + } + }, + "execution": { + "type": "object", + "description": "The shots, the seed and the plan the job ran under; its identifier and times are the host's, outside the result.", + "required": [ + "plan" + ], + "properties": { + "shots": { + "type": [ + "integer", + "null" + ] + }, + "seed": { + "type": [ + "integer", + "null" + ] + }, + "plan": { + "type": "object", + "properties": { + "method": { + "type": "string" + }, + "why": { + "type": "string" + }, + "memory_bytes": { + "type": "integer", + "minimum": 0 + }, + "work": { + "type": "integer", + "minimum": 0 + } + } + } + } + }, + "software": { + "type": "object", + "description": "The engine's name and version, and the host's.", + "required": [ + "engine", + "host" + ], + "properties": { + "engine": { + "type": "string" + }, + "host": { + "type": "string" + } + } + } + } + }, + "mitigation": { + "title": "wai.quantum.mitigation/1", + "description": "A job's mitigation (its request's mitigate, engine::mitigate), in its result: the method and the options it ran with, its bias and variance assumptions, each observable raw and mitigated with a standard error each and the ideal value (or, for readout, the counts inverted as a quasi-distribution), the method's own details and what it spent. docs/qec.md describes each method.", + "type": "object", + "required": [ + "method", + "options", + "assumptions" + ], + "properties": { + "method": { + "enum": [ + "zne", + "pea", + "pec", + "cdr", + "vd", + "readout" + ] + }, + "options": { + "type": "object", + "description": "The options it ran with, the defaults filled in.", + "properties": { + "method": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "factors": { + "type": "array", + "items": { + "type": "number" + } + }, + "extrapolation": { + "enum": [ + "richardson", + "linear", + "exponential" + ] + }, + "samples": { + "type": "integer" + }, + "training": { + "type": "integer" + }, + "keep": { + "type": "integer" + }, + "learn_shots": { + "type": "integer" + } + } + }, + "assumptions": { + "type": "object", + "properties": { + "bias": { + "type": "string" + }, + "variance": { + "type": "string" + } + } + }, + "noise": { + "type": "string", + "description": "How the job's noise model is read for the method." + }, + "note": { + "type": "string" + }, + "observables": { + "type": "array", + "items": { + "type": "object", + "description": "One observable: its raw value and the mitigated one, each with its standard error, and the ideal value a simulation knows.", + "properties": { + "observable": { + "type": "string" + }, + "coeff": { + "type": "number" + }, + "raw": { + "type": "number" + }, + "raw_stderr": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + }, + "ideal": { + "type": "number" + } + } + } + }, + "distribution": { + "type": "array", + "description": "readout: each outcome's raw share and its mitigated quasi-probability, with its standard error.", + "items": { + "type": "object", + "properties": { + "bits": { + "type": "string" + }, + "raw": { + "type": "number" + }, + "mitigated": { + "type": "number" + }, + "stderr": { + "type": "number" + } + } + } + }, + "details": { + "type": "object", + "description": "The method's own: the folded scales and the folding check (zne), the learned model and the amplified values (pea), the quasi-probability and the value it converges to (pec), the training fits (cdr), the purity (vd), the flip and its amplification (readout).", + "additionalProperties": true + }, + "cost": { + "type": "object", + "description": "The circuits and shots it spent beyond the job's own.", + "properties": { + "circuits": { + "type": "integer", + "minimum": 0 + }, + "shots": { + "type": "integer", + "minimum": 0 + }, + "note": { + "type": "string" + } + } + } + } + }, + "pulse": { + "type": "object", + "description": "A pulse run (method pulse, engine::pulse): what was read and its distribution, the final populations, each capture's reading, the final density matrix's digest, the schedule's length, the integrator and its step, the device and where each parameter came from, and what the receipt binds (calibration).", + "required": [ + "read", + "outcome_bits", + "populations", + "simulated_qubits", + "density_hash", + "integrator", + "device", + "calibration" + ], + "properties": { + "read": { + "type": "string", + "description": "What the distribution reads: the captures together (into the program's bits when each writes one), or the final state." + }, + "outcome_bits": { + "type": "array", + "items": { + "type": "string" + }, + "description": "What each character of an outcome is, left to right: a program bit (c[0]) or a qubit ($0)." + }, + "distribution": { + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "number" + }, + "description": "The probability of each outcome, which the counts sample; null when the captures start at different samples." + }, + "populations": { + "type": "object", + "additionalProperties": { + "type": "number" + }, + "description": "The final state read on every simulated qubit, the highest qubit first, a level above 0 read as 1." + }, + "simulated_qubits": { + "type": "array", + "items": { + "type": "integer" + } + }, + "captures": { + "type": "array", + "items": { + "type": "object", + "properties": { + "frame": { + "type": "string" + }, + "qubit": { + "type": "integer" + }, + "start": { + "type": "integer" + }, + "start_ns": { + "type": "number" + }, + "bit": { + "type": [ + "string", + "null" + ] + }, + "p1": { + "type": "number" + }, + "p2": { + "type": "number" + } + } + } + }, + "leakage": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "p2": { + "type": "number" + } + } + }, + "description": "With three levels: each qubit's final probability of level 2." + }, + "trace": { + "type": "number" + }, + "density_hash": { + "type": "string", + "description": "The BLAKE3 of the final density matrix's bits: the same on every platform." + }, + "duration": { + "type": "integer" + }, + "duration_ns": { + "type": "number" + }, + "integrator": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "order": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "substeps": { + "type": "integer" + }, + "step_ns": { + "type": "number" + }, + "steps": { + "type": "integer" + }, + "norm_max": { + "type": "number" + }, + "frame": { + "type": "string" + } + } + }, + "device": { + "type": "object", + "properties": { + "levels": { + "type": "integer" + }, + "dt_ns": { + "type": "number" + }, + "qubits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "qubit": { + "type": "integer" + }, + "frequency_hz": { + "type": "number" + }, + "rabi_hz": { + "type": "number" + }, + "anharmonicity_hz": { + "type": "number" + }, + "t1_ns": { + "type": "number" + }, + "t2_ns": { + "type": "number" + }, + "from": { + "type": "object", + "additionalProperties": { + "enum": [ + "pulse", + "target", + "default", + "none" + ] + } + } + } + } + }, + "couplings": { + "type": "array" + }, + "model": { + "type": "string" + } + } + }, + "calibration": { + "type": "object", + "description": "What the receipt binds: the program's, its calibrations', the schedule's and the device's digests, and the target snapshot.", + "properties": { + "program": { + "type": "string" + }, + "calibrations": { + "type": "string" + }, + "schedule": { + "type": "string" + }, + "device": { + "type": "string" + }, + "target": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "calibration": { + "type": "object" + } + } + } + } + }, + "not_modelled": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "planner": { + "description": "Why this route ran (wai.quantum.planner/1): every route the host could see, each one's price or reason for rejection, and the choice. Sealed by the receipt; a verifier recomputes each route's outcome and the choice from what it states (wai/extensions/quantum-providers.md section 8.7). A plan carries it too, with the refusal in place of the choice when no route meets the contract.", + "type": "object", + "required": [ + "format", + "wanted", + "wanted_from", + "auto", + "host", + "routes", + "choice", + "why", + "stable", + "named", + "question" + ], + "properties": { + "format": { + "const": "wai.quantum.planner/1" + }, + "wanted": { + "type": [ + "string", + "null" + ], + "description": "The class wanted: the contract's, else that of the route the job names or auto's pick." + }, + "wanted_from": { + "enum": [ + "contract", + "named", + "auto", + null + ] + }, + "named": { + "type": [ + "string", + "null" + ], + "description": "The route the job names: the provider or the method its request names, or the one method a device target's job runs on; null when it names none." + }, + "question": { + "enum": [ + "noise", + "counts", + "expectations", + "amplitudes" + ], + "description": "The question the job asks, read from its request, which orders the methods auto tries (section 8.7)." + }, + "auto": { + "type": [ + "string", + "null" + ], + "description": "The route auto picks, when the job leaves the method to it." + }, + "host": { + "type": "object", + "required": [ + "job_bytes", + "providers" + ], + "properties": { + "job_bytes": { + "type": "number", + "minimum": 0 + }, + "providers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "routes": { + "type": "array", + "items": { + "description": "One route the planner could see: its class, its price or why it has none, and what came of it.", + "type": "object", + "required": [ + "route", + "kind", + "class", + "host_dependent", + "price", + "outcome" + ], + "properties": { + "route": { + "type": "string", + "description": "method: or provider:." + }, + "kind": { + "enum": [ + "local", + "provider" + ] + }, + "method": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "device": { + "type": "string" + }, + "provenance": { + "type": "string" + }, + "approximate": { + "const": true + }, + "class": { + "type": "string", + "description": "The accuracy class its result has at worst: a matrix product state's is heuristic, though its result may say exact." + }, + "host_dependent": { + "type": "boolean", + "description": "Whether it depends on the host: a provider's, a method on a GPU, or a registered method." + }, + "auto_rank": { + "type": [ + "integer", + "null" + ], + "minimum": 0, + "description": "On a local route: its rank in auto's order for the job's question, or null where auto does not try it; a built-in method's is section 8.7's table." + }, + "price": { + "anyOf": [ + { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + { + "type": "null" + } + ] + }, + "outcome": { + "enum": [ + "chosen", + "met", + "rejected" + ] + }, + "rejected": { + "type": "object", + "required": [ + "code", + "why" + ], + "properties": { + "code": { + "enum": [ + "not_named", + "fabric", + "class", + "cannot", + "memory", + "providers", + "deadline", + "deadline_unknown", + "cost", + "cost_currency", + "cost_unknown", + "cost_at_least", + "cost_no_ceiling", + "energy", + "energy_unknown" + ] + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "choice": { + "type": [ + "string", + "null" + ] + }, + "why": { + "type": "string" + }, + "refusal": { + "description": "When no route meets the contract, in a plan: the refusal as data.", + "type": "object" + }, + "stable": { + "type": "object", + "required": [ + "scope", + "routes", + "digest", + "choice" + ], + "properties": { + "scope": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + } + }, + "digest": { + "type": "string" + }, + "choice": { + "type": "boolean" + } + } + }, + "shadow": { + "description": "The classical method that would shadow a provider's answer within the contract, or why none can.", + "type": "object", + "required": [ + "route" + ], + "properties": { + "route": { + "type": [ + "string", + "null" + ] + }, + "class": { + "type": "string" + }, + "request": { + "type": "object" + }, + "budget_seconds": { + "type": "number", + "minimum": 0 + }, + "price": { + "description": "What a route costs, with what is really known: a method's memory and work as the planner counts them and its time at the planner's nominal rate; a provider's own estimate, with what that leaves out.", + "type": "object", + "required": [ + "money", + "time", + "memory_bytes", + "work", + "energy", + "leaves_out" + ], + "properties": { + "money": { + "description": "What a route costs in money: free, an amount in a currency, or why that is not known. An unknown cost is not free.", + "type": "object", + "required": [ + "free" + ], + "properties": { + "free": { + "type": "boolean" + }, + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unknown": { + "type": "string" + }, + "at_least": { + "const": true, + "description": "The amount is the least the job can come to: what it takes decides the rest, so it meets no ceiling (cost_at_least)." + } + } + }, + "time": { + "type": "object", + "required": [ + "seconds" + ], + "properties": { + "seconds": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "enum": [ + "nominal", + "provider" + ] + }, + "why": { + "type": "string" + } + } + }, + "memory_bytes": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "work": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "energy": { + "type": "object", + "required": [ + "joules" + ], + "properties": { + "joules": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "basis": { + "type": "string" + }, + "why": { + "type": "string" + } + } + }, + "leaves_out": { + "description": "What this price leaves out: time (it states no time), amount (it states no amount), energy, mitigation (what the provider's own mitigation costs or does), decoder (any decoder's latency), charged (what the provider charges may differ from what it estimates), cancel (its client cannot stop a job it sent).", + "type": "array", + "items": { + "enum": [ + "time", + "amount", + "energy", + "mitigation", + "decoder", + "charged", + "cancel" + ] + } + }, + "program": { + "description": "What the job asks of a provider's device: its shots, and the compiled program's gates and swaps, and its expected success when a calibration states one.", + "type": "object", + "properties": { + "shots": { + "type": "integer", + "minimum": 0 + }, + "native_gates": { + "type": "integer", + "minimum": 0 + }, + "two_qubit_gates": { + "type": "integer", + "minimum": 0 + }, + "swaps": { + "type": "integer", + "minimum": 0 + }, + "expected_success": { + "type": "number" + } + } + } + } + }, + "code": { + "enum": [ + "budget", + "memory", + "none" + ] + }, + "why": { + "type": "string" + }, + "tried": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route": { + "type": "string" + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } + } + } + } + }, + "kept": { + "description": "What the contract asked, against what happened; each kept is null when it cannot be said. A result that missed one is sealed and says so.", + "type": "object", + "properties": { + "deadline": { + "type": "object", + "required": [ + "seconds", + "elapsed_ms", + "kept" + ], + "properties": { + "seconds": { + "type": "number" + }, + "elapsed_ms": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "energy": { + "type": "object", + "required": [ + "max_joules", + "joules", + "kept" + ], + "properties": { + "max_joules": { + "type": "number" + }, + "joules": { + "type": [ + "number", + "null" + ] + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + }, + "cost": { + "type": "object", + "required": [ + "max_cost", + "charged", + "kept" + ], + "properties": { + "max_cost": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "charged": { + "type": [ + "object", + "null" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + } + } + }, + "kept": { + "type": [ + "boolean", + "null" + ] + } + } + } + } + } + } + }, + "shadow": { + "description": "A classical method's answer beside a provider's, and their distance, for a contract job a provider answered; or why there is none. Its request can be run again by anyone, to the same counts.", + "type": "object", + "required": [ + "ran" + ], + "properties": { + "ran": { + "type": "boolean" + }, + "route": { + "type": "string" + }, + "accuracy": { + "type": "object", + "description": "What the method promises of the numbers it gave.", + "required": [ + "class" + ], + "properties": { + "class": { + "enum": [ + "bit-exact", + "exact", + "single", + "bounded", + "estimate", + "heuristic", + "measured", + "simulated" + ], + "description": "bit-exact: the same bits on every machine; exact: no approximation beyond double-precision rounding; single: single-precision arithmetic; bounded: a rigorous bound beside each value; estimate: a statistical estimate with its standard error; heuristic: an approximation with an estimate of its error, not a bound; measured: counts a processor returned through the person's provider, not reproducible by recomputation; simulated: counts a provider's simulator or emulator returned, measured on no device. Results sealed before simulated existed label a provider's simulator measured, and are read by its provenance." + }, + "approximate": { + "const": true, + "description": "A simulated result whose provider states its simulator is approximate." + }, + "note": { + "type": "string" + }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "fusion": { + "type": "integer" + }, + "device": { + "type": "string" + }, + "threshold": { + "type": "number" + }, + "max_weight": { + "type": [ + "integer", + "null" + ] + }, + "max_bond": { + "type": "integer" + }, + "max_bond_used": { + "type": "integer" + }, + "discarded_weight": { + "type": "number" + }, + "fidelity_estimate": { + "type": "number" + }, + "truncations": { + "type": "integer" + }, + "shots": { + "type": "integer" + }, + "trajectories": { + "type": "integer" + }, + "histories": { + "type": "integer" + }, + "gate_applications": { + "type": "integer" + }, + "max_cut": { + "type": "integer" + }, + "order_work": { + "type": "number" + }, + "batch": { + "type": "integer" + }, + "bound": { + "type": "number", + "description": "The bound this result is held to, by method: a pulse run (class bounded): every probability within this of the exact solution of the model's master equation, the truncation bound and the rounding estimate together; stabilizer_rank's sampled mode (class estimate): the bound on the distance of the estimated state from the state, holding with the probability confidence states.", + "minimum": 0 + }, + "truncation_bound": { + "type": "number", + "description": "A pulse run: the proved bound, in the trace norm, on what the integrator's series leaves out." + }, + "rounding_estimate": { + "type": "number", + "description": "A pulse run: an estimate of floating-point rounding beside the bound, not a proof." + }, + "tolerance": { + "type": "number" + }, + "norm": { + "type": "string" + }, + "t_count": { + "type": "integer", + "minimum": 0, + "description": "stabilizer_rank: the T and T† gates the program lowers to." + }, + "terms": { + "type": "integer", + "minimum": 1, + "description": "stabilizer_rank: the stabilizer branches summed (2^t exactly), or drawn." + }, + "confidence": { + "type": "number", + "description": "The probability a stated bound holds." + } + } + }, + "request": { + "type": "object", + "properties": { + "qasm": { + "type": "string" + }, + "shots": { + "type": "integer" + }, + "seed": { + "type": "integer" + }, + "method": { + "type": "string" + } + } + }, + "shots": { + "type": "integer", + "minimum": 1 + }, + "counts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 1 + } + }, + "distinct_outcomes": { + "type": "integer", + "minimum": 0 + }, + "omitted_shots": { + "type": "integer", + "minimum": 0 + }, + "distance": { + "type": "object", + "required": [ + "computed" + ], + "properties": { + "computed": { + "type": "boolean" + }, + "numerator": { + "type": "integer", + "minimum": 0 + }, + "denominator": { + "type": "integer", + "minimum": 1 + }, + "total_variation": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "hellinger_fidelity": { + "type": "number" + }, + "sampling_tvd_bound": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "A bound on the total variation the shots alone leave between two samples of one distribution, on average (section 8.7): each outcome's pooled count split as a fair coin splits it." + }, + "why": { + "type": "string" + } + } + }, + "elapsed_ms": { + "type": "integer", + "minimum": 0 + }, + "code": { + "type": "string" + }, + "why": { + "type": "string" + } + } } } }, diff --git a/wai/wai-quantum-cli/docs/service-mcp.json b/wai/wai-quantum-cli/docs/service-mcp.json index 38a647971..17ca0fd22 100644 --- a/wai/wai-quantum-cli/docs/service-mcp.json +++ b/wai/wai-quantum-cli/docs/service-mcp.json @@ -5048,6 +5048,71 @@ "note": { "type": "string" }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, "fusion": { "type": "integer" }, @@ -9827,6 +9892,71 @@ "note": { "type": "string" }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, "fusion": { "type": "integer" }, @@ -17829,6 +17959,71 @@ "note": { "type": "string" }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, "fusion": { "type": "integer" }, @@ -22608,6 +22803,71 @@ "note": { "type": "string" }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, "fusion": { "type": "integer" }, @@ -32355,6 +32615,71 @@ "note": { "type": "string" }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, "fusion": { "type": "integer" }, @@ -37134,6 +37459,71 @@ "note": { "type": "string" }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, "fusion": { "type": "integer" }, @@ -57848,6 +58238,71 @@ "note": { "type": "string" }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, "fusion": { "type": "integer" }, @@ -62627,6 +63082,71 @@ "note": { "type": "string" }, + "global_phase": { + "type": "object", + "description": "The bit-exact method: method statevector's state of the program that ran is e^(i radians) times the amplitudes given, since this method's lowering drops the phase of rz, rx, ry, rxx, ryy, rzz and u. Absent when that is 1. The language's own state can differ from both: its U is e^(i theta / 2) times the matrix both methods take as u, the reader drops an uncontrolled gphase (Q206), and a compiled job's program is the compile's, right up to a global phase.", + "required": [ + "turns_over_2_33", + "radians", + "note" + ], + "properties": { + "turns_over_2_33": { + "type": "integer", + "minimum": 0, + "description": "The phase exactly, in 2^33rds of a turn." + }, + "radians": { + "type": "number", + "description": "The same in radians, in (-pi, pi]." + }, + "note": { + "type": "string" + } + } + }, + "below_table": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering that are not zero and ran as no phase, within the reader's tolerance (1e-14 of a turn) of a whole turn. `angles` counts those gates: one angle written may be several, and another count in another form of the same program.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, + "moved_angles": { + "type": "object", + "description": "The bit-exact method: phase gates of its lowering within the reader's tolerance (1e-14 of a turn) of a dyadic angle, by more than a double's rounding of it, that ran as it. `angles` counts those gates.", + "required": [ + "angles", + "largest_radians", + "note" + ], + "properties": { + "angles": { + "type": "integer", + "minimum": 1 + }, + "largest_radians": { + "type": "number" + }, + "note": { + "type": "string" + } + } + }, "fusion": { "type": "integer" }, -- 2.54.0 (Apple Git-157) From e6dfb2606e7c6e25b4b27b8aafeecb280afbfbf2 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sun, 8 Nov 2026 09:48:31 -0500 Subject: [PATCH 26/42] wai-quantum: two tests that a loaded or unmetered Linux host failed The fake package counter's test asks the probe longer on a loaded host, and the service's stop test passes a host whose worker nothing reads (it refuses the route, J071), as it may not on a Mac. Co-Authored-By: Claude Opus 5.5 --- wai/wai-quantum-cli/src/estimates.rs | 2 +- wai/wai-quantum-service/tests/contract.rs | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/wai/wai-quantum-cli/src/estimates.rs b/wai/wai-quantum-cli/src/estimates.rs index 65c79d78f..a209f81f4 100644 --- a/wai/wai-quantum-cli/src/estimates.rs +++ b/wai/wai-quantum-cli/src/estimates.rs @@ -857,7 +857,7 @@ mod tests { }; // The probe wants a counter that ticks, and this one is a thread: a busy host // can starve it through a whole probe, which says nothing of what is tested. - let open = || (0..20).find_map(|_| energy::Packages::open_in(&d).ok()).expect("the counter never ticked through a probe"); + let open = || (0..60).find_map(|_| energy::Packages::open_in(&d).ok()).expect("the counter never ticked through a probe"); let p: &'static energy::Packages = Box::leak(Box::new(open())); // Every window is over the updates the probe found; a window the writer was // starved through reads nothing, as it should, so it is taken again. diff --git a/wai/wai-quantum-service/tests/contract.rs b/wai/wai-quantum-service/tests/contract.rs index d96981223..193cedded 100644 --- a/wai/wai-quantum-service/tests/contract.rs +++ b/wai/wai-quantum-service/tests/contract.rs @@ -160,6 +160,15 @@ fn a_job_is_stopped_at_its_energy_ceiling_and_its_receipt_says_so() { } let slow = json!({ "qasm": "OPENQASM 3.0;\nqubit[24] q;\nbit[24] c;\nrx(0.3) q[0];\nc = measure q;\n", "method": "statevector", "shots": 1000000, "contract": { "max_joules": 0.01 } }); let (code, made) = http(port, "POST", "/v1/jobs", Some(&slow)); + // A host whose worker nothing reads refuses the route, with why. + if code == 400 && made["code"] == "J071" && made["error"].as_str().is_some_and(|e| e.contains("reads no energy")) { + let _ = service.kill(); + let _ = service.wait(); + if cfg!(target_os = "macos") { + panic!("a Mac reads its worker's energy, so this test may not pass by skipping: {made}"); + } + return; + } assert_eq!(code, 202, "{made}"); let job = until_done(port, made["id"].as_str().unwrap()); let _ = service.kill(); -- 2.54.0 (Apple Git-157) From 358a61776a0f2e5a219e01ffbc78814b4b2e3183 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sun, 8 Nov 2026 13:40:09 -0500 Subject: [PATCH 27/42] wai-quantum: the fifth check: lists and objects compared alike in both verifiers, and recheck across versions held neither way - Both verifiers compare lists and objects member by member, by the same rule as their members: numbers by value, a boolean only to a boolean, null as absent. - A recheck of a receipt sealed by another engine version gives holds null even where this engine's prices or plans differ: what differs is said. Co-Authored-By: Claude Opus 5.5 --- wai/quantum-conformance/tools/receipt_verify.py | 7 +++++++ wai/wai-quantum/src/engine/planner.rs | 13 +++++++++++-- wai/wai-quantum/src/engine/planner/tests.rs | 9 +++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/wai/quantum-conformance/tools/receipt_verify.py b/wai/quantum-conformance/tools/receipt_verify.py index 8ec52c9fa..eca1c213b 100644 --- a/wai/quantum-conformance/tools/receipt_verify.py +++ b/wai/quantum-conformance/tools/receipt_verify.py @@ -1272,6 +1272,11 @@ def _alike(a, b): return isinstance(a, Num) and isinstance(b, Num) and float(a.value) == float(b.value) if isinstance(a, bool) or isinstance(b, bool): return isinstance(a, bool) and isinstance(b, bool) and a == b + # Lists and objects member by member, by the same rule. + if isinstance(a, list) or isinstance(b, list): + return isinstance(a, list) and isinstance(b, list) and len(a) == len(b) and all(_alike(x, y) for x, y in zip(a, b)) + if isinstance(a, dict) or isinstance(b, dict): + return isinstance(a, dict) and isinstance(b, dict) and all(_alike(a.get(k), b.get(k)) for k in set(a) | set(b)) return a == b @@ -2912,6 +2917,8 @@ def self_test(args): check("the route chosen names another device than ran", reasons_of(contract_edited(lambda b: chosen(b).update(device="elsewhere"))) == ["planner_choice"]) check("members alike by value: 7 and 7.0, -0 and 0", _alike(Num("7", 7.0), Num("7.0", 7.0)) and _alike(Num("-0", -0.0), Num("0", 0.0))) check("a boolean is no number, and null is absent", not _alike(True, Num("1", 1.0)) and _alike(None, None) and not _alike("a", None)) + check("lists and objects alike member by member", _alike([Num("7", 7.0)], [Num("7.0", 7.0)]) and _alike({"a": Num("-0", -0.0), "b": None}, {"a": Num("0", 0.0)}) + and not _alike([True], [Num("1", 1.0)]) and not _alike({"a": "x"}, {"a": "y"})) check("an earlier-form provider result under a contract", "contract_form" in reasons_of(contract_edited( lambda b: [b["result"].pop(k) for k in ("counts_source", "execution")]))) check("the route chosen names the device that ran", reasons_of(contract_edited(lambda b: chosen(b).update(device=b["result"]["provider"]["device"]))) == []) diff --git a/wai/wai-quantum/src/engine/planner.rs b/wai/wai-quantum/src/engine/planner.rs index 6b6f7aa97..bc0a08300 100644 --- a/wai/wai-quantum/src/engine/planner.rs +++ b/wai/wai-quantum/src/engine/planner.rs @@ -1624,6 +1624,11 @@ fn alike(a: Option<&Value>, b: Option<&Value>) -> bool { (None, None) => true, (Some(Value::Number(x)), Some(Value::Number(y))) => x.as_f64() == y.as_f64(), (Some(Value::Number(_)), _) | (_, Some(Value::Number(_))) => false, + // Lists and objects member by member, by the same rule. + (Some(Value::Array(x)), Some(Value::Array(y))) => x.len() == y.len() && x.iter().zip(y).all(|(a, b)| alike(Some(a), Some(b))), + (Some(Value::Object(x)), Some(Value::Object(y))) => { + x.keys().chain(y.keys()).all(|k| alike(x.get(k), y.get(k))) + } (Some(x), Some(y)) => x == y, _ => false, } @@ -1865,9 +1870,13 @@ pub fn recheck(reg: &Registry, job: &Value) -> Result { }; // Held only where everything that applies was checked here, by this engine: a // receipt sealed by another engine version is held neither way. - let holds = if priced["same"] == false || shadow["same"] == false { + // Another engine version prices and plans by its own rules: what differs is said, + // and the receipt is held neither way. + let holds = if !same_engine { + Value::Null + } else if priced["same"] == false || shadow["same"] == false { json!(false) - } else if shadow.get("same") == Some(&Value::Null) || !same_engine { + } else if shadow.get("same") == Some(&Value::Null) { Value::Null } else { json!(true) diff --git a/wai/wai-quantum/src/engine/planner/tests.rs b/wai/wai-quantum/src/engine/planner/tests.rs index cc451b675..d3667b3e9 100644 --- a/wai/wai-quantum/src/engine/planner/tests.rs +++ b/wai/wai-quantum/src/engine/planner/tests.rs @@ -1364,6 +1364,8 @@ fn what_a_receipt_states_of_itself_is_of_its_form() { // Members alike by value, as the second verifier compares them. assert!(alike(Some(&json!(7)), Some(&json!(7.0))) && alike(Some(&json!(-0.0)), Some(&json!(0)))); assert!(!alike(Some(&json!(true)), Some(&json!(1))) && alike(None, Some(&Value::Null)) && !alike(Some(&json!("a")), None)); + assert!(alike(Some(&json!([7])), Some(&json!([7.0]))) && alike(Some(&json!({ "a": -0.0, "b": null })), Some(&json!({ "a": 0 })))); + assert!(!alike(Some(&json!([true])), Some(&json!([1]))) && !alike(Some(&json!({ "a": "x" })), Some(&json!({ "a": "y" })))); let good = provider_body(&device_contract(), vec![quote("qpu", "silicon", usd("0.3"), Some(12.0))], vec![450, 100, 0, 450]); assert_eq!(reasons(&good), Vec::<&str>::new()); cases(&good, vec![ @@ -1412,6 +1414,13 @@ fn recheck_plans_the_shadow_again_and_leaves_the_host_s_routes_to_the_host() { // that ran here alike as well. let other = edited(&|b| b["result"]["engine"]["version"] = json!("0.0.1")); assert!(other["holds"].is_null(), "{other}"); + // Even where this engine's prices or plans differ: what differs is said, and + // the receipt is held neither way. + let elsewhere_differs = edited(&|b| { + b["result"]["engine"]["version"] = json!("0.0.1"); + b["result"]["planner"]["stable"]["digest"] = json!("00".repeat(32)); + }); + assert!(elsewhere_differs["holds"].is_null(), "{elsewhere_differs}"); // Its job memory read as a number by value, however it is spelled. let respelled = edited(&|b| b["result"]["planner"]["host"]["job_bytes"] = json!(1073741824.0)); assert_eq!(respelled["holds"], true, "{respelled}"); -- 2.54.0 (Apple Git-157) From a006b87d460ec6b656527d40793c2b4994f481d2 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sun, 8 Nov 2026 13:40:10 -0500 Subject: [PATCH 28/42] wai-quantum: the fifth check: a run's death-link compares the pid its spawner gave The service, and the command line, can be pid 1 of a namespace, as the shipped image runs it; a worker that took pid 1 for a dead parent exited at once, and every job failed. The spawner now passes its own pid, and the worker compares its parent with that alone, at once and then every 100 ms; a death-link thread that cannot start ends the run. A test runs each as pid 1 of a user and pid namespace, and the service workflow runs the shipped image where it can. Also: the longest gap counts from the run's start; the service's Mac meter reads again after a spin before it calls the counter dead; the SIGCHLD test sets SIG_IGN with perl, which keeps it across exec. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/wai-quantum-service.yml | 13 +++++++ wai/wai-quantum-cli/src/estimates.rs | 5 +-- wai/wai-quantum-cli/src/main.rs | 17 ++++++--- wai/wai-quantum-cli/tests/estimates.rs | 36 ++++++++++++++++--- wai/wai-quantum-service/src/energy.rs | 10 +++++- wai/wai-quantum-service/src/jobs.rs | 2 ++ wai/wai-quantum-service/src/main.rs | 11 ++++-- wai/wai-quantum-service/tests/contract.rs | 43 +++++++++++++++++++++++ 8 files changed, 123 insertions(+), 14 deletions(-) diff --git a/.github/workflows/wai-quantum-service.yml b/.github/workflows/wai-quantum-service.yml index 9d7b03fe6..7120e150c 100644 --- a/.github/workflows/wai-quantum-service.yml +++ b/.github/workflows/wai-quantum-service.yml @@ -131,6 +131,19 @@ jobs: trap 'kill $pid 2>/dev/null || true; cat "$RUNNER_TEMP/service.log"' EXIT for _ in $(seq 1 50); do curl -s -o /dev/null http://127.0.0.1:18241/v1/health && break; sleep 0.2; done bash smoke.sh http://127.0.0.1:18241 + # The image as it ships: built, run with the service as the container's first + # process (pid 1, no --init, as deploy/Containerfile and docs/self-host.md run + # it), and held to the same smoke checks, which run jobs through its workers. + # A runner with no container engine says so; one with an engine must pass. + - name: The image as it ships + shell: bash + run: | + set -euo pipefail + if command -v podman >/dev/null 2>&1; then engine=podman + elif command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then engine=docker + else echo "::warning::this runner has no container engine, so the shipped image was not run"; exit 0; fi + ENGINE=$engine JOBS=8 bash wai/wai-quantum-service/deploy/check-image.sh + grep -q '^test the_service_runs_its_jobs_as_pid_1 \.\.\. ok$' "$RUNNER_TEMP/test.log" || { echo "::error::the service was not run as pid 1"; exit 1; } service-macos: name: service · macos diff --git a/wai/wai-quantum-cli/src/estimates.rs b/wai/wai-quantum-cli/src/estimates.rs index a209f81f4..1002bb3b3 100644 --- a/wai/wai-quantum-cli/src/estimates.rs +++ b/wai/wai-quantum-cli/src/estimates.rs @@ -429,7 +429,7 @@ pub fn run_watched(exe: &Path, input: &Value, ceiling: f64) -> Result Result t, Err(e) => return Err(fail(&mut child, format!("no thread could read the run: {e}"))), }; - let mut watcher = energy::Watcher::new(ceiling); + // The first gap counts from the run's start, not from the watcher's. + let mut watcher = energy::Watcher::new_at(ceiling, began); let ended = loop { // Ended: read whole, then reaped (on macOS a process is readable whole // between its exit and its reaping). diff --git a/wai/wai-quantum-cli/src/main.rs b/wai/wai-quantum-cli/src/main.rs index 4cf10b301..44dc85df6 100644 --- a/wai/wai-quantum-cli/src/main.rs +++ b/wai/wai-quantum-cli/src/main.rs @@ -1023,11 +1023,14 @@ fn worker() { let read = stdin.read_line(&mut line); // The watcher's end of the pipe stays open while it watches: its close is the // end of this run. - let _ = std::thread::Builder::new().spawn(move || { + let linked = std::thread::Builder::new().spawn(move || { let mut rest = [0u8; 64]; while matches!(stdin.read(&mut rest), Ok(n) if n > 0) {} std::process::exit(3); }); + if linked.is_err() { + std::process::exit(3); + } let out = match read.map_err(|e| e.to_string()).and_then(|_| serde_json::from_str::(&line).map_err(|e| e.to_string())) { Ok(v) => match serde_json::from_value::(v["plan"].clone()) { Ok(plan) => planner::run_chosen(Registry::builtins(), &v["request"], &plan, &v["reasoning"]).unwrap_or_else(|e| json!({ "error": e })), @@ -1046,7 +1049,9 @@ fn worker() { fn die_with_parent() { #[cfg(unix)] { - let parent = std::os::unix::process::parent_id(); + // The command line that started this run, as it said: one that is a + // namespace's first process (pid 1) is a parent like any other. + let parent = std::env::var("WAI_QUANTUM_PARENT").ok().and_then(|p| p.parse::().ok()).unwrap_or_else(std::os::unix::process::parent_id); #[cfg(target_os = "linux")] { unsafe extern "C" { @@ -1057,10 +1062,10 @@ fn die_with_parent() { // SAFETY: it sets this process's own death signal. let _ = unsafe { prctl(PR_SET_PDEATHSIG, 9, 0, 0, 0) }; } - if std::os::unix::process::parent_id() != parent || parent == 1 { + if std::os::unix::process::parent_id() != parent { std::process::exit(3); } - let _ = std::thread::Builder::new().spawn(move || { + let watching = std::thread::Builder::new().spawn(move || { loop { std::thread::sleep(std::time::Duration::from_millis(100)); if std::os::unix::process::parent_id() != parent { @@ -1068,6 +1073,10 @@ fn die_with_parent() { } } }); + // A run nothing links to its watcher does not run. + if watching.is_err() { + std::process::exit(3); + } } } diff --git a/wai/wai-quantum-cli/tests/estimates.rs b/wai/wai-quantum-cli/tests/estimates.rs index f8a4a6afe..96ebb0ad7 100644 --- a/wai/wai-quantum-cli/tests/estimates.rs +++ b/wai/wai-quantum-cli/tests/estimates.rs @@ -153,10 +153,11 @@ fn a_run_under_a_ceiling_ends_with_its_command_line() { }); assert!(gone, "{signal}: the run's process {child} outlived its command line"); } - // SIGCHLD ignored, as a parent can leave it: the run is waited for all the same. - let out = Command::new("sh") - .arg("-c") - .arg(format!("trap '' CHLD; exec '{}' run bell.qasm --shots 100 --exactness exact --max-joules 1000 --demo-key --json", env!("CARGO_BIN_EXE_wai-quantum"))) + // SIGCHLD ignored, as a parent can leave it (perl sets SIG_IGN and keeps it + // across the exec, where a shell's trap does not): the run is waited for. + let out = Command::new("perl") + .args(["-e", "$SIG{CHLD} = 'IGNORE'; exec @ARGV or die $!", env!("CARGO_BIN_EXE_wai-quantum")]) + .args(["run", "bell.qasm", "--shots", "100", "--exactness", "exact", "--max-joules", "1000", "--demo-key", "--json"]) .current_dir(&h.0) .env("HOME", &h.0) .env("XDG_CONFIG_HOME", h.0.join("config")) @@ -237,3 +238,30 @@ fn an_estimate_refuses_a_job_clearly_past_a_ceiling_and_keeps_to_its_build() { let out = h.run(&args); assert_eq!(out.status.code(), Some(0), "{}", String::from_utf8_lossy(&out.stderr)); } + +/// The command line as a namespace's first process (pid 1), as a container's +/// entrypoint runs it: its run under a ceiling is its child like any other, and runs. +#[cfg(target_os = "linux")] +#[test] +fn a_run_under_a_ceiling_runs_when_its_command_line_is_pid_1() { + let h = Home::new("pid1"); + let can = Command::new("unshare").args(["--user", "--pid", "--fork", "true"]).status(); + if !can.is_ok_and(|s| s.success()) || !reads_here(&h) { + println!("this host makes no user and pid namespace for this user, or reads no run"); + return; + } + let out = Command::new("unshare") + .args(["--user", "--pid", "--fork"]) + .arg(env!("CARGO_BIN_EXE_wai-quantum")) + .args(["run", "bell.qasm", "--shots", "100", "--exactness", "exact", "--max-joules", "1000", "--demo-key", "--json"]) + .current_dir(&h.0) + .env("HOME", &h.0) + .env("XDG_CONFIG_HOME", h.0.join("config")) + .env("WAI_QUANTUM_TIMINGS", h.timings()) + .output() + .unwrap(); + assert_eq!(out.status.code(), Some(0), "{}", String::from_utf8_lossy(&out.stderr)); + let body: Value = serde_json::from_slice(&out.stdout).unwrap(); + assert!(body["result"]["counts"].is_object(), "{body}"); +} + diff --git a/wai/wai-quantum-service/src/energy.rs b/wai/wai-quantum-service/src/energy.rs index d5bd3a44f..065f054df 100644 --- a/wai/wai-quantum-service/src/energy.rs +++ b/wai/wai-quantum-service/src/energy.rs @@ -57,7 +57,15 @@ pub fn meter() -> &'static Meter { if std::env::var("WAI_QSVC_ENERGY").is_ok_and(|v| v == "0") { Meter::Unmetered("the service was started with energy metering off (WAI_QSVC_ENERGY=0)".into()) } else if cfg!(target_os = "macos") { - mac_meter(wai_quantum::engine::energy::own().is_some()) + mac_meter(wai_quantum::engine::energy::own().is_some() || { + // A read of nothing is read again after a short spin: an idle process + // can read nothing on a live counter. + let until = std::time::Instant::now() + std::time::Duration::from_millis(20); + while std::time::Instant::now() < until { + std::hint::spin_loop(); + } + wai_quantum::engine::energy::own().is_some() + }) } else if cfg!(target_os = "linux") { match Packages::open() { Ok(p) => Meter::Packages(p), diff --git a/wai/wai-quantum-service/src/jobs.rs b/wai/wai-quantum-service/src/jobs.rs index 1ec754acb..7272ccd20 100644 --- a/wai/wai-quantum-service/src/jobs.rs +++ b/wai/wai-quantum-service/src/jobs.rs @@ -1379,6 +1379,8 @@ fn low_priority(exe: &std::path::Path, sandbox: bool) -> tokio::process::Command c }; cmd.arg("worker"); + // The worker's death-link compares its parent with this process, whatever pid it has. + cmd.env("WAI_QSVC_PARENT", std::process::id().to_string()); cmd } diff --git a/wai/wai-quantum-service/src/main.rs b/wai/wai-quantum-service/src/main.rs index 491224150..41c3360af 100644 --- a/wai/wai-quantum-service/src/main.rs +++ b/wai/wai-quantum-service/src/main.rs @@ -73,7 +73,9 @@ fn usage() { fn watch_parent() { #[cfg(unix)] { - let parent = std::os::unix::process::parent_id(); + // The service that started this worker, as it said: a service that is a + // namespace's first process (pid 1) is a parent like any other. + let parent = std::env::var("WAI_QSVC_PARENT").ok().and_then(|p| p.parse::().ok()).unwrap_or_else(std::os::unix::process::parent_id); // On Linux the kernel kills a worker whose service has died. #[cfg(target_os = "linux")] { @@ -85,10 +87,10 @@ fn watch_parent() { // SAFETY: it sets this process's own death signal. let _ = unsafe { prctl(PR_SET_PDEATHSIG, 9, 0, 0, 0) }; } - if std::os::unix::process::parent_id() != parent || parent == 1 { + if std::os::unix::process::parent_id() != parent { std::process::exit(3); } - std::thread::spawn(move || { + let watching = std::thread::Builder::new().spawn(move || { loop { std::thread::sleep(std::time::Duration::from_millis(100)); if std::os::unix::process::parent_id() != parent { @@ -96,6 +98,9 @@ fn watch_parent() { } } }); + if watching.is_err() { + std::process::exit(3); + } } } diff --git a/wai/wai-quantum-service/tests/contract.rs b/wai/wai-quantum-service/tests/contract.rs index 193cedded..8c074a3c3 100644 --- a/wai/wai-quantum-service/tests/contract.rs +++ b/wai/wai-quantum-service/tests/contract.rs @@ -187,3 +187,46 @@ fn a_job_is_stopped_at_its_energy_ceiling_and_its_receipt_says_so() { let body = json!({ "request": job["request"], "result": r }); assert!(wai_quantum::engine::job::check(&body).valid(), "{:?}", wai_quantum::engine::job::check(&body).reasons); } + +/// The service as a namespace's first process (pid 1), as a container runs it with +/// no init: its workers are its children like any others, and run. +#[cfg(target_os = "linux")] +#[test] +fn the_service_runs_its_jobs_as_pid_1() { + let can = Command::new("unshare").args(["--user", "--pid", "--fork", "true"]).status(); + if !can.is_ok_and(|s| s.success()) { + println!("this host makes no user and pid namespace for this user"); + return; + } + let dir = std::env::temp_dir().join(format!("wai-qsvc-pid1-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(&dir).unwrap(); + let port = free_port(); + let mut service = Command::new("unshare") + .args(["--user", "--pid", "--fork"]) + .arg(env!("CARGO_BIN_EXE_wai-quantum-service")) + .arg("serve") + .env("WAI_QSVC_ADDR", format!("127.0.0.1:{port}")) + .env("WAI_QSVC_STORE", dir.join("store")) + .env("WAI_QSVC_KEY", dir.join("signing.key")) + .env("WAI_QSVC_JOB_GB", "2") + .env("WAI_QSVC_BUDGET_GB", "4") + .env("WAI_QSVC_WORKERS", "1") + .env("WAI_QSVC_ENERGY", "0") + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .unwrap(); + let t = Instant::now(); + while TcpStream::connect(("127.0.0.1", port)).is_err() { + assert!(t.elapsed() < Duration::from_secs(60), "the service did not answer"); + std::thread::sleep(Duration::from_millis(50)); + } + let bell = json!({ "qasm": "OPENQASM 3.0; qubit[2] q; bit[2] c; h q[0]; cx q[0], q[1]; c = measure q;", "shots": 100 }); + let (code, done) = http(port, "POST", "/v1/run", Some(&bell)); + let _ = service.kill(); + let _ = service.wait(); + let _ = std::fs::remove_dir_all(&dir); + assert_eq!((code, done["status"].as_str()), (200, Some("done")), "{done}"); +} + -- 2.54.0 (Apple Git-157) From 13fb93388e0b3a25cab8d67e6d54cc8b89abd103 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sun, 8 Nov 2026 13:55:06 -0500 Subject: [PATCH 29/42] wai-quantum: a run that ends before it reads its job is read by how it ended Co-Authored-By: Claude Opus 5.5 --- wai/wai-quantum-cli/src/estimates.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wai/wai-quantum-cli/src/estimates.rs b/wai/wai-quantum-cli/src/estimates.rs index 1002bb3b3..05842edb5 100644 --- a/wai/wai-quantum-cli/src/estimates.rs +++ b/wai/wai-quantum-cli/src/estimates.rs @@ -437,11 +437,11 @@ pub fn run_watched(exe: &Path, input: &Value, ceiling: f64) -> Result>| { std::thread::Builder::new().spawn(move || { -- 2.54.0 (Apple Git-157) From 39246bfa3b650d5814dee013a1eb13e0c84ebfb4 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sun, 8 Nov 2026 14:13:16 -0500 Subject: [PATCH 30/42] wai-quantum: the fifth check's tests that could not fail - The orphan test's run takes far longer than its two-second window. - A stopped run's guard (a whole figure below what stopped it is no reading) is a function with its own test. - On Linux a run's exit wakes the watch (a pidfd), and its whole figure is read as it ends; tested. - On macOS an exited read that stands where the live reads stood while the run spent CPU time is a frozen counter's, and no reading. - The fake package counter's test is given its probe: the live probe wanted a thread a loaded host starves to tick in 12 of 15 20 ms intervals. - A receipt with a stop's time no whole number, the result's the same. Co-Authored-By: Claude Opus 5.5 --- wai/quantum-conformance/receipts/generate.py | 1 + ...ted-contract-stopped-elapsed-fraction.json | 355 ++++++++++++++++++ .../receipts/manifest.json | 9 + wai/wai-quantum-cli/src/estimates.rs | 85 ++++- wai/wai-quantum-cli/tests/estimates.rs | 4 +- wai/wai-quantum/src/engine/energy.rs | 22 ++ 6 files changed, 465 insertions(+), 11 deletions(-) create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-elapsed-fraction.json diff --git a/wai/quantum-conformance/receipts/generate.py b/wai/quantum-conformance/receipts/generate.py index 0a4782e60..87eb58b6f 100644 --- a/wai/quantum-conformance/receipts/generate.py +++ b/wai/quantum-conformance/receipts/generate.py @@ -886,6 +886,7 @@ def contract_cases(run, at, drop): add("stopped-with-counts", edited(local, both(stopped, at(R + ("counts",), {"00": 100}))), ["stopped"], "a stopped run that gives an answer") add("stopped-whole-below", edited(local, both(stopped, at(R + ("energy",), {"joules_micro": 1}))), ["stopped"], "a stopped run whose whole figure is less than what stopped it") add("stopped-whole-above", edited(local, both(stopped, at(R + ("energy",), {"joules_micro": 2600000}))), [], "a stopped run whose whole figure is a little past what stopped it") + add("stopped-elapsed-fraction", edited(local, both(stopped, at(R + ("stopped", "elapsed_ms"), 1.5), at(R + ("elapsed_ms",), 1.5), at(P + ("kept", "deadline", "elapsed_ms"), 1.5))), ["planner_kept", "stopped"], "a stop at a time that is no whole number, the result's the same (a deadline's kept time is whole too)") add("stopped-elapsed-other", edited(local, both(stopped, at(R + ("stopped", "elapsed_ms"), 99999))), ["stopped"], "a stop at another time than the result's") add("stopped-with-verdict", edited(local, both(stopped, at(R + ("verdict",), {"holds": True}))), ["stopped"], "a stopped run that gives a verdict, an answer by another name") add("stopped-with-outputs", edited(local, both(stopped, at(R + ("outputs",), {"x": 1}))), ["stopped"], "a stopped run that gives outputs") diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-elapsed-fraction.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-elapsed-fraction.json new file mode 100644 index 000000000..14fe1062c --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-stopped-elapsed-fraction.json @@ -0,0 +1,355 @@ +{ + "status": "done", + "method": "stabilizer", + "why": "Clifford circuit: the stabilizer tableau of 2 qubits; the cheapest of the 4 of 13 routes that meet the contract", + "estimate": { + "memory_bytes": 67172870, + "work": 2008 + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 1000, + "seed": 7, + "contract": { + "exactness": "exact", + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "deadline_seconds": 60.0, + "max_joules": 2 + } + }, + "result": { + "method": "stabilizer", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "none", + "note": "stopped at its ceiling" + }, + "elapsed_ms": 1.5, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "exact", + "wanted_from": "contract", + "named": null, + "question": "counts", + "auto": "method:stabilizer", + "host": { + "job_bytes": 17179869184, + "providers": [] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 8e-09, + "basis": "nominal" + }, + "memory_bytes": 268459522, + "work": 8, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 2.4096e-07, + "basis": "nominal" + }, + "memory_bytes": 67172870, + "work": 2008, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "chosen" + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 0.027721728, + "basis": "nominal" + }, + "memory_bytes": 270532608, + "work": 18481152, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is heuristic, and exact only when nothing is truncated, which it cannot know before it runs; the job wants exact" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "stabilizer_rank answers amplitudes and expectation values" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "tensor_network answers amplitudes only" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 1.35e-06, + "basis": "nominal" + }, + "memory_bytes": 268435554, + "work": 9000, + "energy": { + "joules": 1.5, + "basis": "an estimate", + "watch": "a host's live reading" + }, + "leaves_out": [] + }, + "outcome": "met" + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is single, and the job wants exact" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "cannot", + "why": "density_matrix is for noisy circuits (give \"noise\")" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is estimate, and the job wants exact" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "class", + "why": "its class is bounded, and the job wants exact" + } + } + ], + "choice": "method:stabilizer", + "why": "the cheapest of the 4 of 13 routes that meet the contract", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "30b5ed16af1556898b035da46b1d388aec9591b3194052e76020b1d83ce9567e", + "choice": false + }, + "kept": { + "deadline": { + "seconds": 60.0, + "elapsed_ms": 1.5, + "kept": true + }, + "cost": { + "max_cost": { + "amount": "1", + "currency": "USD" + }, + "charged": null, + "kept": true + }, + "energy": { + "max_joules": 2, + "joules": 2.5, + "kept": false + } + } + }, + "energy": { + "unmetered": "stopped" + }, + "stopped": { + "at": "max_joules", + "joules": 2.5, + "max_joules": 2, + "elapsed_ms": 1.5, + "read": "a host's live reading" + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "fbb47d46159b5dafb38f7d99b857993993d8f465d746dec7b6445f05dfe72812", + "signature": "cac4da82cd1702f04c98b83693ec369272b1dcec6b02ca3d61c3855d1cd347f73c0fd09a9d9bfe516478d7647dbee0a3c81b1a21631706697f63e31904b89802" + } + } +} diff --git a/wai/quantum-conformance/receipts/manifest.json b/wai/quantum-conformance/receipts/manifest.json index 51d2ddb47..b32f7a039 100644 --- a/wai/quantum-conformance/receipts/manifest.json +++ b/wai/quantum-conformance/receipts/manifest.json @@ -1760,6 +1760,15 @@ "made_by": "crafted", "what": "a stopped run whose whole figure is a little past what stopped it" }, + { + "file": "jobs/crafted-contract-stopped-elapsed-fraction.json", + "reasons": [ + "planner_kept", + "stopped" + ], + "made_by": "crafted", + "what": "a stop at a time that is no whole number, the result's the same (a deadline's kept time is whole too)" + }, { "file": "jobs/crafted-contract-stopped-elapsed-other.json", "reasons": [ diff --git a/wai/wai-quantum-cli/src/estimates.rs b/wai/wai-quantum-cli/src/estimates.rs index 05842edb5..2d5264330 100644 --- a/wai/wai-quantum-cli/src/estimates.rs +++ b/wai/wai-quantum-cli/src/estimates.rs @@ -471,7 +471,14 @@ pub fn run_watched(exe: &Path, input: &Value, ceiling: f64) -> Result Result None, }; let _ = child.wait(); - let (mut figure, _) = whole(&mut meter, reading); - // A whole figure below what stopped the run is no reading of it. - if figure["joules_micro"].as_u64().is_some_and(|u| (u as f64) < joules * 1e6 - 1.0) { - figure = json!({ "unmetered": "the run's whole reading came to less than the reading that stopped it, so it is no reading" }); - } + let figure = no_less_than(whole(&mut meter, reading).0, joules); break Ended::Stopped { stopped: planner::Stopped { joules, elapsed_ms, read: watcher.said(&scope()) }, figure }; } Some(energy::Watched::Lost) => { @@ -502,7 +505,7 @@ pub fn run_watched(exe: &Path, input: &Value, ceiling: f64) -> Result std::thread::sleep(Duration::from_millis(energy::WATCH_MS)), + None => wait_exit_or(pid, Duration::from_millis(energy::WATCH_MS)), } }; drop(held); @@ -513,6 +516,44 @@ pub fn run_watched(exe: &Path, input: &Value, ceiling: f64) -> Result Value { + if figure["joules_micro"].as_u64().is_some_and(|u| (u as f64) < joules * 1e6 - 1.0) { + return json!({ "unmetered": "the run's whole reading came to less than the reading that stopped it, so it is no reading" }); + } + figure +} + +/// Until `pid` exits or `timeout` passes: on Linux the run's exit wakes the watch +/// (a pidfd), so its whole figure is read as it ends; elsewhere a sleep. +fn wait_exit_or(pid: u32, timeout: Duration) { + #[cfg(target_os = "linux")] + { + unsafe extern "C" { + fn syscall(number: i64, ...) -> i64; + fn poll(fds: *mut [i32; 2], nfds: u64, timeout: i32) -> i32; + fn close(fd: i32) -> i32; + } + /// `SYS_pidfd_open`, the same number on x86_64 and aarch64. + const SYS_PIDFD_OPEN: i64 = 434; + /// `POLLIN`, in the low half of `struct pollfd`'s second word. + const POLLIN: i32 = 1; + // SAFETY: pidfd_open takes a pid and flags, and returns a descriptor or -1. + let fd = unsafe { syscall(SYS_PIDFD_OPEN, pid as i64, 0i64) } as i32; + if fd >= 0 { + let mut p = [fd, POLLIN]; + // SAFETY: one pollfd ({fd, events, revents}, two 32-bit words here), for the call. + let _ = unsafe { poll(&mut p, 1, i32::try_from(timeout.as_millis()).unwrap_or(i32::MAX)) }; + // SAFETY: the descriptor is this function's. + let _ = unsafe { close(fd) }; + return; + } + } + let _ = pid; + std::thread::sleep(timeout); +} + /// A run's whole figure, once it has ended: its process's own reading on macOS, the /// packages' read once more and added up on Linux. With the joules it came to. fn whole(meter: &mut Meter<'_>, reading: Option) -> (Value, Option) { @@ -750,6 +791,25 @@ mod tests { let _ = std::fs::remove_dir_all(&d); } + /// A stopped run's whole figure below the reading that stopped it is no reading; + /// one at or past it is kept. + #[test] + fn a_whole_figure_below_what_stopped_the_run_is_no_reading() { + assert!(no_less_than(json!({ "joules_micro": 1 }), 2.5)["unmetered"].is_string()); + assert_eq!(no_less_than(json!({ "joules_micro": 2_600_000 }), 2.5)["joules_micro"], 2_600_000); + } + + /// On Linux the run's exit wakes the watch at once, not at its next look. + #[cfg(target_os = "linux")] + #[test] + fn a_run_s_exit_wakes_its_watch() { + let mut child = std::process::Command::new("sleep").arg("0.05").spawn().unwrap(); + let began = Instant::now(); + wait_exit_or(child.id(), Duration::from_secs(5)); + assert!(began.elapsed() < Duration::from_secs(2), "{:?}", began.elapsed()); + let _ = child.wait(); + } + /// A counter that reads nothing once is read again after a spin, not called dead; /// and a run whose reading is kept nowhere is not read for an estimate. #[test] @@ -856,9 +916,14 @@ mod tests { } }) }; - // The probe wants a counter that ticks, and this one is a thread: a busy host - // can starve it through a whole probe, which says nothing of what is tested. - let open = || (0..60).find_map(|_| energy::Packages::open_in(&d).ok()).expect("the counter never ticked through a probe"); + // The probe is given, not taken: the live probe wants 12 of 15 20 ms intervals + // to see a tick, and this counter is a thread a loaded host starves for whole + // intervals, which is what failed under load and says nothing of what is tested. + let open = || { + let mut p = energy::Packages::open_with_probe(&d, energy::Probe { update_ns: 1_000_000, step_uj: 500 }).unwrap(); + p.probe.update_ns = 1_000_000; + p + }; let p: &'static energy::Packages = Box::leak(Box::new(open())); // Every window is over the updates the probe found; a window the writer was // starved through reads nothing, as it should, so it is taken again. diff --git a/wai/wai-quantum-cli/tests/estimates.rs b/wai/wai-quantum-cli/tests/estimates.rs index 96ebb0ad7..d32e19128 100644 --- a/wai/wai-quantum-cli/tests/estimates.rs +++ b/wai/wai-quantum-cli/tests/estimates.rs @@ -127,7 +127,9 @@ fn a_run_under_a_ceiling_ends_with_its_command_line() { } return; } - std::fs::write(h.0.join("busy.qasm"), BUSY).unwrap(); + // A run that takes far longer than the window it is given to end in. + let long: String = format!("OPENQASM 3.0;\nqubit[24] q;\nbit[24] c;\n{}c = measure q;\n", (0..600).map(|k| format!("rx(0.{}) q[{}];\n", k % 9 + 1, k % 24)).collect::()); + std::fs::write(h.0.join("busy.qasm"), long).unwrap(); let alive = |pid: &str| Command::new("kill").args(["-0", pid]).stderr(Stdio::null()).status().is_ok_and(|s| s.success()); for signal in ["-TERM", "-KILL"] { let mut cli = h.cmd().args(["run", "busy.qasm", "--method", "statevector", "--shots", "1000000", "--max-joules", "100000", "--demo-key"]).stdout(Stdio::null()).stderr(Stdio::null()).spawn().unwrap(); diff --git a/wai/wai-quantum/src/engine/energy.rs b/wai/wai-quantum/src/engine/energy.rs index 79f770d51..d92f76b18 100644 --- a/wai/wai-quantum/src/engine/energy.rs +++ b/wai/wai-quantum/src/engine/energy.rs @@ -178,6 +178,16 @@ impl Watcher { } } + /// Whether `joules`, read at the run's end with its CPU time then, stands where + /// the last live read stood though the run spent CPU time since: the frozen rule + /// applied to an exited read as to a live one. + pub fn stood_still(&self, joules: f64, cpu_ns: Option) -> bool { + match self.last { + Some((before, cpu_before)) => joules == before && !matches!((cpu_before, cpu_ns), (Some(b), Some(a)) if a <= b), + None => false, + } + } + /// What the reads were, as a stopped run's receipt says it. pub fn said(&self, what: &str) -> String { format!("{what}; the longest time between two reads was {} ms", self.longest_gap.as_millis()) @@ -614,6 +624,13 @@ impl Packages { Self::open_in(std::path::Path::new("/sys/class/powercap")) } + /// The packages at `root` taken to update as `probe` says, with no probe of + /// their own: for a counter that a test drives. + pub fn open_with_probe(root: &std::path::Path, probe: Probe) -> Result { + let zones = zones_in(root, &|p| std::fs::read_to_string(p)).map_err(|a| a.why().to_string())?; + Ok(Packages { zones, probe }) + } + /// [`Packages::open`] on the tree at `root`. pub fn open_in(root: &std::path::Path) -> Result { let zones = zones_in(root, &|p| std::fs::read_to_string(p)).map_err(|a| a.why().to_string())?; @@ -1175,6 +1192,11 @@ mod tests { assert_eq!(w.take_at(Some(1.0), Some(10), ms(10)), None); assert_eq!(w.take_at(Some(1.0), Some(500_000_000), ms(500)), None); assert_eq!(w.take_at(Some(1.0), Some(1_000_000_000), ms(1010)), Some(Watched::Lost)); + // An exited read where the last live read stood, the run having spent CPU + // time since, stood still too; one with no CPU time spent did not. + let mut w = Watcher::new_at(2.0, t0); + assert_eq!(w.take_at(Some(0.3), Some(10), ms(10)), None); + assert!(w.stood_still(0.3, Some(900_000_000)) && !w.stood_still(0.4, Some(900_000_000)) && !w.stood_still(0.3, Some(10))); // One value while the run spends none is a run waiting, not a frozen counter. let mut w = Watcher::new_at(2.0, t0); assert_eq!(w.take_at(Some(1.0), Some(10), ms(10)), None); -- 2.54.0 (Apple Git-157) From aec1d6649e70d7bdc0a1e9313a05cab54b08f687 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sun, 8 Nov 2026 14:13:16 -0500 Subject: [PATCH 31/42] wai-quantum: a receipt whose route's estimate is the least, sealed as the whole The at_least comparison in what ran had no receipt that only it could see. Co-Authored-By: Claude Opus 5.5 --- wai/quantum-conformance/receipts/generate.py | 6 + ...rafted-contract-cost-at-least-dropped.json | 435 ++++++++++++++++++ .../receipts/manifest.json | 8 + 3 files changed, 449 insertions(+) create mode 100644 wai/quantum-conformance/receipts/jobs/crafted-contract-cost-at-least-dropped.json diff --git a/wai/quantum-conformance/receipts/generate.py b/wai/quantum-conformance/receipts/generate.py index 658944686..fd2527fe9 100644 --- a/wai/quantum-conformance/receipts/generate.py +++ b/wai/quantum-conformance/receipts/generate.py @@ -921,6 +921,12 @@ def contract_cases(run, at, drop): route("provider:priced", lambda r: r["price"].update(money={"free": False, "unknown": "the provider gives no estimate"}))(b) b["result"]["cost"] = {"free": True, "estimate": {"free": True, "seconds": 0.0}, "charged": None, "confirmed": False} add("cost-unknown-run-free", edited(named, unknown_sealed_free), ["planner_choice"], "a route whose cost is not known, its run sealed as free and unconfirmed") + + def least_dropped(b): + del b["request"]["contract"]["max_cost"] + del b["result"]["planner"]["kept"]["cost"] + route("provider:priced", lambda r: r["price"]["money"].update(at_least=True))(b) + add("cost-at-least-dropped", edited(named, least_dropped), ["planner_choice"], "a route's estimate the least it can come to, its run's estimate sealed as the whole") add("route-device-other", edited(routed, route("provider:ref", lambda r: r.update(device="reference:line-6"))), ["planner_choice"], "the route chosen names another device than the one that ran") add("route-provenance-class", edited(routed, route("provider:priced", lambda r: r.update(provenance="silicon"))), ["planner_route"], "a provider's route whose class is not its provenance's") diff --git a/wai/quantum-conformance/receipts/jobs/crafted-contract-cost-at-least-dropped.json b/wai/quantum-conformance/receipts/jobs/crafted-contract-cost-at-least-dropped.json new file mode 100644 index 000000000..4d1b9cc89 --- /dev/null +++ b/wai/quantum-conformance/receipts/jobs/crafted-contract-cost-at-least-dropped.json @@ -0,0 +1,435 @@ +{ + "status": "done", + "method": "provider", + "why": "on priced, reference:line-5 (wai.quantum.provider/1): compiled exactly to rzsxxcz on its qubits and checked by simulation here before it was sent", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4, + "contract": { + "providers": "allowed" + }, + "provider": "priced" + }, + "result": { + "method": "provider", + "qubits": 2, + "gates": 2, + "accuracy": { + "class": "simulated", + "note": "counts from the provider's simulator or emulator, as provider.provenance names it, not measured on any device: classical software's sample of the program, read as counts_source says; they show what that software gives, under whatever noise it models, not what a device would" + }, + "shots": 300, + "provider": { + "name": "priced", + "kind": "process", + "protocol": "wai.quantum.provider/1", + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "qubits": 5, + "basis": "rzsxxcz", + "describe": "c7626c0d9f68fe8e420df9cfe19f635427160bfe4902af2cc12c480b28d3b439" + }, + "calibration": "reference-f2d9fe570421", + "compiled": { + "basis": "rzsxxcz", + "program": "b96b3d2e44387bac1dab89e43e29706788b0b6ed721f88d5c0f64be293c72df9", + "hash": "BLAKE3 of the program's OpenQASM 3 text, qasm3", + "qasm3": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nbit[2] c;\nrz(pi/2) $0;\nsx $0;\nrz(pi/2) $1;\nsx $1;\ncz $0, $1;\nrz(pi) $1;\nsx $1;\nrz(pi/2) $0;\nrz(pi/2) $1;\nc[0] = measure $0;\nc[1] = measure $1;\n", + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0, + "layout": [ + 0, + 1 + ], + "final_layout": [ + 0, + 1 + ], + "checked": "the compiled program's final state equals the circuit's, each logical qubit on the physical qubit it ends on, by the bit-exact simulator here; nothing has been sent", + "placement": { + "chosen": "the compiler's own layout, the fewest swaps: the description states no errors" + } + }, + "job": { + "id": "ref-1", + "polls": 1 + }, + "ideal": { + "computed": true, + "method": "exact", + "total_variation_distance": 0.03666666666666665, + "hellinger_fidelity": 0.998653743148044, + "sampling_tvd_expected": 0.023032943298089033, + "ideal_outcomes": 2, + "note": "the circuit's exact distribution over its classical bits, by the bit-exact state vector here, against the provider's counts: the total variation distance, the Hellinger fidelity, and the distance this many shots of the exact distribution would leave on average (by the normal approximation); a distance well above that is the device's or the simulator's error, or a program not run as sent" + }, + "cost": { + "free": false, + "estimate": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot", + "seconds": 0.0 + }, + "charged": { + "amount": "0.09", + "currency": "USD" + }, + "confirmed": true + }, + "energy": { + "unmetered": "the work ran at the provider; this host's meter would read only the wait" + }, + "counts_source": "shots", + "execution": { + "stated_by": "provider", + "mitigation": "none", + "twirling": "none", + "decoupling": "none", + "remapping": "none", + "optimisation": "none", + "verbatim": true, + "note": "the reference simulates the program's gates as written, on the qubits named, and corrects nothing" + }, + "counts": { + "11": 161, + "00": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "engine": { + "name": "wai-quantum", + "version": "0.8.1" + }, + "schema": "wai.quantum.job-result/1", + "planner": { + "format": "wai.quantum.planner/1", + "wanted": "simulated", + "wanted_from": "named", + "named": "provider:priced", + "question": "counts", + "auto": null, + "host": { + "job_bytes": 17179869184, + "providers": [ + "priced" + ] + }, + "routes": [ + { + "route": "method:exact", + "kind": "local", + "method": "exact", + "class": "bit-exact", + "host_dependent": false, + "auto_rank": 20, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector", + "kind": "local", + "method": "statevector", + "class": "exact", + "host_dependent": false, + "auto_rank": 30, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:statevector_single", + "kind": "local", + "method": "statevector_single", + "class": "single", + "host_dependent": true, + "auto_rank": 40, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer", + "kind": "local", + "method": "stabilizer", + "class": "exact", + "host_dependent": false, + "auto_rank": 10, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pauli", + "kind": "local", + "method": "pauli", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:mps", + "kind": "local", + "method": "mps", + "class": "heuristic", + "host_dependent": false, + "auto_rank": 60, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:stabilizer_rank", + "kind": "local", + "method": "stabilizer_rank", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:tensor_network", + "kind": "local", + "method": "tensor_network", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank", + "kind": "local", + "method": "cutrank", + "class": "exact", + "host_dependent": false, + "auto_rank": 50, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:cutrank_single", + "kind": "local", + "method": "cutrank_single", + "class": "single", + "host_dependent": true, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:density_matrix", + "kind": "local", + "method": "density_matrix", + "class": "exact", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:trajectories", + "kind": "local", + "method": "trajectories", + "class": "estimate", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "method:pulse", + "kind": "local", + "method": "pulse", + "class": "bounded", + "host_dependent": false, + "auto_rank": null, + "price": null, + "outcome": "rejected", + "rejected": { + "code": "not_named", + "why": "the job names another route" + } + }, + { + "route": "provider:priced", + "kind": "provider", + "provider": "priced", + "class": "simulated", + "host_dependent": true, + "price": { + "money": { + "free": false, + "amount": "0.09", + "currency": "USD", + "unit": "shot", + "at_least": true + }, + "time": { + "seconds": 0.0, + "basis": "provider" + }, + "memory_bytes": null, + "work": null, + "energy": { + "joules": null, + "why": "no provider states a job's energy before it runs" + }, + "leaves_out": [ + "energy", + "mitigation", + "decoder", + "charged" + ], + "program": { + "shots": 300, + "native_gates": 9, + "two_qubit_gates": 1, + "swaps": 0 + } + }, + "device": "reference:line-5", + "provenance": "simulator:the wai-quantum exact simulator: the state vector in fixed point, sampled with the seed given", + "outcome": "chosen" + } + ], + "choice": "provider:priced", + "why": "the route the job names, which meets its contract (1 of 14 routes)", + "stable": { + "scope": "digest: what each route that depends on nothing of the host costs, the same for this request and job memory on every host of one engine; choice: whether the route chosen is one of those whatever the host", + "routes": [ + "method:exact", + "method:statevector", + "method:stabilizer", + "method:pauli", + "method:mps", + "method:stabilizer_rank", + "method:tensor_network", + "method:cutrank", + "method:density_matrix", + "method:trajectories", + "method:pulse" + ], + "digest": "42dab8b20f638eeb9c1d46fd7a0890b574c641a1e11d1306da2abc201ca84c5f", + "choice": false + }, + "shadow": { + "route": "method:exact", + "class": "bit-exact", + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "budget_seconds": 300.0, + "price": { + "money": { + "free": true + }, + "time": { + "seconds": 4e-08, + "basis": "nominal" + }, + "memory_bytes": 134217920, + "work": 8, + "energy": { + "joules": null, + "why": "this host estimates no job's energy before it runs" + }, + "leaves_out": [] + } + }, + "kept": {} + }, + "shadow": { + "ran": true, + "route": "method:exact", + "accuracy": { + "class": "bit-exact" + }, + "request": { + "qasm": "OPENQASM 3.0;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nh q[0];\ncx q[0], q[1];\nc = measure q;\n", + "shots": 300, + "seed": 4294967300, + "method": "exact" + }, + "shots": 300, + "counts": { + "00": 161, + "11": 139 + }, + "distinct_outcomes": 2, + "omitted_shots": 0, + "distance": { + "computed": true, + "numerator": 44, + "denominator": 600, + "total_variation": 0.07333333333333333, + "hellinger_fidelity": 0.9946222222222221, + "sampling_tvd_bound": 0.04602751441903442 + }, + "elapsed_ms": 0 + }, + "receipt": { + "alg": "ed25519", + "canon": "rfc8785", + "key": "197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61", + "digest": "0b97651e8a11914eaa5f5d8c0b69305b8979474670f9b9f61a5f864f42efadd3", + "signature": "aef4cf8266c9a82feeacb5686d1b753b499a58cd298d5f4b6494422c18abc0266ecbcf4e484c2bec4529b244d09525bda3159815b5ed64f34971ef639b8ee801" + } + }, + "id": "pj-e158396f1fd8f81d", + "submitted_ms": 1794033072602, + "finished_ms": 1794033072605 +} diff --git a/wai/quantum-conformance/receipts/manifest.json b/wai/quantum-conformance/receipts/manifest.json index ad0d8a271..bf9f29811 100644 --- a/wai/quantum-conformance/receipts/manifest.json +++ b/wai/quantum-conformance/receipts/manifest.json @@ -1900,6 +1900,14 @@ "made_by": "crafted", "what": "a route whose cost is not known, its run sealed as free and unconfirmed" }, + { + "file": "jobs/crafted-contract-cost-at-least-dropped.json", + "reasons": [ + "planner_choice" + ], + "made_by": "crafted", + "what": "a route's estimate the least it can come to, its run's estimate sealed as the whole" + }, { "file": "jobs/crafted-contract-route-device-other.json", "reasons": [ -- 2.54.0 (Apple Git-157) From 827008ab0752d66c55e7f555613ba093d1e3df20 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sun, 8 Nov 2026 15:05:53 -0500 Subject: [PATCH 32/42] wai-quantum: the fifth check's remaining fixes - The guard that a stopped run's whole figure is no less than what stopped it is a function with its own test, and its mutant is caught. - On Linux a run's exit wakes the watch through a pidfd; tested, and its mutant is caught. - The frozen rule holds an exited read too: one that stands where the live reads stood while the run spent a millisecond or more of CPU time is no reading; a run that only waited and exited is not taken for frozen. - The fake package counter's test is given its probe, the cause of its flake under load; it passed 50 runs of 50 under a niced burner on every core. - Where a kill on Apple silicon leaves no honest whole reading, the stopped receipt says why rather than state a figure below the decision. Co-Authored-By: Claude Opus 5.5 --- wai/wai-quantum-cli/tests/estimates.rs | 5 ++++- wai/wai-quantum/src/engine/energy.rs | 9 ++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/wai/wai-quantum-cli/tests/estimates.rs b/wai/wai-quantum-cli/tests/estimates.rs index d32e19128..efc5fbefa 100644 --- a/wai/wai-quantum-cli/tests/estimates.rs +++ b/wai/wai-quantum-cli/tests/estimates.rs @@ -88,7 +88,10 @@ fn a_run_is_stopped_at_its_ceiling_by_a_live_reading_and_its_receipt_says_so() { let r = &body["result"]; assert!(r["stopped"]["joules"].as_f64().unwrap() >= 0.01 && r["stopped"]["read"].as_str().unwrap().contains("the longest time between two reads") && r.get("counts").is_none(), "{r}"); let whole = r["energy"]["joules_micro"].as_u64().map(|u| u as f64 / 1e6); - assert!(whole.is_some_and(|w| w >= r["stopped"]["joules"].as_f64().unwrap()), "what the killed run took in all is sealed: {}", r["energy"]); + // What the killed run took in all is sealed, no less than what stopped it; where + // the kill left no honest whole reading (on Apple silicon a thread killed on a + // core loses its last stretch), the receipt says why instead. + assert!(whole.map_or(r["energy"]["unmetered"].is_string(), |w| w >= r["stopped"]["joules"].as_f64().unwrap()), "{}", r["energy"]); assert_eq!((r["planner"]["kept"]["energy"]["kept"].as_bool(), r["accuracy"]["class"].as_str()), (Some(false), Some("none")), "{r}"); std::fs::write(h.0.join("job.json"), body.to_string()).unwrap(); let v = h.run(&["verify", "job.json", "--json"]); diff --git a/wai/wai-quantum/src/engine/energy.rs b/wai/wai-quantum/src/engine/energy.rs index d92f76b18..494dd8a9d 100644 --- a/wai/wai-quantum/src/engine/energy.rs +++ b/wai/wai-quantum/src/engine/energy.rs @@ -179,11 +179,13 @@ impl Watcher { } /// Whether `joules`, read at the run's end with its CPU time then, stands where - /// the last live read stood though the run spent CPU time since: the frozen rule - /// applied to an exited read as to a live one. + /// the last live read stood though the run spent at least a millisecond of CPU + /// time since: the frozen rule applied to an exited read. A run that only waited + /// and exited after its last live read spent less, and its read stands honestly. pub fn stood_still(&self, joules: f64, cpu_ns: Option) -> bool { match self.last { - Some((before, cpu_before)) => joules == before && !matches!((cpu_before, cpu_ns), (Some(b), Some(a)) if a <= b), + Some((before, Some(b))) => joules == before && cpu_ns.is_some_and(|a| a >= b.saturating_add(1_000_000)), + Some((before, None)) => joules == before && cpu_ns.is_none(), None => false, } } @@ -1197,6 +1199,7 @@ mod tests { let mut w = Watcher::new_at(2.0, t0); assert_eq!(w.take_at(Some(0.3), Some(10), ms(10)), None); assert!(w.stood_still(0.3, Some(900_000_000)) && !w.stood_still(0.4, Some(900_000_000)) && !w.stood_still(0.3, Some(10))); + assert!(!w.stood_still(0.3, Some(500_010)), "a run that only waited and exited spent under a millisecond"); // One value while the run spends none is a run waiting, not a frozen counter. let mut w = Watcher::new_at(2.0, t0); assert_eq!(w.take_at(Some(1.0), Some(10), ms(10)), None); -- 2.54.0 (Apple Git-157) From 895883f32250b2e59072f622076e19da47d63248 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sun, 8 Nov 2026 15:16:53 -0500 Subject: [PATCH 33/42] wai-quantum: the orphan test's run outlasts its window, so the test can fail A long Clifford circuit on 3000 qubits, a million shots, by the stabilizer method, within every cap (about 14 s on the Framework), killed once it has its job and is working. With every death link removed the run outlives its command line and the test fails, 3 of 3 on Linux and on macOS; with them it passes 10 of 10 on both. Co-Authored-By: Claude Opus 5.5 --- wai/wai-quantum-cli/tests/estimates.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/wai/wai-quantum-cli/tests/estimates.rs b/wai/wai-quantum-cli/tests/estimates.rs index efc5fbefa..835791a26 100644 --- a/wai/wai-quantum-cli/tests/estimates.rs +++ b/wai/wai-quantum-cli/tests/estimates.rs @@ -130,12 +130,15 @@ fn a_run_under_a_ceiling_ends_with_its_command_line() { } return; } - // A run that takes far longer than the window it is given to end in. - let long: String = format!("OPENQASM 3.0;\nqubit[24] q;\nbit[24] c;\n{}c = measure q;\n", (0..600).map(|k| format!("rx(0.{}) q[{}];\n", k % 9 + 1, k % 24)).collect::()); + // A run that takes far longer than the window it is given to end in, within + // every cap: a long Clifford circuit on 3000 qubits, a million shots, by the + // stabilizer method (about 14 s on the Framework, measured). + let layer: String = std::iter::once("h q[0];\n".to_string()).chain((0..2999).map(|i| format!("cx q[{i}], q[{}];\n", i + 1))).collect(); + let long = format!("OPENQASM 3.0;\nqubit[3000] q;\nbit[3000] c;\n{}c = measure q;\n", layer.repeat(40)); std::fs::write(h.0.join("busy.qasm"), long).unwrap(); let alive = |pid: &str| Command::new("kill").args(["-0", pid]).stderr(Stdio::null()).status().is_ok_and(|s| s.success()); for signal in ["-TERM", "-KILL"] { - let mut cli = h.cmd().args(["run", "busy.qasm", "--method", "statevector", "--shots", "1000000", "--max-joules", "100000", "--demo-key"]).stdout(Stdio::null()).stderr(Stdio::null()).spawn().unwrap(); + let mut cli = h.cmd().args(["run", "busy.qasm", "--method", "stabilizer", "--shots", "1000000", "--max-joules", "1000000", "--demo-key"]).stdout(Stdio::null()).stderr(Stdio::null()).spawn().unwrap(); let parent = cli.id().to_string(); let child = (0..400) .find_map(|_| { @@ -147,6 +150,9 @@ fn a_run_under_a_ceiling_ends_with_its_command_line() { found }) .expect("the run's process started"); + // Given its job and working: killed before that, it would end for want of one. + std::thread::sleep(std::time::Duration::from_millis(500)); + assert!(alive(&child), "{signal}: the run ended before its command line was killed; it is meant to run long"); assert!(Command::new("kill").args([signal, &parent]).status().unwrap().success()); let _ = cli.wait(); let gone = (0..80).any(|_| { -- 2.54.0 (Apple Git-157) From f86d211b5e0aba75a88eee20d811f960867ad538 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Mon, 9 Nov 2026 13:27:41 -0500 Subject: [PATCH 34/42] wai-quantum: the receipts' second verifier runs once, through wai conform --independent Main's e068412a4 moved receipt_differential.py --second-only into the step file's `# independent:` line, and the merge of main kept this branch's copy of the run in the body beside it; dx::independent::tests::the_union_is_one_command_and_the_workflow_keeps_no_copy refused it in every job that runs the wai binary's tests. The planted defects stay in the body, with this branch's three. Co-Authored-By: Claude Opus 5.5 --- .github/wai-conformance/verifiers/quantum-receipts.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/wai-conformance/verifiers/quantum-receipts.sh b/.github/wai-conformance/verifiers/quantum-receipts.sh index 5440bc63c..18c06083a 100644 --- a/.github/wai-conformance/verifiers/quantum-receipts.sh +++ b/.github/wai-conformance/verifiers/quantum-receipts.sh @@ -16,7 +16,6 @@ python3 -I wai/quantum-conformance/receipts/generate.py --check python3 -I wai/quantum-conformance/receipts/generate.py --self-test python3 -I wai/quantum-conformance/tools/receipt_verify.py --self-test wai/wai-quantum/src/engine/testdata/es-number-tostring.txt -python3 -I wai/quantum-conformance/tools/receipt_differential.py --second-only for plant in lenient-key no-alg last-duplicate no-inexact measured-simulator whole-cap lax-small-order-r no-canonical-spelling set-seal-only names-layout-only route-unchecked choice-unchecked distance-unchecked; do python3 -I wai/quantum-conformance/tools/receipt_differential.py --second-only --plant "$plant" | tail -1 done -- 2.54.0 (Apple Git-157) From 75ba1253f47dec6f74b436aad24d689255de0be3 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Mon, 9 Nov 2026 13:27:41 -0500 Subject: [PATCH 35/42] wai-quantum: wai.quantum.planner/2 listed as a string refused on purpose The planner's test and the job receipts corpus seal a reasoning of format wai.quantum.planner/2 to see it refused (PLANNER_FORM); the repository's quantum names check found it accounted for nowhere. Listed beside job-result/2, and the registry export written again. Co-Authored-By: Claude Opus 5.5 --- wai/REGISTRY.md | 1 + wai/registry/capabilities.json | 4 ++++ wai/wai-rs/src/codecs/registry.rs | 1 + 3 files changed, 6 insertions(+) diff --git a/wai/REGISTRY.md b/wai/REGISTRY.md index 7661c203f..637fbd7d3 100644 --- a/wai/REGISTRY.md +++ b/wai/REGISTRY.md @@ -459,6 +459,7 @@ and a role are fixed once registered. | `wai.quantum.other` | refused on purpose: not a kernel; the fabric's test puts it in a certificate to see the placement refuse that certificate | | `wai.quantum.x/one` | refused on purpose: not a schema's name, its major not a number; the schema module's test gives it to see no file named for it | | `wai.quantum.job-result/2` | refused on purpose: a major of the job result's schema that no text defines; a test writes it into a sealed result to see the receipt fail | +| `wai.quantum.planner/2` | refused on purpose: a format of a contract job's reasoning that no text defines; the planner's test and the job receipts corpus seal it in a result to see the reasoning refused (quantum-providers §8.7) | | `wai.quantum.target/2` | refused on purpose: a major of the device target's schema that no text defines; the targets' test gives it to see the document refused | | `wai.quantum.provider/2` | refused on purpose: a version of the provider protocol that no text defines; the reference provider's test sends it to see it answered unsupported_version (quantum-providers §10) | | `wai.quantum.provider/9` | refused on purpose: a version of the provider protocol that no text defines; the protocol schema's test sends it to see it answered unsupported_version (quantum-providers §10) | diff --git a/wai/registry/capabilities.json b/wai/registry/capabilities.json index ab6f10cf7..33caf1dd5 100644 --- a/wai/registry/capabilities.json +++ b/wai/registry/capabilities.json @@ -3127,6 +3127,10 @@ "label": "wai.quantum.phasor", "reason": "a module label: wai-quantum's `quantum_phasor` and `quantum_phasor_meter`, the phasor bridge and its energy-accounted receipts" }, + { + "label": "wai.quantum.planner/2", + "reason": "refused on purpose: a format of a contract job's reasoning that no text defines; the planner's test and the job receipts corpus seal it in a result to see the reasoning refused (quantum-providers §8.7)" + }, { "label": "wai.quantum.provider-job/1", "reason": "a document with no schema file: the record wai-quantum-qpu keeps of a job on a person's provider, written before the job is sent" diff --git a/wai/wai-rs/src/codecs/registry.rs b/wai/wai-rs/src/codecs/registry.rs index 09a384928..1ffa11e37 100644 --- a/wai/wai-rs/src/codecs/registry.rs +++ b/wai/wai-rs/src/codecs/registry.rs @@ -1163,6 +1163,7 @@ pub const UNREGISTERED_LABELS: &[UnregisteredLabel] = &[ label("wai.quantum.other", "refused on purpose: not a kernel; the fabric's test puts it in a certificate to see the placement refuse that certificate"), label("wai.quantum.x/one", "refused on purpose: not a schema's name, its major not a number; the schema module's test gives it to see no file named for it"), label("wai.quantum.job-result/2", "refused on purpose: a major of the job result's schema that no text defines; a test writes it into a sealed result to see the receipt fail"), + label("wai.quantum.planner/2", "refused on purpose: a format of a contract job's reasoning that no text defines; the planner's test and the job receipts corpus seal it in a result to see the reasoning refused (quantum-providers §8.7)"), label("wai.quantum.target/2", "refused on purpose: a major of the device target's schema that no text defines; the targets' test gives it to see the document refused"), label("wai.quantum.provider/2", "refused on purpose: a version of the provider protocol that no text defines; the reference provider's test sends it to see it answered unsupported_version (quantum-providers §10)"), label("wai.quantum.provider/9", "refused on purpose: a version of the provider protocol that no text defines; the protocol schema's test sends it to see it answered unsupported_version (quantum-providers §10)"), -- 2.54.0 (Apple Git-157) From b0a7e26ee397f7f166d476698e3f6d65df017131 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Mon, 9 Nov 2026 13:27:41 -0500 Subject: [PATCH 36/42] wai-quantum-qpu: the linux leg pins its library at 93 The library holds 94 tests on macOS and 93 elsewhere: the keychain's test is cfg(target_os = "macos"), and the macOS leg runs it by name. The pin of 94 was counted on macOS. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/wai-quantum-qpu.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/wai-quantum-qpu.yml b/.github/workflows/wai-quantum-qpu.yml index e358e32ee..738f142b9 100644 --- a/.github/workflows/wai-quantum-qpu.yml +++ b/.github/workflows/wai-quantum-qpu.yml @@ -79,10 +79,11 @@ jobs: # tests never touch one but the macOS leg's own. export WAI_QUANTUM_CREDENTIALS=file cargo test --locked 2>&1 | tee "$RUNNER_TEMP/test.log" - # The library (94, the cloud-tasks client's and a job under a contract's among - # them), the clients against their contracts (17), and the providers - # end to end (12), each binary's count pinned. - for n in 94 17 12; do + # The library (93 here, the cloud-tasks client's and a job under a contract's + # among them; the macOS keychain's test makes 94 on macOS, run by the leg + # below), the clients against their contracts (17), and the providers end + # to end (12), each binary's count pinned. + for n in 93 17 12; do grep -qE "^test result: ok\. $n passed; 0 failed" "$RUNNER_TEMP/test.log" || { echo "::error::a test binary did not pass all $n of its tests"; exit 1; } done for t in curl_carries_a_request_to_a_server_and_back every_operation_over_http every_operation_over_a_local_process \ -- 2.54.0 (Apple Git-157) From 56dcf8c2d30fa180ab6da56264b0c9f0baa16dc7 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Mon, 9 Nov 2026 13:27:49 -0500 Subject: [PATCH 37/42] wai-quantum: a contract's reasoning checked from the built-ins' declarations, and the views within 1 MiB again planner::check read a built-in method's classes and auto rank through Registry::builtins(), whose methods are trait objects: every plan and run they reach was linked into whatever checks a receipt. The views' engine checks receipts in the page, and the page grew to 5 MB, past its 1 MiB limit (wai-quantum-views.yml). registry::declared reads the same from the built-ins' table, reaching none of their code; a test holds it to what every built-in says through its trait. With the contract's rules in it the engine is still 36 KB more than main's (282 KB against 246 KB), and the page, which carries the engine twice, 47 KB past the limit. The WebAssembly is now carried raw-deflated (RFC 1951) and inflated in the page by the platform's DecompressionStream, which needs no request and compiles no text: the page is 901 KB. The scripted host draws every view under the default policy (as JavaScript) and with WebAssembly allowed. The committed page is built again, so its engine checks contract jobs as the command line does. Co-Authored-By: Claude Opus 5.5 --- wai/quantum-studio/build-views.mjs | 16 +++++++--- wai/quantum-studio/src/views/check.js | 11 +++++-- wai/wai-quantum-cli/README.md | 2 +- wai/wai-quantum-views/README.md | 8 +++-- wai/wai-quantum/README.md | 2 +- wai/wai-quantum/src/engine/planner.rs | 32 +++++++++++-------- .../src/engine/registry/builtin.rs | 16 ++++++++-- wai/wai-quantum/src/engine/registry/mod.rs | 27 ++++++++++++++++ wai/wai-quantum/src/engine/registry/tests.rs | 23 +++++++++++++ wai/wai-quantum/views/manifest.json | 24 +++++++------- wai/wai-quantum/views/wai-quantum-views.html | 6 ++-- 11 files changed, 124 insertions(+), 43 deletions(-) diff --git a/wai/quantum-studio/build-views.mjs b/wai/quantum-studio/build-views.mjs index cf347e438..fad65a893 100644 --- a/wai/quantum-studio/build-views.mjs +++ b/wai/quantum-studio/build-views.mjs @@ -1,7 +1,9 @@ // Build the views an agent host draws (src/views/) into one self-contained // page: the view's script (the Studio's components, bundled), the Studio's // styles, and the engine inside the view (wai/wai-quantum-views) twice, as -// WebAssembly (base64) and as the same build translated to JavaScript. The page +// WebAssembly (raw-deflated, then base64: the view inflates it with the +// platform's DecompressionStream) and as the same build translated to +// JavaScript. The page // loads nothing and connects nowhere. The servers serve it for each of the six // views, naming the view in its . // @@ -17,6 +19,7 @@ // sources as they are: every source it names unchanged, and no source added. import { build, transform } from 'esbuild'; import { createHash } from 'node:crypto'; +import { deflateRawSync } from 'node:zlib'; import { mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'; import { dirname, join, relative } from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -84,6 +87,9 @@ if (checking) { const engineJs = (await transform(readFileSync(jsPath, 'utf8'), { format: 'iife', globalName: '__wqEngine', minify: true, legalComments: 'none', target: 'es2022' })).code; const factory = `globalThis.wqEngineJs=function(){${engineJs};return __wqEngine};`; const wasm = readFileSync(wasmPath); +// Carried deflated (RFC 1951, zlib's best compression): less than half its +// bytes, and the page within its limit with the engine whole. +const wasmDeflated = deflateRawSync(wasm, { level: 9 }); const css = (await transform(styleFiles.map((f) => readFileSync(join(here, f), 'utf8')).join('\n'), { loader: 'css', minify: true, legalComments: 'none' })).code; // Text inside a + @@ -114,11 +120,11 @@ const manifest = { about: 'The page every view of WAI Quantum is served from, the view named in its . Built by wai/wai-quantum-views/build.sh; do not edit it by hand.', placeholder: PLACEHOLDER, limit_bytes: LIMIT, - bytes: { page: bytes(html), script: bytes(script), styles: bytes(css), engine_wasm: wasm.length, engine_wasm_base64: Math.ceil(wasm.length / 3) * 4, engine_js: bytes(factory) }, - sha256: { page: sha(html), script: sha(script), styles: sha(css), engine_wasm: sha(wasm), engine_js: sha(factory) }, + bytes: { page: bytes(html), script: bytes(script), styles: bytes(css), engine_wasm: wasm.length, engine_wasm_deflated: wasmDeflated.length, engine_wasm_base64: Math.ceil(wasmDeflated.length / 3) * 4, engine_js: bytes(factory) }, + sha256: { page: sha(html), script: sha(script), styles: sha(css), engine_wasm: sha(wasm), engine_wasm_deflated: sha(wasmDeflated), engine_js: sha(factory) }, sources: Object.fromEntries(sources.map((p) => [p, sha(readFileSync(join(repo, p)))])), }; mkdirSync(out, { recursive: true }); writeFileSync(join(out, 'wai-quantum-views.html'), html); writeFileSync(join(out, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\n'); -console.log(`wrote ${join(out, 'wai-quantum-views.html')}: ${bytes(html)} bytes (script ${bytes(script)}, styles ${bytes(css)}, engine ${wasm.length} as WebAssembly and ${bytes(factory)} as JavaScript)`); +console.log(`wrote ${join(out, 'wai-quantum-views.html')}: ${bytes(html)} bytes (script ${bytes(script)}, styles ${bytes(css)}, engine ${wasm.length} as WebAssembly (${wasmDeflated.length} deflated) and ${bytes(factory)} as JavaScript)`); diff --git a/wai/quantum-studio/src/views/check.js b/wai/quantum-studio/src/views/check.js index 457eac798..0b0212da5 100644 --- a/wai/quantum-studio/src/views/check.js +++ b/wai/quantum-studio/src/views/check.js @@ -2,8 +2,9 @@ // on the machine that shows it, by the engine's own code. // // The page carries the engine twice, put in by the build: as WebAssembly -// (globalThis.WQ_ENGINE_WASM, base64) and as the same build translated to -// JavaScript (globalThis.wqEngineJs(), a factory). A host's content-security +// (globalThis.WQ_ENGINE_WASM, the module raw-deflated, RFC 1951, then base64) +// and as the same build translated to JavaScript (globalThis.wqEngineJs(), a +// factory). A host's content-security // policy may refuse to compile WebAssembly (the extension's default policy // has no 'wasm-unsafe-eval'); the page's own script runs wherever the view // does, so the second form checks the receipt there. Both give the same @@ -29,7 +30,11 @@ export function engine() { try { const b64 = globalThis.WQ_ENGINE_WASM; if (!b64) throw new Error('this page carries no WebAssembly engine'); - const bytes = Uint8Array.from(atob(b64), (c) => c.charCodeAt(0)); + const deflated = Uint8Array.from(atob(b64), (c) => c.charCodeAt(0)); + // Inflated here: the platform's own decompressor, no request and no code + // compiled from text, so a policy that refuses both lets it run. + const inflated = new Blob([deflated]).stream().pipeThrough(new DecompressionStream('deflate-raw')); + const bytes = await new Response(inflated).arrayBuffer(); const { instance } = await WebAssembly.instantiate(bytes, {}); return { form: 'WebAssembly', call: driver(instance.exports) }; } catch (e) { diff --git a/wai/wai-quantum-cli/README.md b/wai/wai-quantum-cli/README.md index c1bc9d013..7b8197bb9 100644 --- a/wai/wai-quantum-cli/README.md +++ b/wai/wai-quantum-cli/README.md @@ -458,7 +458,7 @@ It also serves the engine's resources and prompts, the same as the job service's ### Views in the agent's host -A host that draws interactive views (the protocol's extension `io.modelcontextprotocol/ui`, version 2026-01-26, said in the client's `initialize`) gets the engine's answers as views beside the conversation: a run's result with its verdict, a receipt, a circuit (a lint, a drawing, a repair, a compile with its certificate), a critique marked on its circuit, an estimate's frontier and a device target's map. Each tool that has one names it in `_meta.ui.resourceUri`, the six `ui://wai-quantum/*` resources are listed and read, and each answer carries what its view draws (the engine's layout, the circuit in words, a target's map) in its `_meta`, which the model does not read. The views are one self-contained page (`wai/wai-quantum/views/`, 802 KB, held under 1 MiB) that loads nothing and connects nowhere; it checks the receipt of what it shows with the engine inside it, as WebAssembly where the host's content-security policy allows it and translated to JavaScript where it does not (the extension's default policy refuses WebAssembly), and tells the model what it found. A host that draws no views is told nothing of them; every answer that has a view also comes in plain words beside its JSON. +A host that draws interactive views (the protocol's extension `io.modelcontextprotocol/ui`, version 2026-01-26, said in the client's `initialize`) gets the engine's answers as views beside the conversation: a run's result with its verdict, a receipt, a circuit (a lint, a drawing, a repair, a compile with its certificate), a critique marked on its circuit, an estimate's frontier and a device target's map. Each tool that has one names it in `_meta.ui.resourceUri`, the six `ui://wai-quantum/*` resources are listed and read, and each answer carries what its view draws (the engine's layout, the circuit in words, a target's map) in its `_meta`, which the model does not read. The views are one self-contained page (`wai/wai-quantum/views/`, 880 KB, held under 1 MiB) that loads nothing and connects nowhere; it checks the receipt of what it shows with the engine inside it, as WebAssembly where the host's content-security policy allows it and translated to JavaScript where it does not (the extension's default policy refuses WebAssembly), and tells the model what it found. A host that draws no views is told nothing of them; every answer that has a view also comes in plain words beside its JSON. ### Scoring a model diff --git a/wai/wai-quantum-views/README.md b/wai/wai-quantum-views/README.md index d85e72585..21b1ba3d7 100644 --- a/wai/wai-quantum-views/README.md +++ b/wai/wai-quantum-views/README.md @@ -29,9 +29,11 @@ of the binary), optimises it for size and translates it to JavaScript with binaryen, and runs `wai/quantum-studio/build-views.mjs`, which bundles the views (`wai/quantum-studio/src/views/`, from the Studio's components) and writes the page and its `manifest.json`: each part's size and SHA-256, and -every source with its SHA-256. The page is 802 KB: the script 94 KB (the -Studio's English words among it), the styles 49 KB, the engine 194 KB as -WebAssembly (258 KB in base64) and 401 KB as JavaScript. Every view is held under 1 MiB. +every source with its SHA-256. The page is 880 KB: the script 94 KB (the +Studio's English words among it), the styles 50 KB, the engine 274 KB as +WebAssembly, carried raw-deflated (131 KB, 175 KB in base64) and inflated by +the page with the platform's `DecompressionStream`, and 561 KB as JavaScript. +Every view is held under 1 MiB. On x86_64 Linux with Rust 1.98.0 the build gives the same bytes in a clean CI image. The engine's bytes change when anything in `wai-quantum` changes (its diff --git a/wai/wai-quantum/README.md b/wai/wai-quantum/README.md index 8339148a7..d1a768d2a 100644 --- a/wai/wai-quantum/README.md +++ b/wai/wai-quantum/README.md @@ -799,7 +799,7 @@ receipt marker by running it again. Its conformance set is circuit, a result with its verdict, a receipt, a critique, an estimate's frontier, a device target's map) to an agent host through the Model Context Protocol's extension for them (`io.modelcontextprotocol/ui`, 2026-01-26): -`ui://wai-quantum/*` resources, one self-contained page of 802 KB held under +`ui://wai-quantum/*` resources, one self-contained page of 880 KB held under 1 MiB (`views/`, built by `wai/wai-quantum-views/build.sh`), which checks the receipt of what it shows with the engine inside it, as WebAssembly or, under a policy that refuses WebAssembly, translated to JavaScript. Both MCP servers diff --git a/wai/wai-quantum/src/engine/planner.rs b/wai/wai-quantum/src/engine/planner.rs index bc0a08300..491018f4c 100644 --- a/wai/wai-quantum/src/engine/planner.rs +++ b/wai/wai-quantum/src/engine/planner.rs @@ -65,7 +65,7 @@ use super::catalog::{self, Plan, Request}; use super::fabric; use super::receipt; use super::refusal::{self, tag}; -use super::registry::{Identity, Job, Kind, Method, Question, Registry}; +use super::registry::{Identity, Job, Kind, Method, Question, Registry, declared}; use serde_json::{Map, Value, json}; use std::cmp::Ordering; @@ -390,14 +390,7 @@ fn is_gpu(method: &str) -> bool { /// The class a method's result has at worst, as far as the plan can say: the /// weakest it declares, or for the methods whose class the job fixes, that one. fn class_of(m: &dyn Method, r: Option<&Request>, plan: Option<&Plan>, target: bool) -> String { - let worst = || { - let declared = m.classes(); - match declared.as_slice() { - [] => "unknown".to_string(), - [one] => one.clone(), - many => LADDER.iter().find(|c| many.iter().all(|d| meets(c, d))).map_or_else(|| "unknown".to_string(), |c| c.to_string()), - } - }; + let worst = || worst_of(&m.classes()); match (m.name(), r) { ("stabilizer", Some(r)) => if r.noise.is_some() || target { "estimate".into() } else { "exact".into() }, ("stabilizer_rank", Some(r)) => if ["terms", "epsilon"].iter().any(|k| r.options.get(*k).is_some_and(|x| !x.is_null())) { "estimate".into() } else { "exact".into() }, @@ -410,6 +403,16 @@ fn class_of(m: &dyn Method, r: Option<&Request>, plan: Option<&Plan>, target: bo } } +/// The weakest of the classes a method declares: the first of the ladder that +/// each of them meets. +fn worst_of>(declared: &[S]) -> String { + match declared { + [] => "unknown".to_string(), + [one] => one.as_ref().to_string(), + many => LADDER.iter().find(|c| many.iter().all(|d| meets(c, d.as_ref()))).map_or_else(|| "unknown".to_string(), |c| c.to_string()), + } +} + /// A local route's time: at the planner's nominal rate, where its work predicts /// its time. fn time_of(p: &Plan) -> Value { @@ -1505,7 +1508,7 @@ pub fn check(request: &Value, result: &Value) -> Vec<&'static str> { let q = question_of(request); let ranks_ok = routes.iter().filter(|r| r["kind"] == "local").all(|r| { let m = r["route"].as_str().and_then(|n| n.strip_prefix("method:")).unwrap_or(""); - Registry::builtins().method(m).is_none_or(|b| r["auto_rank"].as_f64() == b.auto_rank(question(q)).map(f64::from)) + declared(m).is_none_or(|b| r["auto_rank"].as_f64() == b.auto_rank(question(q)).map(f64::from)) }); let auto = auto_of(routes, request, named.as_deref()); let class_named = |name: &str| routes.iter().find(|r| r["route"] == name).and_then(|r| r["class"].as_str()).map(str::to_string); @@ -1569,9 +1572,10 @@ pub fn check(request: &Value, result: &Value) -> Vec<&'static str> { } /// Whether `class` is one the built-in `method` has; any class of a method that -/// is not one of the built-ins, whose word it is. +/// is not one of the built-ins, whose word it is. Like every rule [`check`] +/// reads of a built-in, from its declaration ([`declared`]), never its code. fn class_of_method(method: &str, class: &str) -> bool { - Registry::builtins().method(method).is_none_or(|m| m.classes().iter().any(|c| c == class)) + declared(method).is_none_or(|m| m.classes.contains(&class)) } /// Whether a route states of itself what section 8.7 gives it. A built-in method @@ -1584,7 +1588,7 @@ fn states_itself(r: &Value, request: &Value) -> bool { return r["host_dependent"] == true && r["provenance"].as_str().and_then(super::provider::class_of_provenance).is_none_or(|c| class == c); }; // A method the host registered is the host's own code. - let Some(builtin) = Registry::builtins().method(m) else { + let Some(builtin) = declared(m) else { return r["host_dependent"] == true; }; let given = |k: &str| request["options"].get(k).is_some_and(|x| !x.is_null()); @@ -1595,7 +1599,7 @@ fn states_itself(r: &Value, request: &Value) -> bool { "cutrank" => true, // Every other method's route has the one class its table gives: the first // each class it declares meets. - _ => class == class_of(builtin, None, None, false), + _ => class == worst_of(builtin.classes), }; by_job && class_of_method(m, class) && r["host_dependent"] == is_gpu(m) } diff --git a/wai/wai-quantum/src/engine/registry/builtin.rs b/wai/wai-quantum/src/engine/registry/builtin.rs index e960c3a84..f9238f6aa 100644 --- a/wai/wai-quantum/src/engine/registry/builtin.rs +++ b/wai/wai-quantum/src/engine/registry/builtin.rs @@ -66,7 +66,16 @@ const METHODS: [BuiltinMethod; 12] = [ m("trajectories", &["estimate"], true, [Some(30), None, None, None]), ]; -fn question_index(q: Question) -> usize { +/// What the built-in method `name` declares of itself that a verifier reads, +/// from the tables alone ([`super::declared`]). +pub(super) fn declared(name: &str) -> Option { + if name == crate::engine::pulse::METHOD { + return Some(super::Declared { classes: PULSE_CLASSES, ranks: [None; 4] }); + } + METHODS.iter().find(|m| m.name == name).map(|m| super::Declared { classes: m.classes, ranks: m.ranks }) +} + +pub(super) fn question_index(q: Question) -> usize { match q { Question::Noise => 0, Question::Counts => 1, @@ -120,6 +129,9 @@ impl Method for BuiltinMethod { #[derive(Clone, Copy)] struct PulseMethod; +/// The pulse method's one class: its error is bounded by its series' order. +const PULSE_CLASSES: &[&str] = &["bounded"]; + impl Method for PulseMethod { fn name(&self) -> &str { crate::engine::pulse::METHOD @@ -128,7 +140,7 @@ impl Method for PulseMethod { ENGINE_VERSION } fn classes(&self) -> Vec { - vec!["bounded".into()] + PULSE_CLASSES.iter().map(|c| c.to_string()).collect() } fn descriptor(&self) -> Value { let mut d = crate::engine::pulse::describe(); diff --git a/wai/wai-quantum/src/engine/registry/mod.rs b/wai/wai-quantum/src/engine/registry/mod.rs index 9791ec43a..6964753e4 100644 --- a/wai/wai-quantum/src/engine/registry/mod.rs +++ b/wai/wai-quantum/src/engine/registry/mod.rs @@ -201,6 +201,33 @@ impl Question { } } +/// What a built-in method declares of itself that a verifier reads: its +/// accuracy classes and where `auto` tries it, as [`Method::classes`] and +/// [`Method::auto_rank`] give them ([`declared`]). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Declared { + /// Its accuracy classes, in the order [`Method::classes`] gives them. + pub classes: &'static [&'static str], + ranks: [Option; 4], +} + +impl Declared { + /// Where `auto` tries it for `question`, as [`Method::auto_rank`] gives it. + pub fn auto_rank(&self, question: Question) -> Option { + self.ranks[builtin::question_index(question)] + } +} + +/// What the built-in method `name` declares of itself that a verifier reads, +/// or `None` for a name no built-in holds. Read from the built-ins' tables +/// alone: nothing reaches a method's plan or run, so a check that reads this +/// (a contract job's reasoning, [`super::planner::check`]) links none of the +/// methods, and a page that carries the check (the views) carries no +/// simulator. A test holds it to [`Registry::builtins`]. +pub fn declared(name: &str) -> Option { + builtin::declared(name) +} + // --------------------------------------------------------------------------- // The four traits // --------------------------------------------------------------------------- diff --git a/wai/wai-quantum/src/engine/registry/tests.rs b/wai/wai-quantum/src/engine/registry/tests.rs index ff05fbdc1..991236527 100644 --- a/wai/wai-quantum/src/engine/registry/tests.rs +++ b/wai/wai-quantum/src/engine/registry/tests.rs @@ -344,6 +344,29 @@ fn every_built_in_registers_through_its_trait_in_a_fixed_order() { } } +/// What a verifier reads of a built-in without reaching its code is what the +/// built-in says through its trait: every class, in order, and its rank for +/// every question; and nothing is declared of a name no built-in holds, a +/// host's own method's included. +#[test] +fn a_built_in_s_declaration_is_what_its_trait_says() { + let r = Registry::with_builtins(); + let mut seen = 0; + for m in r.methods() { + let d = declared(m.name()).unwrap_or_else(|| panic!("{} is declared", m.name())); + assert_eq!(d.classes.iter().map(|c| c.to_string()).collect::>(), m.classes(), "{}", m.name()); + for q in Question::ALL { + assert_eq!(d.auto_rank(q), m.auto_rank(q), "{} for {q:?}", m.name()); + } + seen += 1; + } + assert_eq!(seen, 13, "every built-in method"); + for name in ["basis_table", "auto", "provider", "", "Exact"] { + assert_eq!(declared(name), None, "{name}"); + } + assert!(host().method("basis_table").is_some() && declared("basis_table").is_none(), "a host's method is not a built-in's declaration"); +} + /// `auto` tries the methods in the order it always has. #[test] fn auto_tries_the_built_ins_in_the_order_it_did() { diff --git a/wai/wai-quantum/views/manifest.json b/wai/wai-quantum/views/manifest.json index 970ba68d8..ae581541a 100644 --- a/wai/wai-quantum/views/manifest.json +++ b/wai/wai-quantum/views/manifest.json @@ -4,22 +4,24 @@ "placeholder": "__WAI_QUANTUM_VIEW__", "limit_bytes": 1048576, "bytes": { - "page": 983280, - "script": 95807, + "page": 901474, + "script": 95922, "styles": 50804, - "engine_wasm": 244359, - "engine_wasm_base64": 325812, - "engine_js": 510407 + "engine_wasm": 280265, + "engine_wasm_deflated": 134512, + "engine_wasm_base64": 179352, + "engine_js": 574946 }, "sha256": { - "page": "779aa560416afcc677fc4efb28f2a6ac55ff3e4bb3436f3d381e7197fbaf0ce2", - "script": "6fbf441c1d2f095f0a5f14adaeb10740add48c4122d01a8f15e03b0f59045bde", + "page": "14aa5fa064777f35bb324f2b222f39850e6e61c0686fe7b16c714d2c03a14cc9", + "script": "292084d11ac2b7bacf0c9314a3f0c11362c9cd2a7d739db0f3ff624819c3c04b", "styles": "11ebcd4416c68e9eaf1156ca6f7c92b9a96744895ed13c377eba98fdd8dca9a6", - "engine_wasm": "980a4a222518c3dcc07bc3e537950c115d1fb02ec8a02757ea646b562e329dd6", - "engine_js": "9733679060ee525e68e941477acd9b077b6155950637648e00b7893ab2814f1a" + "engine_wasm": "fd5a7d65cce6d189e508084101e134881909995fe80da9cd1b697e6941dbdad7", + "engine_wasm_deflated": "091200eeb509265b03408ba710cf432be4fcfe965ed62070e21502f08fe68cb6", + "engine_js": "00a4a2cc0630658eb10adfe461ff7e8a1b60fa5800a62761e0cb1f55269b39ba" }, "sources": { - "wai/quantum-studio/build-views.mjs": "da5b161829a990b3d1bb4c1b3ec7c8f254ff7b5078476156e504ae322bc4f010", + "wai/quantum-studio/build-views.mjs": "ae4aca713fb9a2c2b9228deef292ad5d09eac8185a01bcfd87345b6f067f701f", "wai/quantum-studio/locales/en/assistant.json": "3fca2eca4c2eab7b5c1af71bd2c4e92f48c7102cd786962e343f899d367a2e2c", "wai/quantum-studio/locales/en/circuit_svg.json": "d54b6c26e870f45c40b48497699f81b9203c1c201179b4c0d5e9a300e97203a6", "wai/quantum-studio/locales/en/compile_view.json": "d62e2314eb462c944755c90c93ea10ac4cdf2c22a7781b66b5c3a7829b063d3d", @@ -59,7 +61,7 @@ "wai/quantum-studio/src/studio.css": "8891f2a1b71e1ada344ee1dc41939ba9cd41232f25ab2703d05394c141855997", "wai/quantum-studio/src/tokens.css": "492fbaf8a6cc5b1f7e89346336af3e0a1930a0b48a23731d80d86c128a9032c3", "wai/quantum-studio/src/verdict-view.js": "aec18c93c6f502657ffe2981ca4d9ae0956e1277638d1a9bb1b0846ac8e80160", - "wai/quantum-studio/src/views/check.js": "2edae7b446e72a49293478ebcbfe21792b74762dcfb097fb9e75ec3a4feb8d9a", + "wai/quantum-studio/src/views/check.js": "e3bce09f12039f37b892d51dc51aea277ecc9a38ba4c066717d06f9c49c78f5e", "wai/quantum-studio/src/views/host.js": "2390e14b9e58005f2590fe7d7202a003312f07ffb0ee996469f3f9555c748bee", "wai/quantum-studio/src/views/main.js": "4129c45e35f65caaedb9e2fd4e0e2e1a29ba6ff27b33c5190924c8cc13b2a5cd", "wai/quantum-studio/src/views/render.js": "b3f8bd6717bd18b6275ea8fc94cd2be31f81ef0a8d7c46a882e03085a67eaea4", diff --git a/wai/wai-quantum/views/wai-quantum-views.html b/wai/wai-quantum/views/wai-quantum-views.html index e9b68b163..33743e476 100644 --- a/wai/wai-quantum/views/wai-quantum-views.html +++ b/wai/wai-quantum/views/wai-quantum-views.html @@ -11,10 +11,10 @@
- - -- 2.54.0 (Apple Git-157) From be5a3c453875aa8369d6998d6eea5b02e4a67f7c Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Mon, 9 Nov 2026 13:29:09 -0500 Subject: [PATCH 38/42] wai-quantum-cli: wai.quantum.timings/1 listed as a document with no schema file, and /9 as refused on purpose The command line keeps the runs it has timed in a file of format wai.quantum.timings/1, and its test writes wai.quantum.timings/9 to see a file of another format kept aside; the repository's quantum names check found both accounted for nowhere. Listed in their groups, and the registry export written again. Co-Authored-By: Claude Opus 5.5 --- wai/REGISTRY.md | 2 ++ wai/registry/capabilities.json | 8 ++++++++ wai/wai-rs/src/codecs/registry.rs | 2 ++ 3 files changed, 12 insertions(+) diff --git a/wai/REGISTRY.md b/wai/REGISTRY.md index 637fbd7d3..120b752d9 100644 --- a/wai/REGISTRY.md +++ b/wai/REGISTRY.md @@ -453,6 +453,7 @@ and a role are fixed once registered. | `wai.quantum.docs-manifest/1` | a document with no schema file: the list of documents tools/quantum-docs checks | | `wai.quantum.write/1` | a document with no schema file: the transcript wai-quantum-writer keeps of writing a program for a task | | `wai.quantum.model/1` | a document with no schema file: the manifest of a writer's model, the file wai-model.json (wai-quantum-writer's `coder`) | +| `wai.quantum.timings/1` | a document with no schema file: the runs the command line has timed and read the energy of on this machine, by method, that its estimate of a job's energy rests on (wai-quantum-cli's `estimates`) | | `wai.quantum.job-key/1` | a digest domain: the digest a job service keeps a client's idempotency key under, the client's name beside the key (wai-quantum-service) | | `wai.quantum.trace/1` | a digest domain: an optimisation trace's first link is BLAKE3 of it and the request's canonical text (wai-quantum's `engine::variational`) | | `wai.quantum.circuit3` | refused on purpose: not a capability; the circuit core's test gives it to see no gateset read from it | @@ -460,6 +461,7 @@ and a role are fixed once registered. | `wai.quantum.x/one` | refused on purpose: not a schema's name, its major not a number; the schema module's test gives it to see no file named for it | | `wai.quantum.job-result/2` | refused on purpose: a major of the job result's schema that no text defines; a test writes it into a sealed result to see the receipt fail | | `wai.quantum.planner/2` | refused on purpose: a format of a contract job's reasoning that no text defines; the planner's test and the job receipts corpus seal it in a result to see the reasoning refused (quantum-providers §8.7) | +| `wai.quantum.timings/9` | refused on purpose: a major of the command line's timings that no text defines; its test writes it to see the file kept aside and a new one begun | | `wai.quantum.target/2` | refused on purpose: a major of the device target's schema that no text defines; the targets' test gives it to see the document refused | | `wai.quantum.provider/2` | refused on purpose: a version of the provider protocol that no text defines; the reference provider's test sends it to see it answered unsupported_version (quantum-providers §10) | | `wai.quantum.provider/9` | refused on purpose: a version of the provider protocol that no text defines; the protocol schema's test sends it to see it answered unsupported_version (quantum-providers §10) | diff --git a/wai/registry/capabilities.json b/wai/registry/capabilities.json index 33caf1dd5..818add885 100644 --- a/wai/registry/capabilities.json +++ b/wai/registry/capabilities.json @@ -3223,6 +3223,14 @@ "label": "wai.quantum.tdvp", "reason": "a module label: wai-quantum's `quantum_tdvp`, time evolution of spin chains by TDVP" }, + { + "label": "wai.quantum.timings/1", + "reason": "a document with no schema file: the runs the command line has timed and read the energy of on this machine, by method, that its estimate of a job's energy rests on (wai-quantum-cli's `estimates`)" + }, + { + "label": "wai.quantum.timings/9", + "reason": "refused on purpose: a major of the command line's timings that no text defines; its test writes it to see the file kept aside and a new one begun" + }, { "label": "wai.quantum.tn", "reason": "a module label: wai-quantum's `quantum_tn`, tensor-network contraction" diff --git a/wai/wai-rs/src/codecs/registry.rs b/wai/wai-rs/src/codecs/registry.rs index 1ffa11e37..9fb497332 100644 --- a/wai/wai-rs/src/codecs/registry.rs +++ b/wai/wai-rs/src/codecs/registry.rs @@ -1155,6 +1155,7 @@ pub const UNREGISTERED_LABELS: &[UnregisteredLabel] = &[ label("wai.quantum.docs-manifest/1", "a document with no schema file: the list of documents tools/quantum-docs checks"), label("wai.quantum.write/1", "a document with no schema file: the transcript wai-quantum-writer keeps of writing a program for a task"), label("wai.quantum.model/1", "a document with no schema file: the manifest of a writer's model, the file wai-model.json (wai-quantum-writer's `coder`)"), + label("wai.quantum.timings/1", "a document with no schema file: the runs the command line has timed and read the energy of on this machine, by method, that its estimate of a job's energy rests on (wai-quantum-cli's `estimates`)"), // The domains a digest starts with. label("wai.quantum.job-key/1", "a digest domain: the digest a job service keeps a client's idempotency key under, the client's name beside the key (wai-quantum-service)"), label("wai.quantum.trace/1", "a digest domain: an optimisation trace's first link is BLAKE3 of it and the request's canonical text (wai-quantum's `engine::variational`)"), @@ -1164,6 +1165,7 @@ pub const UNREGISTERED_LABELS: &[UnregisteredLabel] = &[ label("wai.quantum.x/one", "refused on purpose: not a schema's name, its major not a number; the schema module's test gives it to see no file named for it"), label("wai.quantum.job-result/2", "refused on purpose: a major of the job result's schema that no text defines; a test writes it into a sealed result to see the receipt fail"), label("wai.quantum.planner/2", "refused on purpose: a format of a contract job's reasoning that no text defines; the planner's test and the job receipts corpus seal it in a result to see the reasoning refused (quantum-providers §8.7)"), + label("wai.quantum.timings/9", "refused on purpose: a major of the command line's timings that no text defines; its test writes it to see the file kept aside and a new one begun"), label("wai.quantum.target/2", "refused on purpose: a major of the device target's schema that no text defines; the targets' test gives it to see the document refused"), label("wai.quantum.provider/2", "refused on purpose: a version of the provider protocol that no text defines; the reference provider's test sends it to see it answered unsupported_version (quantum-providers §10)"), label("wai.quantum.provider/9", "refused on purpose: a version of the provider protocol that no text defines; the protocol schema's test sends it to see it answered unsupported_version (quantum-providers §10)"), -- 2.54.0 (Apple Git-157) From e5a116af625890046f987f9e5df7bfbb6322869e Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Mon, 9 Nov 2026 13:34:44 -0500 Subject: [PATCH 39/42] wai: pack-conformance/multi_verify.py named where it runs, in wai-pack.yml Main's 5df961d52 added the packages of several components' independent verifier, which wai-pack.yml runs; no step file runs it and NOT_HERE did not name it, so dx::independent::tests::every_verifier_in_the_tree_is_an_entry_or_says_why_not failed in every job that runs the wai binary's tests, on main as here. Named beside pack_verify.py, which the same workflow runs. Co-Authored-By: Claude Opus 5.5 --- wai/wai-rs/src/bin/wai_cli/dx/independent.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/wai/wai-rs/src/bin/wai_cli/dx/independent.rs b/wai/wai-rs/src/bin/wai_cli/dx/independent.rs index fe501374b..836ab6ab7 100644 --- a/wai/wai-rs/src/bin/wai_cli/dx/independent.rs +++ b/wai/wai-rs/src/bin/wai_cli/dx/independent.rs @@ -80,6 +80,7 @@ include!(concat!(env!("OUT_DIR"), "/independent_verifiers.rs")); /// no line here: its step says where it runs.) pub const NOT_HERE: &[(&str, &str)] = &[ ("pack-conformance/pack_verify.py", "wai-pack.yml runs it, beside the reference packager's differentials against it"), + ("pack-conformance/multi_verify.py", "wai-pack.yml runs it over the packages of several components, with a planted fault in each it must find"), ]; /// The entry named `name`. -- 2.54.0 (Apple Git-157) From 2eeed68bd1645647bdc6d2ebbd3d24dd771206e1 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Mon, 9 Nov 2026 13:34:44 -0500 Subject: [PATCH 40/42] wai-quantum: the nesting bound's test reads at the bound on the stack a debug build needs Main's 15ae7d457 reads programs nested to the bound (Q130) in a lib test on the test thread's 2 MiB stack. A debug build's frames are many times a release build's, so the debug run (wai-energy-receipts.yml's --lib --tests) overflowed and aborted on x86_64 Linux and on macOS, stopping every test after it. The test is of where the bound falls; what the bound asks of a stack is tests/reader_stack.rs's, which reads at it on 16 MiB in a debug build. The test now reads on a thread of 16 MiB, and inline on wasm32, which has no threads. Co-Authored-By: Claude Opus 5.5 --- wai/wai-quantum/src/qasm/lang_tests.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/wai/wai-quantum/src/qasm/lang_tests.rs b/wai/wai-quantum/src/qasm/lang_tests.rs index 086eb153d..76bfc652e 100644 --- a/wai/wai-quantum/src/qasm/lang_tests.rs +++ b/wai/wai-quantum/src/qasm/lang_tests.rs @@ -652,6 +652,18 @@ pub(crate) fn chain(kind: &str, d: usize, k: usize, inner: usize) -> String { /// through calls is bounded as nesting in one body is. #[test] fn nesting_is_bounded_as_the_text_counts_it() { + // Where the bound falls, read on the stack a debug build needs at it: a debug build's + // frames are many times a release build's, and a program at the bound overflows the + // 2 MiB a test thread has. What the bound asks of a stack is tests/reader_stack.rs's, + // which reads at it on 1 MiB in a release build and 16 MiB in a debug one, as here. + // wasm32 has no threads: there it reads inline. + #[cfg(not(target_family = "wasm"))] + std::thread::Builder::new().stack_size(16 << 20).spawn(nesting_bound).expect("a thread for the reading").join().unwrap_or_else(|e| std::panic::resume_unwind(e)); + #[cfg(target_family = "wasm")] + nesting_bound(); +} + +fn nesting_bound() { for shape in ["parens", "unary", "sum", "product", "index", "concat", "type", "blocks", "ifs", "fors"] { let past = read(&nested(shape, 127)).map(|_| ()).unwrap_err(); assert_eq!(past.code, "Q130", "{shape} at 129: {past}"); -- 2.54.0 (Apple Git-157) From 1a0a3cbabf1d33d9deca9dbb737ca07e0c29c523 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Mon, 9 Nov 2026 13:35:44 -0500 Subject: [PATCH 41/42] wai-quantum: the views page built again, its engine with the energy ceiling's rules Co-Authored-By: Claude Opus 5.5 --- wai/wai-quantum/views/manifest.json | 18 +++++++++--------- wai/wai-quantum/views/wai-quantum-views.html | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/wai/wai-quantum/views/manifest.json b/wai/wai-quantum/views/manifest.json index ae581541a..bc2c97c1c 100644 --- a/wai/wai-quantum/views/manifest.json +++ b/wai/wai-quantum/views/manifest.json @@ -4,21 +4,21 @@ "placeholder": "__WAI_QUANTUM_VIEW__", "limit_bytes": 1048576, "bytes": { - "page": 901474, + "page": 904051, "script": 95922, "styles": 50804, - "engine_wasm": 280265, - "engine_wasm_deflated": 134512, - "engine_wasm_base64": 179352, - "engine_js": 574946 + "engine_wasm": 281266, + "engine_wasm_deflated": 135225, + "engine_wasm_base64": 180300, + "engine_js": 576575 }, "sha256": { - "page": "14aa5fa064777f35bb324f2b222f39850e6e61c0686fe7b16c714d2c03a14cc9", + "page": "5be4f0480029d1fc9fc3aa96ddf0adfa8860f947ba70540a38834a7e114e8e22", "script": "292084d11ac2b7bacf0c9314a3f0c11362c9cd2a7d739db0f3ff624819c3c04b", "styles": "11ebcd4416c68e9eaf1156ca6f7c92b9a96744895ed13c377eba98fdd8dca9a6", - "engine_wasm": "fd5a7d65cce6d189e508084101e134881909995fe80da9cd1b697e6941dbdad7", - "engine_wasm_deflated": "091200eeb509265b03408ba710cf432be4fcfe965ed62070e21502f08fe68cb6", - "engine_js": "00a4a2cc0630658eb10adfe461ff7e8a1b60fa5800a62761e0cb1f55269b39ba" + "engine_wasm": "fac677fe6c7cf12f068a1189a52f45cf9b3b6ed0f01da7a44056df5429a52738", + "engine_wasm_deflated": "ca5d344c68f0bdbabfd56c60f275701a3ad4ae44f751c7dbf68829f6d1247ac4", + "engine_js": "5abe86e71a5568597d1f759fef2a62ffe4a00fd933b131baa2d71ab8a155d192" }, "sources": { "wai/quantum-studio/build-views.mjs": "ae4aca713fb9a2c2b9228deef292ad5d09eac8185a01bcfd87345b6f067f701f", diff --git a/wai/wai-quantum/views/wai-quantum-views.html b/wai/wai-quantum/views/wai-quantum-views.html index 33743e476..fd2eefcba 100644 --- a/wai/wai-quantum/views/wai-quantum-views.html +++ b/wai/wai-quantum/views/wai-quantum-views.html @@ -11,7 +11,7 @@
-