🏛️ Westminster College, London | wcc.co.uk

⚛️ Quantum Computing · Theory & Qiskit Notes

🗓️ 6 Saturdays | 11am–1pm 🎯 Beginner → Advanced 💻 Online · Live + Hands‑on
From qubits and quantum gates to algorithms (Grover, Shor), variational methods (VQE, QAOA), and real IBM quantum hardware. Theory + practical Qiskit implementations.
📌 Module 1 — Qubits, Gates & Qiskit Week 1 · 2h

🔷 Classical Bits vs Qubits & Bloch Sphere

A classical bit is either 0 or 1. A qubit (quantum bit) can exist in a superposition of |0⟩ and |1⟩: |ψ⟩ = α|0⟩ + β|1⟩, where |α|² + |β|² = 1. The Bloch sphere provides a geometric representation: any pure state corresponds to a point on the sphere. Superposition allows quantum parallelism. Measurement collapses the qubit to |0⟩ with probability |α|² or |1⟩ with probability |β|².
  • |0⟩ and |1⟩ basis states (computational basis).
  • Superposition → Hadamard gate creates (|0⟩+|1⟩)/√2.
  • Entanglement → non‑local correlations between qubits (Bell states).

🔹 Single‑Qubit Gates & Multi‑Qubit Gates

Quantum gates are unitary operators. Pauli gates: X (NOT), Y, Z. Hadamard (H) creates superposition. Phase gates (S, T) add relative phases. CNOT (controlled‑NOT) flips target if control is |1⟩; CZ applies Z on target when control is |1⟩; SWAP exchanges two qubits. These gates form universal sets for quantum computation.
# Qiskit example: create Bell state
from qiskit import QuantumCircuit
qc = QuantumCircuit(2, 2)
qc.h(0) # Hadamard on qubit 0
qc.cx(0, 1) # CNOT with control 0, target 1
qc.measure([0,1], [0,1])
print(qc.draw())

🖥️ Qiskit Installation & Quantum Simulators

Qiskit is IBM's open‑source SDK for quantum computing. Install via pip install qiskit. Use Aer simulator for local simulation. IBM Quantum Composer provides a drag‑and‑drop interface to build circuits. Execute on real hardware via IBM Quantum account.
from qiskit import Aer, execute
simulator = Aer.get_backend('qasm_simulator')
job = execute(qc, simulator, shots=1024)
result = job.result()
counts = result.get_counts()
print(counts) # e.g., {'00': 512, '11': 512}
💡 Practice: Build and simulate circuits for Bell states, GHZ states, and simple teleportation on IBM Quantum Composer.
📡 Module 2 — Quantum Teleportation & BB84 Protocol Week 2 · 2h

📡 Quantum Teleportation Protocol

Teleportation transfers an unknown quantum state from one qubit to another using entanglement and classical communication. It requires a Bell pair shared between sender (Alice) and receiver (Bob). Steps: Create Bell pair (qubits 1 & 2). Alice applies CNOT and H on her qubit (0 & 1), measures both, sends classical bits. Bob applies X and Z gates conditioned on the bits to reconstruct the state. No faster‑than‑light communication — classical bits are necessary.
# Teleportation circuit in Qiskit
from qiskit import QuantumCircuit
qc = QuantumCircuit(3, 2) # q0: state to teleport, q1/q2: Bell pair
# create Bell pair
qc.h(1); qc.cx(1,2)
# Alice's operations
qc.cx(0,1); qc.h(0)
qc.measure([0,1], [0,1])
# Bob's conditional gates (simulated with classical control)
# Real implementation uses c_if or dynamic circuits
print(qc.draw())

🔐 BB84 Quantum Key Distribution

BB84 (Bennett‑Brassard 1984) enables two parties to establish a shared secret key with unconditional security against eavesdropping. Alice sends qubits in random bases (rectilinear or diagonal). Bob measures in random bases. They compare bases over a classical channel; matching bits form the raw key. Eavesdropper (Eve) disturbs the quantum states, detectable via error rates. If error > threshold, key is discarded.
  • Bases: Z‑basis (|0⟩,|1⟩) and X‑basis (|+⟩,|−⟩).
  • Eavesdropping detection: Compare a subset of bits — any disturbance reveals Eve.
  • Applications: Secure banking, government comms, quantum networks.
🔐 Simulation: Qiskit provides BB84 examples. Implement a full QKD simulation with noise to test error thresholds.
⚡ Module 3 — Deutsch-Jozsa & Bernstein-Vazirani Algorithms Week 3 · 2h

🔍 Deutsch-Jozsa Algorithm

Determines whether a Boolean function f: {0,1}ⁿ → {0,1} is constant (all 0 or all 1) or balanced (half 0, half 1) with a single query. Classical requires up to 2ⁿ⁻¹+1 queries. Quantum achieves exponential speedup using phase kickback and superposition. Circuit: Hadamard on all input qubits, oracle U_f, Hadamard again, measurement. If all qubits measured as 0 → constant; otherwise balanced.
# Deutsch-Jozsa for n=3
from qiskit import QuantumCircuit
qc = QuantumCircuit(4, 3) # 3 input + 1 ancilla
qc.h([0,1,2]); qc.x(3); qc.h(3) # prepare ancilla |−⟩
# oracle for balanced function (e.g., CNOTs)
qc.cx(0,3); qc.cx(1,3)
qc.h([0,1,2]); qc.measure([0,1,2], [0,1,2])

🔢 Bernstein-Vazirani Algorithm

