Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Lecture 4.0 — Quantum Circuits and the No-Cloning Theorem

Purdue University

From States to Circuits

In Chapters 2 and 3 we built the physics of quantum information: qubits, superposition, measurement, entanglement, Bell’s theorem. We know what quantum states are and how they behave.

Now we need a language for doing things with them. How do you build a Bell state? How do you move quantum information from one qubit to another? How do you combine simple operations into a protocol?

The answer is quantum circuits — the standard computational framework for quantum information. The idea is borrowed from classical electrical engineering: information flows along wires through a network of gates. Today we translate that idea into quantum mechanics, and discover a fundamental constraint that has no classical analog: you cannot copy a quantum state.


Part 1: Classical Circuits

Bits, Wires, and Gates

A classical circuit has three ingredients:

The basic logic gates and their truth tables:

NOT gate (¬\neg): flips a bit.

a¬a0110\begin{array}{c|c} a & \neg a \\ \hline 0 & 1 \\ 1 & 0 \end{array}

AND gate (\wedge): outputs 1 only if both inputs are 1.

abab000010100111\begin{array}{c|c} ab & a \wedge b \\ \hline 00 & 0 \\ 01 & 0 \\ 10 & 0 \\ 11 & 1 \end{array}

XOR gate (\oplus): outputs 1 if the inputs differ.

abab000011101110\begin{array}{c|c} ab & a \oplus b \\ \hline 00 & 0 \\ 01 & 1 \\ 10 & 1 \\ 11 & 0 \end{array}

XOR is addition modulo 2. We’ll see this operation again and again in quantum algorithms.

Here’s what these classical gates look like as circuit symbols:

Source
import schemdraw
from schemdraw import logic
import matplotlib.pyplot as plt

fig, axes = plt.subplots(1, 3, figsize=(10, 2.5))

with schemdraw.Drawing(canvas=axes[0], show=False) as d:
    d.config(fontsize=14)
    d.add(logic.Not().label('NOT', 'top', ofst=0.3))

with schemdraw.Drawing(canvas=axes[1], show=False) as d2:
    d2.config(fontsize=14)
    d2.add(logic.And().label('AND', 'top', ofst=0.3))

with schemdraw.Drawing(canvas=axes[2], show=False) as d3:
    d3.config(fontsize=14)
    d3.add(logic.Xor().label('XOR', 'top', ofst=0.3))

for ax in axes:
    ax.axis('off')
    ax.set_aspect('equal')

plt.tight_layout()
plt.show()

Fan-Out: Copying Is Free

In classical circuits, you can freely copy a bit. If a wire carries the value 1, you can split it into two wires that both carry 1. This is called fan-out, and it’s so natural in classical computing that we barely think about it.

Keep this in mind. It will not survive the transition to quantum mechanics.

The Classical Half-Adder

A useful example: the half-adder computes the sum and carry of two bits.

So 1+1=101 + 1 = 10 in binary: sum bit is 0, carry bit is 1. This tiny circuit is the foundation of all classical arithmetic. We’ll build its quantum version in the next lecture.

Source
import schemdraw
from schemdraw import logic

with schemdraw.Drawing() as d:
    d.config(fontsize=12)
    # XOR gate for Sum (placed first, at top)
    xor = d.add(logic.Xor().at((4, 0)).right())
    d.add(logic.Line().right().length(1.5).label('Sum', 'right'))

    # AND gate for Carry (below)
    andg = d.add(logic.And().at((4, -3)).right())
    d.add(logic.Line().right().length(1.5).label('Carry', 'right'))

    # Input a: horizontal wire, then branch to both gates
    d.add(logic.Line().at((0, 0)).right().length(1.5).label('a', 'left'))
    d.add(logic.Dot())
    d.add(logic.Line().right().to(xor.in1))
    d.add(logic.Line().at((1.5, 0)).down().to((1.5, andg.in1[1])))
    d.add(logic.Line().right().to(andg.in1))

    # Input b: horizontal wire, then branch to both gates
    d.add(logic.Line().at((0, -1)).right().length(2.5).label('b', 'left'))
    d.add(logic.Dot())
    d.add(logic.Line().right().to(xor.in2))
    d.add(logic.Line().at((2.5, -1)).down().to((2.5, andg.in2[1])))
    d.add(logic.Line().right().to(andg.in2))

