A native pytest plugin for testing and verifying quantum circuits - Qiskit, Cirq, PennyLane (via OpenQASM), simulators and real hardware.
Project description
qcoherence
A native pytest plugin for testing and verifying quantum circuits — across Qiskit, Cirq, and PennyLane (via OpenQASM), on simulators and real IBM Quantum hardware.
Why this exists
Only 31% of quantum developers use any quantum-specific testing tooling — most still debug with print statements and circuit visualizations, because observing a quantum state collapses it, so classical debugging habits don't transfer. Several academic tools have tried to close this gap (Muskit, QuCAT, Quito, MorphQ, QuCheck, QUTest), but each requires writing tests as custom classes inheriting from a project-specific runner, each is tied to Qiskit only, and none validates against real hardware.
qcoherence is different on all three counts:
- Native pytest. Install it, write
def test_x():, runpytest. No base class, no custom runner. - Cross-framework. Accepts Qiskit
QuantumCircuits, OpenQASM 2/3 strings/files, Cirq circuits, and PennyLane circuits (via QASM export). - Real hardware, opt-in. Re-run your golden tests on actual IBM Quantum devices with
--qc-hardware, with noise-realistic tolerances.
Install
pip install qcoherence # core (Qiskit + Aer)
pip install qcoherence[cirq] # + Cirq ingestion
pip install qcoherence[pennylane] # + PennyLane examples
pip install qcoherence[hardware] # + IBM Quantum real-device validation
pip install qcoherence[all] # everything
Quickstart
import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from qcoherence import assert_state_equal, assert_entangled, run_statevector
def bell_circuit():
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
return qc
def test_bell_state():
expected = Statevector(np.array([1, 0, 0, 1]) / np.sqrt(2))
actual = run_statevector(bell_circuit())
assert_state_equal(actual, expected)
assert_entangled(actual, qubits=[0])
Run it like any other test suite: pytest.
From Cirq or PennyLane
from qcoherence import to_qiskit, run_statevector
# Cirq: pass the circuit object directly
qc = to_qiskit(my_cirq_circuit)
# PennyLane: export to OpenQASM, pass the string
qasm = qml.workflow.construct_tape(my_qnode)().to_openqasm(measure_all=False)
qc = to_qiskit(qasm)
What's proven, not just claimed
tests/test_bug_demo.py demonstrates the core value proposition: a Bell-state
circuit missing its entangling gate is a bug that looks completely fine under
naive inspection (it's a valid, normalized quantum state) but is caught
immediately by assert_entangled and assert_state_equal:
pytest tests/test_bug_demo.py -v
Assertion API
| Function | Checks |
|---|---|
assert_state_equal(actual, expected, tol=1e-6) |
State fidelity ≈ 1 (equal up to global phase) |
assert_distribution_close(counts, probs, tol=0.05) |
Total variation distance, simple tolerance |
assert_distribution_fits(counts, probs, alpha=0.01) |
Chi-square goodness-of-fit with a real p-value |
assert_entangled(state, qubits) |
Reduced-state purity < 1 |
assert_separable(state, qubits) |
Reduced-state purity ≈ 1 |
holm_bonferroni(pvalues, alpha) |
Family-wise error control across a suite of statistical tests |
pytest integration
pytest -m quantum_test— run only qcoherence-marked tests.pytest --qc-hardware— also run@pytest.mark.hardwaretests on real IBM Quantum devices (requires a free IBM Quantum account; skipped by default so CI stays green).--qc-shots N/--qc-seed N— shot count and reproducibility seed.
Real-hardware validation
import pytest
from qcoherence.hardware import run_counts_on_hardware, assert_hardware_distribution_close
@pytest.mark.hardware
def test_bell_on_real_device():
counts = run_counts_on_hardware(bell_circuit(), shots=4096)
assert_hardware_distribution_close(counts, {"00": 0.5, "11": 0.5}) # tol=0.15, NISQ-realistic
Extending qcoherence
Register custom assertions/backends programmatically or from a separate pip
package via entry points — see qcoherence/registry.py:
from qcoherence.registry import register_assertion
@register_assertion("assert_w_state_like")
def assert_w_state_like(state, *, tol=1e-6):
...
# in another package's pyproject.toml
[project.entry-points."qcoherence.assertions"]
assert_my_thing = "mypkg.assertions:assert_my_thing"
Golden benchmarks
tests/golden/ contains verified reference circuits used as both examples
and a regression suite: Bell state, GHZ state (3-qubit entanglement),
and a VQE ground-state search checked against exact numpy
diagonalization computed in-test.
Prior art
This project builds on ideas published in the quantum software testing research literature, particularly Muskit (mutation testing), QuCAT (combinatorial testing), Quito (coverage-guided generation), MorphQ (metamorphic testing), QuCheck (property-based testing and the statistical multiple-testing insight), and QUTest (native assertion testing). Its contribution is a native pytest integration layer with cross-framework ingestion and opt-in hardware validation, not a new testing paradigm.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file qcoherence-1.0.0.tar.gz.
File metadata
- Download URL: qcoherence-1.0.0.tar.gz
- Upload date:
- Size: 18.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
429dfaa85a023e59551f72938514aa634fe79911d07a37f3d485e62327d6cc9c
|
|
| MD5 |
d792e8f1755ba297f31588f4d1ef8cf2
|
|
| BLAKE2b-256 |
9a0c31951e366e10d595c6da7de5a48e146c3677b44a672e8f47773223070706
|
File details
Details for the file qcoherence-1.0.0-py3-none-any.whl.
File metadata
- Download URL: qcoherence-1.0.0-py3-none-any.whl
- Upload date:
- Size: 16.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5ffe9b8cafec8f7422933decaf74ddb4aa9f2dc83479fd9f660f98ec07c238a
|
|
| MD5 |
fb5a2b0af862b12d7d11a6bde619bee4
|
|
| BLAKE2b-256 |
97658c162b01f6594b1a8fa7e64e8f41d03a591ea7fdfb046f3671eb92a05a3e
|