Finds a hidden string s ∈ {0,1}ⁿ such that f(x) = s·x (mod 2). Classical requires n queries. Quantum solves in 1 query. Circuit: Hadamard on all qubits, oracle U_f (implemented as CNOTs with s), Hadamard again, measure → reveals s directly. Demonstrates quantum parallelism and interference for structured problems.
# Bernstein-Vazirani for s = 101
qc = QuantumCircuit(4, 3)
qc.h([0,1,2]); qc.x(3); qc.h(3)
# oracle: apply CNOT from qubit i to ancilla if s[i]=1
qc.cx(0,3); qc.cx(2,3) # because s = 1 0 1
qc.h([0,1,2]); qc.measure([0,1,2], [0,1,2])
🔎 Module 4 — Grover's Search & Shor's Factoring Week 4 · 2h

🔍 Grover's Search Algorithm

Grover solves unstructured search: find a marked item among N items in O(√N) queries, compared to O(N) classical. Core mechanism: amplitude amplification. Repeatedly apply oracle (marks target) + diffusion operator (inverts about mean). After ≈ √N iterations, measurement yields target with high probability. Optimal for unstructured databases.
# Grover for 2 qubits (4 items)
from qiskit import QuantumCircuit
from qiskit.algorithms import Grover, AmplificationProblem
# define oracle for |11⟩
oracle = QuantumCircuit(2)
oracle.cz(0,1)
problem = AmplificationProblem(oracle, is_good_state='11')
grover = Grover()
result = grover.amplify(problem)

🧮 Shor's Factoring Algorithm

Shor's algorithm factors large integers exponentially faster than classical algorithms, threatening RSA cryptography. Steps: (1) Choose random a; (2) Use Quantum Fourier Transform (QFT) to find period r of aˣ mod N; (3) If r even and a^(r/2) ≠ ±1, factors = gcd(a^(r/2) ± 1, N). QFT performs period finding with exponential speedup. Shor's algorithm works in polynomial time O((log N)³).
  • Quantum order finding is the core subroutine.
  • Impact: RSA, ECC could be broken by large‑scale fault‑tolerant quantum computers.
  • Current limits: Largest factored by Shor is 21 (though 15, 21 demonstrated).
⚠️ Note: Full Shor requires thousands of logical qubits. Qiskit provides educational implementations for small numbers.
🔄 Module 5 — VQE & QAOA (Hybrid Algorithms) Week 5 · 2h

⚛️ Variational Quantum Eigensolver (VQE)

VQE estimates ground state energy of a Hamiltonian (e.g., molecule). Hybrid: quantum circuit prepares parameterized trial state (ansatz); classical optimizer minimizes expectation value. Used in quantum chemistry, materials science. Scales better than classical exact diagonalization for certain systems. Common ansätze: UCCSD (Unitary Coupled Cluster), RyRz, EfficientSU2.
from qiskit.algorithms import VQE
from qiskit.circuit.library import TwoLocal
from qiskit.opflow import Z, I
# Example H₂ Hamiltonian (simplified)
hamiltonian = (Z ^ I) + (I ^ Z) + 0.5*(Z ^ Z)
ansatz = TwoLocal(2, ['ry','rz'], 'cz', reps=2)
vqe = VQE(ansatz, optimizer='SPSA')
result = vqe.compute_minimum_eigenvalue(hamiltonian)

📊 Quantum Approximate Optimization Algorithm (QAOA)

QAOA solves combinatorial optimization problems (MaxCut, portfolio optimization, logistics). Alternates between problem Hamiltonian (cost) and mixer Hamiltonian. Parameterized by angles γ, β. Classical optimizer finds optimal angles. Approximates solution to NP‑hard problems with potential quantum advantage on near‑term devices.
from qiskit.algorithms import QAOA
from qiskit_optimization import QuadraticProgram
# MaxCut example
qp = QuadraticProgram()
qp.binary_var('x0'); qp.binary_var('x1'); qp.binary_var('x2')
qp.maximize(linear={'x0':1,'x1':1,'x2':1}, quadratic={('x0','x1'):2,('x1','x2'):2})
qaoa = QAOA(reps=2, optimizer='COBYLA')
result = qaoa.compute_minimum_eigenvalue(qp.to_ising()[0])
⚠️ Module 6 — Noise, Error Mitigation & Real Hardware Week 6 · 2h

🔧 Quantum Noise Sources & Error Mitigation

Real quantum devices suffer from decoherence, gate errors, readout errors, crosstalk. Decoherence caused by T₁ (relaxation) and T₂ (dephasing). Error mitigation techniques: readout error correction, zero‑noise extrapolation, probabilistic error cancellation. Quantum error correction (QEC) requires many physical qubits per logical qubit (e.g., surface code). Not yet practical for NISQ devices.
  • Noise models in Qiskit Aer: thermal relaxation, depolarizing, amplitude damping.
  • Calibration data from real backends (IBMQ) — measure error rates and gate fidelities.
  • Best practices: use shallow circuits, dynamical decoupling, measurement error mitigation.

🖥️ Running on IBM Quantum Hardware

To execute on real devices: create IBM Quantum account, save API token. Choose backend (e.g., ibmq_manila, ibm_brisbane) via provider.get_backend(). Jobs are submitted with transpile() and assemble(). Monitor queue, retrieve results, compare with simulator. Real hardware results show noise — use error mitigation and multiple shots for statistical significance.
from qiskit import IBMQ
IBMQ.save_account('YOUR_API_TOKEN')
provider = IBMQ.load()
backend = provider.get_backend('ibmq_manila')
transpiled = transpile(qc, backend)
job = backend.run(transpiled, shots=8192)
result = job.result()
📈 Future trends: Fault‑tolerant quantum computing, logical qubits with surface code, quantum advantage in practical problems. Stay updated with IBM Quantum Roadmap.