Part 2: Quantum Circuits

The Three Ingredients

A quantum circuit also has three ingredients:

Information flows left to right. Applying a sequence of gates composes their unitaries: if gate AA comes first and gate BB comes second, the total operation is BABA (matrix multiplication is right to left, even though the circuit reads left to right).

Single-Qubit Gates (Review)

You already know these from Chapter 2. Now they appear as boxes on a wire:

Pauli-X (NOT gate): flips 01|0\rangle \leftrightarrow |1\rangle.

X=(0110)X = \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}

Drawn as a box labeled XX, or sometimes as a circle with a plus: \oplus.

Hadamard: creates superposition.

H=12(1111)H = \frac{1}{\sqrt{2}}\begin{pmatrix} 1 & 1 \\ 1 & -1 \end{pmatrix}
H0=0+12=+,H1=012=H|0\rangle = \frac{|0\rangle + |1\rangle}{\sqrt{2}} = |+\rangle, \qquad H|1\rangle = \frac{|0\rangle - |1\rangle}{\sqrt{2}} = |-\rangle

Pauli-Z: phase flip on 1|1\rangle.

Z=(1001)Z = \begin{pmatrix} 1 & 0 \\ 0 & -1 \end{pmatrix}

Drawn as a box labeled ZZ. Note that Z0=0Z|0\rangle = |0\rangle and Z1=1Z|1\rangle = -|1\rangle.

S and T gates: smaller phase rotations. SS applies a phase of ii to 1|1\rangle; TT applies eiπ/4e^{i\pi/4}.

S=(100i),T=(100eiπ/4)S = \begin{pmatrix} 1 & 0 \\ 0 & i \end{pmatrix}, \qquad T = \begin{pmatrix} 1 & 0 \\ 0 & e^{i\pi/4} \end{pmatrix}

These are less familiar, but they appear in many quantum algorithms. The Hadamard and T gate together are sufficient to approximate any single-qubit unitary to arbitrary precision — a fact we won’t prove but is worth knowing.

Here’s what these gates look like as circuit elements — a sequence of TT, HH, SS, HH applied to a single qubit:

Source
from qiskit import QuantumCircuit

qc = QuantumCircuit(1)
qc.h(0)
qc.s(0)
qc.h(0)
qc.t(0)
qc.draw("mpl")

The circuit reads left to right: Hadamard first, then SS, then another Hadamard, then TT. The total unitary is THSHTHSH (right to left in matrix multiplication).

Source
import matplotlib.pyplot as plt
import numpy as np

fig, axes = plt.subplots(1, 3, figsize=(10, 3))

labels = ['0', '1']

# Histogram A: all |0⟩
axes[0].bar(labels, [1000, 0], color=['#1f77b4', '#1f77b4'])
axes[0].set_title('A', fontsize=16, fontweight='bold')
axes[0].set_ylim(0, 1100)
axes[0].set_ylabel('Counts')

# Histogram B: 50/50
axes[1].bar(labels, [512, 488], color=['#1f77b4', '#1f77b4'])
axes[1].set_title('B', fontsize=16, fontweight='bold')
axes[1].set_ylim(0, 1100)

# Histogram C: all |1⟩
axes[2].bar(labels, [0, 1000], color=['#1f77b4', '#1f77b4'])
axes[2].set_title('C', fontsize=16, fontweight='bold')
axes[2].set_ylim(0, 1100)

plt.tight_layout()
plt.show()

