Open this lesson in your favourite AI. It'll walk you through the why, explain the demo, and quiz you on the try-it list.
Entanglement is the resource that makes quantum computing different in kind from classical probabilistic computing. A two-qubit state is entangled when it cannot be factored as a tensor product of two single-qubit states; the four maximally-entangled Bell states are the canonical examples. From a cryptographic standpoint, entanglement is what powers BB84-style quantum key distribution (security from no-cloning of entangled halves), what enables superdense coding and teleportation, and what makes Shor's algorithm efficient — the period-finding subroutine produces an entangled state across the input and output registers, and the interference that follows extracts the period in a way no separable state could. If you can't recognise an entangled state on sight (and prove it), you can't follow the security arguments in any post-quantum protocol.
The four Bell states form an orthonormal basis for . They are produced from computational-basis inputs by the standard 'Hadamard-then-CNOT' circuit. None of them can be written as a tensor product of single-qubit states — that is the algebraic definition of entanglement.
Use these three in order. Each builds on the one before.
In one paragraph, explain entanglement to someone who knows what a tensor product is. Why does 'cannot be written as a product' capture something physically real, rather than just being an algebraic curiosity?
Walk me step by step through how the circuit $\mathrm{CNOT}(H \otimes I)$ converts $|00\rangle$ into $|\Phi^+\rangle$. Show each intermediate state explicitly, and explain at which step the state stops being a product state.
Bell's inequality experiments show that entanglement cannot be reproduced by any local hidden-variable model. Explain in concrete terms what 'local hidden variable' means, why classical correlations satisfy the CHSH inequality $|S| \leq 2$ but Bell states reach $S = 2\sqrt{2}$, and why this matters for the security claims of device-independent QKD.
// main.go
// Run: go run main.go
package main
import (
"fmt"
"math"
"math/cmplx"
)
// mulMV multiplies a square complex matrix by a complex vector.
func mulMV(m [][]complex128, v []complex128) []complex128 {
n := len(v)
out := make([]complex128, n)
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
out[i] += m[i][j] * v[j]
}
}
return out
}
// kron computes the Kronecker (tensor) product of two square complex matrices.
func kron(a, b [][]complex128) [][]complex128 {
na, nb := len(a), len(b)
n := na * nb
out := make([][]complex128, n)
for i := range out {
out[i] = make([]complex128, n)
}
for i := 0; i < na; i++ {
for j := 0; j < na; j++ {
for k := 0; k < nb; k++ {
for l := 0; l < nb; l++ {
out[i*nb+k][j*nb+l] = a[i][j] * b[k][l]
}
}
}
}
return out
}
// kronV computes the Kronecker product of two complex vectors.
func kronV(a, b []complex128) []complex128 {
out := make([]complex128, len(a)*len(b))
for i, ai := range a {
for j, bj := range b {
out[i*len(b)+j] = ai * bj
}
}
return out
}
func roundC(c complex128, prec int) complex128 {
scale := math.Pow(10, float64(prec))
return complex(math.Round(real(c)*scale)/scale, math.Round(imag(c)*scale)/scale)
}
func main() {
s := 1 / math.Sqrt(2)
// Hadamard gate
H := [][]complex128{
{complex(s, 0), complex(s, 0)},
{complex(s, 0), complex(-s, 0)},
}
// 2x2 identity
I2 := [][]complex128{
{1, 0},
{0, 1},
}
// CNOT gate (4x4)
CNOT := [][]complex128{
{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 0, 1},
{0, 0, 1, 0},
}
ket0 := []complex128{1, 0}
ket1 := []complex128{0, 1}
_ = ket1 // defined for completeness; unused in this demo
// Build |Phi+> = CNOT (H tensor I) |00>
start := kronV(ket0, ket0) // |00>
step1 := mulMV(kron(H, I2), start) // (|0>+|1>)/sqrt2 tensor |0>
phiPlus := mulMV(CNOT, step1)
// Round each amplitude for display
rounded := make([]complex128, len(phiPlus))
for i, c := range phiPlus {
rounded[i] = roundC(c, 4)
}
fmt.Printf("|Phi+> = %v\n", rounded)
fmt.Printf("amplitudes on |00>,|01>,|10>,|11>: %v\n", rounded)
// Try to factor as |a> tensor |b>: would need phiPlus[1] = a0*b1 = 0 and
// phiPlus[2] = a1*b0 = 0 simultaneously with phiPlus[0] and [3] non-zero.
// That forces a0=0 or b1=0, and a1=0 or b0=0 — impossible if both non-zero.
fmt.Println("Is |Phi+> a product state? -> no")
_ = cmplx.Abs // import used for completeness
}
go run main.go