Quantum Fourier transform
このページはまだ翻訳されていません。英語の原文を表示しています。
For this Qiskit in Classrooms module, students must have a working Python environment with the following packages installed:
qiskitv2.1.0 or newerqiskit-ibm-runtimev0.40.1 or newerqiskit-aerv0.17.0 or newerqiskit.visualizationnumpypylatexenc
To set up and install the packages above, see the Install Qiskit guide. In order to run jobs on real quantum computers, students will need to set up an account with IBM Quantum® by following the steps in the Set up your IBM Cloud account guide.
This module was tested and used 13 seconds of QPU time. This is a good-faith estimate; your actual usage may vary.
# Uncomment and modify this line as needed to install dependencies
#!pip install 'qiskit>=2.1.0' 'qiskit-ibm-runtime>=0.40.1' 'qiskit-aer>=0.17.0' 'numpy' 'pylatexenc'
Introduction
A Fourier transform is a ubiquitous tool with applications in math, physics, signal processing, data compression, and countless other fields. A quantum version of the Fourier transform, aptly named the quantum Fourier transform, forms the basis for some of the most important quantum algorithms.
Today, after a reminder of the classical Fourier transform, we'll talk about how we implement the quantum Fourier transform on a quantum computer. Then, we'll discuss one of the applications of the quantum Fourier transform to an algorithm called the phase estimation algorithm. Quantum phase estimation is a subroutine in Shor's famous factoring algorithm, which is sometimes referred to as the "crown jewel" of quantum computing. This module builds toward another module all about Shor's algorithm, but it's also meant to be stand-alone. The quantum Fourier transform is a fascinating and useful algorithm in its own right!
The classical Fourier transform
Before we jump into the quantum Fourier transform, let's first remind ourselves of the classical version. The Fourier transform is a method of transforming from one so-called "basis" to another. You can think of two bases as different perspectives of the same problem — they are both valid ways to express a function, but one or the other might be more illuminating, depending on the problem at hand. Some examples of pairs of bases that are connected by Fourier transform are position and momentum, and time and frequency.
Let's see an example of how the Fourier transform might help us figure out what note an instrument is playing based on its audio waveform. Typically, we see the waveforms represented in the time basis — that is, the amplitude of the wave is expressed as a function of time.

We can Fourier transform this waveform to go from the time basis to the frequency basis:

In the frequency basis, we can easily see a clear peak at about 260 Hz. That's a middle C!
Now, you might have been able to determine that a middle C was being played without the use of a Fourier transform, but what if multiple notes are played at once? Then the waveform becomes more complicated when we plot it in the time basis:

But the frequency spectrum clearly identifies three peaks:

This was a C-major chord, playing the notes C, E, and G.
This kind of Fourier analysis can help us extract the frequency components of any sort of complicated signal.
Discrete Fourier transform
The Fourier transform is useful for any number of signal-processing applications. But in most of these real-world applications (including the music example we used above), we want to transform a discrete set of data points — not a continuous function. In this case, we use the discrete Fourier transform. The discrete Fourier transform (DFT) acts on a vector and maps it to the vector according to the formula:
where we take . (Note that there are other conventions that have a minus sign in the exponential, so be careful when you see the DFT in the wild.) Recall that is a periodic function, with period . So, by multiplying by this function, the Fourier transform is essentially a way to break the (discrete) function into a linear combination of its constituent periodic functions, each with period .
The quantum Fourier transform
So now, we've seen how the Fourier transform is used to represent a function as a linear combination of a new set of so-called "basis functions." Basis transformations are regularly done on qubit states, too. For example, the state of a single qubit can be expressed in the computational basis , with basis states and , or in the basis with basis states and . Both are equally valid, but one might be more natural than the other, depending on the type of problem you are trying to solve.
Qubit states can also be expressed in the Fourier basis where a state is expressed in terms of a linear combination of the Fourier basis states , rather than the usual, computational basis states, . To do this, you need to apply a quantum Fourier transform (QFT):
with as above, and is the number of basis states in your quantum system. Note that, since we're working with qubits now, qubits gives you basis states, so . Here, the basis states are written as a single number where ranges from to , but you might more typically see the basis states expressed as , , , ..., , where each binary digit represents the state of qubit 0 through , from right to left. There's an easy way to convert these binary states to a single number: simply treat them like binary numbers! So, , , , , and so on, all the way up to .
Build intuition for the Fourier basis states
So, we've just gone over what the computational basis states are and how they're ordered: they're the set of states where each qubit is either in or , and we order them from the state where all qubits are , , to the state where they are all , .
But how can we make sense of the Fourier basis states? All of the Fourier basis states are equal superpositions of all the computational basis states, but each state differs from the other in the periodicity in the components' phase. To understand this more concretely, let's take a look at the four Fourier basis states of a two-qubit system. The lowest Fourier state is one whose phase does not vary at all:
We can visualize this state by plotting the complex amplitude of each of the terms. The red line guides the eye to show you how the phase of this amplitude winds around the complex plane as a function of the computational basis state. For , the phase remains constant:

The next Fourier basis state is the one whose components' phases wind around from to just once:
And we can see this winding in the plot of complex amplitude versus computational basis state:

