Python and Quantum Programming Workflow
A quantum result you cannot rerun is a story, not evidence. This chapter sets up the Python workflow — pinned environments, runnable tests, explicit run records — that makes a quantum experiment reproducible enough for someone else to audit.
The deliverable of a quantum experiment is not the plot; it is the run record that lets a stranger reproduce the plot. Most failed quantum demos fail as software, not as physics.
This chapter builds a working standard: separate the stable mathematical idea from the SDK-dependent plumbing, record every environment detail that can drift, and keep the checks in scripts and tests rather than in notebook cells nobody reruns.
Core concepts: sdk and transpilation, benchmarking and reproducibility.
Two ways a demo dies
Quantum programming fails in two ways that a polished demo hides completely. The first is conceptual: the circuit does not mean what its author thinks it means. The second is environmental: package versions, simulator settings, backend options, seeds, and shot counts drift, and the observed output changes with them. A serious workflow makes both visible instead of hoping neither happened.
The defense is separation. Keep five things distinct, as the figure shows: the stable mathematical idea, the local tested code, the SDK-dependent execution, the backend-dependent execution, and the recorded output with its interpretation. When an SDK releases a breaking change, only two of those five need attention. When a result looks wrong, the separation tells you where to look first.
The run record
The unit of reproducible quantum work is the run record. A complete one includes:
- the objective of the run,
- the code path or notebook path,
- the Python version and the package versions that matter,
- the exact command,
- the simulator or backend used,
- the shot count and the seed, if randomness is involved,
- the expected output — deterministic value, or stochastic range,
- the known limitation or migration risk, and
- the date it was last checked.
This looks bureaucratic until the first time a result changes under you. Then it looks like the difference between debugging for an hour and shrugging for a week. It also protects the material itself: stable lessons stay stable, while SDK instructions can be refreshed in place when APIs move.
Worked example: a test that earns its keep
The workspace includes a small statevector simulator with a unittest suite. From the repository root:
python3 -m unittest labs/python/test_mini_statevector.py
Run it, and record the command, the expected result, and what the result proves. It does not prove that every quantum circuit is correct. It proves that this local simulator handles normalization, Hadamard interference, the CNOT basis action, Bell-state outcomes, and seeded sampling for the cases it covers. That scope, written down, is what makes the test useful as evidence.
Then write the three-line note that turns the run into understanding:
- The exact statevector output is deterministic.
- The sampled counts vary from run to run unless a seed is fixed.
- The simulator exposes amplitudes that hardware never shows you directly.
That note — not a screenshot of a passing test — is the artifact worth keeping.
Where the workflow fails
The first trap is treating a notebook as evidence. Notebooks are excellent for exploration and explanation, but a rerunnable script, a test command, an expected output, and a limitation statement are what survive contact with a second person. If the evidence cannot outlive the kernel session, it is not evidence yet.
The second trap is confusing SDK success with conceptual correctness. A library will happily execute a circuit that is semantically wrong — qubit order reversed, the wrong register measured, the counts misread. The SDK did its job; the bug is in the mental model. This is why the local, inspectable layer exists.
The engineering view
A quantum experiment should look like any serious engineering artifact:
- a small source file,
- focused tests,
- an explicit command,
- controlled randomness,
- logged configuration,
- a plain-language interpretation, and
- a note on the failure modes.
Use notebooks where they are strong — narrative, visualization, exploration — and keep the core checks in scripts and tests. This matters most when later chapters compare SDKs or hardware backends, because a benchmark without metadata is not a benchmark. It is a story with numbers in it.
What this buys you in diligence
When you review a team's quantum work, the reproducibility questions are the cheapest probe you have. Can they rerun the demo from a clean checkout? Can they name the package versions? Can they explain the shot count and the seed? Do they know the expected failure modes?
A team that answers these in one breath has engineering discipline; a team that cannot has a demo. A result that cannot be reproduced should not drive an investment, a partnership, or a product decision — no matter how good the chart looks.
Exercise
Run an SDK reproducibility check. Execute one local lab test — the mini statevector suite above is ideal — and produce the run record for it.
- Record: Python version, command, code path, simulator or backend, shot count or seed if used, and the expected output.
- Write: a run note another learner could follow without guessing a single environment detail.
- Check: in your note, separate exact simulator behavior from sampled counts and from future SDK-dependent behavior.
- Decide: write one sentence on whether the artifact is ready for a teammate, a partner, an investor, or a public reader to audit.
Check your understanding
Without notes, list what belongs in a reproducible run record and why each item is there. A passing answer includes code version, backend, shot count, expected output — and can say what breaks when each is missing.
Oral defense: explain why a passing test with no recorded environment is weaker evidence than a failing test with a complete run record.
If you get stuck
If your run note amounts to "install the dependencies" with no expected output, go back to Chapter 16 (Circuit Notation as a Programming Language) to firm up what the circuit is supposed to mean, then return here — the workflow in this chapter only protects a computation you can already state precisely.