Case Study 2: Building a Universal Single-Qubit Gate from Three Rotations
"Universality is not a philosophical property. It is a compiler requirement."
Executive Summary
Hardware implements a handful of gates. Your algorithm needs arbitrary ones. Something has to bridge that gap, and this case study builds the bridge for the single-qubit case: a demonstration that three rotations suffice to produce any single-qubit unitary whatsoever, followed by the construction, a numerical proof, and an examination of what it costs on real hardware.
This is the simplest instance of a result that Chapter 10 relies on completely and Chapter 28 optimizes: gate synthesis. It is also a satisfying piece of mathematics that you can verify entirely in code, and it explains a fact from Chapter 2 that probably looked arbitrary — why IBM's native basis is exactly $\{r_z, s_x, x\}$ and not some other set.
Skills applied: rotation gates (§3.6); global phase (§3.7); Operator and matrix–gate
conversion (§3.8); the Bloch sphere as a rotation group (§3.4).
The Problem
You want to apply this gate:
$$U = \frac{1}{\sqrt{7}}\begin{pmatrix} 1+i & -1+2i \\ 1+2i & 1-i \end{pmatrix}$$
It is unitary — verify it below rather than take my word — and it is not H, X, Y, Z, S, T, or any named gate. Hardware has never heard of it.
import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import Operator
U = np.array([[1 + 1j, -1 + 2j],
[1 + 2j, 1 - 1j]]) / np.sqrt(7)
print((U.conj().T @ U).round(10)) # U^dagger U should be the identity
qc = QuantumCircuit(1)
qc.unitary(Operator(U), 0, label="U")
[[ 1.+0.j -0.-0.j]
[-0.+0.j 1.+0.j]]
⚠️ Common Pitfall — Choose a generic test case.
A first draft of this case study used the real matrix $\frac{1}{\sqrt5}\begin{pmatrix}1 & -2\\ 2 & 1\end{pmatrix}$, which looks arbitrary and is not: it is real, orthogonal, and has determinant $+1$, which makes it exactly $R_y(2\arctan 2)$. The transpiler collapsed it to a single
rygate and the three-rotation structure never appeared.That is a general hazard when testing synthesis, decomposition, or optimization code: a special case can pass your test while the general case is broken. Real orthogonal matrices, permutation matrices, and diagonal matrices are all "arbitrary-looking" and all degenerate. When you want to exercise a general path, use a complex unitary — or better, use
random_unitarywith a fixed seed, as the verification below does.
But qc.unitary is a promise, not an implementation. Something must eventually turn it into pulses.
That something is the transpiler, and this case study is what the transpiler does.
The Claim
Any single-qubit unitary can be written, up to global phase, as three rotations about two alternating axes. The standard forms are:
$$U = e^{i\alpha}\, R_z(\phi)\, R_y(\theta)\, R_z(\lambda) \qquad\text{or}\qquad U = e^{i\alpha}\, R_z(\phi)\, R_x(\theta)\, R_z(\lambda)$$
Three real parameters plus a phase — four numbers, which is exactly the number of real degrees of freedom in a $2\times2$ unitary.
Why three, geometrically
A single-qubit gate is a rotation of the Bloch sphere, and rotations of a sphere form the group $SO(3)$, which is three-dimensional. Three parameters is therefore not a coincidence and not an upper bound that might be improvable — it is exactly right, and these are Euler angles, the same ones used for aircraft attitude and robot arms.
The count also explains the fourth number. A $2\times2$ unitary has four real degrees of freedom; the Bloch-sphere rotation captures three; the leftover one is the global phase, which is physically invisible (§3.7) and is precisely why it does not show up in the geometry.
Why two axes and not three
You might expect three rotations to need three different axes. They do not, and this is worth seeing: rotating about $z$, then $y$, then $z$ again reaches every orientation. Two alternating axes suffice as long as they are not parallel. Hardware exploits this — and, as we will see, exploits it in a very specific direction.
The Construction
Qiskit will do the decomposition for you. First let us see the answer, then extract it.
from qiskit import transpile
qc = QuantumCircuit(1)
qc.unitary(Operator(U), 0, label="U")
decomposed = transpile(qc, basis_gates=["rz", "ry"], optimization_level=3)
print(decomposed.draw())
print(f"global phase: {decomposed.global_phase:.6f}")
print(f"\nreproduces U: {Operator(decomposed).equiv(Operator(U))}")
┌─────────────┐┌────────────┐┌─────────────┐
q: ┤ Rz(-1.8925) ├┤ Ry(2.0137) ├┤ Rz(0.32175) ├
└─────────────┘└────────────┘└─────────────┘
global phase: 0.000000
reproduces U: True
Three rotations, two alternating axes, exactly as claimed. Three angles, one gate — and none of the three angles is a recognizable constant, which is the point: this is the generic case, not a special one.
📐 Math Aside — Extracting the angles by hand.
For $U = e^{i\alpha} R_z(\phi) R_y(\theta) R_z(\lambda)$, the parameters come from the matrix entries directly:
$$\theta = 2\arccos\bigl(|U_{00}|\bigr), \qquad > \phi + \lambda = 2\arg(U_{11}) - 2\arg(U_{00}) \ \ (\text{when } \theta \neq 0),$$ $$\phi - \lambda = 2\arg(U_{10}) - 2\arg(U_{00}) + \pi.$$
The special cases — $\theta = 0$ or $\pi$, where $\phi$ and $\lambda$ become degenerate and only their sum or difference is determined — are exactly the ones that bite. A synthesis routine that divides by $\sin(\theta/2)$ without guarding it will produce a
nanon the identity gate, which is a real and common bug in hand-rolled decomposers.This is why you use the library's version. Exercise 3.20 has you write one anyway, because writing it once is how you learn to trust it.
Verification
A claim about every unitary needs more than one example. Test it on random ones:
import numpy as np
from qiskit.quantum_info import Operator, random_unitary
rng = np.random.default_rng(1234)
failures = 0
for trial in range(200):
U = random_unitary(2, seed=int(rng.integers(1 << 31)))
qc = QuantumCircuit(1)
qc.unitary(U, 0)
d = transpile(qc, basis_gates=["rz", "ry"], optimization_level=3)
n_rot = sum(v for k, v in d.count_ops().items() if k in ("rz", "ry"))
if not Operator(d).equiv(U):
failures += 1
if n_rot > 3:
print(f" trial {trial}: needed {n_rot} rotations")
print(f"failures: {failures} / 200")
failures: 0 / 200
Two hundred random unitaries, every one reproduced, none requiring more than three rotations.
Note equiv rather than ==: the decomposition matches up to global phase, and comparing
exactly would report 200 failures for a construction that is entirely correct. This is §3.7's rule
doing real work, and getting it wrong here is the classic way to convince yourself a correct
synthesis routine is broken.
What It Costs on Hardware
Now the part that matters practically. rz and ry are not what hardware has. Transpile to the
real basis:
for basis in (["rz", "ry"], ["rz", "rx"], ["rz", "sx", "x"], ["u"]):
d = transpile(qc, basis_gates=basis, optimization_level=3)
ops = dict(d.count_ops())
pulses = (ops.get("sx", 0) + ops.get("x", 0) + ops.get("ry", 0)
+ ops.get("rx", 0) + ops.get("u", 0))
print(f" {str(basis):<20} {str(ops):<26} real pulses: {pulses}")
['rz', 'ry'] {'rz': 2, 'ry': 1} real pulses: 1
['rz', 'rx'] {'rz': 2, 'rx': 1} real pulses: 1
['rz', 'sx', 'x'] {'rz': 3, 'sx': 2} real pulses: 2
['u'] {'u': 1} real pulses: 1
Read the third line carefully, because it is the payoff.
In the hardware basis, an arbitrary single-qubit gate costs three rz gates and two sx
pulses. And from §3.8 we know rz is virtual — zero duration, zero error.
So an arbitrary single-qubit gate costs two physical pulses. Always. Regardless of which gate.
That is a remarkable engineering fact and it explains the basis choice from Chapter 2. IBM did not pick $\{r_z, s_x, x\}$ arbitrarily. They picked the smallest set with the property that every single-qubit operation costs the same two pulses, with the angular freedom carried entirely by error-free virtual rotations. A complicated gate is no more expensive than a simple one.
⚙️ Under the Transpiler — The consequence for how you write circuits.
Because every single-qubit gate costs exactly two pulses:
- Merging adjacent single-qubit gates is free money. Ten consecutive single-qubit gates collapse to one arbitrary unitary — two pulses instead of twenty. The transpiler does this automatically at optimization level 1 and above, which is a large part of why level 1 beat level 0 so decisively in Chapter 2's Exercise 2.20 (25 operations down to 14).
- Single-qubit gate count is a bad cost metric. Depth in two-qubit gates is the one that matters, because two-qubit gates are an order of magnitude noisier and cannot be merged nearly so freely.
- Do not hand-optimize single-qubit sequences. The transpiler does it optimally and you will not beat it. Spend the effort on two-qubit structure instead. Chapter 28 makes this quantitative.
The Limit of This Result
One qubit is easy. The result does not scale the way you might hope.
Two qubits: an arbitrary two-qubit unitary requires at most three CNOTs plus single-qubit gates — a real theorem, and the basis of the KAK decomposition that Chapter 28 covers. Still constant, still tractable.
$n$ qubits: an arbitrary $n$-qubit unitary requires a number of two-qubit gates growing like $4^n$. For ten qubits that is on the order of a million gates, which is far beyond any current device's coherence budget.
This is the most important caveat in gate synthesis, and it is easy to miss after a chapter that makes decomposition look easy. Arbitrary unitaries are not efficiently implementable. The unitaries that are implementable are the structured ones — the ones built from a few layers of local gates, which is exactly what every algorithm in Part IV and every ansatz in Part VI is made of.
🔬 Honest Assessment — What universality does and does not buy.
"This gate set is universal" is one of the most-cited and least-informative claims in quantum computing. It means any unitary can be approximated to arbitrary accuracy by some sequence from the set. It says nothing about how long that sequence is.
The Solovay–Kitaev theorem gives the standard bound: approximating a single-qubit gate to accuracy $\epsilon$ from a discrete universal set takes a sequence of length polylogarithmic in $1/\epsilon$ — which is genuinely efficient, and is why fault-tolerant architectures can use the discrete Clifford+T gate set.
But universality plus polylog approximation still leaves the $4^n$ problem above. Universality guarantees you can express the computation. It guarantees nothing about whether you can afford it. When a vendor tells you their gate set is universal, they have told you almost nothing about what their machine can run.
Lessons
- Three rotations about two alternating axes give any single-qubit unitary, up to global phase. The three matches the dimension of the rotation group; the leftover phase is the fourth degree of freedom in the matrix.
- Compare with
equiv, not==. Synthesis matches up to global phase, and exact comparison makes correct code look broken. - On IBM hardware, an arbitrary single-qubit gate costs exactly two pulses — three virtual
rzand twosx. Complexity is free at the single-qubit level. - That is why the basis is $\{r_z, s_x, x\}$. The choice is engineered so all angular freedom rides on error-free virtual gates.
- Therefore: merge single-qubit gates aggressively, and measure cost in two-qubit depth. The transpiler already does the former optimally.
- The result does not scale. Arbitrary $n$-qubit unitaries need $O(4^n)$ two-qubit gates. Structured circuits are the only implementable ones.
- Universality is a weak claim. It says a computation is expressible, not affordable.
- Guard the degenerate cases. Synthesis routines that divide by $\sin(\theta/2)$ produce
nanon the identity — a real bug in hand-rolled decomposers.
Questions
-
Verify that $U$ in this case study is unitary by computing $U^\dagger U$. Then find its eigenvalues and confirm both have magnitude 1. Why must that be true for any unitary?
-
Decompose the same $U$ into the
["rz", "rx"]basis. Do you get the same middle angle? Should you? Explain in terms of Bloch-sphere geometry. -
The
["u"]basis needed only one gate. Is that a cheaper implementation, or a different accounting? What doesu(θ, φ, λ)become when transpiled to["rz", "sx", "x"]? -
Run the 200-random-unitary verification with
==instead of.equiv(). How many "failures" do you get? Explain each one in a sentence. -
Construct a single-qubit unitary for which the naive angle-extraction formulas in the 📐 Math Aside produce a division by zero. What is special about it geometrically, and how should a robust implementation handle it?
-
Take a circuit of ten random single-qubit gates on one qubit. Transpile at optimization levels 0 and 3 to
["rz", "sx", "x"]and compare pulse counts. By what factor did merging help? Now repeat with a two-qubit gate inserted in the middle and explain the difference. -
Hardest. The $4^n$ scaling means arbitrary unitaries are unimplementable. Yet Part VI's variational circuits have only $O(n \cdot d)$ parameters for depth $d$. What fraction of the unitary group can such a circuit reach, and what does that imply about whether a variational ansatz can represent an arbitrary target state? (This question has a name — expressibility — and it is the subject of an active literature. Chapter 33 §33.2 returns to it, and it is intimately connected to the barren plateaus of Chapter 32 §32.5.)