shotgate 0.2.2__tar.gz → 0.3.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.3.0}/.github/workflows/ci.yml +73 -10
- {shotgate-0.2.2 → shotgate-0.3.0}/CHANGELOG.md +59 -1
- {shotgate-0.2.2 → shotgate-0.3.0}/PKG-INFO +39 -19
- {shotgate-0.2.2 → shotgate-0.3.0}/README.md +27 -18
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/README.md +9 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/adr/0006-hardware-oracle-policy.md +5 -3
- shotgate-0.3.0/docs/adr/0007-fail-closed-workflow-validation.md +49 -0
- shotgate-0.3.0/docs/adr/0008-counts-based-oracle-expansion.md +52 -0
- shotgate-0.3.0/docs/adr/0009-noise-model-simulation.md +55 -0
- shotgate-0.3.0/docs/adr/0010-noise-aware-expected-distribution.md +56 -0
- shotgate-0.3.0/docs/adr/0011-aws-braket-backend.md +48 -0
- shotgate-0.3.0/docs/assertions.md +253 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/getting-started.md +17 -5
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/hardware-validation.md +18 -12
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/workflow-spec.md +2 -1
- shotgate-0.3.0/examples/bell-state-braket/workflow.yaml +40 -0
- shotgate-0.3.0/examples/bell-state-noisy-sim/workflow.yaml +50 -0
- shotgate-0.3.0/examples/bell-state-observables/workflow.yaml +43 -0
- shotgate-0.3.0/examples/bell-state-qasm3/workflow.yaml +43 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/pyproject.toml +13 -10
- shotgate-0.3.0/src/shotgate/backends/braket.py +73 -0
- shotgate-0.3.0/src/shotgate/backends/local_aer.py +91 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/src/shotgate/backends/registry.py +8 -1
- {shotgate-0.2.2 → shotgate-0.3.0}/src/shotgate/circuits/loader.py +11 -2
- {shotgate-0.2.2 → shotgate-0.3.0}/src/shotgate/cli.py +12 -1
- {shotgate-0.2.2 → shotgate-0.3.0}/src/shotgate/config.py +20 -4
- {shotgate-0.2.2 → shotgate-0.3.0}/src/shotgate/report.py +25 -2
- {shotgate-0.2.2 → shotgate-0.3.0}/src/shotgate/runner.py +13 -1
- shotgate-0.3.0/src/shotgate/validation/assertions.py +536 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/src/shotgate/validation/metrics.py +102 -0
- shotgate-0.3.0/tests/test_assertions.py +231 -0
- shotgate-0.3.0/tests/test_braket_backend.py +59 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/tests/test_config.py +47 -0
- shotgate-0.3.0/tests/test_loader.py +70 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/tests/test_metrics.py +50 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/tests/test_report.py +4 -0
- shotgate-0.3.0/tests/test_runner_integration.py +196 -0
- shotgate-0.2.2/docs/assertions.md +0 -140
- 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.3.0}/.containerignore +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/.github/dependabot.yml +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/.github/scripts/pin-device.py +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/.github/scripts/pull-base-image.sh +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/.github/workflows/dockerhub-mirror.yml +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/.github/workflows/hardware-validation.yml +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/.github/workflows/pypi-smoke.yml +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/.github/workflows/release.yml +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/.gitignore +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/.gitlab-ci.yml +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/CODEOWNERS +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/CODE_OF_CONDUCT.md +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/CONTRIBUTING.md +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/Containerfile +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/GOVERNANCE.md +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/Jenkinsfile +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/LICENSE +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/MAINTAINERS.md +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/Makefile +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/NOTICE +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/SECURITY.md +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/adr/0001-record-architecture-decisions.md +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/adr/0002-statistical-validation-core.md +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/adr/0003-container-and-vm-isolation.md +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/adr/0004-rename-qforge-to-shotgate.md +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/adr/0005-license-apache-2-0.md +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/architecture.md +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/assets/bell-state-demo.svg +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/assets/shotgate-logomark.svg +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/diagrams/architecture.mmd +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/diagrams/pipeline.mmd +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/motivation.md +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/docs/pipeline.md +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/examples/bell-state/bell.qasm +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/examples/bell-state/workflow.yaml +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/examples/bell-state-hardware/bell.qasm +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/examples/bell-state-hardware/workflow.yaml +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/examples/bell-state-hardware-oracle-coverage/bell.qasm +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/examples/bell-state-hardware-oracle-coverage/workflow.yaml +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/examples/ghz-state/ghz.qasm +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/examples/ghz-state/workflow.yaml +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/examples/ghz-state-hardware/ghz.qasm +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/examples/ghz-state-hardware/workflow.yaml +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/examples/grover-2q/grover.qasm +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/examples/grover-2q/workflow.yaml +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/examples/grover-2q-hardware/grover.qasm +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/examples/grover-2q-hardware/workflow.yaml +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/infra/qemu/README.md +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/infra/qemu/cloud-init/meta-data +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/infra/qemu/cloud-init/user-data +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/infra/qemu/create-runner-vm.sh +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/infra/terraform/README.md +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/infra/terraform/examples/basic/main.tf +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/infra/terraform/main.tf +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/infra/terraform/outputs.tf +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/infra/terraform/variables.tf +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/infra/terraform/versions.tf +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/scripts/demo.sh +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/src/shotgate/__init__.py +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/src/shotgate/__main__.py +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/src/shotgate/backends/__init__.py +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/src/shotgate/backends/base.py +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/src/shotgate/backends/ibm_runtime.py +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/src/shotgate/circuits/__init__.py +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/src/shotgate/pytest_plugin.py +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/src/shotgate/telemetry.py +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/src/shotgate/validation/__init__.py +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/tests/conftest.py +0 -0
- {shotgate-0.2.2 → shotgate-0.3.0}/tests/test_ibm_backend.py +0 -0
- {shotgate-0.2.2 → shotgate-0.3.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,63 @@ All notable changes to this project are documented here. The format is based on
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.3.0] - 2026-06-26
|
|
10
|
+
|
|
11
|
+
> Bundles the work the roadmap sketched across several minor milestones (oracle breadth,
|
|
12
|
+
> noise-aware validation, the AWS Braket backend) into one release after `0.2.2`.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **AWS Braket backend (ADR-0011).** `provider: braket` runs the same workflows on Braket.
|
|
17
|
+
Local simulation needs **no AWS account** (omit `backend.name`); cloud devices are reached
|
|
18
|
+
by setting `backend.name` (e.g. `SV1`) and need configured AWS credentials. Dependencies
|
|
19
|
+
live in the `braket` extra (`pip install shotgate[braket]`); a dedicated CI job validates
|
|
20
|
+
the local path. Promotes `braket` from a planned to a working backend. The cloud path is
|
|
21
|
+
implemented but not yet validated on real Braket hardware.
|
|
22
|
+
- **Noise-aware expected distributions: `chi_square` and `kl_divergence` can gate on
|
|
23
|
+
hardware (ADR-0010).** An optional `readout_error: { p0, p1 }` block transforms the ideal
|
|
24
|
+
`expected` through a calibration-derived per-qubit readout model, giving the test nonzero
|
|
25
|
+
mass on the device's error states. On the measured `ibm_fez` Bell counts this takes
|
|
26
|
+
`chi_square` from statistic 1.5e17 / p-value 0 to statistic 5.51 / p-value 0.138 (passes
|
|
27
|
+
at alpha 0.01); the readout parameters are declared from calibration, not fit to the
|
|
28
|
+
counts, so the gate stays honest. Partially lifts the ADR-0006 simulator-only policy.
|
|
29
|
+
- **Declarative noise-model simulation on `local-aer` (ADR-0009).** A backend can carry a
|
|
30
|
+
`noise` block (`depolarizing_1q`/`depolarizing_2q`/`readout_p0`/`readout_p1`) so the
|
|
31
|
+
noise-aware `*-hardware` thresholds can be regression-tested in CI without a QPU. A
|
|
32
|
+
simulated-noisy Bell pair lands in the measured device regime (TVD ~0.12 vs the measured
|
|
33
|
+
`ibm_fez` 0.1284); a `bell-state-noisy-sim` example gates it against hardware-profile
|
|
34
|
+
bounds. Non-simulator backends ignore `noise`.
|
|
35
|
+
- **Four new assertion oracles (5 -> 9), see ADR-0008:** `kl_divergence` (bound the
|
|
36
|
+
Kullback-Leibler divergence to an expected distribution, in bits; simulator-oriented
|
|
37
|
+
like `chi_square`), `shannon_entropy` (bound the distribution entropy in a min/max
|
|
38
|
+
window), `expectation_value` (bound the Pauli-Z product `<Z..Z>` in [-1, 1] via a
|
|
39
|
+
window or a target), and `most_frequent_outcome` (assert the modal state, optionally
|
|
40
|
+
above a probability). All are counts-based and keep the validation core SDK-free. A
|
|
41
|
+
`bell-state-observables` example exercises the new observable oracles. The JSON reporter
|
|
42
|
+
now serialises a non-finite metric (a diverged KL) as `null` so output stays valid.
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- **JUnit reports carry `timestamp` and `skipped`** attributes on the root and every
|
|
47
|
+
testsuite, for fuller xUnit-schema compliance in CI dashboards. Declared the supported
|
|
48
|
+
Python grid (3.10-3.13) as trove classifiers.
|
|
49
|
+
- **Fail-closed validation (see ADR-0007).** A job that runs but declares no
|
|
50
|
+
assertions now **fails** by default, instead of silently passing a gate that checked
|
|
51
|
+
nothing; opt out with `--allow-empty` (CLI) or `allow_empty=True` (`Runner`).
|
|
52
|
+
Basis-state keys in `expected`, `state`, and `states` are validated at schema-parse
|
|
53
|
+
time: non-empty, `0`/`1` only, and a single consistent width, so a malformed key
|
|
54
|
+
(e.g. `"0x"`, or mixed `"0"`/`"11"`) raises a clear `ValidationError` instead of being
|
|
55
|
+
silently mis-compared. Both are behaviour changes, intended at `0.x`.
|
|
56
|
+
|
|
57
|
+
### Fixed
|
|
58
|
+
|
|
59
|
+
- **OpenQASM 3 circuits now load.** The `qasm3` circuit format was advertised in
|
|
60
|
+
the schema but failed at runtime: `qiskit.qasm3.loads` needs the
|
|
61
|
+
`qiskit-qasm3-import` package, which no extra declared. It is now a dependency of
|
|
62
|
+
the `aer` and `ibm` extras (and the published images), the loader raises an
|
|
63
|
+
actionable error if it is somehow absent, and a `bell-state-qasm3` example plus
|
|
64
|
+
loader tests cover the path.
|
|
65
|
+
|
|
9
66
|
## [0.2.2] - 2026-06-11
|
|
10
67
|
|
|
11
68
|
### Added
|
|
@@ -193,7 +250,8 @@ All notable changes to this project are documented here. The format is based on
|
|
|
193
250
|
(with the math), getting-started guide, and ADRs.
|
|
194
251
|
- **Examples**: Bell state, 3-qubit GHZ, and 2-qubit Grover workflows.
|
|
195
252
|
|
|
196
|
-
[Unreleased]: https://github.com/coldqubit/shotgate/compare/v0.
|
|
253
|
+
[Unreleased]: https://github.com/coldqubit/shotgate/compare/v0.3.0...HEAD
|
|
254
|
+
[0.3.0]: https://github.com/coldqubit/shotgate/compare/v0.2.2...v0.3.0
|
|
197
255
|
[0.2.2]: https://github.com/coldqubit/shotgate/compare/v0.2.1...v0.2.2
|
|
198
256
|
[0.2.1]: https://github.com/coldqubit/shotgate/compare/v0.2.0...v0.2.1
|
|
199
257
|
[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.3.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,15 @@ 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) |
|
|
234
249
|
|
|
235
250
|
Full reference: [`docs/assertions.md`](docs/assertions.md). The statistical core is pure Python
|
|
236
251
|
(no SciPy), including a from-scratch χ² survival function via the regularised incomplete gamma
|
|
@@ -271,7 +286,7 @@ The same artifact therefore runs in a small CI container and against a real QPU.
|
|
|
271
286
|
```text
|
|
272
287
|
shotgate/
|
|
273
288
|
├── src/shotgate/ # the package (validation core, backends, runner, CLI, pytest plugin)
|
|
274
|
-
├── examples/ # runnable workflows: bell
|
|
289
|
+
├── examples/ # runnable workflows: bell/ghz/grover + backend & oracle variants
|
|
275
290
|
├── tests/ # unit tests (core) + integration tests (gated on aer)
|
|
276
291
|
├── infra/
|
|
277
292
|
│ ├── terraform/ # IaC module: "quantum workflow as code"
|
|
@@ -288,7 +303,7 @@ shotgate/
|
|
|
288
303
|
| --- | --- |
|
|
289
304
|
| `local-aer` (Qiskit Aer simulator) | **Working**, default, baked into the image |
|
|
290
305
|
| `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) | **
|
|
306
|
+
| `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
307
|
| Error mitigation ([Mitiq](https://mitiq.readthedocs.io/)) | **Planned** |
|
|
293
308
|
|
|
294
309
|
## Roadmap
|
|
@@ -296,14 +311,19 @@ shotgate/
|
|
|
296
311
|
- **v0.1:** YAML workflows, local Aer backend, χ²/TVD/fidelity/structural oracles,
|
|
297
312
|
JUnit/JSON/MD reporters, Podman and KVM/QEMU isolation, Terraform module, pytest plugin,
|
|
298
313
|
PyPI package, published GHCR image with an IBM-enabled variant.
|
|
299
|
-
- **v0.2
|
|
314
|
+
- **v0.2:** statistical gates **validated against real quantum hardware** (`ibm_fez`,
|
|
300
315
|
2026-06-11, Bell/GHZ/Grover at 4096 shots; measured baseline and runbook in
|
|
301
316
|
[`docs/hardware-validation.md`](docs/hardware-validation.md)), hardware example gates for
|
|
302
317
|
GHZ and Grover, and a dispatchable QPU validation workflow.
|
|
303
|
-
- **v0.3:**
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
318
|
+
- **v0.3.0 (latest release):** the OpenQASM 3 fix and fail-closed validation, four more
|
|
319
|
+
oracles (`kl_divergence`, `shannon_entropy`, `expectation_value`, `most_frequent_outcome`),
|
|
320
|
+
declarative noise-model simulation and noise-aware expected distributions (so
|
|
321
|
+
`chi_square`/`kl_divergence` can gate on hardware), and the AWS Braket backend (local
|
|
322
|
+
simulation; the cloud path awaits validation on real hardware).
|
|
323
|
+
- **Planned:** error mitigation via [Mitiq](https://mitiq.readthedocs.io/), multi-backend
|
|
324
|
+
differential testing, circuit fixtures and property-based generation, a Helm chart, an
|
|
325
|
+
optional OpenTelemetry exporter for the telemetry layer (kept out of the core
|
|
326
|
+
dependencies), and validation of the Braket cloud path on real hardware.
|
|
307
327
|
|
|
308
328
|
See [`CHANGELOG.md`](CHANGELOG.md) and the [ADRs](docs/adr/) for decisions and rationale.
|
|
309
329
|
|
|
@@ -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,15 @@ 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) |
|
|
187
191
|
|
|
188
192
|
Full reference: [`docs/assertions.md`](docs/assertions.md). The statistical core is pure Python
|
|
189
193
|
(no SciPy), including a from-scratch χ² survival function via the regularised incomplete gamma
|
|
@@ -224,7 +228,7 @@ The same artifact therefore runs in a small CI container and against a real QPU.
|
|
|
224
228
|
```text
|
|
225
229
|
shotgate/
|
|
226
230
|
├── src/shotgate/ # the package (validation core, backends, runner, CLI, pytest plugin)
|
|
227
|
-
├── examples/ # runnable workflows: bell
|
|
231
|
+
├── examples/ # runnable workflows: bell/ghz/grover + backend & oracle variants
|
|
228
232
|
├── tests/ # unit tests (core) + integration tests (gated on aer)
|
|
229
233
|
├── infra/
|
|
230
234
|
│ ├── terraform/ # IaC module: "quantum workflow as code"
|
|
@@ -241,7 +245,7 @@ shotgate/
|
|
|
241
245
|
| --- | --- |
|
|
242
246
|
| `local-aer` (Qiskit Aer simulator) | **Working**, default, baked into the image |
|
|
243
247
|
| `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) | **
|
|
248
|
+
| `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
249
|
| Error mitigation ([Mitiq](https://mitiq.readthedocs.io/)) | **Planned** |
|
|
246
250
|
|
|
247
251
|
## Roadmap
|
|
@@ -249,14 +253,19 @@ shotgate/
|
|
|
249
253
|
- **v0.1:** YAML workflows, local Aer backend, χ²/TVD/fidelity/structural oracles,
|
|
250
254
|
JUnit/JSON/MD reporters, Podman and KVM/QEMU isolation, Terraform module, pytest plugin,
|
|
251
255
|
PyPI package, published GHCR image with an IBM-enabled variant.
|
|
252
|
-
- **v0.2
|
|
256
|
+
- **v0.2:** statistical gates **validated against real quantum hardware** (`ibm_fez`,
|
|
253
257
|
2026-06-11, Bell/GHZ/Grover at 4096 shots; measured baseline and runbook in
|
|
254
258
|
[`docs/hardware-validation.md`](docs/hardware-validation.md)), hardware example gates for
|
|
255
259
|
GHZ and Grover, and a dispatchable QPU validation workflow.
|
|
256
|
-
- **v0.3:**
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
+
- **v0.3.0 (latest release):** the OpenQASM 3 fix and fail-closed validation, four more
|
|
261
|
+
oracles (`kl_divergence`, `shannon_entropy`, `expectation_value`, `most_frequent_outcome`),
|
|
262
|
+
declarative noise-model simulation and noise-aware expected distributions (so
|
|
263
|
+
`chi_square`/`kl_divergence` can gate on hardware), and the AWS Braket backend (local
|
|
264
|
+
simulation; the cloud path awaits validation on real hardware).
|
|
265
|
+
- **Planned:** error mitigation via [Mitiq](https://mitiq.readthedocs.io/), multi-backend
|
|
266
|
+
differential testing, circuit fixtures and property-based generation, a Helm chart, an
|
|
267
|
+
optional OpenTelemetry exporter for the telemetry layer (kept out of the core
|
|
268
|
+
dependencies), and validation of the Braket cloud path on real hardware.
|
|
260
269
|
|
|
261
270
|
See [`CHANGELOG.md`](CHANGELOG.md) and the [ADRs](docs/adr/) for decisions and rationale.
|
|
262
271
|
|
|
@@ -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.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# ADR-0009: Declarative noise-model simulation on the local Aer backend
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted
|
|
4
|
+
- **Date:** 2026-06-26
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
The `*-hardware` example gates carry noise-aware thresholds (Bell: TVD <= 0.15, fidelity
|
|
9
|
+
>= 0.85, leakage <= 0.15; full table in `docs/hardware-validation.md` section 4). Until now
|
|
10
|
+
those thresholds could only be exercised against a real QPU, which is queued and metered:
|
|
11
|
+
there was no way to regression-test the noise-aware profiles in ordinary CI, and a profile
|
|
12
|
+
could silently rot (become too loose or too tight) between hardware runs.
|
|
13
|
+
|
|
14
|
+
A measurement on this codebase showed that an Aer noise model with a per-gate depolarizing
|
|
15
|
+
error plus a readout error reproduces the measured `ibm_fez` Bell regime closely (simulated
|
|
16
|
+
TVD 0.1223 against a measured 0.1284), so a simulated device is a faithful enough proxy to
|
|
17
|
+
gate the noise-aware thresholds offline.
|
|
18
|
+
|
|
19
|
+
## Decision
|
|
20
|
+
|
|
21
|
+
Add an optional, declarative `noise` block to a backend spec, consumed by the `local-aer`
|
|
22
|
+
backend:
|
|
23
|
+
|
|
24
|
+
```yaml
|
|
25
|
+
backend:
|
|
26
|
+
provider: local-aer
|
|
27
|
+
noise:
|
|
28
|
+
depolarizing_1q: 0.004 # per single-qubit gate
|
|
29
|
+
depolarizing_2q: 0.012 # per two-qubit gate
|
|
30
|
+
readout_p0: 0.06 # P(measure 1 | prepared 0)
|
|
31
|
+
readout_p1: 0.07 # P(measure 0 | prepared 1)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- `NoiseSpec` is a strict (`extra="forbid"`) pydantic model with each parameter bounded in
|
|
35
|
+
`[0, 1]`; an all-zero spec is identical to the noiseless simulator.
|
|
36
|
+
- The spec rides through the backend `options` dict (set by the registry) so the `Backend`
|
|
37
|
+
ABC stays minimal. The `local-aer` backend separates it out, builds a Qiskit Aer
|
|
38
|
+
`NoiseModel` (uniform depolarizing on common 1- and 2-qubit gates, plus an assignment
|
|
39
|
+
readout error), and records a `noisy` flag in the result metadata.
|
|
40
|
+
- Real-hardware backends ignore `noise` (a device carries its own noise).
|
|
41
|
+
|
|
42
|
+
## Consequences
|
|
43
|
+
|
|
44
|
+
- **+** The noise-aware `*-hardware` thresholds become testable in CI with zero QPU time; a
|
|
45
|
+
`bell-state-noisy-sim` example gates a simulated-noisy Bell pair against hardware-profile
|
|
46
|
+
bounds.
|
|
47
|
+
- **+** Contributors can develop and tune noise-aware thresholds offline before spending a
|
|
48
|
+
hardware run.
|
|
49
|
+
- **-** The model is an approximate, uniform device proxy, not a calibration: it applies one
|
|
50
|
+
depolarizing rate per gate class and one readout matrix to every qubit, and only to the
|
|
51
|
+
enumerated gate names (others stay noiseless). It does not capture crosstalk, coherent
|
|
52
|
+
errors, or qubit-specific calibration. It is a threshold-exercising tool, not a device
|
|
53
|
+
digital twin.
|
|
54
|
+
- **-** `noise` is meaningful only for the `local-aer` backend; setting it on `ibm` is a
|
|
55
|
+
silent no-op (documented).
|