Skip to content

Quantum Gates — Hadamard, Pauli, CNOT and Toffoli Explained

DodaTech Updated 2026-06-21 11 min read

In this tutorial, you'll learn about Quantum Gates. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

Quantum gates are unitary operations that manipulate qubits, forming the building blocks of quantum circuits just as logic gates form the building blocks of classical circuits.

What You'll Learn

By the end of this tutorial, you will understand the matrix representations of single-qubit gates (Pauli X, Y, Z, Hadamard, phase), two-qubit gates (CNOT, SWAP), and three-qubit gates (Toffoli), and you will implement them in Python.

Why It Matters

Every quantum algorithm from Shor to Grover to VQE is built from quantum gates. Understanding gates is essential for programming quantum computers at any level — whether in Qiskit, Cirq, or Q#.

Real-World Use

When Google demonstrated quantum supremacy with Sycamore in 2019, the experiment consisted of applying a specific sequence of gates (a random Quantum Circuit) and sampling the output distribution. The choice and ordering of gates determines what computation is performed.

Learning Path

flowchart LR
  A[Qubits and Superposition] --> B[Quantum Gates]
  B --> C[Quantum Circuits]
  C --> D[Entanglement]
  D --> E[Algorithms]
  B --> F{You Are Here}
  style F fill:#f90,color:#fff
ℹ️ Info

Prerequisites: Understand qubits and superposition and Dirac notation. Familiarity with Python and basic linear algebra helps.

Properties of Quantum Gates

All quantum gates share three essential properties:

  1. Unitary: U†U = UU† = I, meaning gates are reversible
  2. Linear: U(α|ψ⟩ + β|φ⟩) = αU|ψ⟩ + βU|φ⟩
  3. Norm-preserving: The output state always satisfies normalization

Why Unitarity Matters

Since measurement is probabilistic, the total probability must always sum to 1. Unitary gates preserve the norm of the state vector, ensuring valid probabilities. Classical AND and OR gates are not reversible, but quantum gates must be.

Single-Qubit Gates

Pauli-X Gate (Quantum NOT)

The X gate flips |0⟩ to |1⟩ and |1⟩ to |0⟩, analogous to the classical NOT gate.

X = [0  1]
    [1  0]

X|0⟩ = |1⟩
X|1⟩ = |0⟩
X|+⟩ = |+⟩  (|+⟩ is an eigenstate)
# pauli_x_gate.py
import numpy as np

# Pauli matrices
X = np.array([[0, 1], [1, 0]], dtype=complex)
Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
Z = np.array([[1, 0], [0, -1]], dtype=complex)

def apply_gate(gate, state):
    return gate @ state

# Test X gate
ket0 = np.array([1, 0], dtype=complex)
ket1 = np.array([0, 1], dtype=complex)

print("=== Pauli-X Gate ===")
print(f"X|0⟩ = {apply_gate(X, ket0)}")
print(f"X|1⟩ = {apply_gate(X, ket1)}")

# X is self-inverse
print(f"\nX²|0⟩ = {apply_gate(X, apply_gate(X, ket0))}")

Expected output:

=== Pauli-X Gate ===
X|0⟩ = [0 1]
X|1⟩ = [1 0]

X²|0⟩ = [1 0]

Pauli-Y Gate

The Y gate combines bit flip and phase flip.

Y = [0  -i]
    [i   0]

Y|0⟩ = i|1⟩
Y|1⟩ = -i|0⟩

Pauli-Z Gate (Phase Flip)

The Z gate flips the phase of the |1⟩ component while leaving |0⟩ unchanged.

Z = [1   0]
    [0  -1]

Z|0⟩ = |0⟩
Z|1⟩ = -|1⟩
Z|+⟩ = |−⟩
# pauli_yz_gates.py
import numpy as np

Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
Z = np.array([[1, 0], [0, -1]], dtype=complex)