Multi-Qubit Gates

This is where circuits become powerful. To act on more than one qubit, we use the tensor product structure from Lecture 3.1.

Applying a gate to one qubit of a pair. If we apply UU to one qubit and do nothing to the other, we tensor with the identity. For example, UU on the first qubit and identity on the second gives UIU \otimes I; identity on the first and UU on the second gives IUI \otimes U.

Example: identity on the first qubit, Hadamard on the second:

IH=12(1100110000110011).I \otimes H = \frac{1}{\sqrt{2}}\begin{pmatrix} 1 & 1 & 0 & 0 \\ 1 & -1 & 0 & 0 \\ 0 & 0 & 1 & 1 \\ 0 & 0 & 1 & -1 \end{pmatrix}.

The block-diagonal structure makes sense: the first qubit’s state selects which 2×22\times 2 block we’re in, and within each block, HH acts on the second qubit.

The Controlled-NOT (CNOT)

The most important two-qubit gate. It has a control qubit and a target qubit:

In Dirac notation, using the projector formalism from Lecture 3.1:

CNOT=00I+11X.\text{CNOT} = |0\rangle\langle 0| \otimes I + |1\rangle\langle 1| \otimes X.

Read this as: “project the control onto 0|0\rangle, do nothing to the target; project the control onto 1|1\rangle, flip the target.” The projectors 00|0\rangle\langle 0| and 11|1\rangle\langle 1| are exactly the same objects you used in measurement theory (Lecture 2.3). Now they build gates.

Action on the computational basis:

0000,0101,1011,1110|00\rangle \to |00\rangle, \quad |01\rangle \to |01\rangle, \quad |10\rangle \to |11\rangle, \quad |11\rangle \to |10\rangle

In matrix form:

CNOT=(1000010000010010)\text{CNOT} = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \end{pmatrix}

Circuit symbol: a solid dot on the control wire connected by a vertical line to \oplus on the target wire.

Source
qc = QuantumCircuit(2)
qc.cx(0, 1)
qc.draw("mpl")
Source
import matplotlib.pyplot as plt

fig, axes = plt.subplots(1, 4, figsize=(12, 3))

labels = ['00', '01', '10', '11']

# A: only |00⟩ and |11⟩
axes[0].bar(labels, [500, 0, 0, 500], color='#1f77b4')
axes[0].set_title('A', fontsize=16, fontweight='bold')
axes[0].set_ylim(0, 1100)
axes[0].set_ylabel('Counts')

# B: all four equal
axes[1].bar(labels, [250, 250, 250, 250], color='#1f77b4')
axes[1].set_title('B', fontsize=16, fontweight='bold')
axes[1].set_ylim(0, 1100)

# C: only |00⟩
axes[2].bar(labels, [1000, 0, 0, 0], color='#1f77b4')
axes[2].set_title('C', fontsize=16, fontweight='bold')
axes[2].set_ylim(0, 1100)

# D: only |00⟩ and |10⟩
axes[3].bar(labels, [500, 0, 500, 0], color='#1f77b4')
axes[3].set_title('D', fontsize=16, fontweight='bold')
axes[3].set_ylim(0, 1100)

plt.tight_layout()
plt.show()

We can also verify the CNOT matrix directly with Qiskit’s Operator class. But watch out — Qiskit’s qubit ordering puts qubit 0 as the rightmost bit in the ket (we’ll discuss this more in Part 4). So cx(0, 1) produces a matrix with rows/columns ordered as q1q0|q_1\, q_0\rangle, which shuffles the middle two rows compared to the textbook convention:

from qiskit.quantum_info import Operator
import numpy as np

# Qiskit ordering: qubit 0 = rightmost in ket
qc_cnot = QuantumCircuit(2)
qc_cnot.cx(0, 1)
op = Operator(qc_cnot)
print("CNOT matrix (Qiskit ordering |q₁ q₀⟩):")
print(np.real(op.data).astype(int))

