Skip to main content
← Quantum Computing Math

Lesson 2 of 3

Multi-Qubit States and Gates

Building a state out of several qubits, why every gate is unitary, and what eigenvalues say about one.

What you will learn

  • outer products
  • projectors
  • tensor products
  • np.kron
  • conjugate transpose
  • Hermitian matrices
  • unitary matrices
  • gate order
  • entanglement
  • eigenvalues
  • eigenvectors

Before you start

Qubits and Complex Numbers. Run that lesson's two setup cells at the top of this notebook — everything here uses dag, ket0, ket1 and the gate matrices.

Outer and tensor products

0:00–0:30 · Part One, slides 21–26

Outer product: a column times a row gives a matrix. Tensor product: how separate qubits become one state vector.

Watch the ordering. The position of the single 1 in the vector for |01⟩ is the label read as a binary number.

psi = (ket0 + 1j * ket1) / np.sqrt(2)     # same state as lesson 1

print(np.outer(psi, psi))                 # not |ψ⟩⟨ψ|: np.outer never conjugates
print(np.outer(psi, psi.conj()))          # |ψ⟩⟨ψ|, its diagonal holds the probabilities

P0 = np.outer(ket0, ket0.conj())          # |0⟩⟨0|
print(P0 @ psi)                           # keeps only the |0⟩ part

ket01 = np.kron(ket0, ket1)               # |01⟩ = |0⟩ ⊗ |1⟩
print(ket01.real)                         # the 1 sits at index 1 = binary 01

ket101 = reduce(np.kron, [ket1, ket0, ket1])
print(np.flatnonzero(ket101), ket101.size)   # index 5 = 0b101, and 2³ entries

Explain it. Answer each of these in a sentence or two before you open the answers at the foot of the page.

  1. Inner product versus outer product: what shape comes out of each?
  2. What does |0⟩⟨0| do to a state?
  3. How do you combine two qubits into one state?
  4. Why does simulating qubits on a classical computer blow up?

Gates as matrices

0:30–1:00 · Part One, slides 27–31

Three words to know: the dagger M†, which is the conjugate transpose; Hermitian, meaning a matrix equals its own dagger; and unitary, meaning the dagger times the matrix is the identity.

Unitary is the two gate conditions from lesson 1 in one property: lengths are preserved, and the dagger undoes the gate. Being its own inverse is a bonus some gates have, not a requirement.

for name, M in {"X": X, "Z": Z, "H": H, "S": S}.items():
    print(f"{name}: unitary={np.allclose(dag(M) @ M, I2)}, "
          f"hermitian={np.allclose(M, dag(M))}, "
          f"self-inverse={np.allclose(M @ M, I2)}")

psi = (ket0 + 1j * ket1) / np.sqrt(2)
print(np.round([np.linalg.norm(G @ psi) for G in (X, Z, H, S)], 6))   # lengths survive

print(np.allclose(dag(S) @ (S @ psi), psi))   # S† undoes S
print(np.allclose(S @ (S @ psi), psi))        # S does not undo S

Explain it.

  1. What is the dagger of a matrix?
  2. Why does a unitary matrix make a valid gate?
  3. Why are gates that are both Hermitian and unitary convenient?
  4. Name a unitary gate that isn't its own inverse.

Gates on several qubits

1:00–1:20 · Part One, slides 32–33

To act on one qubit of many, tensor the gate with identities. Gates in a row multiply; gates side by side tensor.

The matrices double in size with every qubit added, which is why this only works for small circuits.

ket00 = np.kron(ket0, ket0)
print(np.round(np.kron(H, I2) @ ket00, 3))   # H on the left qubit only
print(np.round(np.kron(H, H) @ ket00, 3))    # H on both qubits

CNOT = np.array([[1, 0, 0, 0],
                 [0, 1, 0, 0],
                 [0, 0, 0, 1],
                 [0, 0, 1, 0]], dtype=complex)
bell = CNOT @ np.kron(H, I2) @ ket00          # rightmost matrix acts first
print(np.round(np.abs(bell) ** 2, 3))         # only 00 or 11 can appear

Explain it.

  1. How do you apply a one-qubit gate to one qubit of a two-qubit state?
  2. In C·B·A|ψ⟩, which gate acts first?
  3. When do you multiply gates, and when do you tensor them?
  4. Stretch: why is the Bell state entangled?

Eigenvalues and eigenvectors

1:20–1:45 · Part One, slides 34–38

A|v⟩ = λ|v⟩: the matrix only rescales that one vector instead of mixing it with other directions.

Unitary means every eigenvalue has modulus 1, so each one is a pure phase. Hermitian means every eigenvalue is real.

for name, M in {"Z": Z, "X": X, "S": S}.items():
    vals, _ = np.linalg.eig(M)
    print(f"{name}: eigenvalues {np.round(vals, 3)}, |λ| = {np.round(np.abs(vals), 3)}")