ket0 = np.array([1, 0], dtype=complex)
ket1 = np.array([0, 1], dtype=complex)
plus = (ket0 + ket1) / np.sqrt(2)

print("=== Pauli-Y Gate ===")
print(f"Y|0⟩ = {Y @ ket0}")
print(f"Y|1⟩ = {Y @ ket1}")

print("\n=== Pauli-Z Gate ===")
print(f"Z|0⟩ = {Z @ ket0}")
print(f"Z|1⟩ = {Z @ ket1}")
print(f"Z|+⟩ = {Z @ plus}")

Expected output:

=== Pauli-Y Gate ===
Y|0⟩ = [0.+0.j 0.+1.j]
Y|1⟩ = [0.-1.j 0.+0.j]

=== Pauli-Z Gate ===
Z|0⟩ = [1 0]
Z|1⟩ = [0 -1]
Z|+⟩ = [ 0.70710678 -0.70710678]

Hadamard Gate (Superposition)

The Hadamard gate creates Superposition. It maps the computational basis to the X basis.

H = 1/√2 [1  1]
         [1 -1]

Phase Gate (S and T)

The S gate (√Z) and T gate (⁴√Z) add specific phases:

S = [1  0]    T = [1     0   ]
    [0  i]        [0  e^(iπ/4)]
# hadamard_phase.py
import numpy as np

H = (1/np.sqrt(2)) * np.array([[1, 1], [1, -1]], dtype=complex)
S = np.array([[1, 0], [0, 1j]], dtype=complex)
T = np.array([[1, 0], [0, np.exp(1j * np.pi / 4)]], dtype=complex)

ket0 = np.array([1, 0], dtype=complex)
ket1 = np.array([0, 1], dtype=complex)

print("=== Hadamard Gate ===")
print(f"H|0⟩ = {H @ ket0}")
print(f"H|1⟩ = {H @ ket1}")

print("\n=== S Gate ===")
print(f"S|0⟩ = {S @ ket0}")
print(f"S|1⟩ = {S @ ket1}")

print("\n=== T Gate ===")
print(f"T|0⟩ = {T @ ket0}")
print(f"T|1⟩ = {T @ ket1}")

Expected output:

=== Hadamard Gate ===
H|0⟩ = [0.70710678 0.70710678]
H|1⟩ = [ 0.70710678 -0.70710678]

=== S Gate ===
S|0⟩ = [1 0]
S|1⟩ = [0+0.j 0+1.j]

=== T Gate ===
T|0⟩ = [1 0]
T|1⟩ = [0.+0.j         0.+0.70710678j]

Two-Qubit Gates

CNOT Gate (Controlled-NOT)

The CNOT gate flips the target qubit if the control qubit is |1⟩. It is the canonical two-qubit entangling gate.

CNOT = [1 0 0 0]
       [0 1 0 0]
       [0 0 0 1]
       [0 0 1 0]
# cnot_gate.py
import numpy as np

CNOT = np.array([
    [1, 0, 0, 0],
    [0, 1, 0, 0],
    [0, 0, 0, 1],
    [0, 0, 1, 0]
], dtype=complex)

# Basis states
ket00 = np.array([1, 0, 0, 0], dtype=complex)
ket01 = np.array([0, 1, 0, 0], dtype=complex)
ket10 = np.array([0, 0, 1, 0], dtype=complex)
ket11 = np.array([0, 0, 0, 1], dtype=complex)

# Test CNOT on all basis states
print("=== CNOT Gate ===")
print(f"CNOT|00⟩ = {CNOT @ ket00} → |00⟩")
print(f"CNOT|01⟩ = {CNOT @ ket01} → |01⟩")
print(f"CNOT|10⟩ = {CNOT @ ket10} → |11⟩ (target flipped)")
print(f"CNOT|11⟩ = {CNOT @ ket11} → |10⟩ (target flipped)")

