Case Study 2: The Abstraction That Hid the Decision

The promise

A single API over every quantum computer. Write your circuit once, change one line, run it anywhere:

device = LocalSimulator()                          # development
device = AwsDevice("arn:aws:braket:::device/...")  # superconducting
device = AwsDevice("arn:aws:braket:::device/...")  # trapped ion
device = AwsDevice("arn:aws:braket:::device/...")  # neutral atom

This is a genuinely good abstraction, and the promise is largely kept. The circuit construction is identical. The result types are identical. The workflow is identical. A Bell state built once runs on all of them and produces the same distribution.

And that is precisely the problem.

What the abstraction preserves

Verified across the three frameworks this book has now used, and across Braket's own backends:

Property Transfers?
Circuit construction yes
Result types (probability, expectation, …) yes
Noise channel semantics yes — Chapter 11's signature table reproduced exactly
Correctness of the output distribution yes
The cost of running it no
Which failure modes exist no
Whether it is feasible at all no

The noise reproduction is worth showing, because it demonstrates how much genuinely does transfer:

  channel                        error fraction   imbalance
  depolarizing 0.05                      0.0630     +0.0042
  bit flip 0.05                          0.0930     +0.0008
  phase flip 0.05                        0.0000     +0.0012
  amplitude damping 0.15                 0.1073     +0.3228
  phase damping 0.30                     0.0000     -0.0068

This is Chapter 11 §11.7's table, in a third framework, unchanged. Depolarizing and bit flip produce impossible outcomes with balanced peaks; amplitude damping tilts the peaks (+0.32) without producing many impossible outcomes; phase damping and phase flip are invisible.

That last row is the same finding from Chapter 11 (Aer), Chapter 14 (Cirq), and now Braket. The computational basis is blind to phase in every framework, because it is a fact about measurement rather than about software. Physics transfers perfectly.

What it hides

Everything about whether your program is a good idea.

It hides a 3.18× cost multiplier

Case Study 1's star circuit costs 11 two-qubit gates on all-to-all hardware and 35 on heavy-hex. Nothing in the Braket API surfaces this. device.run(circuit, shots=1000) returns counts either way. The circuit is valid, the results are correct, and one of them cost three times as much and had seven times the depth.

It hides which failure modes exist

Chapter 12 built an entire apparatus around superconducting hardware's problems:

  • a 288× spread in two-qubit gate error across one chip,
  • twelve qubits with readout error above 10%,
  • nine dead gate pairs,
  • and qubit 84, stuck at a constant output.

None of that exists on a trapped-ion machine. Every ion of a species is identical by the laws of physics; there is no fabrication lottery. device_health(), best_layout(), and preflight() are answers to a question ion traps do not pose.

Conversely, ion traps have their own constraints — gate speed, chain length limits, and mode heating — that superconducting devices do not. The portable API describes neither.

It hides feasibility

A variational workload running thousands of circuits (Chapter 16 §16.4: $2n+1$ executions per gradient, per iteration) is dominated by wall-clock time. Ion gates are ~100× slower. A workload that is comfortable on superconducting hardware may be simply impractical on ions — not slower, but not worth attempting — and the one-line device swap gives no hint.

The pattern

This is a specific instance of a general failure, and naming it is the point of the case study.

An abstraction that unifies an interface implies that the things behind it are interchangeable. When they are not, the abstraction is making an argument, and the argument is wrong.

It has appeared before in this book, at every level:

Level Abstraction What it hid
A number readout_error = 0.5 (Ch. 12) stuck-at-1 versus a coin flip
A pass dynamical_decoupling.enable = True (Ch. 13) that it inserted 4 gates and did nothing
A framework counts = {'01': ...} (Ch. 14) which qubit is which bit
A device swap AwsDevice(...) (here) a 3.18× cost and a different failure catalogue

In every case the abstraction was correct and insufficient. None of them lied. Each answered the question it was asked and silently declined to mention the question you should have asked.

The response

Not to abandon the abstraction — it is genuinely useful, and rewriting circuits per vendor would be much worse.

The response is to make the hidden decision explicit and cheap. vqelab/topology.py does exactly this: connectivity_overhead() transpiles against the target and against all-to-all and reports the ratio; breakeven_error_rate() turns that into the error threshold an alternative modality would need to beat; and recommend_modality() returns an answer that is required to cite a number.

That last constraint is deliberate, and one of the module's tests enforces it:

def test_a_recommendation_always_carries_its_evidence():
    for circuit in (chain_ghz(8), star_ghz(8)):
        rec = recommend_modality(circuit)
        assert rec.reason, "a recommendation must state why"
        assert any(ch.isdigit() for ch in rec.reason), (
            "the reason must cite a measurement, not just an opinion")

A recommendation without a measurement behind it is exactly the thing this case study is about — a confident interface over an unexamined choice.

The lessons

Portability of code is not portability of results. The circuit runs everywhere and performs very differently, and only one of those facts is visible in the API.

Physics transfers; economics does not. Chapter 11's noise signatures reproduce exactly across three frameworks and two modalities, because they are facts about measurement. Cost, feasibility, and failure modes are facts about machines, and they do not transfer at all.

When an interface makes two things look interchangeable, check whether they are. The uniformity of the API is a design choice, not evidence about the hardware behind it.

Make the hidden decision explicit, and require evidence. A measurement that takes one transpilation should not be optional at the point where the choice is made. Build it into the tool, not the discipline of the user — Chapter 16's converged flag is the same move, for the same reason.

And the recurring theme, now at the architectural level: the abstraction answered the question it was asked. Chapter 12's averaged statistic, Chapter 13's enabled-but-inert pass, Chapter 14's symmetric test, and now a device swap. The failures in this book are rarely wrong answers. They are correct answers to the wrong question, and the skill being built across these chapters is noticing which question you actually asked.


Reproduce it: code/example-04-noise-and-modalities.py for the noise reproduction and the modality table; code/project-checkpoint.py for the tooling that makes the decision explicit.