# To get the textbook matrix, swap the qubit order:
qc_cnot2 = QuantumCircuit(2)
qc_cnot2.cx(1, 0)
op2 = Operator(qc_cnot2)
print("\nCNOT matrix (textbook ordering |q₀ q₁⟩):")
print(np.real(op2.data).astype(int))

The Controlled-Z (CZ)

Replace XX with ZZ in the controlled-gate formula:

CZ=00I+11Z=(1000010000100001)\text{CZ} = |0\rangle\langle 0| \otimes I + |1\rangle\langle 1| \otimes Z = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & -1 \end{pmatrix}

The only effect: 1111|11\rangle \to -|11\rangle. Everything else is unchanged.

Notice something interesting: the CZ matrix is symmetric under exchange of the two qubits. It doesn’t matter which qubit you call “control” and which you call “target.” This is not true for CNOT.

Circuit symbol: solid dots on both wires, connected by a vertical line.

Source
qc = QuantumCircuit(2)
qc.cz(0, 1)
qc.draw("mpl")

The SWAP Gate

Exchanges two qubits:

SWAPab=ba\text{SWAP}|a\rangle|b\rangle = |b\rangle|a\rangle
SWAP=(1000001001000001)\text{SWAP} = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}

It swaps the middle two rows: 0110|01\rangle \leftrightarrow |10\rangle, while 00|00\rangle and 11|11\rangle are unchanged (they’re already symmetric).

SWAP can be decomposed into three CNOTs:

SWAP=CNOT12CNOT21CNOT12\text{SWAP} = \text{CNOT}_{12} \cdot \text{CNOT}_{21} \cdot \text{CNOT}_{12}

Circuit symbol: two ×\times marks connected by a vertical line.

Source
qc = QuantumCircuit(2)
qc.swap(0, 1)
qc.draw("mpl")

We can verify the SWAP = three CNOTs decomposition:

Source
qc_swap_decomposed = QuantumCircuit(2)
qc_swap_decomposed.cx(0, 1)
qc_swap_decomposed.cx(1, 0)
qc_swap_decomposed.cx(0, 1)
qc_swap_decomposed.draw("mpl")

General Controlled-UU

For any single-qubit unitary UU:

CU=00I+11UC_U = |0\rangle\langle 0| \otimes I + |1\rangle\langle 1| \otimes U

CNOT is CXC_X. CZ is CZC_Z. This generalizes to any gate. Circuit symbol: solid dot connected to a box labeled UU.

The Toffoli Gate (CCX)

A three-qubit gate with two controls and one target: flip the target only if both controls are 1|1\rangle.

CCX=(0000+0101+1010)I+1111X\text{CCX} = (|00\rangle\langle 00| + |01\rangle\langle 01| + |10\rangle\langle 10|) \otimes I + |11\rangle\langle 11| \otimes X

The Toffoli gate is the quantum version of a classical AND gate (it computes AND reversibly). Circuit symbol: two solid dots connected to \oplus.

Source
qc = QuantumCircuit(3)
qc.ccx(0, 1, 2)
qc.draw("mpl")

Measurement

A measurement gate is drawn as a meter symbol. It collapses the qubit to 0|0\rangle or 1|1\rangle and outputs a classical bit, drawn as a double wire.

After measurement, the qubit’s quantum information is destroyed — it’s now a definite classical value. Classical bits from measurements can be used to control later operations (we’ll use this in teleportation).

Source
qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0, 1)
qc.measure([0, 1], [0, 1])
qc.draw("mpl")

The double lines coming out of the meter symbols are classical bit wires.

Circuit Symbol Summary

GateSymbol
Single-qubit UUBox labeled “UU
XX (NOT)\oplus or box labeled XX
CNOTSolid dot — vertical line — \oplus
CZSolid dot — vertical line — solid dot
SWAP×\times — vertical line — ×\times
Toffoli (CCX)Two solid dots — vertical line — \oplus
Controlled-UUSolid dot — vertical line — box “UU
MeasurementMeter symbol → double wire (classical bit)

