Quantum Teleportation in Python — Deep Dive
The Mathematics of Teleportation
To understand the protocol precisely, we need to track the quantum state through each step.
Alice wants to teleport an arbitrary qubit state: |ψ⟩ = α|0⟩ + β|1⟩
The shared Bell pair between Alice (qubit B) and Bob (qubit C) is: |Φ⁺⟩ = (1/√2)(|00⟩ + |11⟩)
The combined three-qubit system starts as: |ψ⟩_A ⊗ |Φ⁺⟩_BC = (α|0⟩ + β|1⟩) ⊗ (1/√2)(|00⟩ + |11⟩)
Expanding and regrouping in the Bell basis for qubits A and B:
= (1/2)[|Φ⁺⟩_AB(α|0⟩ + β|1⟩)_C + |Φ⁻⟩_AB(α|0⟩ - β|1⟩)_C + |Ψ⁺⟩_AB(α|1⟩ + β|0⟩)_C + |Ψ⁻⟩_AB(α|1⟩ - β|0⟩)_C]
Each Bell measurement outcome leaves Bob’s qubit in a known transformation of |ψ⟩:
| Bell state measured | Bob’s state | Correction needed |
|---|---|---|
| Φ⁺⟩ (00) | α|0⟩ + β|1⟩ | |
| Φ⁻⟩ (01) | α|0⟩ - β|1⟩ | |
| Ψ⁺⟩ (10) | α|1⟩ + β|0⟩ | |
| Ψ⁻⟩ (11) | α|1⟩ - β|0⟩ |
Implementation in Qiskit
Basic Teleportation Circuit
from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
import numpy as np
def teleportation_circuit(state_params=None):
"""
Full quantum teleportation protocol.
state_params: (theta, phi) for the state to teleport
"""
qc = QuantumCircuit(3, 2)
# Step 0: Prepare the state to teleport on qubit 0
if state_params:
theta, phi = state_params
qc.ry(theta, 0)
qc.rz(phi, 0)
else:
# Default: teleport |+⟩ state
qc.h(0)
qc.barrier()
# Step 1: Create Bell pair between qubits 1 and 2
qc.h(1)
qc.cx(1, 2)
qc.barrier()
# Step 2: Alice's Bell measurement on qubits 0 and 1
qc.cx(0, 1)
qc.h(0)
qc.measure(0, 0) # First classical bit
qc.measure(1, 1) # Second classical bit
qc.barrier()
# Step 3: Bob's conditional corrections
# Classical bit 1 → X correction on qubit 2
qc.x(2).c_if(1, 1)
# Classical bit 0 → Z correction on qubit 2
qc.z(2).c_if(0, 1)
return qc
# Build and run
qc = teleportation_circuit(state_params=(np.pi/3, np.pi/4))
print(qc.draw())
sim = AerSimulator()
qc_with_measure = qc.copy()
qc_with_measure.measure(2, 0) # Measure Bob's qubit
transpiled = transpile(qc_with_measure, sim)
result = sim.run(transpiled, shots=10000).result()
counts = result.get_counts()
print(f"Measurement results: {counts}")
Verification with Statevector
To prove teleportation works perfectly, compare statevectors:
from qiskit.quantum_info import Statevector, state_fidelity
def verify_teleportation(theta, phi):
"""Verify teleportation by comparing input and output states."""
# Prepare the target state
target_circuit = QuantumCircuit(1)
target_circuit.ry(theta, 0)
target_circuit.rz(phi, 0)
target_state = Statevector.from_instruction(target_circuit)
# Run teleportation without measurement (use deferred measurement)
qc = QuantumCircuit(3)
qc.ry(theta, 0)
qc.rz(phi, 0)
# Bell pair
qc.h(1)
qc.cx(1, 2)
# Bell measurement (without collapsing)
qc.cx(0, 1)
qc.h(0)
# Corrections (using controlled gates instead of classical feedback)
qc.cx(1, 2) # X correction
qc.cz(0, 2) # Z correction
# Get final statevector
sv = Statevector.from_instruction(qc)
# Trace out qubits 0 and 1 to get Bob's state
# After successful teleportation, qubit 2 should match target
reduced = sv.trace([0, 1])
fidelity = state_fidelity(target_state.to_operator(), reduced)
return fidelity
# Test with various states
for theta in [0, np.pi/4, np.pi/2, np.pi]:
for phi in [0, np.pi/3, np.pi]:
f = verify_teleportation(theta, phi)
print(f"θ={theta:.2f}, φ={phi:.2f}: fidelity={f:.6f}")
assert abs(f - 1.0) < 1e-10, "Teleportation failed!"
Implementation in Cirq
import cirq
import numpy as np
def teleport_cirq(state_to_teleport):
"""Teleportation using Cirq with classical feedback."""
msg = cirq.NamedQubit("message")
alice = cirq.NamedQubit("alice")
bob = cirq.NamedQubit("bob")
circuit = cirq.Circuit()
# Prepare state to teleport
circuit.append(cirq.ry(state_to_teleport[0]).on(msg))
circuit.append(cirq.rz(state_to_teleport[1]).on(msg))
# Create Bell pair
circuit.append(cirq.H(alice))
circuit.append(cirq.CNOT(alice, bob))
# Bell measurement
circuit.append(cirq.CNOT(msg, alice))
circuit.append(cirq.H(msg))
circuit.append(cirq.measure(msg, key='m1'))
circuit.append(cirq.measure(alice, key='m2'))
# Classical feedback with Cirq's classical control
circuit.append(cirq.X(bob).with_classical_controls('m2'))
circuit.append(cirq.Z(bob).with_classical_controls('m1'))
return circuit
circuit = teleport_cirq([np.pi/3, np.pi/4])
print(circuit)
simulator = cirq.Simulator()
result = simulator.simulate(circuit)
Entanglement Swapping
Entanglement swapping extends teleportation to create entanglement between particles that never interacted:
def entanglement_swapping():
"""
Particles 1-2 are entangled. Particles 3-4 are entangled.
Bell measurement on 2-3 entangles 1-4 (which never met).
"""
qc = QuantumCircuit(4, 4)
# Bell pair 1: qubits 0 and 1
qc.h(0)
qc.cx(0, 1)
# Bell pair 2: qubits 2 and 3
qc.h(2)
qc.cx(2, 3)
qc.barrier()
# Bell measurement on qubits 1 and 2
qc.cx(1, 2)
qc.h(1)
qc.measure(1, 0)
qc.measure(2, 1)
# Corrections on qubit 3
qc.x(3).c_if(1, 1)
qc.z(3).c_if(0, 1)
# Now qubits 0 and 3 are entangled!
qc.measure(0, 2)
qc.measure(3, 3)
return qc
qc = entanglement_swapping()
sim = AerSimulator()
result = sim.run(transpile(qc, sim), shots=10000).result()
counts = result.get_counts()
# Verify: qubits 0 and 3 should be correlated
for outcome, count in sorted(counts.items()):
bits = outcome.replace(' ', '')
q0, q3 = bits[1], bits[0] # Qiskit reverses bit order
print(f"{outcome}: {count} (q0={q0}, q3={q3})")
Quantum Repeater Chain
For long-distance quantum communication, repeaters use entanglement swapping in sequence:
def quantum_repeater_chain(n_segments, noise_per_segment=0.0):
"""
Chain of entanglement swapping to extend quantum communication range.
n_segments: number of intermediate segments
"""
n_qubits = 2 * (n_segments + 1) # Two qubits per segment
n_classical = 2 * n_segments # Two bits per swapping measurement
qc = QuantumCircuit(n_qubits, n_classical)
# Create Bell pairs for each segment
for seg in range(n_segments + 1):
q1 = 2 * seg
q2 = 2 * seg + 1
qc.h(q1)
qc.cx(q1, q2)
if noise_per_segment > 0:
# Simulate channel noise with depolarizing errors
# (In real Qiskit, use noise models)
pass
qc.barrier()
# Entanglement swapping at each intermediate node
for node in range(n_segments):
q_left = 2 * node + 1 # Right qubit of left segment
q_right = 2 * (node + 1) # Left qubit of right segment
c_base = 2 * node
qc.cx(q_left, q_right)
qc.h(q_left)
qc.measure(q_left, c_base)
qc.measure(q_right, c_base + 1)
# Correction on the rightmost qubit of the chain
target = 2 * (n_segments + 1) - 1
qc.x(target).c_if(c_base + 1, 1)
qc.z(target).c_if(c_base, 1)
return qc
# 3-segment repeater chain
chain = quantum_repeater_chain(3)
print(f"Chain uses {chain.num_qubits} qubits, {chain.num_clbits} classical bits")
Teleportation on Noisy Hardware
On real quantum devices, teleportation fidelity degrades:
from qiskit_aer.noise import NoiseModel, depolarizing_error
def noisy_teleportation(error_rate):
"""Simulate teleportation with realistic noise."""
noise_model = NoiseModel()
noise_model.add_all_qubit_quantum_error(
depolarizing_error(error_rate, 1), ['h', 'x', 'z', 'ry', 'rz']
)
noise_model.add_all_qubit_quantum_error(
depolarizing_error(error_rate * 5, 2), ['cx']
)
qc = teleportation_circuit(state_params=(np.pi/4, 0))
qc.measure(2, 0)
sim = AerSimulator(noise_model=noise_model)
transpiled = transpile(qc, sim)
result = sim.run(transpiled, shots=10000).result()
return result.get_counts()
# Compare ideal vs noisy
print("Ideal:", noisy_teleportation(0.0))
print("1% noise:", noisy_teleportation(0.01))
print("5% noise:", noisy_teleportation(0.05))
Teleportation-Based Quantum Computing
Measurement-based quantum computing uses teleportation as a computational primitive:
def gate_teleportation(gate_name='T'):
"""
Teleport a gate: apply a gate to a qubit using only
Bell measurements and pre-prepared resource states.
"""
qc = QuantumCircuit(3, 2)
# Prepare resource state (gate applied to half of Bell pair)
qc.h(1)
qc.cx(1, 2)
if gate_name == 'T':
qc.t(2) # T gate applied to resource state
elif gate_name == 'S':
qc.s(2)
# Input state on qubit 0
qc.h(0) # Example: |+⟩ state
qc.barrier()
# Teleportation protocol
qc.cx(0, 1)
qc.h(0)
qc.measure(0, 0)
qc.measure(1, 1)
# Corrections (may need additional Clifford corrections
# depending on the teleported gate)
qc.x(2).c_if(1, 1)
qc.z(2).c_if(0, 1)
return qc
This technique is fundamental to fault-tolerant quantum computing, where non-Clifford gates (like the T gate) are implemented via “magic state” distillation and gate teleportation.
Real-World Teleportation Experiments
- 2017: Chinese team teleported a photon’s state from Earth to the Micius satellite (1,400 km)
- 2020: Fermilab demonstrated teleportation over 44 km of fiber optic cable
- 2022: Teams in the Netherlands demonstrated teleportation between non-neighboring nodes in a 3-node quantum network
- 2024-2025: Multiple groups demonstrated teleportation with error-corrected logical qubits
These experiments validate the protocol that Python simulations model, bridging theory and physical implementation.
One thing to remember: Quantum teleportation isn’t a parlor trick — it’s the fundamental data transfer protocol for quantum networks. Every time a future quantum internet moves information between nodes, it will use this exact protocol, and Python simulations are how researchers design and optimize it today.
See Also
- Python Cirq Quantum Programming Google's Cirq lets you program quantum computers in Python — like writing a recipe for the world's weirdest kitchen
- Python Pennylane Quantum Ml How PennyLane mixes quantum computing and AI together — like teaching a magical calculator to learn from its mistakes
- Python Qiskit Quantum Circuits How IBM's Qiskit lets you build quantum computer programs in Python — like snapping together LEGO blocks that follow alien physics
- Python Quantum Annealing Python How quantum annealing finds the best solution by shaking problems until the answer falls out — and how D-Wave lets you try it in Python
- Python Quantum Cryptography Simulation How quantum physics creates unbreakable secret codes — and how you can simulate the whole thing in Python