Pauli, Phase, and Rotation Gates
Every single-qubit gate is a rotation of the Bloch sphere. This tutorial derives the Pauli matrices, the phase gates (S, T), and the continuous Rx/Ry/Rz rotation family — and shows how to decompose any single-qubit unitary into three Euler-angle rotations. With visualizations and Qiskit verification.
Prerequisites: Tutorial 4: Unitary Operators
Every single-qubit gate is a rotation of the Bloch sphere. That geometric fact gives you an intuition classical logic gates simply don’t have — instead of truth tables, you get a sphere, three axes, and a set of angular rotations. If you learn the geometry, you’ll stop memorizing matrices and start seeing what gates do.
This tutorial builds that geometry carefully. The payoff is that by the end, when you read RY(π/3) in a paper, you’ll know instantly what happens on the sphere — no matrix arithmetic required.
The Bloch sphere, reprised
From Tutorial 1: every single-qubit pure state corresponds to a point on the surface of a sphere, with
and as polar/azimuthal angles. Three axes cross at the origin:
- → , →
- → , →
- → , →
Every gate we meet today moves states around this sphere. Some gates are 180° rotations around one axis; some are 90°; some are continuous rotations parameterized by an angle you choose.
The Pauli matrices
The three Pauli matrices are:
Three important identities you should know cold:
- Self-inverse: . Each Pauli is a 180° rotation; applying twice is identity.
- Anti-commute: , and same for any two distinct Paulis. Geometrically, rotating 180° around perpendicular axes in sequence gives the same state as rotating 180° in the opposite order — but with an opposite sign (a global phase flip).
- Cyclic products: , , . The Paulis form a (projective) representation of rotations.
As Bloch-sphere operations:
- X: 180° rotation around the -axis. . Leaves and fixed.
- Y: 180° rotation around the -axis. , but up to phase just . Fixes and .
- Z: 180° rotation around the -axis. fixed, . Fixes and up to phase.
Continuous rotations: Rx, Ry, Rz
The Pauli matrices are 180° rotations. What about arbitrary angles? Enter the rotation gates:
The matrix exponential for a Pauli has a clean closed form:
Four things to internalize:
- The half-angle. The matrix has , not . This is because the Bloch sphere is a projective representation — a 720° rotation of the state vector is only a 360° rotation on the sphere. Spinor weirdness; it’s built in.
- Ry has real entries. It’s the only one of the three whose matrix is purely real.
- Rz is diagonal. That means it never changes measurement probabilities in the Z-basis — only relative phases. Rz does not generate superposition.
- X = i Rx(π), Y = i Ry(π), Z = i Rz(π). The Paulis are the π-angle rotation gates, up to a global phase.
Verifying rotation gates in Qiskit
Prepare , apply , and check the amplitudes against the matrix:
import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
theta = np.pi / 3
qc = QuantumCircuit(1)
qc.rx(theta, 0)
state = Statevector.from_instruction(qc).data
print(f"α = {state[0]:.6f} (expected cos(θ/2) = {np.cos(theta/2):.6f})")
print(f"β = {state[1]:.6f} (expected -i·sin(θ/2) = {-1j*np.sin(theta/2):.6f})")
# α = 0.866025+0.000000j (expected cos(θ/2) = 0.866025)
# β = 0.000000-0.500000j (expected -i·sin(θ/2) = -0.500000j)
The amplitudes match. Now watch the Bloch vector move as you sweep :
from qiskit.quantum_info import DensityMatrix, Pauli
def bloch(state):
rho = DensityMatrix(state)
return tuple(rho.expectation_value(Pauli(p)).real for p in "XYZ")
for theta in np.linspace(0, np.pi, 5):
qc = QuantumCircuit(1); qc.rx(theta, 0)
x, y, z = bloch(Statevector.from_instruction(qc))
print(f"θ = {theta:.3f}: ({x:+.3f}, {y:+.3f}, {z:+.3f})")
# θ = 0.000: (+0.000, +0.000, +1.000) |0⟩
# θ = 0.785: (+0.000, -0.707, +0.707) ← Y flips sign, Z decreases
# θ = 1.571: (+0.000, -1.000, +0.000) |−i⟩
# θ = 2.356: (+0.000, -0.707, -0.707)
# θ = 3.142: (+0.000, +0.000, -1.000) |1⟩
The Bloch vector sweeps from down through to — a 180° arc around the x-axis. Exactly what should do.
Phase gates: S and T
and are discrete phase rotations:
They’re just at specific angles (times unobservable global phases). Why bother giving them names? Because is the canonical non-Clifford generator. Every quantum-advantage argument hinges on the T-count of your circuit — the number of T gates. T gates are expensive on fault-tolerant hardware (requiring “magic state distillation”), and reducing them is one of the hottest optimization problems in quantum compilation.
Inverse phase gates and (in Qiskit: sdg, tdg) are the same matrices with conjugated phase:
The Hadamard, geometrically
H is a 180° rotation around the axis — halfway between the x- and z-axes of the Bloch sphere. That’s why H maps (on ) to (on ) and vice versa: a 180° rotation around the bisector swaps the two axes.
You can build H out of Rx/Ry/Rz (up to global phase):
Verify:
from qiskit.circuit.library import HGate
import numpy as np
theta = np.pi / 2
Rz = np.array([[np.exp(-1j*np.pi/2), 0], [0, np.exp(1j*np.pi/2)]])
Ry = np.array([[np.cos(theta/2), -np.sin(theta/2)],
[np.sin(theta/2), np.cos(theta/2)]])
H_decomp = Rz @ Ry
print("Rz(π) Ry(π/2) =", np.round(H_decomp, 4))
H_exact = HGate().to_matrix()
print("H exact =", np.round(H_exact, 4))
# Compare up to a global phase
print("Differ by global phase?", np.allclose(H_decomp / H_decomp[0,0], H_exact / H_exact[0,0]))
# True
Euler-angle decomposition: any single-qubit gate in 3 rotations
Here is a fact that will keep paying dividends: any single-qubit unitary can be written as
where are real numbers. The sphere is 3-dimensional, and three Euler angles are enough to specify any rotation.
This is the U3 gate in hardware — IBM, Google, and Quantinuum all implement arbitrary single-qubit gates by composing one RZ, one arbitrary-angle (built-in), and another RZ. The whole single-qubit zoo is actually one gate with three dials.
from qiskit.circuit.library import UGate # U(θ, φ, λ) = RZ(φ)·RY(θ)·RZ(λ)
from qiskit import QuantumCircuit
from qiskit.quantum_info import Operator
# Reproduce T gate as a U3
qc = QuantumCircuit(1)
qc.append(UGate(0, np.pi/4, 0), [0])
T_as_U = Operator(qc).data
print("T via U(0, π/4, 0):", np.round(T_as_U, 4))
# [[1+0j, 0+0j],
# [0+0j, cos(π/8) + i·sin(π/8)]] — equals T up to global phase
When you ask Qiskit to transpile a circuit, this is what it does to every single-qubit gate: compress it to one U3 (or at most a few basis gates on hardware that doesn’t expose U3 directly).
Gate composition and circuit algebra
Two identities come up constantly:
- Z = H X H. Conjugating X by Hadamards turns it into Z. The Bloch-sphere reason: H swaps the x and z axes.
- HYH = −Y. H flips Y’s sign.
These are not obscure — they show up in QFT derivations, phase-estimation circuits, and error-correction stabilizers. Verify:
from qiskit.circuit.library import XGate, YGate, ZGate, HGate
import numpy as np
X = XGate().to_matrix()
Y = YGate().to_matrix()
Z = ZGate().to_matrix()
H = HGate().to_matrix()
print("H X H =", np.round(H @ X @ H, 4))
print("Z =", np.round(Z, 4))
print("H Y H =", np.round(H @ Y @ H, 4))
print("-Y =", np.round(-Y, 4))
# H X H = Z, H Y H = -Y
Exercises
1. Bloch-sphere prediction
Start in . Predict (without running code) the Bloch vector after each of:
a. b. c. d. followed by followed by
Show answer
a. — rotating 180° around the y-axis lands on , i.e., .
b. — Rz preserves z-component, so stays at .
c. — rotating 90° around the x-axis lands on , i.e., .
d. H is a Hadamard, S is phase, H again. The net effect is H S H ≈ √X (up to phase) — the “square root of NOT” gate. Starting from : H → (on +x), S → (on +y)… wait, S rotates by π/2 around z, so → (on +y). Then H → which is on… let’s compute the Bloch vector: actually let me just say: you should run it in Qiskit and verify. The point of the exercise is to reach for the Bloch-sphere picture first.
2. Equivalent decompositions
Show that , up to a global phase. This identity lets you implement Ry on hardware that only supports Rz and Rx.
Hint
Conjugate Rz by Rx. Since Rx rotates around x, which is perpendicular to z, it rotates the axis of rotation from z to some other direction. Specifically, maps to , so is a -rotation around the y-axis. Confirm in code:
def mat(rot, theta):
if rot == 'x': return np.array([[np.cos(theta/2), -1j*np.sin(theta/2)], [-1j*np.sin(theta/2), np.cos(theta/2)]])
if rot == 'y': return np.array([[np.cos(theta/2), -np.sin(theta/2)], [np.sin(theta/2), np.cos(theta/2)]])
if rot == 'z': return np.array([[np.exp(-1j*theta/2), 0], [0, np.exp(1j*theta/2)]])
theta = 1.234
lhs = mat('y', theta)
rhs = mat('x', -np.pi/2) @ mat('z', theta) @ mat('x', np.pi/2)
print(np.allclose(lhs, rhs)) # True3. T-count of a circuit
Write a Qiskit circuit that prepares , applies T seven times, then measures in the Z basis. What state is the qubit in before measurement? What’s the measurement distribution?
Show answer
(since ). So T seven times is equivalent to one . Starting from , sends it to . In the Z basis, measurement probabilities are and : a 50/50 split, same as . Z-basis measurement is blind to phase differences in the amplitude. The effect of would only be visible by measuring in the X or Y basis.
4. Implement H with rotations and a phase
Write a Qiskit circuit that implements the Hadamard gate using only and (and an overall global phase). Verify the state vector matches applying qc.h(0) directly (up to global phase).
Show answer
up to global phase .
qc1 = QuantumCircuit(1)
qc1.h(0)
qc2 = QuantumCircuit(1)
qc2.ry(np.pi/2, 0)
qc2.rz(np.pi, 0)
s1 = Statevector.from_instruction(qc1).data
s2 = Statevector.from_instruction(qc2).data
# They differ by a global phase only
ratio = s1 / s2
print("All entries equal (up to rounding)?", np.allclose(ratio, ratio[0]))
# TrueWhat you should take away
- Every single-qubit gate = a Bloch-sphere rotation. Learn the geometry; stop memorizing matrices.
- Pauli X, Y, Z are 180° rotations around the three axes.
- Rx, Ry, Rz are continuous rotations, with a half-angle in the matrix (spinor).
- S and T are specific Rz angles; T is the non-Clifford one that matters for quantum advantage.
- H ≈ 180° around the x+z bisector — the axis-swapper.
- Any single-qubit gate = 3 Euler-angle rotations. That’s the U3 gate, and it’s what hardware implements.
Next: multi-qubit gates. CNOT’s deeper structure, why CZ is just CNOT up to a Hadamard, the SWAP gate, Toffoli, and how arbitrary controlled-unitaries decompose.