Part 3: Building Bell States

Now we use circuits to build something we already know: Bell states. The point is that the formalism we just set up actually produces the entangled states from Chapter 3.

The E-bit Circuit

Start with two qubits in 00|00\rangle. Apply Hadamard to the first qubit, then CNOT with the first qubit as control.

Source
bell_circuit = QuantumCircuit(2)
bell_circuit.h(0)
bell_circuit.cx(0, 1)
bell_circuit.draw("mpl")

Step 1: Hadamard on the first qubit.

(HI)00=(0+12)0=12(00+10)(H \otimes I)|00\rangle = \left(\frac{|0\rangle + |1\rangle}{\sqrt{2}}\right) \otimes |0\rangle = \frac{1}{\sqrt{2}}(|00\rangle + |10\rangle)

After the Hadamard, the first qubit is in a superposition. The second qubit is still 0|0\rangle. This state is not entangled — it’s a product state.

Step 2: CNOT (first qubit controls second qubit).

CNOT12(00+10)=12(00+11)=Φ+\text{CNOT} \cdot \frac{1}{\sqrt{2}}(|00\rangle + |10\rangle) = \frac{1}{\sqrt{2}}(|00\rangle + |11\rangle) = |\Phi^+\rangle

The CNOT correlates the second qubit with the first: whenever the first is 1|1\rangle, it flips the second to 1|1\rangle too. The result is a Bell state — maximally entangled.

Let’s verify with Qiskit — the Statevector class tracks the quantum state through each gate:

from qiskit.quantum_info import Statevector

# Build the Bell state circuit
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)

# Compute the output state
psi = Statevector.from_instruction(qc)
psi.draw("text")

That’s Φ+=12(00+11)|\Phi^+\rangle = \frac{1}{\sqrt{2}}(|00\rangle + |11\rangle).

All Four Bell States

The same circuit with different inputs produces all four Bell states:

InputAfter HIH \otimes IAfter CNOTOutput
00|00\rangle12(00+10)\frac{1}{\sqrt{2}}(|00\rangle + |10\rangle)12(00+11)\frac{1}{\sqrt{2}}(|00\rangle + |11\rangle)Φ+|\Phi^+\rangle
01|01\rangle12(01+11)\frac{1}{\sqrt{2}}(|01\rangle + |11\rangle)12(01+10)\frac{1}{\sqrt{2}}(|01\rangle + |10\rangle)Ψ+|\Psi^+\rangle
10|10\rangle12(0010)\frac{1}{\sqrt{2}}(|00\rangle - |10\rangle)12(0011)\frac{1}{\sqrt{2}}(|00\rangle - |11\rangle)Φ|\Phi^-\rangle
11|11\rangle12(0111)\frac{1}{\sqrt{2}}(|01\rangle - |11\rangle)12(0110)\frac{1}{\sqrt{2}}(|01\rangle - |10\rangle)Ψ-|\Psi^-\rangle

The circuit is a unitary map from the computational basis to the Bell basis. It converts product states into maximally entangled states.

Let’s verify all four with Qiskit:

inputs = ["00", "01", "10", "11"]
bell_names = ["|Φ⁺⟩", "|Ψ⁺⟩", "|Φ⁻⟩", "-|Ψ⁻⟩"]

for label, name in zip(inputs, bell_names):
    qc = QuantumCircuit(2)
    # Prepare input state
    if label[1] == "1":  # qubit 0 (rightmost bit)
        qc.x(0)
    if label[0] == "1":  # qubit 1 (leftmost bit)
        qc.x(1)
    # Apply Bell circuit
    qc.h(0)
    qc.cx(0, 1)
    psi = Statevector.from_instruction(qc)
    print(f"|{label}⟩ → {name}: {psi}")

