Skip to content

Commit 51a8b9c

Browse files
committed
updating week 11
1 parent 2d04eff commit 51a8b9c

File tree

8 files changed

+143
-2727
lines changed

8 files changed

+143
-2727
lines changed

doc/pub/week11/html/week11-bs.html

Lines changed: 3 additions & 441 deletions
Large diffs are not rendered by default.

doc/pub/week11/html/week11-reveal.html

Lines changed: 2 additions & 411 deletions
Large diffs are not rendered by default.

doc/pub/week11/html/week11-solarized.html

Lines changed: 3 additions & 425 deletions
Large diffs are not rendered by default.

doc/pub/week11/html/week11.html

Lines changed: 3 additions & 425 deletions
Large diffs are not rendered by default.
0 Bytes
Binary file not shown.

doc/pub/week11/ipynb/week11.ipynb

Lines changed: 132 additions & 704 deletions
Large diffs are not rendered by default.

doc/pub/week11/pdf/week11.pdf

-22.1 KB
Binary file not shown.

doc/src/week11/week11.do.txt

Lines changed: 0 additions & 321 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ DATE: April 2, 2025
1010
o Discrete Fourier transforms (DFTs, reminder from last week) ) and the fast Fourier Transform (FFT) (see URL:"https://en.wikipedia.org/wiki/Fast_Fourier_transform")
1111
o Quantum Fourier transforms (QFTs), reminder from last week
1212
o Setting up circuits for QFTs
13-
o Quantum phase estimation algorithm (QPE)
1413
o Reading recommendation Hundt, Quantum Computing for Programmers, sections 6.1-6.4 on QFTs and QPE.
1514
#o "Video of lecture TBA":"https://youtu.be/"
1615
o "Whiteboard notes":"https://github.com/CompPhysics/QuantumComputingMachineLearning/blob/gh-pages/doc/HandWrittenNotes/2025/NotesApril2.pdf"
@@ -816,323 +815,3 @@ print("Probabilities after performing QFT:")
816815
print(probabilities)
817816
!ec
818817

