Source code for qtest.fixtures.common_states

"""Pytest fixtures (and plain factory functions) for common quantum states.

Each fixture / factory returns a :class:`qiskit.QuantumCircuit` that prepares
the named state starting from :math:`|0\\rangle^{\\otimes n}`. Circuits are
unitary-only (no measurement / reset); add ``qc.measure_all()`` in your test
when sampling.

The same builders are exposed twice:

* As **pytest fixtures** (``bell_state``, ``ghz_state``, ``plus_state``,
  ``ghz_3`` …) — request them in test signatures.
* As **plain functions** (``bell_circuit``, ``ghz_circuit(n)``,
  ``plus_circuit`` …) — call them directly outside of pytest tests.

For pytest discovery, list this module in the consumer's
``pytest_plugins`` or import individual fixtures into your ``conftest.py``::

    # tests/conftest.py
    pytest_plugins = ["qtest.fixtures.common_states"]

Examples
--------
>>> # In a pytest test:
>>> def test_bell(bell_state, qiskit_backend):  # doctest: +SKIP
...     assert_state_close(bell_state, "bell")

>>> # As a plain function:
>>> from qtest.fixtures.common_states import bell_circuit  # doctest: +SKIP
>>> qc = bell_circuit()
"""

from __future__ import annotations

from typing import Any, Callable

import numpy as np
import pytest

# --------------------------------------------------------------------------- #
# Plain factory functions                                                     #
# --------------------------------------------------------------------------- #


[docs] def bell_circuit() -> Any: """Return a circuit preparing the Bell state :math:`(|00\\rangle + |11\\rangle)/\\sqrt{2}`.""" from qiskit import QuantumCircuit qc = QuantumCircuit(2, name="bell") qc.h(0) qc.cx(0, 1) return qc
[docs] def plus_circuit() -> Any: """Return a 1-qubit circuit preparing :math:`|+\\rangle = (|0\\rangle + |1\\rangle)/\\sqrt{2}`.""" from qiskit import QuantumCircuit qc = QuantumCircuit(1, name="plus") qc.h(0) return qc
[docs] def minus_circuit() -> Any: """Return a 1-qubit circuit preparing :math:`|-\\rangle = (|0\\rangle - |1\\rangle)/\\sqrt{2}`.""" from qiskit import QuantumCircuit qc = QuantumCircuit(1, name="minus") qc.x(0) qc.h(0) return qc
[docs] def ghz_circuit(n: int) -> Any: """Return an n-qubit GHZ-state preparation circuit. Builds :math:`(|0\\rangle^{\\otimes n} + |1\\rangle^{\\otimes n}) / \\sqrt{2}` via the standard ``H + (n-1) × CX`` recipe. Parameters ---------- n Qubit count (``n >= 1``). """ from qiskit import QuantumCircuit if not isinstance(n, int) or isinstance(n, bool) or n < 1: raise ValueError(f"n must be a positive integer, got {n!r}") qc = QuantumCircuit(n, name=f"ghz_{n}") qc.h(0) for k in range(1, n): qc.cx(0, k) return qc
[docs] def w_circuit(n: int) -> Any: """Return an n-qubit W-state preparation circuit. For ``n == 1`` returns ``X|0> = |1>``; for ``n == 2`` uses the closed-form ``H + CX + X`` recipe; for ``n >= 3`` it appends a unitary :class:`qiskit.circuit.library.StatePreparation` block with the target amplitudes :math:`(|10\\dots0\\rangle + |01\\dots0\\rangle + \\dots) / \\sqrt{n}`. Parameters ---------- n Qubit count (``n >= 1``). """ from qiskit import QuantumCircuit if not isinstance(n, int) or isinstance(n, bool) or n < 1: raise ValueError(f"n must be a positive integer, got {n!r}") if n == 1: qc = QuantumCircuit(1, name="w_1") qc.x(0) return qc if n == 2: # Hand-coded: |00> -H(0)-> (|00>+|01>)/√2 -CX(0,1)-> (|00>+|11>)/√2 # -X(0)-> (|01>+|10>)/√2 = |W_2>. qc = QuantumCircuit(2, name="w_2") qc.h(0) qc.cx(0, 1) qc.x(0) return qc # n >= 3: build the target amplitude vector and use a unitary # StatePreparation block. from qiskit.circuit.library import StatePreparation dim = 1 << n vec = np.zeros(dim, dtype=complex) for k in range(n): vec[1 << k] = 1.0 vec /= np.sqrt(n) qc = QuantumCircuit(n, name=f"w_{n}") qc.append(StatePreparation(vec), range(n)) return qc
# --------------------------------------------------------------------------- # # Pytest fixtures # # --------------------------------------------------------------------------- #
[docs] @pytest.fixture def bell_state() -> Any: """Yield a fresh Bell-state preparation circuit per test. Example:: def test_bell(bell_state): assert_state_close(bell_state, "bell") """ return bell_circuit()
[docs] @pytest.fixture def plus_state() -> Any: """Yield a fresh :math:`|+\\rangle` preparation circuit per test.""" return plus_circuit()
[docs] @pytest.fixture def minus_state() -> Any: """Yield a fresh :math:`|-\\rangle` preparation circuit per test.""" return minus_circuit()
[docs] @pytest.fixture def ghz_state() -> Callable[[int], Any]: """Factory fixture yielding ``n -> QuantumCircuit`` for GHZ-n states. Example:: def test_ghz_5(ghz_state): assert_state_close(ghz_state(5), "ghz_5") """ return ghz_circuit
[docs] @pytest.fixture def w_state() -> Callable[[int], Any]: """Factory fixture yielding ``n -> QuantumCircuit`` for W-n states. Example:: def test_w_4(w_state): assert_state_close(w_state(4), "w_4") """ return w_circuit
[docs] @pytest.fixture def ghz_3() -> Any: """Shortcut for a 3-qubit GHZ preparation circuit.""" return ghz_circuit(3)
[docs] @pytest.fixture def ghz_4() -> Any: """Shortcut for a 4-qubit GHZ preparation circuit.""" return ghz_circuit(4)
[docs] @pytest.fixture def ghz_5() -> Any: """Shortcut for a 5-qubit GHZ preparation circuit.""" return ghz_circuit(5)