Case Study 1: The Qubit That Was Not a Coin Flip

The setup

While building §12.2's device-health query, one line of output looked like a rounding artifact:

  readout error    min 0.0029   median 0.0198   max 0.5000   ratio 170.7x

A maximum of exactly 0.5000. Not 0.4987, not 0.512. Exactly one half.

Numbers that land exactly on a round value are usually either a clamp, a default, or a coincidence. This one was none of those, and chasing it produced the most useful paragraph in the chapter.

Step 1: Which qubit, and is it plausible?

worst = int(np.argmax(readout))
print(worst, readout[worst])
  84  0.5

Qubit 84, readout error 0.5. The natural interpretation is immediate and, everyone agrees, a little poetic: a qubit whose measurement is a coin flip. It carries no information. Route around it.

That interpretation is wrong. It took a measurement to find out.

Step 2: Measure it

The cleanest possible test. Prepare $|0\rangle$ — which requires no gates at all, since qubits initialize there — and measure:

qc = QuantumCircuit(1, 1)
qc.measure(0, 0)
pm = generate_preset_pass_manager(optimization_level=1, backend=backend,
                                  initial_layout=[84], seed_transpiler=42)

A coin flip predicts roughly 2048 zeros and 2048 ones.

  {'1': 4096}

Every single shot returned 1. Not approximately; exactly. 4096 of 4096.

And prepared in $|1\rangle$:

  {'1': 4096}

The same. The qubit returns 1 regardless of what state it is in. It is not a coin flip — it is stuck at 1.

Step 3: Why does 0.5 describe a stuck qubit?

Because readout_error is not one number. It is an average of two:

$$\texttt{readout\_error} = \frac{P(1|0) + P(0|1)}{2}$$

For a qubit stuck at 1: it always reports 1 when the state is $|0\rangle$, so $P(1|0) = 1$. And it never reports 0 when the state is $|1\rangle$, so $P(0|1) = 0$.

$$\frac{1 + 0}{2} = 0.5$$

The averaged value 0.5 is not what a random qubit produces. It is precisely what a stuck qubit produces. Both readings give 0.5; only one of them is the actual failure.

Confirmed against the raw fields, which the backend has been carrying all along:

  q84:  readout_error 0.5   prob_meas1_prep0 = 1   prob_meas0_prep1 = 0

Step 4: How common is this?

Both directions, for all twelve bad-readout qubits:

qubit readout_error $P(1\mid 0)$ $P(0\mid 1)$ measured $P(1)$ from $\lvert 0\rangle$
6 0.2573 0.5044 0.0103 0.5044
9 0.1606 0.3071 0.0142 0.3130
13 0.1270 0.2500 0.0039 0.2554
16 0.1023 0.1201 0.0845 0.1172
34 0.1045 0.1514 0.0576 0.1489
52 0.1538 0.2627 0.0449 0.2676
56 0.1094 0.1899 0.0288 0.1863
57 0.2173 0.2910 0.1436 0.2981
64 0.2031 0.3335 0.0728 0.3396
70 0.1626 0.3188 0.0063 0.3262
84 0.5000 1.0000 0.0000 1.0000
92 0.3406 0.0127 0.6685 0.0142

Three things fall out.

The measured column tracks $P(1|0)$, not the averaged value. In every row. For qubit 6 it matches to four decimals — 0.5044 against 0.5044. The average is not what the device does; it is a summary of what the device does, and the summary is not the thing.

The asymmetry is usually large. Qubit 70 is 0.3188 one way and 0.0063 the other — a factor of 51. Averaging those into 0.1626 describes neither.

Qubit 92 is the mirror image of 84. Its 0.3406 average hides $P(1|0) = 0.0127$ against $P(0|1) = 0.6685$. It is nearly perfect at reporting zeros and fails two times in three at reporting ones. A circuit whose answer is mostly zeros would run on qubit 92 almost cleanly; one whose answer is mostly ones would be destroyed. The averaged number cannot tell you which.

Step 5: The part that changes how you work

Then the tooling disagreed with itself.

NoiseModel.from_backend builds a symmetric readout matrix from the averaged value:

  q84: [[0.5, 0.5], [0.5, 0.5]]

That is a model of a coin flip. And it behaves like one:

  AerSimulator.from_backend(backend):
      seed  1234: {'0': 2054, '1': 2042}
      seed     7: {'0': 2041, '1': 2055}
      seed    99: {'0': 2031, '1': 2065}

Whereas the primitive path honors the asymmetry:

  SamplerV2(mode=backend):
      seed  1234: {'1': 4096}
      seed     7: {'1': 4096}
      seed    99: {'1': 4096}

Same backend. Same circuit. Same calibration snapshot. Two different physics. One says the qubit is random; the other says it is stuck. And the seed changes nothing in the second, which is the tell — nothing is being sampled.

Chapter 11 §11.6 called AerSimulator.from_backend "the most useful line in the chapter," and it remains that. But "I simulated it with the device noise model" is now an ambiguous statement, and the ambiguity bites exactly where it hurts most: on the pathological qubits you reach for the simulator to understand.

What this cost, and what it bought

Cost: about twenty minutes, because an exactly-round number looked wrong.

Bought:

  • A stuck-qubit check in preflight() that a threshold on the averaged value would not have caught. A limit of readout_error > 0.6 passes qubit 84 — the worst qubit on the device.
  • The knowledge that a layout scored on averaged readout error is scored on the wrong number.
  • A version note that will save somebody a day of confusion when two simulations disagree.

The lessons

A summary statistic is a lossy compression, and you rarely get to choose what it loses. Here it lost the distinction between random and stuck — arguably the most actionable distinction there is, since one is hopeless and the other is a hardware fault you can report and route around.

Exactly-round numbers deserve suspicion. 0.5000 was not a coincidence and not a clamp; it was the signature of a specific failure mode, legible once you knew the definition of the field.

When a field is an average, find the terms. They were sitting in qubit_property() the whole time under prob_meas1_prep0 and prob_meas0_prep1. Nothing was hidden. It was summarized.

This is the third instance of the same pattern in twelve chapters. Chapter 2's Case Study 2 found the readout asymmetry running opposite to the textbook's claim. Chapter 11 §11.7 found phase damping completely invisible in the computational basis. Now: the averaging that hides a stuck qubit.

Each time, the instrument reported a number that was correct and insufficient.

Your measurement can only see what it is sensitive to — and that applies to the numbers you read about the device just as much as to the qubits themselves.


Reproduce it: code/example-06-the-averaged-number.py, and code/project-checkpoint.py for the preflight check that came out of it.