The Reverse: Bell Measurement

Running the circuit backward — first CNOT, then Hadamard — takes Bell states back to the computational basis. This is how you measure in the Bell basis: apply CNOT then H, then measure in the standard basis.

This reverse circuit is exactly what Bob does in superdense coding (coming in Lecture 3.8). Keep it in mind.

Source
# The reverse circuit: Bell measurement
qc_reverse = QuantumCircuit(2)
qc_reverse.cx(0, 1)
qc_reverse.h(0)
qc_reverse.draw("mpl")
# Verify: apply reverse circuit to |Φ⁺⟩ → should give |00⟩
phi_plus = Statevector.from_label("00")

# Forward: create Bell state
qc_bell = QuantumCircuit(2)
qc_bell.h(0)
qc_bell.cx(0, 1)
phi_plus = phi_plus.evolve(qc_bell)
print(f"After Bell circuit: {phi_plus}")

# Reverse: undo it
qc_rev = QuantumCircuit(2)
qc_rev.cx(0, 1)
qc_rev.h(0)
result = phi_plus.evolve(qc_rev)
print(f"After reverse: {result}")

Part 4: Qiskit’s Qubit Ordering Convention

Before we go further, there’s a bookkeeping issue that will cause confusion if we don’t address it now.

Qiskit’s convention:

So for two qubits with q0q_0 on top and q1q_1 on bottom, Qiskit writes the state as q1q0|q_1\, q_0\rangle.

This means: when you apply HH to the top wire (qubit 0) and II to the bottom wire (qubit 1), the matrix is IHI \otimes Hnot HIH \otimes I.

In these lectures, we will mostly follow the textbook convention (q1q2|q_1\, q_2\rangle with the first qubit on the left). When we write Qiskit code, we’ll note where the ordering flips.

Here’s a concrete example. We apply HH to qubit 0 (top wire) and II to qubit 1 (bottom wire). The matrix Qiskit produces is IHI \otimes H, not HIH \otimes I:

qc = QuantumCircuit(2)
qc.h(0)   # Hadamard on qubit 0 (top wire)
print("Circuit:")
print(qc.draw())
print("\nMatrix (note: this is I⊗H, not H⊗I):")
print(np.round(Operator(qc).data, 3).real)

Part 5: The No-Cloning Theorem

Can We Copy a Qubit?

In classical circuits, fan-out is free: if a wire carries 1, you can split it into two wires that both carry 1. Can we do the same with quantum states?

Let’s try. We want a cloning machine: a unitary UU acting on two qubits (the original and a blank) such that

U(ψ0)=ψψU(|\psi\rangle \otimes |0\rangle) = |\psi\rangle \otimes |\psi\rangle

for every possible qubit state ψ|\psi\rangle.

It Works for Basis States

Consider ψ=0|\psi\rangle = |0\rangle: we need U(00)=00U(|00\rangle) = |00\rangle. That’s just the identity on 00|00\rangle. Fine.

Consider ψ=1|\psi\rangle = |1\rangle: we need U(10)=11U(|10\rangle) = |11\rangle. That’s a CNOT! The CNOT gate “copies” basis states perfectly:

CNOT00=00,CNOT10=11.\text{CNOT}|00\rangle = |00\rangle, \qquad \text{CNOT}|10\rangle = |11\rangle.

So far so good. CNOT clones 0|0\rangle and 1|1\rangle.

It Fails for Superpositions

Now try ψ=12(0+1)=+|\psi\rangle = \frac{1}{\sqrt{2}}(|0\rangle + |1\rangle) = |+\rangle.

If UU is a cloning machine, it should produce

U(+0)=++=12(00+01+10+11).U(|+\rangle \otimes |0\rangle) = |+\rangle \otimes |+\rangle = \frac{1}{2}(|00\rangle + |01\rangle + |10\rangle + |11\rangle).