# Create Bell state with H + CNOT
H_on_first = np.kron(H, np.eye(2))
bell_state = CNOT @ H_on_first @ ket00
print(f"\nBell state |Φ+⟩: {bell_state}")
print(f"= (|00⟩ + |11⟩)/√2")

Expected output:

=== CNOT Gate ===
CNOT|00⟩ = [1 0 0 0] → |00⟩
CNOT|01⟩ = [0 1 0 0] → |01⟩
CNOT|10⟩ = [0 0 0 1] → |11⟩ (target flipped)
CNOT|11⟩ = [0 0 1 0] → |10⟩ (target flipped)

Bell state |Φ+⟩: [0.70710678 0.         0.         0.70710678]
= (|00⟩ + |11⟩)/√2

The combination of Hadamard + CNOT creates the Bell state, a maximally entangled two-qubit state.

SWAP Gate

The SWAP gate exchanges the states of two qubits.

SWAP = [1 0 0 0]
       [0 0 1 0]
       [0 1 0 0]
       [0 0 0 1]

Three-Qubit Gates

Toffoli Gate (CCNOT)

The Toffoli gate is a controlled-controlled-NOT. It flips the target qubit only if both control qubits are |1⟩. It is universal for classical reversible computation.

Toffoli = [I 0 0 0]
          [0 I 0 0]
          [0 0 I 0]
          [0 0 0 X]

Implementing a Toffoli Gate

# toffoli_gate.py
import numpy as np

def toffoli_matrix():
    """Construct 8x8 Toffoli gate matrix."""
    mat = np.eye(8, dtype=complex)
    # Flip the last two basis states: |110⟩ ↔ |111⟩
    mat[6, 6] = 0
    mat[6, 7] = 1
    mat[7, 6] = 1
    mat[7, 7] = 0
    return mat

TOFFOLI = toffoli_matrix()

# Test on all basis states where target might flip
for i in range(8):
    state = np.zeros(8, dtype=complex)
    state[i] = 1
    result = TOFFOLI @ state
    control_bits = (i & 4) >> 2, (i & 2) >> 1
    target = i & 1
    flipped = (i & 4) and (i & 2)
    new_target = target ^ (1 if flipped else 0)
    new_state = i
    if flipped:
        new_state = (i & 0b110) | new_target
    print(f"|{i:03b}⟩ → |{new_state:03b}⟩ (controls={control_bits}, flip={flipped})")

Expected output:

|000⟩ → |000⟩ (controls=(0, 0), flip=False)
|001⟩ → |001⟩ (controls=(0, 0), flip=False)
|010⟩ → |010⟩ (controls=(0, 1), flip=False)
|011⟩ → |011⟩ (controls=(0, 1), flip=False)
|100⟩ → |100⟩ (controls=(1, 0), flip=False)
|101⟩ → |101⟩ (controls=(1, 0), flip=False)
|110⟩ → |111⟩ (controls=(1, 1), flip=True)
|111⟩ → |110⟩ (controls=(1, 1), flip=True)

Gate Universality

A set of gates is universal if any unitary operation can be approximated using gates from that set. Common universal sets:

  • {H, T, CNOT} — Clifford + T set
  • {Toffoli, H} — classical + Superposition
  • {CNOT, single-qubit gates} — any controlled unitary

Solovay-Kitaev Theorem

Any single-qubit gate can be approximated to precision ε using O(log²(1/ε)) gates from a finite universal set. This means we do not need infinite gate types.

Common Mistakes

1. Assuming Quantum Gates are like Classical Logic Gates

Classical gates (AND, OR) are irreversible and consume inputs. Quantum gates are unitary, reversible, and preserve information. There is no quantum AND gate.

2. Forgetting the Global Phase

Multiplying a quantum state by e^(iθ) does not change any measurement outcome. States that differ only by a global phase are physically equivalent.

3. Misordering Gates

