Tutorial 2: Quantum Entanglement & Bell States
Quantum entanglement is one of the definitive phenomena distinguishing quantum from classical computation. In an entangled state, the quantum states of two or more particles cannot be described independently of the state of the others, regardless of spatial separation.
In this tutorial, you will generate and measure a canonical Bell State () using the Quantum Virtual Machine (QVM).
🎯 Learning Objectives
- Understand mathematical state evolution through multi-qubit tensor products.
- Build an entanglement circuit using the Hadamard () and Controlled-NOT () gates.
- Verify perfect correlations analytically and through shot-based measurement sampling.
- Execute the circuit via QVM Python IR, OpenQASM, the CLI, and the REST API.
- Cross-validate the circuit against Qiskit and Cirq backends.
🔬 Theory & Step-by-Step State Evolution
The Bell state is defined as:
Let us trace the quantum state vector as it moves through the circuit:
Step 0: Initialization
Both qubits begin in the ground state :
Step 1: Hadamard on Qubit 0
Applying to qubit 0 creates an equal superposition on wire 0 while leaving wire 1 unchanged ():
Step 2: Controlled-NOT () from Qubit 0 to Qubit 1
The gate flips the target qubit (qubit 1) if and only if the control qubit (qubit 0) is :
Applying gives:
Measurement Probabilities
Evaluating probability :
Measuring qubit 0 immediately determines qubit 1: if qubit 0 collapses to , qubit 1 is guaranteed to be ; if qubit 0 collapses to , qubit 1 is guaranteed to be .
💻 Python Implementation
from qvm.ir import QuantumCircuit
from qvm.simulator import Simulator
from qvm.parser import OpenQASM2Parser
# Define Bell state in OpenQASM
QASM = """
OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
creg c[2];
h q[0];
cx q[0], q[1];
measure q[0] -> c[0];
measure q[1] -> c[1];
"""
# Parse into QVM Intermediate Representation
bell_circuit = OpenQASM2Parser.parse(QASM)
# 1. Exact simulation
sim = Simulator()
state, mem = sim.simulate(bell_circuit)
probs = (abs(state) ** 2).round(3)
print("Exact probabilities [00, 01, 10, 11]:", probs)
# 2. Sample 2,000 shots
counts = sim.sample(bell_circuit, shots=2000, seed=42)
print("Sampled counts:", sorted(counts.items()))
# Verification: only '00' and '11' can appear in an ideal simulation
assert set(counts.keys()) <= {"00", "11"}, "Violation of entanglement correlation!"
print("Bell state successfully verified!")Verified Output
Exact probabilities [00, 01, 10, 11]: [0.5 0. 0. 0.5]
Sampled counts: [('00', 986), ('11', 1014)]
Bell state successfully verified!🔄 Cross-Framework Export (Qiskit & Cirq)
QVM provides a bidirectional bridge. Any QVM circuit converts directly to native Qiskit QuantumCircuit and Cirq Circuit objects:
# Convert to Qiskit
qiskit_circ = bell_circuit.to_qiskit()
print("Qiskit ops:", qiskit_circ.count_ops())
# Convert to Cirq
cirq_circ = bell_circuit.to_cirq()
print("Cirq ops count:", len(list(cirq_circ.all_operations())))
# Execute directly on Qiskit Aer via QVM helper
aer_counts = bell_circuit.run_qiskit_simulator(shots=1000)
print("Aer counts:", aer_counts)🌐 Running via the REST API (/run)
You can execute this Bell-state simulation via the FastAPI endpoint:
curl -X POST "http://127.0.0.1:8000/run" \
-H "Content-Type: application/json" \
-d '{
"source_type": "json",
"nqubits": 2,
"circuit": [
{"name": "h", "qubits": [0]},
{"name": "cx", "qubits": [0, 1]},
{"name": "measure", "qubits": [0], "register": "c", "cbit": 0},
{"name": "measure", "qubits": [1], "register": "c", "cbit": 1}
],
"transpile": true,
"routing": "sabre",
"shots": 1000,
"seed": 42
}'Response Highlights
probabilities:[0.5, 0.0, 0.0, 0.5]counts:{"00": 498, "11": 502}circuit_plot: Base64 PNG showing the routed circuit.histogram_plot: Base64 PNG with 50/50 bars on00and11.
🖥️ Running in the Web Dashboard
- Start the web application:
npm run devinweb/(or visit the deployed dashboard). - Enter the OpenQASM 3.0 snippet:
qasm
OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; bit[2] c; h q[0]; cx q[0], q[1]; c[0] = measure q[0]; c[1] = measure q[1]; - In the right control panel, set Shots to
1000. - Click Run.
- Observe the probability histogram: two equal spikes at
00and11.
Next tutorial: Tutorial 3: Grover's Search Algorithm.