print(np.allclose(X @ plus, plus), np.allclose(X @ minus, -minus))   # |±⟩ are eigenvectors of X

vals, vecs = np.linalg.eig(S)                 # rebuild S from its eigenpairs
rebuilt = sum(vals[j] * np.outer(vecs[:, j], vecs[:, j].conj()) for j in range(2))
print(np.allclose(rebuilt, S))

Explain it.

  1. What makes |v⟩ an eigenvector of A?
  2. Why does every eigenvalue of a unitary have modulus 1?
  3. Why are a Hermitian matrix's eigenvalues real?
  4. Why will this matter later in the course?

Close the book

1:45–2:00

Same drill as last time for this lesson's prompts, then retry anything you missed in lesson 1.

Try these changes

Make these changes in the files beside this guide. Each one only uses what this lesson has already covered. Tick each one when it works.

Check yourself

Three quick questions on this lesson. Get them all right to finish the lesson and earn a pack.

Loading your answers

Teacher's versionHow to run this lesson, what to check, and any answers. Students do not need this.

Answers to the prompts

  1. Inner versus outer. ⟨a|b⟩ is a row times a column, so a single number. |a⟩⟨b| is a column times a row, so a matrix.
  2. What |0⟩⟨0| does. It keeps the |0⟩ component and zeroes the rest. It is a projector.
  3. Combining two qubits. Take their tensor (Kronecker) product. Each entry of the result is one amplitude from each qubit multiplied together, so 2 × 2 gives 4 entries.
  4. Why simulation blows up. n qubits need 2ⁿ amplitudes, and their gates are 2ⁿ × 2ⁿ matrices. Around 20 qubits fits on a laptop; each extra qubit doubles the memory.
  5. The dagger. The transpose of the matrix with every entry conjugated.
  6. Why unitary means valid. U†U = I gives ⟨Uψ|Uψ⟩ = ⟨ψ|ψ⟩, so probabilities still sum to 1, and U† undoes U, so the gate is reversible.
  7. Hermitian and unitary together. The gate equals its own dagger and its own inverse, so applying it twice returns the input.
  8. A unitary that isn't its own inverse. S, the diagonal gate with entries 1 and i. Applying it twice gives Z, so undoing it takes S†, with entries 1 and −i.
  9. Applying a gate to one qubit of two. Tensor it with the identity — U ⊗ I or I ⊗ U — to get a 4 × 4 matrix, then multiply.
  10. Which gate acts first. A, the rightmost. Circuit diagrams read left to right; matrix products apply right to left.
  11. Multiply or tensor. Multiply for gates applied one after another. Tensor for gates applied to different qubits at the same step.
  12. Why the Bell state is entangled. Its amplitudes, 1/√2 on 00 and 1/√2 on 11, can't be written as a tensor product of two one-qubit states, so neither qubit has a state of its own. Measuring only ever gives 00 or 11.
  13. What makes |v⟩ an eigenvector. A|v⟩ = λ|v⟩: A scales it by λ, possibly a complex factor, instead of mixing it with other directions.
  14. Why a unitary's eigenvalues have modulus 1. Unitaries preserve length, so |λ| times the length of v equals the length of v. That leaves a pure phase.
  15. Why a Hermitian matrix's eigenvalues are real. ⟨v|H|v⟩ = λ⟨v|v⟩, and when H equals its own dagger that number equals its own conjugate, so λ is real. Real eigenvalues are why measurable quantities are modelled with Hermitian matrices.
  16. Why it matters later. Phase estimation, and Shor's algorithm built on it, works by extracting the phase hidden in a unitary's eigenvalue.

Where the slides simplify

  • Reversible doesn't mean self-inverse (Part One, slides 28 and 31). Gates must be unitary, so the dagger undoes the gate. Gates that are also Hermitian — X, Z, H, CNOT — are their own inverse. S and T are unitary but aren't, so undoing them takes S† and T†.
  • The bra carries a conjugate (Part One, slides 22–23). The entries of |a⟩⟨b| conjugate the b side, which makes it a dagger rather than a plain transpose. The difference only shows up for complex vectors, which is where you will be working. In NumPy, np.outer and np.dot never conjugate; np.vdot conjugates its first argument.
  • Qiskit numbers qubits right to left (coming up once you start Qiskit). Qiskit calls the rightmost character of a label like 01 qubit 0, so a gate on qubit 0 of two qubits is I ⊗ U, not U ⊗ I. The slides treat the leftmost symbol as the first qubit. The vectors are the same; only the numbering flips.
  • Typo, Part One slide 30. The middle step of the length-preservation proof should read q†A†Aq.
  • Typo, Part One slide 33. The bottom-right block of the tensor product should be a₂₂B.