Quantum gates are applied right-to-left in circuit diagrams but left-to-right in matrix multiplication. Always verify the order: U₂U₁|ψ⟩ means apply U₁ first, then U₂.

4. Using Non-Unitary Matrices

If a proposed gate matrix is not unitary (U†U ≠ I), it is not a valid Quantum Gate. Non-unitary operations would not preserve probability.

5. Thinking CNOT Copies Qubits

CNOT does not copy a qubit. It entangles the control and target. Copying a quantum state is impossible due to the no-cloning theorem.

Practice Questions

1. What makes a valid Quantum Gate?

A valid Quantum Gate must be unitary: U†U = UU† = I. It must also be linear and norm-preserving.

2. Why is the Hadamard gate its own inverse?

H² = I because the Hadamard matrix is both unitary and Hermitian. Applying it twice cancels the Superposition.

3. What is the difference between CNOT and classical XOR?

CNOT is the quantum version of XOR but with the control qubit preserved. Classical XOR overwrites one input. CNOT is reversible: applying it twice returns the original state.

4. How do you create a Bell state using H and CNOT?

Apply H to the first qubit, then CNOT with first qubit as control and second as target: CNOT(H ⊗ I)|00⟩ = (|00⟩ + |11⟩)/√2.

5. Why is the Toffoli gate universal for classical computation?

Toffoli can implement NAND (universal for classical logic) by fixing two inputs. Since NAND can build any classical circuit, Toffoli is classically universal.

Challenge: Build a Quantum Half-Adder

Implement a quantum half-adder using CNOT and Toffoli gates. The circuit should take two input qubits (a and b) and produce sum (a ⊕ b) and carry (a AND b):

def quantum_half_adder():
    """Build a quantum half-adder circuit.
    Input: |a⟩|b⟩|0⟩|0⟩ (4 qubits: a, b, sum, carry)
    Output: |a⟩|b⟩|a⊕b⟩|a∧b⟩
    """
    # Use CNOT for sum, Toffoli for carry
    pass

Hints: The sum bit is a XOR b (use CNOT). The carry bit is a AND b (use Toffoli on the carry qubit with controls a and b).

Real-World Task: Noise Simulation

Add a simple noise model to your gate simulations. After each gate application, add a small probability of bit-flip (X error) or phase-flip (Z error). Measure how the output distribution degrades with increasing error rate.

This simulates the real challenge faced by quantum hardware teams. For example, IBM's quantum processors have gate error rates around 0.1% to 1%, requiring error correction for long computations.

FAQ

What is a Quantum Gate?

A Quantum Gate is a unitary operation that acts on one or more qubits. It transforms quantum states while preserving total probability.

How many quantum gates exist?

There are infinitely many single-qubit gates (any 2×2 unitary matrix), but a finite universal gate set can approximate any of them to arbitrary precision.

Are quantum gates physical?

Yes. Quantum gates are implemented by applying precisely timed control pulses (microwave or laser) to physical qubits. For example, an X gate on a superconducting qubit is a microwave pulse of specific duration and frequency.

Can quantum gates be measured?

You cannot measure a gate directly. You prepare a known input state, apply the gate, and measure the output. By repeating with different inputs and measurements, you can characterize the gate (quantum process tomography).

What is gate fidelity?

Gate fidelity measures how close the implemented gate is to the ideal gate. It ranges from 0 (completely wrong) to 1 (perfect). Current hardware achieves 99.9%+ fidelity for single-qubit gates.

Try It Yourself

Run the Python gate examples. Modify the code to:

  1. Create a custom gate by defining a 2×2 unitary matrix
  2. Apply sequences of gates and verify they match expected outputs
  3. Build a circuit that creates the Bell state and verify entanglement

What's Next

Quantum Circuits Explained
Qubits and Superposition
Quantum Entanglement Guide

You now have a solid understanding of quantum gates. Next, you will combine gates into quantum circuits to build complete quantum programs.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Last updated: 2026-06-21.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro