run and job_request take intent, verdict and repair, and Job.verdict reads the verdict the receipt seals. verdict() gives a job's verdict, its own or one worked out here for another intent (marked not sealed); repair() makes the mechanical fixes on the flagged lines and refuses a proposal that changes another line. EngineError's code reads the job layer's codes as well as the reader's. The getting-started notebook's stored refusal carries its J011. Co-Authored-By: Claude Opus 5.5 <[email protected]>
135 lines
4.6 KiB
Python
135 lines
4.6 KiB
Python
"""A job's answer as a plain dict, with helpers for what is read most."""
|
||
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
from typing import Any, Dict, List, Optional
|
||
|
||
__all__ = ["Job", "Verification"]
|
||
|
||
|
||
class Verification(dict):
|
||
"""Whether a receipt seals its request and its result: ``valid``, the
|
||
``key`` it names (64 hex digits) and the ``signer`` (that key as a
|
||
``did:key``). True exactly when the receipt is valid."""
|
||
|
||
@property
|
||
def valid(self) -> bool:
|
||
return self.get("valid") is True
|
||
|
||
@property
|
||
def signer(self) -> Optional[str]:
|
||
return self.get("signer")
|
||
|
||
@property
|
||
def key(self) -> Optional[str]:
|
||
return self.get("key")
|
||
|
||
def __bool__(self) -> bool:
|
||
return self.valid
|
||
|
||
def _repr_html_(self) -> str:
|
||
from . import _render
|
||
|
||
return _render.verification_html(self)
|
||
|
||
|
||
class Job(dict):
|
||
"""A job as every surface returns it, the service's form: ``status``,
|
||
``method``, ``why``, ``estimate``, ``request``, and ``result`` with its
|
||
``receipt``. It is a plain dict (``json.dumps`` writes it as the service
|
||
sends it); the properties read the parts most often wanted.
|
||
"""
|
||
|
||
@property
|
||
def status(self) -> Optional[str]:
|
||
return self.get("status")
|
||
|
||
@property
|
||
def method(self) -> Optional[str]:
|
||
return self.get("method") or self.result.get("method")
|
||
|
||
@property
|
||
def request(self) -> Dict[str, Any]:
|
||
return self.get("request") or {}
|
||
|
||
@property
|
||
def result(self) -> Dict[str, Any]:
|
||
return self.get("result") or {}
|
||
|
||
@property
|
||
def accuracy(self) -> Optional[str]:
|
||
"""The result's accuracy class: ``bit-exact``, ``exact``, ``bounded``,
|
||
``estimate``, ``heuristic`` or ``single``."""
|
||
a = self.result.get("accuracy")
|
||
return a.get("class") if isinstance(a, dict) else a
|
||
|
||
@property
|
||
def receipt(self) -> Optional[Dict[str, Any]]:
|
||
return self.result.get("receipt")
|
||
|
||
@property
|
||
def verdict(self) -> Optional[Dict[str, Any]]:
|
||
"""How far the engine checked the job, sealed by its receipt, when
|
||
the job asked for it (``intent=``, or ``verdict=True``): its
|
||
``level``, whether its intents ``hold``, and its ``statement``."""
|
||
return self.result.get("verdict")
|
||
|
||
@property
|
||
def counts(self) -> Dict[str, int]:
|
||
"""Each outcome's count, the most frequent first (bit strings with
|
||
the highest classical bit first)."""
|
||
return dict(self.result.get("counts") or {})
|
||
|
||
@property
|
||
def shots(self) -> int:
|
||
"""The shots sampled: the counts listed and those omitted."""
|
||
return sum(self.counts.values()) + int(self.result.get("omitted_shots") or 0)
|
||
|
||
def probabilities(self) -> Dict[str, float]:
|
||
"""Each listed outcome's sampled frequency: its count over the shots.
|
||
These are samples of the distribution, as exact as the shots allow;
|
||
for an exact probability ask for the amplitude."""
|
||
n = self.shots
|
||
return {k: v / n for k, v in self.counts.items()} if n else {}
|
||
|
||
@property
|
||
def expectations(self) -> Dict[str, float]:
|
||
"""Each observable's expectation value, by the observable as asked."""
|
||
return {e["observable"]: e["value"] for e in self.result.get("expectations") or []}
|
||
|
||
@property
|
||
def amplitudes(self) -> Dict[str, complex]:
|
||
"""Each asked-for basis state's amplitude, by its bit string (one bit
|
||
per qubit, qubit n − 1 first)."""
|
||
return {a["bits"]: complex(a["re"], a["im"]) for a in self.result.get("amplitudes") or []}
|
||
|
||
def verify(self) -> Verification:
|
||
"""Whether the result's receipt seals it and the request, checked
|
||
here, offline."""
|
||
from ._api import verify
|
||
|
||
return verify(self)
|
||
|
||
def to_json(self, **kw: Any) -> str:
|
||
return json.dumps(self, **kw)
|
||
|
||
def summary(self) -> str:
|
||
"""One line: the method, the accuracy class and what the result holds."""
|
||
bits: List[str] = [f"{self.method or '?'}", f"accuracy {self.accuracy or '?'}"]
|
||
if self.counts:
|
||
bits.append(f"{self.shots} shots, {len(self.counts)} outcomes listed")
|
||
if self.result.get("expectations"):
|
||
bits.append(f"{len(self.result['expectations'])} expectation values")
|
||
if self.result.get("amplitudes"):
|
||
bits.append(f"{len(self.result['amplitudes'])} amplitudes")
|
||
if self.verdict:
|
||
bits.append(f"verdict {self.verdict.get('level')}")
|
||
if self.receipt:
|
||
bits.append("sealed")
|
||
return ", ".join(bits)
|
||
|
||
def _repr_html_(self) -> str:
|
||
from . import _render
|
||
|
||
return _render.job_html(self)
|