Quantum Phase Estimation (My Lab)
Cahyati Supriyati Sangaji (My Note)
In this lab, you will implement a quantum program to determine the global phase applied by a unitary operator on its eigenstate. In order to do this, you will write Qiskit
code for the quantum phase estimation algorithm.
You might find the following chapters of the Qiskit Textbook useful:
- Quantum phase estimation: https://qiskit.org/textbook/ch-algorithms/quantum-phase-estimation.html
- Quantum Fourier transform: https://qiskit.org/textbook/ch-algorithms/quantum-fourier-transform.html
Remember, to run a cell in Jupyter notebooks, you press Shift
+ Return/Enter
on your keyboard.
Installing necessary packages
Before we begin, you will need to install some prerequisites into your environment. Run the cell below to complete these installations. At the end, the cell outputs will be cleared.
!pip install -U qiskit==0.19
!pip install -U qiskit-ibmq-provider==0.7from IPython.display import clear_output
clear_output()
Review of Quantum Phase Estimation
The goal of quantum phase estimation is to determine the phase π applied by a unitary operator π on its eigenstate |πβ© such that
This is done in four main steps.
Graded Exercise 1: Implementing Quantum Phase Estimation
In this lab, we will implement the unitary operator π of a single qubit given by
for which an eigenstate is the single-qubit state |1β©. The operator applies a phase
Our objective is to determine theta using quantum phase estimation. We will use π=0.5 and π=5 measurement qubits.
1. Initializing the qubits
We will need to initialize our qubits as described above by applying a Hadamard gate on each of the πn measurement qubits. We will also set the target qubit to |1β©, since that is the eigenstate onto which the unitary operator π will be applied.
We have created a function below called initialize_qubits
which takes in three arguments. The first argument is the quantum circuit onto which the gates will be applied. The second argument, measurement_qubits
, is the list of measurement qubits. The third argument, target_qubit
, is the target qubit for the unitary operator.
def initialize_qubits(given_circuit, measurement_qubits, target_qubit):
### WRITE YOUR CODE BETWEEN THESE LINES - START
#for measurement_qubits in range(target_qubit):
given_circuit.h(measurement_qubits)
given_circuit.x(target_qubit)
return given_circuit
### WRITE YOUR CODE BETWEEN THESE LINES - END
2. Implementing the unitary operator
We have created a function below called unitary_operator
which takes in three arguments. The first argument is the quantum circuit onto which the operator will be applied. The second argument, control_qubit
, is the control qubit for the unitary operator. The third argument, target_qubit
, is the target qubit for the unitary operator. Finally, the fourth argument, theta
, sets the value of π.
import numpy as np
pi = np.pidef unitary_operator(given_circuit, control_qubit, target_qubit, theta):
#print(control_qubit)
given_circuit.cu1(theta*2*pi , control_qubit , target_qubit)
# This is C-U
return given_circuit
### WRITE YOUR CODE BETWEEN THESE LINES - END
We have created a function below called unitary_operator_exponent
which takes in four arguments. The first argument is the quantum circuit onto which the operator will be applied. The second argument, control_qubit
, is the control qubit for the unitary operator. The third argument, target_qubit
, is the target qubit for the unitary operator. Finally, the fourth argument, theta
, sets the value of πΞΈ. The fourth argument, exponent
is the number of times that the unitary operator needs to be applied.
def unitary_operator_exponent(given_circuit, control_qubit, target_qubit, theta, exponent):
#for control_qubit in range(target_qubit):
for _ in range(exponent):
given_circuit = unitary_operator(given_circuit,
control_qubit,
target_qubit,
theta*exponent)
return given_circuit
### WRITE YOUR CODE BETWEEN THESE LINES - END
3. Implementing an inverse quantum Fourier transform
You will also need to implement an inverse quantum Fourier transform as part of the quantum phase estimation algorithm. You can do this using two methods.
β Method 1 (easier) is to use Qiskit
's circuit library to give you a box that implements the inverse quantum fourier transform. You can do this using qiskit.circuit.library.qft(num_qubits).inverse()
. The documentation for this is here: https://qiskit.org/documentation/stubs/qiskit.circuit.library.QFT.html
β Method 2 (harder) is to implement the gates of the inverse quantum Fourier transform by hand. We strongly recommend following the detailed discussion in the Qiskit
textbook for examples.
We have created a function below called apply_iqft
which takes in three arguments. The first argument is the quantum circuit onto which the operator will be applied. The second argument, measurement_qubits
, is the set of qubits onto which the inverse quantum Fourier transform will be applied. The third argument, n
, is the number of measurement qubits for which the inverse quantum Fourier transform needs to be created.
from qiskit.circuit.library import QFTdef apply_iqft(given_circuit, measurement_qubits, n):
### WRITE YOUR CODE BETWEEN THESE LINES - START
# Apply inverse QFT
myQFT = QFT(num_qubits=n, approximation_degree=n, do_swaps=True,
inverse=True, insert_barriers=False, name='iqft')
# Measure
given_circuit.append(measurement_qubits,measurement_qubits)
### WRITE YOUR CODE BETWEEN THESE LINES - END
4. Putting it all together
Finally, we combine the functions to construct the quantum program that implements the quantum phase estimation algorithm.
The next lines of code put everything together.
from qiskit import QuantumCircuitdef qpe_program(n, theta):
# Create a quantum circuit on n+1 qubits (
# n measurement, 1 target)
qc = QuantumCircuit(n+1, n)
# Initialize the qubits
initialize_qubits(qc, range(n), n)
# Apply the controlled unitary operators in sequence
for x in range(n):
exponent = 2**(n-x-1)
unitary_operator_exponent(qc, x, n, theta, exponent)
# Apply the inverse quantum Fourier transform
apply_iqft(qc, range(n), n)
# Measure all qubits
qc.measure(range(n), range(n))
return qcn = 5; theta = 0.5
mycircuit = qpe_program(n, theta)
mycircuit.draw(output='text')
Thatβs it! You might find it useful to run your quantum circuit and see the measurement outcomes, as well as visualize the statevector at the end.
In order to run your quantum circuit and get the measurement outcomes, you simply need to run Qiskit
's execute
function as follows.
from qiskit import Aer, execute
simulator = Aer.get_backend('qasm_simulator')
counts = execute(mycircuit, backend=simulator, shots=1000).result().get_counts(mycircuit)
from qiskit.visualization import plot_histogram
plot_histogram(counts)
import operatorhighest_probability_outcome = max(counts.items(), key=operator.itemgetter(1))[0][::-1]measured_theta = int(highest_probability_outcome, 2)/2**nprint("Using %d qubits with theta = %.2f, measured_theta = %.2f." % (n, theta, measured_theta))
Out:
Using 5 qubits with theta = 0.50, measured_theta = 0.50.
Additional reading
- On pi day of 2020 (March 14, 2020), we added a chapter to the
Qiskit
textbook showing how to estimate the value of π using the quantum phase estimation algorithm. You can find that implementation here: https://qiskit.org/textbook/ch-demos/piday-code.html
References:
Qiskit (Global Summer School), Introduction to Quantum Computing and Quantum Hardware β Lab 3.