Exercises: Qiskit Architecture
Orientation, then two things that will change how you write code: the primitive choice, and the transpile-once pattern.
Difficulty: ⭐ warm-up · ⭐⭐ standard · ⭐⭐⭐ deeper.
Solutions: worked answers to the daggered (†) and odd-numbered problems are in
appendices/answers-to-selected.md; runnable code in
code/exercise-solutions.py.
Part A — Warm-ups ⭐
7.1 † What happened to Terra, Aer, Ignis, and Aqua? For each, say where its functionality lives now.
7.2 You find a tutorial containing from qiskit.aqua.algorithms import VQE. Roughly what year is
it from, and will any of its code run? What is the fastest way to date quantum code you find online?
7.3 † Name the two primitives and the question each one answers. Which requires circuits with measurements, and which requires circuits without?
7.4 For an $n$-qubit circuit, how do the shots required scale for (a) estimating the full output distribution to fixed precision, and (b) estimating one expectation value to fixed precision?
7.5 † What does observable.apply_layout(isa.layout) do, and what happens if you forget it? Give
both failure modes.
Part B — Anatomy ⭐⭐
7.6 † Print the instruction list of a Bell circuit, showing operation name and the qubit and classical bit indices for each. Why does Qiskit store bits as objects rather than indices?
7.7 Convert a Bell circuit to a DAG. Report the number of operation nodes and the depth, then print the operations in each layer. Explain why 4 operations give a depth of 3.
7.8 † List Aer's simulation methods. Then time statevector against stabilizer on a GHZ chain
at $n = 16, 20, 24, 26$ and tabulate the ratio. Finally, run stabilizer alone at $n = 100$, 500,
and 1000 — report the times and the outcomes. What does this tell you about which circuits are
classically hard?
7.9 † Compute $\langle ZZ\rangle + \langle XX\rangle$ for a Bell state two ways: with a Sampler (you will need two circuits and the parity arithmetic of Chapter 5), and with an Estimator. Compare the amount of code and the number of circuit executions.
Part C — Primitives in Practice ⭐⭐⭐
7.10 † Run an Estimator at precisions 0.05, 0.01, and 0.001, three times each, and tabulate the
value, the returned stds, the absolute error against the true value of 2.0, and whether the error
is within one standard deviation. How many of your nine trials fell inside? Is that consistent with
expectation? Explain why the values differ between runs even though the circuit does not.
7.11 † Reproduce the layout trap. Transpile a Bell circuit at optimization level 3 for
FakeSherbrooke and report the physical qubits chosen. Then run the Estimator three ways: with
apply_layout, with an unpadded observable, and with the observable padded onto physical qubits 0
and 1. Report all three outcomes and classify each as correct, loudly wrong, or silently wrong.
7.12 Measure the transpile-once-bind-many speedup at 5, 20, 50, and 100 iterations on a 4-qubit depth-3 ansatz. Plot or tabulate the speedup against iteration count. Is the relationship linear? Explain why from the structure of the two loops.
7.13 † Extend 7.12 across circuit sizes: 2×1, 4×3, 6×4, 8×5 (qubits × depth). Report the transpilation time and the speedup at 20 iterations for each. Does the speedup grow or shrink with circuit size? Explain what two competing effects determine the answer.
7.14 Write estimate_with_error(circuit, observable, backend, precision) that transpiles, lays
out, runs, and returns (value, stds, layout). Then write a version that deliberately omits
apply_layout and confirm that on a large backend it either raises or silently returns a different
number. Which happens, and what determines it?
Part D — Deeper ⭐⭐⭐
7.15 † The Estimator's precision is a statistical requirement. Construct a demonstration that
it says nothing about systematic error: run a circuit on FakeSherbrooke at precision=1e-4 and
compare to the exact value. Report the returned stds and the actual error. By what factor do they
differ, and what should you report?
7.16 For a Hamiltonian with $k$ Pauli terms, how many distinct measurement bases are needed in
the worst case? In the best case? Write a function that partitions a SparsePauliOp into
qubit-wise-commuting groups and report the group count for a 4-qubit Hamiltonian of your
construction. (This is Chapter 5 Case Study 1's Reduction 1, implemented.)
7.17 † Sessions keep your queue position but are metered while open. Model the trade-off: for a VQE with $N$ iterations, each needing $t_q$ seconds of QPU time and $t_c$ seconds of classical optimizer time, and with a per-job queue wait of $t_w$, write expressions for the total wall-clock time with and without a session. At what values does a session stop being worth it?
7.18 Read the DAG API and write a function that reports, for any circuit, the critical path — the specific sequence of operations that determines the depth. Test it on a 5-qubit GHZ chain. Why is this more useful than the depth number alone?
Part E — Project ⭐⭐
7.19 † Implement the Chapter 7 🧱 Project Checkpoint: extend vqelab/backends.py with
get_estimator, get_sampler, prepare, reference_value, and check_against_reference.
7.20 The Prepared dataclass bundles a circuit with its laid-out observable so they cannot be
separated. Argue for and against this design: what does it prevent, and what flexibility does it
cost? Propose one situation where a caller would legitimately want them apart, and say how you would
support it without reopening the trap.
7.21 ⭐⭐⭐ Extend check_against_reference to take the measured value's stds and decide
statistically rather than by a fixed tolerance ratio — that is, report whether the difference from
the reference is consistent with the combined statistical and expected systematic error. What do
you need to know about the device to set the systematic term, and where would you get it?
(Chapter 12 §12.7 is the full version of this decision procedure.)