So, each state has a phase that is radians higher than the state before it when they're ordered in the standard way, since in this example we have four basis states (). The next basis state winds around from 0 to 2 twice:

Finally, the highest Fourier component is the one with the fastest varying phase. For our example with two qubits, it's the one whose phases wind around from 0 to three times:

In general, for an -qubit state, there will be Fourier basis states, whose frequency in phase variation ranges from constant, for , to rapidly varying for , completing windings around over the superposition of states. So, when we take a QFT of a quantum state, we're essentially doing the same basic analysis that we did for the musical waveform in the Intro. We're determining the Fourier frequency components that contribute to creating the quantum state of interest.
Try some example QFTs
Let's try to continue to build our intuition for the quantum Fourier transform by making a state in the computational basis, then seeing what happens when we apply the QFT to it. For now, we'll just treat the QFT as a black box that we apply using the QFTGate from the Qiskit circuit library. Later, we'll take a peak under the hood to see how it's implemented.
We start by loading the necessary packages and selecting a device to run our circuit on:
import numpy as np
from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
from qiskit.circuit.library import QFTGate
# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService
# Load the Runtime primitive and session
from qiskit_ibm_runtime import SamplerV2 as Sampler
service = QiskitRuntimeService()
# Use the least busy backend
# backend = service.least_busy(operational=True, simulator=False, min_num_qubits = 127)
backend = service.backend("ibm_pinguino2")
print(backend.name)
ibm_pinguino2
If you don't have time available on your account or want to use a simulator for any reason, you can run the cell below to set up a simulator that will mimic the quantum device we selected above:
# Load the backend sampler
from qiskit.primitives import BackendSamplerV2
# Load the Aer simulator and generate a noise model based on the currently-selected backend.
from qiskit_aer import AerSimulator
from qiskit_aer.noise import NoiseModel
noise_model = NoiseModel.from_backend(backend)
# Define a simulator using Aer, and use it in Sampler.
backend_sim = AerSimulator(noise_model=noise_model)
sampler_sim = BackendSamplerV2(backend=backend_sim)
# Alternatively, load a fake backend with generic properties and define a simulator.
from qiskit.providers.fake_provider import GenericBackendV2
backend_gen = GenericBackendV2(num_qubits=18)
sampler_gen = BackendSamplerV2(backend=backend_gen)
Single computational basis state
First, let's try transforming a single computational basis state. We'll start with making a random computational state:
# Step 1: Map
qubits = 4
N = 2**qubits
qc = QuantumCircuit(qubits)
# flip state of random qubits to put in a random single computational basis state
for i in range(1, qubits):
if np.random.randint(0, 2):
qc.x(i)
# make a copy of the above circuit. (to be used when we apply the QFT in next part)
qc_qft = qc.copy()
qc.measure_all()
qc.draw("mpl")
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
# Step 3: Run the job on a real quantum computer OR try fake backend
sampler = Sampler(mode=backend)
pubs = [qc_isa]
# Run the job on real quantum device
job = sampler.run(pubs, shots=1000)
res = job.result()
counts = res[0].data.meas.get_counts()
# OR Run the job on the Aer simulator with noise model from real backend
# job = sampler_sim.run([qc_isa])
# res = job.result()
# counts = res[0].data.meas.get_counts()
# Step 4: Post-Process
plot_histogram(counts)
Now, let's Fourier transform this state with QFTGate:
# Step 1: Map
qc_qft.compose(QFTGate(qubits), inplace=True)
qc_qft.measure_all()
qc_qft.draw("mpl")
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc_qft)
# Step 3: Run the job on a real quantum computer - try fake backend
sampler = Sampler(mode=backend)
pubs = [qc_isa]
# Run the job on real quantum device
job = sampler.run(pubs, shots=1000)
res = job.result()
counts = res[0].data.meas.get_counts()
# OR Run the job on the Aer simulator with noise model from real backend
# job = sampler_sim.run([qc_isa])
# res = job.result()
# counts = res[0].data.meas.get_counts()
# Step 4: Post-Process
plot_histogram(counts)
As you can see, we measure the populations of each state to be more or less equal, give or take some experimental and statistical noise. So, if you take the QFT of a single computational basis state, the result is an equal superposition of all states. If you're familiar with Fourier transforms, this probably doesn't surprise you. One basic principle that can help us build an intuitive connection between a function and its Fourier transform is that the width of a function is inversely proportional to the width of its Fourier transform. So, something that is very localized in time, for example, like a very short pulse, will require a broad range of frequencies to generate that pulse. That signal will be very broad in Fourier space.
This fact is actually related to quantum uncertainty! Heisenberg's uncertainty principle is typically stated as . So if the uncertainty in () is small, the uncertainty in momentum () must be big, and vice versa. It turns out that transforming from the position basis to the momentum basis is accomplished through a Fourier transform.
Note: Keep in mind, we're measuring populations in each of the basis states, so we're losing information about the relative phases between the various parts of the superposition. So, while the QFT of any single computational basis state will yield the same even spread in population over all the basis states, the phases won't necessarily be the same.