Quantum Outpost
gates and circuits beginner · 20 min read ·

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

ψ  =  cos ⁣θ20  +  eiφsin ⁣θ21,|\psi\rangle \;=\; \cos\!\tfrac{\theta}{2}\,|0\rangle \;+\; e^{i\varphi}\sin\!\tfrac{\theta}{2}\,|1\rangle,

and (θ,φ)(\theta, \varphi) as polar/azimuthal angles. Three axes cross at the origin:

  • +z+z0|0\rangle, z-z1|1\rangle
  • +x+x+|+\rangle, x-x|-\rangle
  • +y+yi|i\rangle, y-yi|-i\rangle

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:

X=(0110),Y=(0ii0),Z=(1001).X = \begin{pmatrix}0&1\\1&0\end{pmatrix},\quad Y = \begin{pmatrix}0&-i\\i&0\end{pmatrix},\quad Z = \begin{pmatrix}1&0\\0&-1\end{pmatrix}.

Three important identities you should know cold:

  1. Self-inverse: X2=Y2=Z2=IX^2 = Y^2 = Z^2 = I. Each Pauli is a 180° rotation; applying twice is identity.
  2. Anti-commute: XY=YXXY = -YX, 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).
  3. Cyclic products: XY=iZXY = iZ, YZ=iXYZ = iX, ZX=iYZX = iY. The Paulis form a (projective) representation of rotations.

As Bloch-sphere operations:

  • X: 180° rotation around the xx-axis. 01|0\rangle \leftrightarrow |1\rangle. Leaves +|+\rangle and |-\rangle fixed.
  • Y: 180° rotation around the yy-axis. 0i1|0\rangle \leftrightarrow -i|1\rangle, but up to phase just 01|0\rangle \leftrightarrow |1\rangle. Fixes i|i\rangle and i|-i\rangle.
  • Z: 180° rotation around the zz-axis. 0|0\rangle fixed, 11|1\rangle \to -|1\rangle. Fixes 0|0\rangle and 1|1\rangle up to phase.

Continuous rotations: Rx, Ry, Rz

The Pauli matrices are 180° rotations. What about arbitrary angles? Enter the rotation gates:

Rx(θ)=eiθX/2,Ry(θ)=eiθY/2,Rz(θ)=eiθZ/2.R_x(\theta) = e^{-i\theta X/2},\quad R_y(\theta) = e^{-i\theta Y/2},\quad R_z(\theta) = e^{-i\theta Z/2}.

The matrix exponential eiθP/2e^{-i\theta P/2} for a Pauli PP has a clean closed form:

Rx(θ)=(cosθ2isinθ2isinθ2cosθ2),R_x(\theta) = \begin{pmatrix}\cos\tfrac{\theta}{2} & -i\sin\tfrac{\theta}{2}\\ -i\sin\tfrac{\theta}{2} & \cos\tfrac{\theta}{2}\end{pmatrix}, Ry(θ)=(cosθ2sinθ2sinθ2cosθ2),R_y(\theta) = \begin{pmatrix}\cos\tfrac{\theta}{2} & -\sin\tfrac{\theta}{2}\\ \sin\tfrac{\theta}{2} & \cos\tfrac{\theta}{2}\end{pmatrix}, Rz(θ)=(eiθ/200eiθ/2).R_z(\theta) = \begin{pmatrix}e^{-i\theta/2} & 0\\ 0 & e^{i\theta/2}\end{pmatrix}.

Four things to internalize:

  1. The half-angle. The matrix has θ/2\theta/2, not θ\theta. 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.
  2. Ry has real entries. It’s the only one of the three whose matrix is purely real.
  3. Rz is diagonal. That means it never changes measurement probabilities in the Z-basis — only relative phases. Rz does not generate superposition.
  4. 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 0|0\rangle, apply Rx(π/3)R_x(\pi/3), 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 θ\theta:

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 +z+z down through y-y to z-z — a 180° arc around the x-axis. Exactly what RxR_x should do.

Phase gates: S and T

SS and TT are discrete phase rotations:

S=Rz(π/2)eiπ/4=(100i),T=Rz(π/4)eiπ/8=(100eiπ/4).S = R_z(\pi/2)\,e^{i\pi/4} = \begin{pmatrix}1&0\\0&i\end{pmatrix},\qquad T = R_z(\pi/4)\,e^{i\pi/8} = \begin{pmatrix}1&0\\0&e^{i\pi/4}\end{pmatrix}.