But UU is linear (it’s a unitary matrix), so we can compute what it actually does:

U(0+120)=12(U00+U10)=12(00+11)=Φ+.U\left(\frac{|0\rangle + |1\rangle}{\sqrt{2}} \otimes |0\rangle\right) = \frac{1}{\sqrt{2}}\bigl(U|00\rangle + U|10\rangle\bigr) = \frac{1}{\sqrt{2}}(|00\rangle + |11\rangle) = |\Phi^+\rangle.

We get a Bell state, not two copies of +|+\rangle. The CNOT entangles the two qubits instead of cloning the first one.

Let’s see this directly:

# CNOT "clones" basis states
# Qiskit label "XY" means |X⟩ ⊗ |Y⟩ with qubit 1 = X, qubit 0 = Y
# We use cx(1, 0): qubit 1 (left/first) controls qubit 0 (right/second)
for label in ["0", "1"]:
    sv = Statevector.from_label(label + "0")  # |label⟩ ⊗ |0⟩
    qc = QuantumCircuit(2)
    qc.cx(1, 0)  # first qubit controls second
    result = sv.evolve(qc)
    print(f"CNOT |{label}0⟩ = {result}")

print()

# CNOT FAILS to clone |+⟩
sv_plus = Statevector.from_label("+0")  # |+⟩ ⊗ |0⟩
qc = QuantumCircuit(2)
qc.cx(1, 0)
result = sv_plus.evolve(qc)
print(f"CNOT |+0⟩ = {result}")
print("This is |Φ⁺⟩ (a Bell state), NOT |+⟩⊗|+⟩!")
print()

# What |+⟩⊗|+⟩ would actually look like
plus_plus = Statevector.from_label("++")
print(f"|+⟩⊗|+⟩ = {plus_plus}")
print("↑ Four equal amplitudes — clearly different from the Bell state above.")

The General Proof

This isn’t special to CNOT. No unitary can clone arbitrary states.

Proof. Suppose such a UU exists. Pick two orthogonal states a|a\rangle and b|b\rangle. Then by assumption:

U(aϕ)=aaU(|a\rangle \otimes |\phi\rangle) = |a\rangle \otimes |a\rangle
U(bϕ)=bbU(|b\rangle \otimes |\phi\rangle) = |b\rangle \otimes |b\rangle

Now apply UU to the superposition ψ=12(a+b)|\psi\rangle = \frac{1}{\sqrt{2}}(|a\rangle + |b\rangle).

By linearity:

U(a+b2ϕ)=12(aa+bb)U\left(\frac{|a\rangle + |b\rangle}{\sqrt{2}} \otimes |\phi\rangle\right) = \frac{1}{\sqrt{2}}\bigl(|a\rangle \otimes |a\rangle + |b\rangle \otimes |b\rangle\bigr)

But if UU clones, it should produce:

a+b2a+b2=12(aa+ab+ba+bb)\frac{|a\rangle + |b\rangle}{\sqrt{2}} \otimes \frac{|a\rangle + |b\rangle}{\sqrt{2}} = \frac{1}{2}\bigl(|aa\rangle + |ab\rangle + |ba\rangle + |bb\rangle\bigr)

These are not the same state. The linearity result has two terms; the cloning result has four. Contradiction. \square

The essential point: cloning is a nonlinear operation, but quantum mechanics only allows linear (unitary) evolution. That single sentence is the entire no-cloning theorem.

Why No-Cloning Matters

This is not just a mathematical curiosity. No-cloning has profound consequences:


Summary


What’s Next

Next lecture we’ll get hands-on with Qiskit: build circuits, run them on a simulator and real quantum hardware, and see measurement statistics. After that, we’ll use circuits + no-cloning to build our first quantum protocols: quantum key distribution and teleportation.

HOMEWORK

Homework is posted at the end of Lecture 4.1.