shotgate 0.2.2__tar.gz → 0.4.0__tar.gz
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.
- {shotgate-0.2.2 → shotgate-0.4.0}/.github/workflows/ci.yml +73 -10
- {shotgate-0.2.2 → shotgate-0.4.0}/CHANGELOG.md +79 -1
- {shotgate-0.2.2 → shotgate-0.4.0}/PKG-INFO +43 -19
- {shotgate-0.2.2 → shotgate-0.4.0}/README.md +31 -18
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/README.md +9 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/adr/0006-hardware-oracle-policy.md +5 -3
- shotgate-0.4.0/docs/adr/0007-fail-closed-workflow-validation.md +49 -0
- shotgate-0.4.0/docs/adr/0008-counts-based-oracle-expansion.md +52 -0
- shotgate-0.4.0/docs/adr/0009-noise-model-simulation.md +55 -0
- shotgate-0.4.0/docs/adr/0010-noise-aware-expected-distribution.md +56 -0
- shotgate-0.4.0/docs/adr/0011-aws-braket-backend.md +48 -0
- shotgate-0.4.0/docs/adr/0012-structural-oracles.md +42 -0
- shotgate-0.4.0/docs/assertions.md +287 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/getting-started.md +17 -5
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/hardware-validation.md +66 -12
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/motivation.md +1 -1
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/workflow-spec.md +2 -1
- shotgate-0.4.0/examples/bell-state-braket/workflow.yaml +40 -0
- shotgate-0.4.0/examples/bell-state-hardware-oracle-coverage/workflow.yaml +79 -0
- shotgate-0.4.0/examples/bell-state-noisy-sim/workflow.yaml +50 -0
- shotgate-0.4.0/examples/bell-state-observables/workflow.yaml +43 -0
- shotgate-0.4.0/examples/bell-state-qasm3/workflow.yaml +43 -0
- shotgate-0.4.0/examples/bell-state-structural/workflow.yaml +35 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/examples/grover-2q-hardware/workflow.yaml +5 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/pyproject.toml +13 -10
- shotgate-0.4.0/src/shotgate/backends/braket.py +73 -0
- shotgate-0.4.0/src/shotgate/backends/local_aer.py +91 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/src/shotgate/backends/registry.py +8 -1
- {shotgate-0.2.2 → shotgate-0.4.0}/src/shotgate/circuits/loader.py +11 -2
- {shotgate-0.2.2 → shotgate-0.4.0}/src/shotgate/cli.py +12 -1
- {shotgate-0.2.2 → shotgate-0.4.0}/src/shotgate/config.py +20 -4
- {shotgate-0.2.2 → shotgate-0.4.0}/src/shotgate/report.py +25 -2
- {shotgate-0.2.2 → shotgate-0.4.0}/src/shotgate/runner.py +37 -10
- shotgate-0.4.0/src/shotgate/validation/assertions.py +703 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/src/shotgate/validation/metrics.py +102 -0
- shotgate-0.4.0/tests/test_assertions.py +264 -0
- shotgate-0.4.0/tests/test_braket_backend.py +59 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/tests/test_config.py +47 -0
- shotgate-0.4.0/tests/test_loader.py +70 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/tests/test_metrics.py +50 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/tests/test_report.py +4 -0
- shotgate-0.4.0/tests/test_runner_integration.py +229 -0
- shotgate-0.2.2/docs/assertions.md +0 -140
- shotgate-0.2.2/examples/bell-state-hardware-oracle-coverage/workflow.yaml +0 -54
- shotgate-0.2.2/src/shotgate/backends/local_aer.py +0 -46
- shotgate-0.2.2/src/shotgate/validation/assertions.py +0 -240
- shotgate-0.2.2/tests/test_assertions.py +0 -108
- shotgate-0.2.2/tests/test_runner_integration.py +0 -72
- {shotgate-0.2.2 → shotgate-0.4.0}/.containerignore +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/.github/dependabot.yml +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/.github/scripts/pin-device.py +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/.github/scripts/pull-base-image.sh +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/.github/workflows/dockerhub-mirror.yml +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/.github/workflows/hardware-validation.yml +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/.github/workflows/pypi-smoke.yml +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/.github/workflows/release.yml +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/.gitignore +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/.gitlab-ci.yml +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/CODEOWNERS +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/CODE_OF_CONDUCT.md +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/CONTRIBUTING.md +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/Containerfile +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/GOVERNANCE.md +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/Jenkinsfile +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/LICENSE +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/MAINTAINERS.md +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/Makefile +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/NOTICE +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/SECURITY.md +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/adr/0001-record-architecture-decisions.md +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/adr/0002-statistical-validation-core.md +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/adr/0003-container-and-vm-isolation.md +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/adr/0004-rename-qforge-to-shotgate.md +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/adr/0005-license-apache-2-0.md +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/architecture.md +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/assets/bell-state-demo.svg +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/assets/shotgate-logomark.svg +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/diagrams/architecture.mmd +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/diagrams/pipeline.mmd +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/docs/pipeline.md +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/examples/bell-state/bell.qasm +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/examples/bell-state/workflow.yaml +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/examples/bell-state-hardware/bell.qasm +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/examples/bell-state-hardware/workflow.yaml +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/examples/bell-state-hardware-oracle-coverage/bell.qasm +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/examples/ghz-state/ghz.qasm +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/examples/ghz-state/workflow.yaml +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/examples/ghz-state-hardware/ghz.qasm +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/examples/ghz-state-hardware/workflow.yaml +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/examples/grover-2q/grover.qasm +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/examples/grover-2q/workflow.yaml +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/examples/grover-2q-hardware/grover.qasm +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/infra/qemu/README.md +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/infra/qemu/cloud-init/meta-data +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/infra/qemu/cloud-init/user-data +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/infra/qemu/create-runner-vm.sh +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/infra/terraform/README.md +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/infra/terraform/examples/basic/main.tf +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/infra/terraform/main.tf +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/infra/terraform/outputs.tf +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/infra/terraform/variables.tf +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/infra/terraform/versions.tf +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/scripts/demo.sh +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/src/shotgate/__init__.py +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/src/shotgate/__main__.py +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/src/shotgate/backends/__init__.py +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/src/shotgate/backends/base.py +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/src/shotgate/backends/ibm_runtime.py +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/src/shotgate/circuits/__init__.py +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/src/shotgate/pytest_plugin.py +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/src/shotgate/telemetry.py +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/src/shotgate/validation/__init__.py +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/tests/conftest.py +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/tests/test_ibm_backend.py +0 -0
- {shotgate-0.2.2 → shotgate-0.4.0}/tests/test_pytest_plugin.py +0 -0
|
@@ -22,8 +22,8 @@ concurrency:
|
|
|
22
22
|
cancel-in-progress: true
|
|
23
23
|
|
|
24
24
|
jobs:
|
|
25
|
-
lint
|
|
26
|
-
name: lint +
|
|
25
|
+
lint:
|
|
26
|
+
name: lint + types
|
|
27
27
|
runs-on: ubuntu-latest
|
|
28
28
|
steps:
|
|
29
29
|
- uses: actions/checkout@v6
|
|
@@ -34,22 +34,47 @@ jobs:
|
|
|
34
34
|
docker.io/library/python:3.12-slim \
|
|
35
35
|
public.ecr.aws/docker/library/python:3.12-slim
|
|
36
36
|
|
|
37
|
-
- name: ruff + mypy
|
|
37
|
+
- name: ruff + mypy (containerized)
|
|
38
38
|
run: |
|
|
39
39
|
podman run --rm -v "$PWD:/work:Z" -w /work \
|
|
40
40
|
docker.io/library/python:3.12-slim bash -euc "
|
|
41
41
|
pip install -q -e '.[dev]'
|
|
42
42
|
ruff check src tests
|
|
43
43
|
mypy
|
|
44
|
-
|
|
44
|
+
"
|
|
45
|
+
|
|
46
|
+
core-tests:
|
|
47
|
+
name: core unit tests (py ${{ matrix.python }})
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
# The validation core is SDK-free, so the core suite runs across the declared
|
|
50
|
+
# Python support grid (requires-python >= 3.10) without a quantum SDK.
|
|
51
|
+
strategy:
|
|
52
|
+
fail-fast: false
|
|
53
|
+
matrix:
|
|
54
|
+
python: ["3.10", "3.11", "3.12", "3.13"]
|
|
55
|
+
steps:
|
|
56
|
+
- uses: actions/checkout@v6
|
|
57
|
+
|
|
58
|
+
- name: Pull base image (retry + mirror fallback)
|
|
59
|
+
run: |
|
|
60
|
+
.github/scripts/pull-base-image.sh \
|
|
61
|
+
"docker.io/library/python:${{ matrix.python }}-slim" \
|
|
62
|
+
"public.ecr.aws/docker/library/python:${{ matrix.python }}-slim"
|
|
63
|
+
|
|
64
|
+
- name: core unit tests, SDK-free (containerized)
|
|
65
|
+
run: |
|
|
66
|
+
podman run --rm -v "$PWD:/work:Z" -w /work \
|
|
67
|
+
"docker.io/library/python:${{ matrix.python }}-slim" bash -euc "
|
|
68
|
+
pip install -q -e '.[dev]'
|
|
69
|
+
pytest -q -m 'not integration' --junitxml=core-junit-${{ matrix.python }}.xml
|
|
45
70
|
"
|
|
46
71
|
|
|
47
72
|
- name: Upload core test report
|
|
48
73
|
if: always()
|
|
49
74
|
uses: actions/upload-artifact@v7
|
|
50
75
|
with:
|
|
51
|
-
name: core-junit
|
|
52
|
-
path: core-junit.xml
|
|
76
|
+
name: core-junit-${{ matrix.python }}
|
|
77
|
+
path: core-junit-${{ matrix.python }}.xml
|
|
53
78
|
|
|
54
79
|
image-and-integration:
|
|
55
80
|
name: build image + integration + example gates
|
|
@@ -96,8 +121,16 @@ jobs:
|
|
|
96
121
|
integration-junit.xml
|
|
97
122
|
|
|
98
123
|
pip-consumer-path:
|
|
99
|
-
name: pip path (
|
|
124
|
+
name: pip path (qiskit ${{ matrix.label }})
|
|
100
125
|
runs-on: ubuntu-latest
|
|
126
|
+
# Exercise the consumer path against both ends of the declared qiskit range
|
|
127
|
+
# (qiskit>=1.2,<3): the supported floor and the latest 2.x.
|
|
128
|
+
strategy:
|
|
129
|
+
fail-fast: false
|
|
130
|
+
matrix:
|
|
131
|
+
include:
|
|
132
|
+
- { qiskit: "qiskit==1.2.*", label: "floor-1.2" }
|
|
133
|
+
- { qiskit: "qiskit<3", label: "latest-2.x" }
|
|
101
134
|
steps:
|
|
102
135
|
- uses: actions/checkout@v6
|
|
103
136
|
|
|
@@ -107,11 +140,12 @@ jobs:
|
|
|
107
140
|
docker.io/library/python:3.12-slim \
|
|
108
141
|
public.ecr.aws/docker/library/python:3.12-slim
|
|
109
142
|
|
|
110
|
-
- name: pip install and exercise the CLI and pytest plugin
|
|
143
|
+
- name: pip install (pinned qiskit) and exercise the CLI and pytest plugin
|
|
111
144
|
run: |
|
|
112
145
|
podman run --rm -v "$PWD:/work:Z" -w /work \
|
|
113
146
|
docker.io/library/python:3.12-slim bash -euc "
|
|
114
|
-
pip install -q '.[aer,dev]'
|
|
147
|
+
pip install -q '.[aer,dev]' '${{ matrix.qiskit }}'
|
|
148
|
+
python -c 'import qiskit; print(\"using qiskit\", qiskit.__version__)'
|
|
115
149
|
# The pytest11 entry point must expose --shotgate after a pip install.
|
|
116
150
|
pytest --help 2>/dev/null | grep -q -- '--shotgate'
|
|
117
151
|
# CLI consumer path: gate a Bell workflow and emit a JUnit report.
|
|
@@ -128,11 +162,40 @@ jobs:
|
|
|
128
162
|
if: always()
|
|
129
163
|
uses: actions/upload-artifact@v7
|
|
130
164
|
with:
|
|
131
|
-
name: pip-path-junit
|
|
165
|
+
name: pip-path-junit-${{ matrix.label }}
|
|
132
166
|
path: |
|
|
133
167
|
cli-junit.xml
|
|
134
168
|
plugin-junit.xml
|
|
135
169
|
|
|
170
|
+
braket-local:
|
|
171
|
+
name: braket local simulation
|
|
172
|
+
runs-on: ubuntu-latest
|
|
173
|
+
# The Braket backend's local-simulation path runs with no AWS account; the cloud
|
|
174
|
+
# path (named devices) needs AWS credentials and is not exercised in CI.
|
|
175
|
+
steps:
|
|
176
|
+
- uses: actions/checkout@v6
|
|
177
|
+
|
|
178
|
+
- name: Pull base image (retry + mirror fallback)
|
|
179
|
+
run: |
|
|
180
|
+
.github/scripts/pull-base-image.sh \
|
|
181
|
+
docker.io/library/python:3.12-slim \
|
|
182
|
+
public.ecr.aws/docker/library/python:3.12-slim
|
|
183
|
+
|
|
184
|
+
- name: braket local-simulation backend test (containerized)
|
|
185
|
+
run: |
|
|
186
|
+
podman run --rm -v "$PWD:/work:Z" -w /work \
|
|
187
|
+
docker.io/library/python:3.12-slim bash -euc "
|
|
188
|
+
pip install -q '.[braket,dev]'
|
|
189
|
+
pytest -q tests/test_braket_backend.py --junitxml=/work/braket-junit.xml
|
|
190
|
+
"
|
|
191
|
+
|
|
192
|
+
- name: Upload braket report
|
|
193
|
+
if: always()
|
|
194
|
+
uses: actions/upload-artifact@v7
|
|
195
|
+
with:
|
|
196
|
+
name: braket-junit
|
|
197
|
+
path: braket-junit.xml
|
|
198
|
+
|
|
136
199
|
terraform:
|
|
137
200
|
name: terraform fmt + validate
|
|
138
201
|
runs-on: ubuntu-latest
|
|
@@ -6,6 +6,82 @@ All notable changes to this project are documented here. The format is based on
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.4.0] - 2026-06-26
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Two structural oracles (9 -> 11), see ADR-0012:** `circuit_depth` and `gate_set` gate on
|
|
14
|
+
the authored circuit's structure (its depth and its gate set) rather than its output. They
|
|
15
|
+
are static: a job whose assertions are all structural runs with no shots, no QPU time, and
|
|
16
|
+
no backend execution. The assertion contract gains an optional `circuit_metrics` argument
|
|
17
|
+
(the runner passes the telemetry it already computes); existing oracles are unaffected. A
|
|
18
|
+
`bell-state-structural` example demonstrates the no-execution path.
|
|
19
|
+
- **`most_frequent_outcome` on the Grover hardware example,** giving that oracle a gating
|
|
20
|
+
hardware data point on its natural use case (a single intended answer).
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Documented a 2026-06-26 real-QPU re-run exercising the post-v0.2 oracles on hardware
|
|
25
|
+
(`expectation_value`, noise-aware `chi_square`/`kl_divergence`, `most_frequent_outcome`):
|
|
26
|
+
see `docs/hardware-validation.md` section 10.
|
|
27
|
+
|
|
28
|
+
## [0.3.0] - 2026-06-26
|
|
29
|
+
|
|
30
|
+
> Bundles the work the roadmap sketched across several minor milestones (oracle breadth,
|
|
31
|
+
> noise-aware validation, the AWS Braket backend) into one release after `0.2.2`.
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- **AWS Braket backend (ADR-0011).** `provider: braket` runs the same workflows on Braket.
|
|
36
|
+
Local simulation needs **no AWS account** (omit `backend.name`); cloud devices are reached
|
|
37
|
+
by setting `backend.name` (e.g. `SV1`) and need configured AWS credentials. Dependencies
|
|
38
|
+
live in the `braket` extra (`pip install shotgate[braket]`); a dedicated CI job validates
|
|
39
|
+
the local path. Promotes `braket` from a planned to a working backend. The cloud path is
|
|
40
|
+
implemented but not yet validated on real Braket hardware.
|
|
41
|
+
- **Noise-aware expected distributions: `chi_square` and `kl_divergence` can gate on
|
|
42
|
+
hardware (ADR-0010).** An optional `readout_error: { p0, p1 }` block transforms the ideal
|
|
43
|
+
`expected` through a calibration-derived per-qubit readout model, giving the test nonzero
|
|
44
|
+
mass on the device's error states. On the measured `ibm_fez` Bell counts this takes
|
|
45
|
+
`chi_square` from statistic 1.5e17 / p-value 0 to statistic 5.51 / p-value 0.138 (passes
|
|
46
|
+
at alpha 0.01); the readout parameters are declared from calibration, not fit to the
|
|
47
|
+
counts, so the gate stays honest. Partially lifts the ADR-0006 simulator-only policy.
|
|
48
|
+
- **Declarative noise-model simulation on `local-aer` (ADR-0009).** A backend can carry a
|
|
49
|
+
`noise` block (`depolarizing_1q`/`depolarizing_2q`/`readout_p0`/`readout_p1`) so the
|
|
50
|
+
noise-aware `*-hardware` thresholds can be regression-tested in CI without a QPU. A
|
|
51
|
+
simulated-noisy Bell pair lands in the measured device regime (TVD ~0.12 vs the measured
|
|
52
|
+
`ibm_fez` 0.1284); a `bell-state-noisy-sim` example gates it against hardware-profile
|
|
53
|
+
bounds. Non-simulator backends ignore `noise`.
|
|
54
|
+
- **Four new assertion oracles (5 -> 9), see ADR-0008:** `kl_divergence` (bound the
|
|
55
|
+
Kullback-Leibler divergence to an expected distribution, in bits; simulator-oriented
|
|
56
|
+
like `chi_square`), `shannon_entropy` (bound the distribution entropy in a min/max
|
|
57
|
+
window), `expectation_value` (bound the Pauli-Z product `<Z..Z>` in [-1, 1] via a
|
|
58
|
+
window or a target), and `most_frequent_outcome` (assert the modal state, optionally
|
|
59
|
+
above a probability). All are counts-based and keep the validation core SDK-free. A
|
|
60
|
+
`bell-state-observables` example exercises the new observable oracles. The JSON reporter
|
|
61
|
+
now serialises a non-finite metric (a diverged KL) as `null` so output stays valid.
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- **JUnit reports carry `timestamp` and `skipped`** attributes on the root and every
|
|
66
|
+
testsuite, for fuller xUnit-schema compliance in CI dashboards. Declared the supported
|
|
67
|
+
Python grid (3.10-3.13) as trove classifiers.
|
|
68
|
+
- **Fail-closed validation (see ADR-0007).** A job that runs but declares no
|
|
69
|
+
assertions now **fails** by default, instead of silently passing a gate that checked
|
|
70
|
+
nothing; opt out with `--allow-empty` (CLI) or `allow_empty=True` (`Runner`).
|
|
71
|
+
Basis-state keys in `expected`, `state`, and `states` are validated at schema-parse
|
|
72
|
+
time: non-empty, `0`/`1` only, and a single consistent width, so a malformed key
|
|
73
|
+
(e.g. `"0x"`, or mixed `"0"`/`"11"`) raises a clear `ValidationError` instead of being
|
|
74
|
+
silently mis-compared. Both are behaviour changes, intended at `0.x`.
|
|
75
|
+
|
|
76
|
+
### Fixed
|
|
77
|
+
|
|
78
|
+
- **OpenQASM 3 circuits now load.** The `qasm3` circuit format was advertised in
|
|
79
|
+
the schema but failed at runtime: `qiskit.qasm3.loads` needs the
|
|
80
|
+
`qiskit-qasm3-import` package, which no extra declared. It is now a dependency of
|
|
81
|
+
the `aer` and `ibm` extras (and the published images), the loader raises an
|
|
82
|
+
actionable error if it is somehow absent, and a `bell-state-qasm3` example plus
|
|
83
|
+
loader tests cover the path.
|
|
84
|
+
|
|
9
85
|
## [0.2.2] - 2026-06-11
|
|
10
86
|
|
|
11
87
|
### Added
|
|
@@ -193,7 +269,9 @@ All notable changes to this project are documented here. The format is based on
|
|
|
193
269
|
(with the math), getting-started guide, and ADRs.
|
|
194
270
|
- **Examples**: Bell state, 3-qubit GHZ, and 2-qubit Grover workflows.
|
|
195
271
|
|
|
196
|
-
[Unreleased]: https://github.com/coldqubit/shotgate/compare/v0.
|
|
272
|
+
[Unreleased]: https://github.com/coldqubit/shotgate/compare/v0.4.0...HEAD
|
|
273
|
+
[0.4.0]: https://github.com/coldqubit/shotgate/compare/v0.3.0...v0.4.0
|
|
274
|
+
[0.3.0]: https://github.com/coldqubit/shotgate/compare/v0.2.2...v0.3.0
|
|
197
275
|
[0.2.2]: https://github.com/coldqubit/shotgate/compare/v0.2.1...v0.2.2
|
|
198
276
|
[0.2.1]: https://github.com/coldqubit/shotgate/compare/v0.2.0...v0.2.1
|
|
199
277
|
[0.2.0]: https://github.com/coldqubit/shotgate/compare/v0.1.1...v0.2.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shotgate
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Container-native CI/CD quality gates for quantum circuits: statistically validate probabilistic output across simulators and QPUs.
|
|
5
5
|
Project-URL: Homepage, https://github.com/coldqubit/shotgate
|
|
6
6
|
Project-URL: Documentation, https://github.com/coldqubit/shotgate/tree/main/docs
|
|
@@ -15,6 +15,10 @@ Classifier: Development Status :: 3 - Alpha
|
|
|
15
15
|
Classifier: Intended Audience :: Developers
|
|
16
16
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
17
17
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
22
|
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
19
23
|
Classifier: Topic :: Software Development :: Testing
|
|
20
24
|
Classifier: Topic :: System :: Distributed Computing
|
|
@@ -25,13 +29,19 @@ Requires-Dist: pyyaml>=6.0
|
|
|
25
29
|
Requires-Dist: rich>=13.0
|
|
26
30
|
Provides-Extra: aer
|
|
27
31
|
Requires-Dist: qiskit-aer>=0.15; extra == 'aer'
|
|
32
|
+
Requires-Dist: qiskit-qasm3-import>=0.5; extra == 'aer'
|
|
28
33
|
Requires-Dist: qiskit<3,>=1.2; extra == 'aer'
|
|
29
34
|
Provides-Extra: all
|
|
35
|
+
Requires-Dist: amazon-braket-sdk>=1.80; extra == 'all'
|
|
30
36
|
Requires-Dist: qiskit-aer>=0.15; extra == 'all'
|
|
37
|
+
Requires-Dist: qiskit-braket-provider>=0.4; extra == 'all'
|
|
31
38
|
Requires-Dist: qiskit-ibm-runtime>=0.30; extra == 'all'
|
|
39
|
+
Requires-Dist: qiskit-qasm3-import>=0.5; extra == 'all'
|
|
32
40
|
Requires-Dist: qiskit<3,>=1.2; extra == 'all'
|
|
33
41
|
Provides-Extra: braket
|
|
34
42
|
Requires-Dist: amazon-braket-sdk>=1.80; extra == 'braket'
|
|
43
|
+
Requires-Dist: qiskit-braket-provider>=0.4; extra == 'braket'
|
|
44
|
+
Requires-Dist: qiskit<3,>=1.2; extra == 'braket'
|
|
35
45
|
Provides-Extra: dev
|
|
36
46
|
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
37
47
|
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
@@ -40,6 +50,7 @@ Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
|
40
50
|
Requires-Dist: types-pyyaml; extra == 'dev'
|
|
41
51
|
Provides-Extra: ibm
|
|
42
52
|
Requires-Dist: qiskit-ibm-runtime>=0.30; extra == 'ibm'
|
|
53
|
+
Requires-Dist: qiskit-qasm3-import>=0.5; extra == 'ibm'
|
|
43
54
|
Requires-Dist: qiskit<3,>=1.2; extra == 'ibm'
|
|
44
55
|
Provides-Extra: mitigation
|
|
45
56
|
Requires-Dist: mitiq>=0.40; extra == 'mitigation'
|
|
@@ -123,15 +134,15 @@ jobs: [
|
|
|
123
134
|
$ shotgate run examples/bell-state/workflow.yaml
|
|
124
135
|
─────────────────────────── shotgate :: bell-state ───────────────────────────
|
|
125
136
|
job: bell-pair · aer_simulator · 8192 shots
|
|
126
|
-
|
|
127
|
-
┃ Assertion ┃ Result ┃ Detail
|
|
128
|
-
|
|
129
|
-
│ chi-square p >= 0.01 │ PASS │ chi-square=0.410 dof=1 p-value=0.5220
|
|
130
|
-
│ TVD <= 0.03 │ PASS │ total variation distance 0.0043 (<= 0.03)
|
|
131
|
-
│ fidelity >= 0.99 │ PASS │ Hellinger fidelity 1.0000 (>= 0.99)
|
|
132
|
-
│ leakage <= 0.0 │ PASS │ support leakage 0.0000 (<= 0.0)
|
|
133
|
-
│ P(00) >= 0.45 and <= 0.55 │ PASS │ P(00) = 0.4957
|
|
134
|
-
|
|
137
|
+
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
138
|
+
┃ Assertion ┃ Result ┃ Detail ┃
|
|
139
|
+
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
|
140
|
+
│ chi-square p >= 0.01 │ PASS │ chi-square=0.410 dof=1 p-value=0.5220 │
|
|
141
|
+
│ TVD <= 0.03 │ PASS │ total variation distance 0.0043 (<= 0.03) │
|
|
142
|
+
│ fidelity >= 0.99 │ PASS │ Hellinger fidelity 1.0000 (>= 0.99) │
|
|
143
|
+
│ leakage <= 0.0 │ PASS │ support leakage 0.0000 (<= 0.0) │
|
|
144
|
+
│ P(00) >= 0.45 and <= 0.55 │ PASS │ P(00) = 0.4957 │
|
|
145
|
+
└───────────────────────────┴────────┴───────────────────────────────────────────┘
|
|
135
146
|
PASSED · 5/5 assertions · 0.214s
|
|
136
147
|
```
|
|
137
148
|
|
|
@@ -226,11 +237,17 @@ For hardware-isolated runs (each pipeline in a throwaway KVM micro-VM), see
|
|
|
226
237
|
|
|
227
238
|
| Type | Oracle | Use it for |
|
|
228
239
|
| --- | --- | --- |
|
|
229
|
-
| `chi_square` | Pearson χ² GoF test (p-value vs α) |
|
|
230
|
-
| `distribution_tvd` | Total variation distance (TVD) ≤ bound |
|
|
240
|
+
| `chi_square` | Pearson χ² GoF test (p-value vs α) | Formal hypothesis test; **simulator-only** (see catalog) |
|
|
241
|
+
| `distribution_tvd` | Total variation distance (TVD) ≤ bound | Default distribution check; interpretable, shot-count-agnostic |
|
|
231
242
|
| `hellinger_fidelity` | Classical fidelity ≥ threshold | Fidelity tracking against an ideal distribution |
|
|
232
243
|
| `state_probability` | Marginal P(state) in a window / ≈ target | Single-outcome amplitude checks (e.g. Grover) |
|
|
233
244
|
| `allowed_states` | Probability mass outside support ≤ budget | Structural/leakage guarantees (e.g. GHZ corners) |
|
|
245
|
+
| `kl_divergence` | KL D(obs‖exp) ≤ bound (bits) | Information-theoretic distance; **simulator-only** (zero-support) |
|
|
246
|
+
| `shannon_entropy` | Entropy in a min/max window (bits) | Assert the intended randomness/concentration |
|
|
247
|
+
| `expectation_value` | `<Z..Z>` in [-1, 1] via window / target | Correlation/parity observable tracking |
|
|
248
|
+
| `most_frequent_outcome` | Modal state (optional min probability) | Single intended answer (e.g. Grover) |
|
|
249
|
+
| `circuit_depth` | Authored-circuit depth in a window | Static complexity budget (no execution) |
|
|
250
|
+
| `gate_set` | Circuit uses only allowed gate names | Enforce a basis / catch unexpected gates (no execution) |
|
|
234
251
|
|
|
235
252
|
Full reference: [`docs/assertions.md`](docs/assertions.md). The statistical core is pure Python
|
|
236
253
|
(no SciPy), including a from-scratch χ² survival function via the regularised incomplete gamma
|
|
@@ -271,7 +288,7 @@ The same artifact therefore runs in a small CI container and against a real QPU.
|
|
|
271
288
|
```text
|
|
272
289
|
shotgate/
|
|
273
290
|
├── src/shotgate/ # the package (validation core, backends, runner, CLI, pytest plugin)
|
|
274
|
-
├── examples/ # runnable workflows: bell
|
|
291
|
+
├── examples/ # runnable workflows: bell/ghz/grover + backend & oracle variants
|
|
275
292
|
├── tests/ # unit tests (core) + integration tests (gated on aer)
|
|
276
293
|
├── infra/
|
|
277
294
|
│ ├── terraform/ # IaC module: "quantum workflow as code"
|
|
@@ -288,7 +305,7 @@ shotgate/
|
|
|
288
305
|
| --- | --- |
|
|
289
306
|
| `local-aer` (Qiskit Aer simulator) | **Working**, default, baked into the image |
|
|
290
307
|
| `ibm` (IBM Quantum via Qiskit Runtime) | **Validated on real hardware** (`ibm_fez`, 2026-06-11: Bell/GHZ/Grover gates passed at 4096 shots; [measured baseline](docs/hardware-validation.md)) |
|
|
291
|
-
| `braket` (AWS Braket) | **
|
|
308
|
+
| `braket` (AWS Braket via qiskit-braket-provider) | **Working: local simulation** (no AWS account). Cloud devices need AWS credentials; not yet validated on real Braket hardware. |
|
|
292
309
|
| Error mitigation ([Mitiq](https://mitiq.readthedocs.io/)) | **Planned** |
|
|
293
310
|
|
|
294
311
|
## Roadmap
|
|
@@ -296,14 +313,21 @@ shotgate/
|
|
|
296
313
|
- **v0.1:** YAML workflows, local Aer backend, χ²/TVD/fidelity/structural oracles,
|
|
297
314
|
JUnit/JSON/MD reporters, Podman and KVM/QEMU isolation, Terraform module, pytest plugin,
|
|
298
315
|
PyPI package, published GHCR image with an IBM-enabled variant.
|
|
299
|
-
- **v0.2
|
|
316
|
+
- **v0.2:** statistical gates **validated against real quantum hardware** (`ibm_fez`,
|
|
300
317
|
2026-06-11, Bell/GHZ/Grover at 4096 shots; measured baseline and runbook in
|
|
301
318
|
[`docs/hardware-validation.md`](docs/hardware-validation.md)), hardware example gates for
|
|
302
319
|
GHZ and Grover, and a dispatchable QPU validation workflow.
|
|
303
|
-
- **v0.3:**
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
320
|
+
- **v0.3.0 (latest release):** the OpenQASM 3 fix and fail-closed validation, four more
|
|
321
|
+
oracles (`kl_divergence`, `shannon_entropy`, `expectation_value`, `most_frequent_outcome`),
|
|
322
|
+
declarative noise-model simulation and noise-aware expected distributions (so
|
|
323
|
+
`chi_square`/`kl_divergence` can gate on hardware), and the AWS Braket backend (local
|
|
324
|
+
simulation; the cloud path awaits validation on real hardware).
|
|
325
|
+
- **v0.4.0 (latest release):** structural oracles `circuit_depth` and `gate_set`, static
|
|
326
|
+
circuit-property gates that run with no execution (no shots, no QPU, no backend).
|
|
327
|
+
- **Planned:** error mitigation via [Mitiq](https://mitiq.readthedocs.io/), multi-backend
|
|
328
|
+
differential testing, circuit fixtures and property-based generation, a Helm chart, an
|
|
329
|
+
optional OpenTelemetry exporter for the telemetry layer (kept out of the core
|
|
330
|
+
dependencies), and validation of the Braket cloud path on real hardware.
|
|
307
331
|
|
|
308
332
|
See [`CHANGELOG.md`](CHANGELOG.md) and the [ADRs](docs/adr/) for decisions and rationale.
|
|
309
333
|
|
|
@@ -76,15 +76,15 @@ jobs: [
|
|
|
76
76
|
$ shotgate run examples/bell-state/workflow.yaml
|
|
77
77
|
─────────────────────────── shotgate :: bell-state ───────────────────────────
|
|
78
78
|
job: bell-pair · aer_simulator · 8192 shots
|
|
79
|
-
|
|
80
|
-
┃ Assertion ┃ Result ┃ Detail
|
|
81
|
-
|
|
82
|
-
│ chi-square p >= 0.01 │ PASS │ chi-square=0.410 dof=1 p-value=0.5220
|
|
83
|
-
│ TVD <= 0.03 │ PASS │ total variation distance 0.0043 (<= 0.03)
|
|
84
|
-
│ fidelity >= 0.99 │ PASS │ Hellinger fidelity 1.0000 (>= 0.99)
|
|
85
|
-
│ leakage <= 0.0 │ PASS │ support leakage 0.0000 (<= 0.0)
|
|
86
|
-
│ P(00) >= 0.45 and <= 0.55 │ PASS │ P(00) = 0.4957
|
|
87
|
-
|
|
79
|
+
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
80
|
+
┃ Assertion ┃ Result ┃ Detail ┃
|
|
81
|
+
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
|
82
|
+
│ chi-square p >= 0.01 │ PASS │ chi-square=0.410 dof=1 p-value=0.5220 │
|
|
83
|
+
│ TVD <= 0.03 │ PASS │ total variation distance 0.0043 (<= 0.03) │
|
|
84
|
+
│ fidelity >= 0.99 │ PASS │ Hellinger fidelity 1.0000 (>= 0.99) │
|
|
85
|
+
│ leakage <= 0.0 │ PASS │ support leakage 0.0000 (<= 0.0) │
|
|
86
|
+
│ P(00) >= 0.45 and <= 0.55 │ PASS │ P(00) = 0.4957 │
|
|
87
|
+
└───────────────────────────┴────────┴───────────────────────────────────────────┘
|
|
88
88
|
PASSED · 5/5 assertions · 0.214s
|
|
89
89
|
```
|
|
90
90
|
|
|
@@ -179,11 +179,17 @@ For hardware-isolated runs (each pipeline in a throwaway KVM micro-VM), see
|
|
|
179
179
|
|
|
180
180
|
| Type | Oracle | Use it for |
|
|
181
181
|
| --- | --- | --- |
|
|
182
|
-
| `chi_square` | Pearson χ² GoF test (p-value vs α) |
|
|
183
|
-
| `distribution_tvd` | Total variation distance (TVD) ≤ bound |
|
|
182
|
+
| `chi_square` | Pearson χ² GoF test (p-value vs α) | Formal hypothesis test; **simulator-only** (see catalog) |
|
|
183
|
+
| `distribution_tvd` | Total variation distance (TVD) ≤ bound | Default distribution check; interpretable, shot-count-agnostic |
|
|
184
184
|
| `hellinger_fidelity` | Classical fidelity ≥ threshold | Fidelity tracking against an ideal distribution |
|
|
185
185
|
| `state_probability` | Marginal P(state) in a window / ≈ target | Single-outcome amplitude checks (e.g. Grover) |
|
|
186
186
|
| `allowed_states` | Probability mass outside support ≤ budget | Structural/leakage guarantees (e.g. GHZ corners) |
|
|
187
|
+
| `kl_divergence` | KL D(obs‖exp) ≤ bound (bits) | Information-theoretic distance; **simulator-only** (zero-support) |
|
|
188
|
+
| `shannon_entropy` | Entropy in a min/max window (bits) | Assert the intended randomness/concentration |
|
|
189
|
+
| `expectation_value` | `<Z..Z>` in [-1, 1] via window / target | Correlation/parity observable tracking |
|
|
190
|
+
| `most_frequent_outcome` | Modal state (optional min probability) | Single intended answer (e.g. Grover) |
|
|
191
|
+
| `circuit_depth` | Authored-circuit depth in a window | Static complexity budget (no execution) |
|
|
192
|
+
| `gate_set` | Circuit uses only allowed gate names | Enforce a basis / catch unexpected gates (no execution) |
|
|
187
193
|
|
|
188
194
|
Full reference: [`docs/assertions.md`](docs/assertions.md). The statistical core is pure Python
|
|
189
195
|
(no SciPy), including a from-scratch χ² survival function via the regularised incomplete gamma
|
|
@@ -224,7 +230,7 @@ The same artifact therefore runs in a small CI container and against a real QPU.
|
|
|
224
230
|
```text
|
|
225
231
|
shotgate/
|
|
226
232
|
├── src/shotgate/ # the package (validation core, backends, runner, CLI, pytest plugin)
|
|
227
|
-
├── examples/ # runnable workflows: bell
|
|
233
|
+
├── examples/ # runnable workflows: bell/ghz/grover + backend & oracle variants
|
|
228
234
|
├── tests/ # unit tests (core) + integration tests (gated on aer)
|
|
229
235
|
├── infra/
|
|
230
236
|
│ ├── terraform/ # IaC module: "quantum workflow as code"
|
|
@@ -241,7 +247,7 @@ shotgate/
|
|
|
241
247
|
| --- | --- |
|
|
242
248
|
| `local-aer` (Qiskit Aer simulator) | **Working**, default, baked into the image |
|
|
243
249
|
| `ibm` (IBM Quantum via Qiskit Runtime) | **Validated on real hardware** (`ibm_fez`, 2026-06-11: Bell/GHZ/Grover gates passed at 4096 shots; [measured baseline](docs/hardware-validation.md)) |
|
|
244
|
-
| `braket` (AWS Braket) | **
|
|
250
|
+
| `braket` (AWS Braket via qiskit-braket-provider) | **Working: local simulation** (no AWS account). Cloud devices need AWS credentials; not yet validated on real Braket hardware. |
|
|
245
251
|
| Error mitigation ([Mitiq](https://mitiq.readthedocs.io/)) | **Planned** |
|
|
246
252
|
|
|
247
253
|
## Roadmap
|
|
@@ -249,14 +255,21 @@ shotgate/
|
|
|
249
255
|
- **v0.1:** YAML workflows, local Aer backend, χ²/TVD/fidelity/structural oracles,
|
|
250
256
|
JUnit/JSON/MD reporters, Podman and KVM/QEMU isolation, Terraform module, pytest plugin,
|
|
251
257
|
PyPI package, published GHCR image with an IBM-enabled variant.
|
|
252
|
-
- **v0.2
|
|
258
|
+
- **v0.2:** statistical gates **validated against real quantum hardware** (`ibm_fez`,
|
|
253
259
|
2026-06-11, Bell/GHZ/Grover at 4096 shots; measured baseline and runbook in
|
|
254
260
|
[`docs/hardware-validation.md`](docs/hardware-validation.md)), hardware example gates for
|
|
255
261
|
GHZ and Grover, and a dispatchable QPU validation workflow.
|
|
256
|
-
- **v0.3:**
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
262
|
+
- **v0.3.0 (latest release):** the OpenQASM 3 fix and fail-closed validation, four more
|
|
263
|
+
oracles (`kl_divergence`, `shannon_entropy`, `expectation_value`, `most_frequent_outcome`),
|
|
264
|
+
declarative noise-model simulation and noise-aware expected distributions (so
|
|
265
|
+
`chi_square`/`kl_divergence` can gate on hardware), and the AWS Braket backend (local
|
|
266
|
+
simulation; the cloud path awaits validation on real hardware).
|
|
267
|
+
- **v0.4.0 (latest release):** structural oracles `circuit_depth` and `gate_set`, static
|
|
268
|
+
circuit-property gates that run with no execution (no shots, no QPU, no backend).
|
|
269
|
+
- **Planned:** error mitigation via [Mitiq](https://mitiq.readthedocs.io/), multi-backend
|
|
270
|
+
differential testing, circuit fixtures and property-based generation, a Helm chart, an
|
|
271
|
+
optional OpenTelemetry exporter for the telemetry layer (kept out of the core
|
|
272
|
+
dependencies), and validation of the Braket cloud path on real hardware.
|
|
260
273
|
|
|
261
274
|
See [`CHANGELOG.md`](CHANGELOG.md) and the [ADRs](docs/adr/) for decisions and rationale.
|
|
262
275
|
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# shotgate documentation
|
|
2
2
|
|
|
3
|
+
shotgate runs container-native CI/CD quality gates for quantum circuits: it executes a
|
|
4
|
+
circuit on a simulator or a real quantum processing unit (QPU) and gates the pipeline on
|
|
5
|
+
the *statistical* properties of the measured shot distribution (chi-square goodness-of-fit,
|
|
6
|
+
total variation distance, Hellinger fidelity, support leakage) rather than on exact
|
|
7
|
+
equality, which probabilistic output makes meaningless. New here? Read
|
|
8
|
+
[Getting Started](getting-started.md) first, then the
|
|
9
|
+
[Workflow Specification](workflow-spec.md) for the YAML schema and the
|
|
10
|
+
[Assertion Catalog](assertions.md) for the oracles and how to set thresholds.
|
|
11
|
+
|
|
3
12
|
| Document | What it covers |
|
|
4
13
|
| --- | --- |
|
|
5
14
|
| [Getting Started](getting-started.md) | Zero to a passing quantum gate with Podman. |
|
|
@@ -18,9 +18,11 @@ came out of those runs:
|
|
|
18
18
|
on the same counts (TVD 0.1350, fidelity 0.8650, leakage 0.1350, P(`00`) 0.4343).
|
|
19
19
|
The ideal expected distribution `{00: 0.5, 11: 0.5}` assigns probability 0 to
|
|
20
20
|
the error states `01`/`10`; the implementation floors expected counts at
|
|
21
|
-
`_MIN_EXPECTED = 1e-12` to keep the statistic finite, so each
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
`_MIN_EXPECTED = 1e-12` to keep the statistic finite, so each error state
|
|
22
|
+
contributes `observed^2 / 1e-12` (the 304 and 249 counts in `10`/`01` sum to about
|
|
23
|
+
`1.5e17`, a magnitude set by the floor, not the data). Against an ideal support,
|
|
24
|
+
any device leakage forces rejection regardless of thresholds; the rejection is
|
|
25
|
+
floor-independent even though the statistic's magnitude is not.
|
|
24
26
|
|
|
25
27
|
## Decision
|
|
26
28
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# ADR-0007: Fail-closed workflow validation (empty gates and malformed expected distributions)
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted
|
|
4
|
+
- **Date:** 2026-06-26
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
Two ways a shotgate gate could pass while not actually validating anything were found
|
|
9
|
+
by exercising the runner and the schema:
|
|
10
|
+
|
|
11
|
+
1. **A job with no assertions reported PASS.** The runner computed
|
|
12
|
+
`all(o.passed for o in outcomes)`, and `all([])` is `True`, so a workflow whose
|
|
13
|
+
jobs declared `assertions: []` passed the pipeline while checking nothing. A quality
|
|
14
|
+
gate that can be green without testing is a correctness hazard, not a convenience.
|
|
15
|
+
2. **Expected distributions accepted any string key.** The `expected` maps of the
|
|
16
|
+
distribution oracles, and the `state`/`states` fields, were typed `dict[str, float]`
|
|
17
|
+
/ `str` / `list[str]` with no constraint, so a 3-bit key against a 2-qubit circuit,
|
|
18
|
+
mixed-width keys, or a typo like `"0x"` parsed cleanly and were then silently
|
|
19
|
+
mis-compared, producing a wrong-but-green result instead of an error.
|
|
20
|
+
|
|
21
|
+
## Decision
|
|
22
|
+
|
|
23
|
+
shotgate validates fail-closed: a gate that cannot meaningfully check something is an
|
|
24
|
+
error, not a pass.
|
|
25
|
+
|
|
26
|
+
1. **An empty gate fails by default.** A job that runs but declares no assertions is
|
|
27
|
+
marked failed with an explanatory message. The behaviour is opt-out: `--allow-empty`
|
|
28
|
+
on `shotgate run` (or `allow_empty=True` on `Runner`) restores a passing empty job
|
|
29
|
+
for the rare case where that is intended (a placeholder, a circuit-only smoke run).
|
|
30
|
+
2. **Basis-state keys are validated at schema-parse time.** Keys in `expected`, and the
|
|
31
|
+
`state`/`states` fields, must be non-empty, contain only `0`/`1` (whitespace from
|
|
32
|
+
multi-register formatting is stripped, matching `metrics.clean_key`), and all
|
|
33
|
+
describe the same number of bits. A malformed key now raises a pydantic
|
|
34
|
+
`ValidationError` with the offending key named.
|
|
35
|
+
|
|
36
|
+
## Consequences
|
|
37
|
+
|
|
38
|
+
- **+** No silent no-op gates: a green shotgate run means assertions actually ran.
|
|
39
|
+
- **+** Distribution typos fail fast at load time with a clear message, the same way the
|
|
40
|
+
strict (`extra="forbid"`) schema already catches unknown fields.
|
|
41
|
+
- **+** The cross-check against the circuit's qubit width is now well-defined to add at
|
|
42
|
+
evaluate time later, because the keys are guaranteed internally consistent.
|
|
43
|
+
- **-** This is a behaviour change: a previously-passing empty gate now fails, and a
|
|
44
|
+
workflow with a malformed key that previously parsed now raises. Both are pre-1.0
|
|
45
|
+
(`0.x`) and intended; the empty-gate change is documented in `CHANGELOG.md`, and the
|
|
46
|
+
escape hatch (`--allow-empty`) covers the legitimate case.
|
|
47
|
+
- The validation is internal-consistency only (binary, equal width). Matching the key
|
|
48
|
+
width to the executed circuit's classical-bit count is a separate evaluate-time check
|
|
49
|
+
deferred to a later version.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# ADR-0008: Counts-based oracle expansion (divergence, entropy, expectation, mode)
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted
|
|
4
|
+
- **Date:** 2026-06-26
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
shotgate shipped five assertion oracles: a distance test (`distribution_tvd`), a
|
|
9
|
+
goodness-of-fit test (`chi_square`), a closeness score (`hellinger_fidelity`), a marginal
|
|
10
|
+
(`state_probability`), and a structural/leakage bound (`allowed_states`). The quantum
|
|
11
|
+
software-testing field, and adjacent tools such as QUTest, cover a wider assertion set,
|
|
12
|
+
notably observable expectation values, distribution entropy, and information-theoretic
|
|
13
|
+
divergence. These are real gaps for a tool that markets itself as the statistical quality
|
|
14
|
+
gate for quantum circuits.
|
|
15
|
+
|
|
16
|
+
The constraint that has served the project well is that oracles are **counts-based and
|
|
17
|
+
pure-Python**: each assertion's `evaluate(counts, shots)` operates only on a histogram of
|
|
18
|
+
measured bitstrings, so the validation core never imports a quantum SDK (ADR-0002).
|
|
19
|
+
|
|
20
|
+
## Decision
|
|
21
|
+
|
|
22
|
+
Add four oracles that stay inside that contract, taking the count from five to nine:
|
|
23
|
+
|
|
24
|
+
1. `kl_divergence`: bound the Kullback-Leibler divergence `D(observed || expected)` in bits.
|
|
25
|
+
2. `shannon_entropy`: bound the distribution's Shannon entropy (min/max bits).
|
|
26
|
+
3. `expectation_value`: bound the Pauli-Z product `<Z_{q0} Z_{q1} ...>` in `[-1, 1]`, read
|
|
27
|
+
off the computational-basis counts as a parity expectation.
|
|
28
|
+
4. `most_frequent_outcome`: assert the modal measured state, optionally above a probability.
|
|
29
|
+
|
|
30
|
+
Two related oracles are **deferred** because they do not fit the `evaluate(counts, shots)`
|
|
31
|
+
contract:
|
|
32
|
+
|
|
33
|
+
- **Arbitrary-Pauli observables** (e.g. `<X>`, `<Y>`, entanglement witnesses) need
|
|
34
|
+
basis-change measurement circuits, not just computational-basis counts. `expectation_value`
|
|
35
|
+
is therefore Z-basis only for now.
|
|
36
|
+
- **Structural assertions on the circuit** (depth, width, gate-set membership) need the
|
|
37
|
+
circuit/telemetry, which `evaluate` does not receive; they require a signature change and
|
|
38
|
+
are left to a later version.
|
|
39
|
+
|
|
40
|
+
## Consequences
|
|
41
|
+
|
|
42
|
+
- **+** Closes the distribution/observable breadth gap while keeping the core SDK-free and
|
|
43
|
+
unit-tested against analytic values (`<Z0 Z1> = +1` for a Bell pair, `H = 1` bit for a
|
|
44
|
+
balanced two-outcome distribution, `D(p||p) = 0`).
|
|
45
|
+
- **+** `expectation_value` gives a hardware-friendly single-number observable to track,
|
|
46
|
+
complementing the distribution oracles.
|
|
47
|
+
- **-** `kl_divergence` inherits the zero-support pathology of `chi_square`: an ideal
|
|
48
|
+
`expected` that assigns probability 0 to a device's error states diverges to infinity, so
|
|
49
|
+
KL is simulator-oriented unless `expected` is noise-aware (the v0.5 work). The reporter
|
|
50
|
+
serialises a non-finite metric as JSON `null` so output stays valid.
|
|
51
|
+
- **-** `expectation_value` covers only Z-basis products; the broader Pauli and
|
|
52
|
+
entanglement-witness oracles remain future work, as do the circuit-structural oracles.
|