They’re just RzR_z at specific angles (times unobservable global phases). Why bother giving them names? Because TT 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 SS^\dagger and TT^\dagger (in Qiskit: sdg, tdg) are the same matrices with conjugated phase:

S=(100i),T=(100eiπ/4).S^\dagger = \begin{pmatrix}1&0\\0&-i\end{pmatrix},\quad T^\dagger = \begin{pmatrix}1&0\\0&e^{-i\pi/4}\end{pmatrix}.

The Hadamard, geometrically

H is a 180° rotation around the axis 12(x^+z^)\frac{1}{\sqrt{2}}(\hat{x} + \hat{z}) — halfway between the x- and z-axes of the Bloch sphere. That’s why H maps 0|0\rangle (on +z+z) to +|+\rangle (on +x+x) 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):

H  =  Rz(π)Ry(π/2).H \;=\; R_z(\pi)\,R_y(\pi/2).

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

U  =  eiαRz(γ)Ry(β)Rz(δ),U \;=\; e^{i\alpha}\,R_z(\gamma)\,R_y(\beta)\,R_z(\delta),

where α,β,γ,δ\alpha, \beta, \gamma, \delta 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 0|0\rangle. Predict (without running code) the Bloch vector after each of:

a. Ry(π)R_y(\pi) b. Rz(π/2)R_z(\pi/2) c. Rx(π/2)R_x(\pi/2) d. HH followed by SS followed by HH

Show answer

a. (0,0,1)(0, 0, -1) — rotating 0|0\rangle 180° around the y-axis lands on z-z, i.e., 1|1\rangle.

b. (0,0,+1)(0, 0, +1) — Rz preserves z-component, so stays at 0|0\rangle.

c. (0,1,0)(0, -1, 0) — rotating 0|0\rangle 90° around the x-axis lands on y-y, i.e., i|-i\rangle.

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 0|0\rangle: H → +|+\rangle (on +x), S → +i|+i\rangle (on +y)… wait, S rotates by π/2 around z, so +|+\rangle12(0+i1)=i\tfrac{1}{\sqrt{2}}(|0\rangle + i|1\rangle) = |i\rangle (on +y). Then H → 12((1+i)0+(1i)1)\tfrac{1}{2}((1+i)|0\rangle + (1-i)|1\rangle) which is on… let’s compute the Bloch vector: X=12,Y=122=...\langle X \rangle = \tfrac{1}{2}, \langle Y\rangle = -\tfrac{1}{2}\cdot 2 = ... 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 Ry(θ)=Rx(π/2)Rz(θ)Rx(π/2)R_y(\theta) = R_x(-\pi/2)\,R_z(\theta)\,R_x(\pi/2), 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, Rx(π/2)R_x(\pi/2) maps z^\hat{z} to y^\hat{y}, so Rx(π/2)Rz(θ)Rx(π/2)R_x(-\pi/2)\,R_z(\theta)\,R_x(\pi/2) is a θ\theta-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))   # True

3. T-count of a circuit

Write a Qiskit circuit that prepares +|+\rangle, 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

T7=T1T8=T1=TT^7 = T^{-1} \cdot T^8 = T^{-1} = T^\dagger (since T8=IT^8 = I). So T seven times is equivalent to one TT^\dagger. Starting from +|+\rangle, TT^\dagger sends it to 12(0+eiπ/41)\tfrac{1}{\sqrt{2}}(|0\rangle + e^{-i\pi/4}|1\rangle). In the Z basis, measurement probabilities are α2=12|\alpha|^2 = \tfrac{1}{2} and β2=12|\beta|^2 = \tfrac{1}{2}: a 50/50 split, same as +|+\rangle. Z-basis measurement is blind to phase differences in the 1|1\rangle amplitude. The effect of T7T^7 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 RyR_y and RzR_z (and an overall global phase). Verify the state vector matches applying qc.h(0) directly (up to global phase).

Show answer

H=Rz(π)Ry(π/2)H = R_z(\pi)\,R_y(\pi/2) up to global phase eiπ/2e^{-i\pi/2}.

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]))
# True

What 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.


Weekly dispatch

Quantum, for people who already code.

One serious tutorial per week, plus the industry moves that actually matter. No hype, no hand-waving.

Free. Unsubscribe anytime. We will never sell your email.