819-
820-
!split
821-
===== Introduction to Quantum Phase Estimation (QPE) =====
822-
The QPE is a fundamental quantum algorithm used to estimate the phase $\phi$ in eigenvalue equations of unitary operators.
823-
Given a unitary operator $U$ and an eigenvector $| \psi \rangle$ such that:
824-
!bt
825-
\[
826-
U | \psi \rangle = \exp{2\pi i \phi} | \psi \rangle
827-
\]
828-
!et
829-
the goal of QPE is to estimate $\phi$.
830-
831-
The QPE provides an estimate of $\phi$ with high probability. It is a
832-
crucial subroutine for algorithms like
833-
o Shor's factoring algorithm and
834-
o quantum many-body simulations.
835-
836-
!split
837-
===== Mathematical Background =====
838-
839-
The goal of QPE is to estimate the phase $\phi \in [0,1)$ where:
840-
!bt
841-
\[
842-
U\vert \psi\rangle = \exp{2\pi i \phi} \vert\psi\rangle.
843-
\]
844-
!et
845-
846-
The Quantum Fourier Transform on $n$ qubits is defined as (see above):
847-
!bt
848-
\[
849-
\vert x\rangle \rightarrow \frac{1}{\sqrt{2^n}}\sum_{y=0}^{2^n-1} e^{2\pi i xy / 2^n}\vert y\rangle.
850-
\]
851-
!et
852-
The QFT is essential for extracting phase information in QPE.
853-
854-
!split
855-
===== Quantum Circuit and Working =====
856-
857-
The quantum circuit for QPE consists of two quantum registers:
858-
o The first register with $n$ qubits is initialized to $\vert 0\rangle^{\otimes n}$.
859-
o second register is initialized to the eigenstate $\vert\psi\rangle$ of $U$.
860-
861-
Figure to be added
862-
863-
!split
864-
===== Derivation of the Algorithm, Step 1: Initialization =====
865-
!bblock
866-
The system starts in the state:
867-
!bt
868-
\[
869-
\vert 0 \rangle ^{\otimes n} \otimes \vert\psi\rangle .
870-
\]
871-
!et
872-
Applying Hadamard gates to the first register creates a superposition:
873-
!bt
874-
\[
875-
\frac{1}{2^{n/2}}\sum_{k=0}^{2^n -1} \vert k \rangle \otimes \vert\psi\rangle .
876-
\]
877-
!et
878-
!eblock
879-
!split
880-
===== Step 2: Controlled Unitary Operations =====
881-
Controlled-$U^{2^j}$ gates apply the operation $U$ with exponential powers:
882-
!bblock
883-
!bt
884-
\[
885-
\frac{1}{2^{n/2}}\sum_{k=0}^{2^n -1} \vert k \rangle \otimes U^k\vert\psi\rangle .
886-
\]
887-
!et
888-
For eigenstate $\vert\psi\rangle $, this becomes:
889-
!bt
890-
\[
891-
\frac{1}{2^{n/2}}\sum_{k=0}^{2^n -1} e^{2\pi i \phi k}\vert k \rangle \otimes \vert\psi\rangle .
892-
\]
893-
!et
894-
!eblock
895-
896-
!split
897-
===== Step 3: Quantum Fourier Transform (QFT) =====
898-
899-
!bblock
900-
Applying QFT to the first register transforms the state to:
901-
!bt
902-
\[
903-
\sum_{k=0}^{2^n -1} c_k \vert k \rangle ,
904-
\]
905-
!et
906-
where coefficients $c_k$ are peaked near $k \approx 2^n \phi$.
907-
908-
!eblock
909-
!split
910-
===== Step 4: Measurement =====
911-
!bblock
912-
Measuring the first register gives an $n$-bit estimate of $\phi$ with high probability.
913-
!eblock
914-
915-
!split
916-
===== Simple code which implements the QPE =====
917-
!bc pycod
918-
import numpy as np
919-
def hadamard(n):
920-
# Creates an n-qubit Hadamard gate as a matrix.
921-
H = np.array([[1, 1], [1, -1]]) / np.sqrt(2)
922-
H_n = H
923-
for _ in range(n - 1):
924-
H_n = np.kron(H_n, H) # Tensor product to expand Hadamard gate
925-
return H_n
926-
927-
def qft(n):
928-
# Creates an n-qubit Quantum Fourier Transform (QFT) matrix.
929-
N = 2**n
930-
omega = np.exp(2j * np.pi / N)
931-
qft_matrix = np.array([[omega**(i * j) for j in range(N)] for i in range(N)]) / np.sqrt(N)
932-
return qft_matrix
933-
934-
def inverse_qft(n):
935-
# Creates an n-qubit inverse Quantum Fourier Transform (QFT†) matrix.
936-
return np.conj(qft(n)).T # Hermitian transpose of QFT
937-
938-
def controlled_unitary(U, control, target, n):
939-
# Creates an n-qubit controlled unitary matrix
940-
I = np.eye(2**n) # Identity matrix
941-
CU = np.copy(I)
942-
for i in range(2**n):
943-
if (i >> control) & 1: # Check if control qubit is |1⟩
944-
CU[i, :] = np.kron(np.eye(2**target), U).dot(I[i, :])
945-
return CU
946-
947-
def apply_gate(state, gate):
948-
# Applies a gate (matrix) to a quantum state (vector).
949-
return gate @ state
950-
951-
def measure(state):
952-
# Simulates measurement by computing probability distribution
953-
probabilities = np.abs(state) ** 2
954-
return np.argmax(probabilities) # Return the most probable outcome
955-
956-
def qpe(unitary, phi, num_counting_qubits):
957-
# Simulates the Quantum Phase Estimation algorithm.
958-
n = num_counting_qubits
959-
total_qubits = n + 1
960-
dim = 2**total_qubits
961-
962-
# Step 1: Initialize state |0...0⟩ tensor product with psi
963-
state = np.zeros(dim, dtype=complex)
964-
state[0] = 1 # |00...0⟩
965-
966-
# Step 2: Apply Hadamard to counting qubits
967-
H_n = hadamard(n)
968-
state = apply_gate(state.reshape(2**n, 2), H_n).reshape(dim)
969-
970-
# Step 3: Apply controlled-U^2^j operations
971-
for j in range(n):
972-
power = 2**j
973-
U_power = np.linalg.matrix_power(unitary, power)
974-
CU = controlled_unitary(U_power, j, n, total_qubits)
975-
state = apply_gate(state, CU)
976-
977-
# Step 4: Apply inverse QFT
978-
IQFT = inverse_qft(n)
979-
state = apply_gate(state.reshape(2**n, 2), IQFT).reshape(dim)
980-
981-
# Step 5: Measure and return estimated phase
982-
measurement_result = measure(state)
983-
return measurement_result / (2**n) # Convert binary to decimal
984-
985-
# Define the unitary U with phase phi = 1/3
986-
phi = 1/3
987-
U = np.array([[1, 0], [0, np.exp(2j * np.pi * phi)]]) # Phase gate
988-
989-
# Run QPE
990-
num_counting_qubits = 3 # More qubits give higher precision
991-
estimated_phi = qpe(U, phi, num_counting_qubits)
992-
print(f"Estimated phase: {estimated_phi}")
993-
print(f"Actual phase: {phi}")
994-
!ec
995-
996-
!split
997-
===== Code which implements the QPE using Qiskit =====
998-
!bc pycod
999-
from qiskit import QuantumCircuit, Aer, transpile, assemble, execute
1000-
from qiskit.visualization import plot_histogram
1001-
import numpy as np
1002-
1003-
def qpe(unitary, num_counting_qubits):
1004-
"""
1005-
Quantum Phase Estimation Algorithm.
1006-
Args:
1007-
unitary (QuantumCircuit): The unitary operator whose phase we estimate.
1008-
num_counting_qubits (int): Number of qubits in the counting register.
1009-
1010-
Returns:
1011-
QuantumCircuit: QPE quantum circuit
1012-
"""
1013-
n = num_counting_qubits
1014-
qc = QuantumCircuit(n + 1, n) # n counting qubits + 1 eigenstate qubit
1015-
# Step 1: Apply Hadamard to counting qubits
1016-
for qubit in range(n):
1017-
qc.h(qubit)
1018-
# Step 2: Apply controlled-U^2^j operations
1019-
for j in range(n):
1020-
power = 2**j
1021-
controlled_U = unitary.control(1).power(power)
1022-
qc.append(controlled_U, [j] + [n]) # Control: j, Target: n
1023-
# Step 3: Apply inverse QFT
1024-
qc.append(qft_dagger(n), range(n))
1025-
# Step 4: Measure counting qubits
1026-
qc.measure(range(n), range(n))
1027-
return qc
1028-
1029-
def qft_dagger(n):
1030-
"""Creates an inverse Quantum Fourier Transform (QFT†) circuit."""
1031-
qc = QuantumCircuit(n)
1032-
for qubit in range(n//2):
1033-
qc.swap(qubit, n-qubit-1)
1034-
for j in range(n):
1035-
for m in range(j):
1036-
qc.cp(-np.pi / (2**(j-m)), m, j)
1037-
qc.h(j)
1038-
return qc
1039-
# Define the unitary U with phase phi = 1/3
1040-
phi = 1/3
1041-
U = QuantumCircuit(1)
1042-
U.p(2 * np.pi * phi, 0) # Phase gate
1043-
# Number of counting qubits
1044-
num_counting_qubits = 3
1045-
# Generate QPE circuit
1046-
qpe_circuit = qpe(U, num_counting_qubits)
1047-
# Simulate the circuit
1048-
simulator = Aer.get_backend('qasm_simulator')
1049-
compiled_circuit = transpile(qpe_circuit, simulator)
1050-
qobj = assemble(compiled_circuit)
1051-
result = simulator.run(qobj).result()
1052-
# Get measurement results
1053-
counts = result.get_counts()
1054-
# Plot histogram of results
1055-
plot_histogram(counts)
1056-
!ec
1057-
1058-
1059-
!split
1060-
===== Code which implements the QPE using PennyLane =====
1061-
1062-
!bc pycod
1063-
import pennylane as qml
1064-
import numpy as np
1065-
def qft(n):
1066-
# Applies the inverse Quantum Fourier Transform (QFT†) circuit
1067-
for i in range(n):
1068-
qml.Hadamard(wires=i)
1069-
for j in range(i):
1070-
qml.CPhase(-np.pi / (2 ** (i - j)), wires=[j, i])
1071-
for i in range(n // 2):
1072-
qml.SWAP(wires=[i, n - i - 1])
1073-
1074-
def controlled_unitary(U, control, target):
1075-
# Applies a controlled-unitary operation
1076-
qml.ctrl(U, control=control)(wires=target)
1077-
1078-
1079-
def qpe(phi, num_counting_qubits):
1080-
# Quantum Phase Estimation circuit in PennyLane.
1081-
total_qubits = num_counting_qubits + 1
1082-
dev = qml.device("default.qubit", wires=total_qubits, shots=1000)
1083-
@qml.qnode(dev)
1084-
def circuit():
1085-
# Initialize the counting register in |0> and eigenstate register in |1>
1086-
qml.PauliX(wires=num_counting_qubits) # Set last qubit to |1>
1087-
# Apply Hadamard to counting qubits
1088-
for qubit in range(num_counting_qubits):
1089-
qml.Hadamard(wires=qubit)
1090-
# Apply controlled-U^2^j operations
1091-
for j in range(num_counting_qubits):
1092-
power = 2**j
1093-
U = qml.RZ(2 * np.pi * phi, wires=num_counting_qubits) # Phase shift
1094-
controlled_unitary(U, control=j, target=num_counting_qubits)
1095-
# Apply inverse QFT
1096-
qft(num_counting_qubits)
1097-
# Measure counting qubits
1098-
return qml.sample(wires=range(num_counting_qubits))
1099-
# Run the circuit
1100-
samples = circuit()
1101-
# Convert measurement results to decimal phase estimate
1102-
binary_result = "".join(map(str, samples[0])) # Take the first sample
1103-
estimated_phi = int(binary_result, 2) / (2 ** num_counting_qubits)
1104-
return estimated_phi
1105-
# Define the phase phi
1106-
phi = 1/3
1107-
# Number of counting qubits (higher gives better precision)
1108-
num_counting_qubits = 3
1109-
# Run QPE
1110-
estimated_phi = qpe(phi, num_counting_qubits)
1111-
print(f"Estimated phase: {estimated_phi}")
1112-
print(f"Actual phase: {phi}")
1113-
!ec
1114-
1115-
!split
1116-
===== Applications of QPE =====
1117-
1118-
The QPE is a foundational algorithm with several key applications:
1119-
o \textbf{Factoring and Cryptography:} Integral to Shor's algorithm for integer factoring.
1120-
o \textbf{Quantum Simulations:} Estimating eigenvalues of Hamiltonians in many-body physics.
1121-
o \textbf{Amplitude Estimation:} Enhances algorithms like Grover's search.
1122-
1123-
!split
1124-
===== Challenges and Practical Considerations =====
1125-
1126-
o \textbf{Qubit Requirements:} Requires a large number of qubits for high precision.
1127-
o \textbf{Gate Depth:} Controlled-$U^{2^j}$ operations increase gate complexity.
1128-
o \textbf{Noise Sensitivity:} Errors in QFT or controlled gates impact accuracy.
1129-
1130-
It is a powerful quantum algorithm for extracting phase information of
1131-
unitary operators. It forms the foundation for many advanced quantum
1132-
algorithms and demonstrates the power of quantum Fourier transforms in
1133-
computational tasks. For many-body simulations it is however not as efficient as the VQE algorithm.
1134-
1135-
1136-
1137-
1138-

0 commit comments

Comments
 (0)