Skip to content

CHAPTER 23

# Programming reproducible quantum experiments

Learning goals. Run current local Qiskit workflows, convert wire conventions, separate sampling from exact simulation, and prepare reproducible experiments.

## 23.1 A program is an executable specification

A circuit diagram leaves choices that software must make explicit: register ordering, preparation, parameter units, measurement placement, classical-bit mapping, shot count, random seed, noise model, and output interpretation. These choices should travel with an experiment.

The accompanying Python examples use Qiskit 2.5.2 and were executed during this edition’s validation. This is the tested version, not a promise that it will remain the latest release. The official documentation consulted at the research cutoff uses the modern V2 primitive interfaces [71, 72, 73].

Create an isolated environment and install the pinned dependency:

    python -m venv .venv
    # Activate the environment using your operating system's command.
    python -m pip install qiskit==2.5.2
    python qiskit_examples.py

The web chapter links to the actual script and requirements file. All examples run locally without an account, hardware reservation, API key, or cloud charge.

The complete executable examples and pinned requirements accompany this chapter. Run `python qiskit_examples.py` in the environment above; the script asserts the basis, ordering, Bell-state, estimator, and channel identities before printing results.

## 23.2 Exact state-vector calculations

    import numpy as np
    from qiskit.quantum_info import Statevector, Pauli

    psi = Statevector(np.array([2, 3j]) / np.sqrt(13))
    for axis in ("X", "Y", "Z"):
        expectation = psi.expectation_value(Pauli(axis)).real
        print(axis, expectation)

Expected values are 0,12/13,−5/13. These are exact simulator expectations up to floating-point error, not estimates from finite measurements. State-vector simulation should omit measurement instructions when the desired object is a coherent state before readout.

A Bell circuit is equally direct:

    from qiskit import QuantumCircuit
    from qiskit.quantum_info import DensityMatrix, partial_trace

    bell = QuantumCircuit(2)
    bell.h(0)
    bell.cx(0, 1)
    state = Statevector.from_instruction(bell)
    reduced = partial_trace(DensityMatrix(state), [1])
    print(reduced.data)

The reduction is I/2. In Qiskit, the argument lists subsystems to trace out, not retain. The Bell example is symmetric; use asymmetric examples to test ordering.

## 23.3 Convert wire conventions deliberately

This book displays |q 0 q 1⋯q n−1⟩|q_0q_1\cdots q_{n-1}\rangle with q0 most significant. Qiskit state-vector indices give its qubit 0 the least significant weight. To preserve the book’s displayed wire labels, map book wire j to Qiskit wire n−1−j.

For three qubits, applying X to book q0 is:

    asymmetric = QuantumCircuit(3)
    asymmetric.x(2)  # book q0 maps to Qiskit wire 2
    assert np.argmax(Statevector.from_instruction(asymmetric).probabilities()) == 4

Index four is binary 100 in both displayed integer conventions after this mapping. A Bell state alone would not expose a reversed-order mistake.

Classical measurement registers also have display conventions. Name them, record the qubit-to-classical-bit mapping, and inspect an asymmetric known state before interpreting a histogram.

## 23.4 Finite shots with a V2 sampler

    from qiskit.primitives import StatevectorSampler

    measured = bell.copy()
    measured.measure_all()
    sampler = StatevectorSampler(seed=2026)
    result = sampler.run([measured], shots=2048).result()
    counts = result[0].data.meas.get_counts()
    print(counts)

Only 00 and 11 should occur in this ideal example, with frequencies near one half. The default classical register created by measure_all is named meas, which is why the result path uses that name. A circuit with a differently named register needs the corresponding data field.

StatevectorSampler implements a local pure-state sampler and does not support mid-circuit measurements. A dynamic circuit needs a simulator or backend supporting its actual control flow. Removing an intermediate measurement to make code run changes the experiment and can change its answer.

## 23.5 Estimators and observables

V2 estimator primitives accept a circuit and observable specification. A local StatevectorEstimator can compute expectations of Pauli-sum observables:

    from qiskit.primitives import StatevectorEstimator
    from qiskit.quantum_info import SparsePauliOp

    observable = SparsePauliOp.from_list([("XX", 1.0), ("ZZ", 1.0)])
    value = StatevectorEstimator().run([(bell, observable)]).result()[0].data.evs
    print(value)  # 2.0 for the ideal Bell state

A hardware estimator has sampling, compilation, and service-specific options. The local exact value is a validation reference, not evidence that a physical processor will return it without uncertainty.

For hardware work, map the logical circuit to the target’s instruction set and connectivity, transform observables consistently with any layout, inspect the compiled depth and operations, then execute with explicit shots or precision. The current provider documentation governs credentials, supported modes, and costs. No cloud submission is needed for this textbook’s reproducible examples.

## 23.6 Other tools in the ecosystem

Tool / interface | Useful role | What to verify
--- | --- | ---
Qiskit | Circuit construction, quantum information, compilation, primitives | Version, register order, target instructions, V2 result shapes
Cirq | Circuit and device modeling, state-vector and density simulation | Qubit order, supported operations and noise
PennyLane | Differentiable quantum circuits and hybrid workflows | Device, interface, gradient assumptions, shots
Stim | Large stabilizer circuits and detector models | Clifford restrictions and detector semantics
OpenQASM 3 | Circuit-level language with classical control constructs | Supported subset and backend execution semantics

These descriptions follow official technical documentation [74, 75, 32, 76]. A language supporting a feature does not imply every backend implements it. Cross-platform conversion can lose timing, control-flow, or noise semantics.

## 23.7 A reproducibility record

Save the source circuit, dependency versions, backend or simulator identity, compilation options, layout, noise equations, shots, seeds, raw results, and the analysis code. Hardware calibrations change; a backend name alone is insufficient.

Validate small cases before scaling. Check normalization, known basis outputs, unitary inverses, analytical probabilities, and ordering conversions. Compare independent implementations where possible. A shared bug can pass a test that merely repeats the implementation’s formula, so use known identities and independent libraries.

A random seed makes a software experiment repeatable within its stated implementation; it does not make a physical device’s measurement outcomes deterministic. A change of library version can also change a pseudorandom stream or transpilation result while preserving correct distributions.

## 23.8 Exercises

23.1. Which Qiskit wire represents book q1 in a four-qubit register under the mapping?

Show solution / guidance

Wire 4−1−1=2 4-1-1=2.

23.2. Why should the exact Bell-state expectation of XX+ZZ be two?

Show solution / guidance

The Bell state is a +1 eigenstate of both XX and ZZ, so their expectations sum to two.

23.3. Can the local StatevectorSampler example execute teleportation with intermediate measurements and feed-forward?

Show solution / guidance

No. Use a compatible dynamic-circuit simulator or a branch-by-branch mathematical calculation. The browser teleportation lab computes all conditioned branches explicitly.

23.4. Why pin package versions if the formulas are timeless?

Show solution / guidance

APIs, result containers, supported operations, and compilation behavior change. Pinning separates mathematical reproducibility from software-interface drift.

23.5. Name a stronger ordering test than a Bell histogram.

Show solution / guidance

Prepare an asymmetric basis state such as book |100⟩|100\rangle, map its wires explicitly, and verify its integer index and measurement-string interpretation.

IN THIS CHAPTER