Quantum circuits are the standard model for quantum computation. Just as classical computers use logic gates (AND, OR, NOT), quantum computers use quantum gates that manipulate qubits.

Qubits and State Vectors

A qubit exists in a superposition of $|0\rangle$ and $|1\rangle$:

$$|\psi\rangle = \alpha|0\rangle + \beta|1\rangle$$

where $\alpha, \beta \in \mathbb{C}$ and $|\alpha|^2 + |\beta|^2 = 1$. We represent this as a column vector:

$$|\psi\rangle = \begin{pmatrix} \alpha \\ \beta \end{pmatrix}$$

Essential Single-Qubit Gates

Pauli-X (NOT gate): Flips $|0\rangle \leftrightarrow |1\rangle$

$$X = \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}$$

Hadamard: Creates superposition

$$H = \frac{1}{\sqrt{2}} \begin{pmatrix} 1 & 1 \\ 1 & -1 \end{pmatrix}$$

$$H|0\rangle = \frac{|0\rangle + |1\rangle}{\sqrt{2}} = |+\rangle$$

Phase Gate (S): Adds a phase of $i$ to $|1\rangle$

$$S = \begin{pmatrix} 1 & 0 \\ 0 & i \end{pmatrix}$$

T Gate: Adds a phase of $e^{i\pi/4}$ — essential for universal computation.

Multi-Qubit Gates

CNOT (Controlled-NOT): The fundamental two-qubit gate:

$$\text{CNOT} = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \end{pmatrix}$$

It flips the target qubit if and only if the control qubit is $|1\rangle$.

Building the Deutsch-Jozsa Algorithm

The Deutsch-Jozsa algorithm determines whether a function $f: \{0,1\}^n \to \{0,1\}$ is constant or balanced with just one query — exponentially faster than any classical algorithm.

from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector

def deutsch_jozsa(oracle_type='balanced'):
    """
    Deutsch-Jozsa algorithm for 2-qubit oracle.
    oracle_type: 'constant' or 'balanced'
    """
    n = 2  # number of input qubits
    qc = QuantumCircuit(n + 1, n)

    # Initialize output qubit to |1⟩
    qc.x(n)

    # Apply Hadamard to all qubits
    qc.h(range(n + 1))
    qc.barrier()

    # Oracle
    if oracle_type == 'balanced':
        # Balanced oracle: f(x) = x₀ ⊕ x₁
        qc.cx(0, n)
        qc.cx(1, n)
    else:
        # Constant oracle: f(x) = 0 (identity)
        pass

    qc.barrier()

    # Apply Hadamard to input qubits
    qc.h(range(n))

    # Measure input qubits
    qc.measure(range(n), range(n))

    return qc

# Test with balanced oracle
circuit = deutsch_jozsa('balanced')
print(circuit.draw())
print("If all measurements are 0 → constant")
print("If any measurement is 1 → balanced")

Universal Gate Sets

A key theorem in quantum computing: the set $\{H, T, \text{CNOT}\}$ is universal — any quantum computation can be approximated to arbitrary precision using only these three gates. This is the quantum analog of classical universality (NAND gates).

Measurement

Measurement in the computational basis collapses the state:

$$|\psi\rangle = \alpha|0\rangle + \beta|1\rangle \xrightarrow{\text{measure}} \begin{cases} |0\rangle & \text{with probability } |\alpha|^2 \\ |1\rangle & \text{with probability } |\beta|^2 \end{cases}$$

This irreversibility is what makes quantum algorithms so interesting — the challenge is designing circuits that amplify the probability of the correct answer before measurement.