Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
name: Nightly SDK Breakage Detection

# Installs the newest releases of every dependency and fails visibly when the
# install, dependency resolution or tests break. Do not add continue-on-error,
# "|| true" or "|| echo" here: a red nightly run is the signal.
on:
schedule:
- cron: "0 2 * * *"
Expand All @@ -9,27 +12,22 @@ jobs:
nightly:
name: Test against latest SDK versions
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Checkout WestQuant Core
- name: Checkout WestQuant Core main
uses: actions/checkout@v4
with:
repository: WestQuantOpen/westquant-core
path: _westquant-core
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install latest SDKs
python-version: "3.12"
- name: Install latest dependencies
run: |
pip install --upgrade pip
pip install -e ./_westquant-core[test]
pip install --upgrade qiskit pytket pennylane pulser 2>/dev/null || true
pip install -e .[test] 2>/dev/null || pip install -e .
python -m pip install --upgrade pip
pip install -e ./_westquant-core
pip install --upgrade --upgrade-strategy eager -e ".[test]"
pip check
pip freeze
- name: Run tests
run: |
pytest tests/ -v || echo "Nightly tests failed — SDK breakage detected"
- name: Report status
if: always()
run: |
echo "Nightly run completed. Check for SDK breakage above."
run: pytest tests/ -v
65 changes: 40 additions & 25 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,40 +1,55 @@
name: Publish to PyPI

# Single publication path. PyPI Trusted Publishing is bound to this file name
# (publish.yml) and the "pypi" environment. Tests must pass and the release tag
# must match the pyproject version before anything is uploaded.
on:
release:
types: [published]
workflow_dispatch:
inputs:
confirm:
description: 'Type "publish" to confirm'
required: true
default: 'publish'

permissions:
contents: read

jobs:
publish:
name: Build and publish
test:
uses: ./.github/workflows/tests.yml

build:
needs: test
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
- name: Checkout WestQuant Core
uses: actions/checkout@v4
with:
repository: WestQuantOpen/westquant-core
path: _westquant-core
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Build package
python-version: "3.12"
- name: Check release tag matches package version
if: github.event_name == 'release'
run: |
pip install -e ./_westquant-core
pip install build
python -m build
- name: Check package
version=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
if [ "${GITHUB_REF_NAME#v}" != "$version" ]; then
echo "::error::Release tag $GITHUB_REF_NAME does not match pyproject version $version"
exit 1
fi
- name: Build and check distributions
run: |
pip install twine
twine check dist/*
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
python -m pip install --upgrade build twine
python -m build
twine check --strict dist/*
- uses: actions/upload-artifact@v4
with:
name: python-package-distributions
path: dist/

publish:
needs: build
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/
- uses: pypa/gh-action-pypi-publish@release/v1
1 change: 1 addition & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: Tests

on:
workflow_call:
push:
branches: [main]
pull_request:
Expand Down
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Changelog

## 0.1.1

- Fix: `westquant compare` printed `verified=yes` for every Qiskit baseline and
`Verification: EXACT` for the WestQuant result without running any check.
Each row now shows the status returned by `QiskitEquivalenceVerifier`
(`exact`, `invalid` or `unknown`), and reductions are only printed when the
selected candidate is verified.
- `westquant compare -f pytket|pennylane|pulser` now exits with status 2 and a
"not implemented" message instead of exiting 0.
- `-o 0` is no longer replaced by optimization level 2.
- `westquant version` / `doctor` report the installed package version instead
of a hard-coded string.
- README: removed `from westquant import optimize` (never exported) and the
synthetic compare output; documented the real search API and actual output.
- The `qiskit` and `all` extras now require `westquant-qiskit>=0.1.2`, whose
stage plugins work on Qiskit 2.x.
- `westquant-qcsc` 0.2.0 no longer installs a `westquant` command, so this
package is the only owner of `westquant`.
41 changes: 25 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,16 @@ pip install westquant[qiskit]
```

```python
from westquant import optimize
from westquant_qiskit.search import DeterministicSearchEngine

result = optimize(circuit, framework="qiskit", backend=backend, budget=64)
print(result.pareto_front)
result = DeterministicSearchEngine().search(circuit, challenge_id="demo", backend=backend, max_candidates=64)
print(result.best.metrics, result.best.verification.equivalence)
print([c.metrics for c in result.pareto_front])
```

The umbrella package itself exports the WQDF dataset helpers
(`from westquant import generate_training_data, WQDFSample`).

Or from the command line:

```bash
Expand Down Expand Up @@ -88,19 +92,24 @@ pip install westquant[all]
westquant compare circuit.qasm -f qiskit
```

Output:
Actual output for a 5-qubit QFT (westquant 0.1.1, Qiskit 2.6.1, no target):
```
2Q gates depth verified
Qiskit default 143 212 yes
Qiskit opt-3 128 195 yes
WestQuant search 113 179 yes

Candidates evaluated: 64
Verification: EXACT
2Q gate reduction: 20.9%
Depth reduction: 15.6%
2Q gates depth verification
──────────────────── ────────── ────────── ────────────
Qiskit opt-2 (base) 26 29 exact
Qiskit opt-3 26 29 exact
WestQuant search 26 34 exact

Candidates evaluated: 8 (8 verified exact)
Verification of selected candidate: exact
```

The verification column is the status returned by `QiskitEquivalenceVerifier`
for that exact circuit: `exact`, `invalid` or `unknown`. Circuits with
measurements, resets or more than 8 qubits are reported as `unknown`, and
reductions are then not printed. Only `-f qiskit` is implemented; other
frameworks exit with status 2.

## Architecture

```
Expand All @@ -118,9 +127,9 @@ WestQuant Open

## Verification

Every transformation is independently verified:
- **EXACT**: Unitary equivalence via `Operator.equiv()`
- **UNKNOWN**: Conservative — never promoted to EXACT
Every candidate carries an explicit verification status:
- **EXACT**: Unitary equivalence via `Operator.equiv()` (small, unitary circuits)
- **UNKNOWN**: Conservative — not checked or not checkable; never promoted to EXACT
- **same_problem_different_dynamics**: Pulser-specific — never collapsed with EXACT

## Design philosophy
Expand Down
8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "westquant"
version = "0.1.0a2"
version = "0.1.1"
description = "WestQuant Open — Search the representation, not just the parameters"
readme = "README.md"
requires-python = ">=3.10"
Expand All @@ -23,20 +23,20 @@ dependencies = [
]

[project.optional-dependencies]
qiskit = ["westquant-qiskit>=0.1.0a3"]
qiskit = ["westquant-qiskit>=0.1.2"]
pytket = ["westquant-pytket>=0.1.0a1"]
pennylane = ["westquant-pennylane>=0.1.0a1"]
pulser = ["westquant-pulser>=0.1.0a1"]
orchestrator = ["westquant-orchestrator>=0.1.0a1"]
bridges = ["westquant-bridges>=0.1.0a1"]
all = [
"westquant-qiskit>=0.1.0a3",
"westquant-qiskit>=0.1.2",
"westquant-pytket>=0.1.0a1",
"westquant-pennylane>=0.1.0a1",
"westquant-pulser>=0.1.0a1",
"westquant-orchestrator>=0.1.0a1",
]
test = ["pytest>=8"]
test = ["pytest>=8", "westquant-qiskit>=0.1.2"]

[project.scripts]
westquant = "westquant.cli:main"
Expand Down
2 changes: 1 addition & 1 deletion src/westquant/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
westquant doctor # Check what's installed and working
westquant compare # Compare default vs WestQuant search
"""
__version__ = "0.1.0a2"
__version__ = "0.1.1"

from .wqdf import WQDFSample, WQDF_VERSION, write_wqdf_jsonl, read_wqdf_jsonl, wqdf_schema
from .generate import generate_training_data
Loading
Loading