quantbom 0.6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- quantbom/__init__.py +497 -0
- quantbom/_bitorder.py +121 -0
- quantbom/_circuit.py +77 -0
- quantbom/_collect.py +661 -0
- quantbom/_drift.py +333 -0
- quantbom/_fidelity.py +280 -0
- quantbom/_merge.py +187 -0
- quantbom/_qir.py +224 -0
- quantbom/_scan.py +118 -0
- quantbom/_sign.py +284 -0
- quantbom/_stats.py +125 -0
- quantbom/_verify.py +530 -0
- quantbom/actions/__init__.py +27 -0
- quantbom/actions/base.py +68 -0
- quantbom/actions/benchmark.py +53 -0
- quantbom/actions/bind_backend.py +71 -0
- quantbom/actions/capture.py +106 -0
- quantbom/actions/check_qir.py +44 -0
- quantbom/actions/check_results.py +75 -0
- quantbom/actions/compare_native.py +88 -0
- quantbom/actions/disclose_error_handling.py +66 -0
- quantbom/actions/execute.py +85 -0
- quantbom/actions/inventory.py +24 -0
- quantbom/actions/layout.py +118 -0
- quantbom/actions/prove_equivalence.py +225 -0
- quantbom/actions/record_provenance.py +49 -0
- quantbom/actions/verify_conversion.py +53 -0
- quantbom/attest.py +363 -0
- quantbom/cli.py +378 -0
- quantbom/frameworks/__init__.py +67 -0
- quantbom/frameworks/base.py +155 -0
- quantbom/frameworks/braket.py +132 -0
- quantbom/frameworks/cirq.py +106 -0
- quantbom/frameworks/cudaq.py +223 -0
- quantbom/frameworks/pennylane.py +116 -0
- quantbom/frameworks/qiskit.py +67 -0
- quantbom/frameworks/qrisp.py +267 -0
- quantbom/harness.json +1730 -0
- quantbom/harness.py +88 -0
- quantbom-0.6.0.dist-info/METADATA +207 -0
- quantbom-0.6.0.dist-info/RECORD +45 -0
- quantbom-0.6.0.dist-info/WHEEL +5 -0
- quantbom-0.6.0.dist-info/entry_points.txt +2 -0
- quantbom-0.6.0.dist-info/licenses/LICENSE +202 -0
- quantbom-0.6.0.dist-info/top_level.txt +1 -0
quantbom/_circuit.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Preconditions on the circuit being certified (HARNESS_KITS_PLAN.md K0).
|
|
2
|
+
|
|
3
|
+
The certified object must be the circuit that ran. Two properties decide what
|
|
4
|
+
the harness can honestly say about it, before any evidence is written:
|
|
5
|
+
|
|
6
|
+
* **closed** — every parameter bound. An unbound `Parameter` cannot be
|
|
7
|
+
executed; certifying it once produced a "measured" result for a run that
|
|
8
|
+
never happened, and QBOM-BENCH-02 then blamed the circuit. Refused here.
|
|
9
|
+
* **dynamic** — mid-circuit measurement or reset, or classical control flow
|
|
10
|
+
(`if_test`, `while_loop`, `for_loop`, `switch`). Accepted (decision
|
|
11
|
+
2 Oct 2026), and recorded, because it changes how the circuit can be
|
|
12
|
+
executed (qiskit-aer) and proved equivalent (QCEC's dynamic-circuit
|
|
13
|
+
transformation).
|
|
14
|
+
"""
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
CONTROL_FLOW = {"if_else", "while_loop", "for_loop", "switch_case", "box"}
|
|
20
|
+
_PASSIVE = {"barrier", "delay"}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def inspect_circuit(qc: Any) -> dict[str, Any]:
|
|
24
|
+
"""{'unbound_parameters': [...], 'dynamic': bool, 'dynamic_features': [...]}."""
|
|
25
|
+
features: set[str] = set()
|
|
26
|
+
measured: set[int] = set() # qubits measured so far
|
|
27
|
+
touched: set[int] = set() # qubits any operation has acted on
|
|
28
|
+
index = {q: i for i, q in enumerate(qc.qubits)}
|
|
29
|
+
for inst in qc.data:
|
|
30
|
+
name = inst.operation.name
|
|
31
|
+
qubits = [index[q] for q in inst.qubits]
|
|
32
|
+
if name in CONTROL_FLOW:
|
|
33
|
+
features.add("classical-control-flow")
|
|
34
|
+
elif name == "measure":
|
|
35
|
+
measured.update(qubits)
|
|
36
|
+
elif name == "reset":
|
|
37
|
+
if any(q in touched for q in qubits):
|
|
38
|
+
features.add("mid-circuit-reset")
|
|
39
|
+
elif name not in _PASSIVE and any(q in measured for q in qubits):
|
|
40
|
+
features.add("mid-circuit-measurement")
|
|
41
|
+
if name in CONTROL_FLOW and measured:
|
|
42
|
+
features.add("mid-circuit-measurement")
|
|
43
|
+
touched.update(qubits)
|
|
44
|
+
return {
|
|
45
|
+
"unbound_parameters": sorted(str(p) for p in getattr(qc, "parameters", ())),
|
|
46
|
+
"dynamic": bool(features),
|
|
47
|
+
"dynamic_features": sorted(features),
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def require_closed(info: dict[str, Any]) -> None:
|
|
52
|
+
refuse_open(info["unbound_parameters"])
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def refuse_dynamic(features: list[str], framework: str) -> None:
|
|
56
|
+
"""A dynamic program from an adapter that does not claim dynamic support.
|
|
57
|
+
|
|
58
|
+
The adapter's lowering is conformance-tested for static circuits only, so
|
|
59
|
+
certifying this program would rest on an unverified translation. Refused
|
|
60
|
+
with the same wording for every framework; Qiskit input is accepted and
|
|
61
|
+
other frameworks gain support through their own conformance fixture (C7)."""
|
|
62
|
+
if features:
|
|
63
|
+
raise ValueError(
|
|
64
|
+
f"{framework} programs with {', '.join(features)} are not supported yet: the {framework} adapter's "
|
|
65
|
+
"lowering is conformance-tested for static circuits only, so a dynamic circuit cannot be certified "
|
|
66
|
+
"on it. Dynamic circuits are accepted as Qiskit input (qiskit.QuantumCircuit)"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def refuse_open(unbound: list[str], how: str = "qc.assign_parameters({...})") -> None:
|
|
71
|
+
"""One refusal, worded the same for every framework."""
|
|
72
|
+
if unbound:
|
|
73
|
+
shown = ", ".join(unbound[:5]) + (" …" if len(unbound) > 5 else "")
|
|
74
|
+
raise ValueError(
|
|
75
|
+
f"the circuit has {len(unbound)} unbound parameter(s) ({shown}). Bind them before certifying "
|
|
76
|
+
f"(e.g. {how}): the certified circuit must be the circuit that ran"
|
|
77
|
+
)
|