Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quantum-kittens
GitHub Repository: quantum-kittens/platypus
Path: blob/main/notebooks/ch-algorithms/quantum-fourier-transform.ipynb
3855 views
Kernel: Python 3

Quantum Fourier Transform

In this tutorial, we introduce the quantum fourier transform (QFT), derive the circuit, and implement it using Qiskit. We show how to run QFT on a simulator and a five qubit device.

1. Introduction

The Fourier transform occurs in many different versions throughout classical computing, in areas ranging from signal processing to data compression to complexity theory. The quantum Fourier transform (QFT) is the quantum implementation of the discrete Fourier transform over the amplitudes of a wavefunction. It is part of many quantum algorithms, most notably Shor's factoring algorithm and quantum phase estimation.

The discrete Fourier transform acts on a vector (x0,...,xN1)(x_0, ..., x_{N-1}) and maps it to the vector (y0,...,yN1)(y_0, ..., y_{N-1}) according to the formula

yk=1Nj=0N1xjωNjky_k = \frac{1}{\sqrt{N}}\sum_{j=0}^{N-1}x_j\omega_N^{jk}

where ωNjk=e2πijkN\omega_N^{jk} = e^{2\pi i \frac{jk}{N}}.

Similarly, the quantum Fourier transform acts on a quantum state X=j=0N1xjj\vert X\rangle = \sum_{j=0}^{N-1} x_j \vert j \rangle and maps it to the quantum state Y=k=0N1ykk\vert Y\rangle = \sum_{k=0}^{N-1} y_k \vert k \rangle according to the formula

yk=1Nj=0N1xjωNjky_k = \frac{1}{\sqrt{N}}\sum_{j=0}^{N-1}x_j\omega_N^{jk}

with ωNjk\omega_N^{jk} defined as above. Note that only the amplitudes of the state were affected by this transformation.

This can also be expressed as the map:

j1Nk=0N1ωNjkk\vert j \rangle \mapsto \frac{1}{\sqrt{N}}\sum_{k=0}^{N-1}\omega_N^{jk} \vert k \rangle

Or the unitary matrix:

UQFT=1Nj=0N1k=0N1ωNjkkjU_{QFT} = \frac{1}{\sqrt{N}} \sum_{j=0}^{N-1} \sum_{k=0}^{N-1} \omega_N^{jk} \vert k \rangle \langle j \vert

2. Intuition

The quantum Fourier transform (QFT) transforms between two bases, the computational (Z) basis, and the Fourier basis. The H-gate is the single-qubit QFT, and it transforms between the Z-basis states 0|0\rangle and 1|1\rangle to the X-basis states +|{+}\rangle and |{-}\rangle. In the same way, all multi-qubit states in the computational basis have corresponding states in the Fourier basis. The QFT is simply the function that transforms between these bases.

State in Computational BasisQFTState in Fourier Basis|\text{State in Computational Basis}\rangle \quad \xrightarrow[]{\text{QFT}} \quad |\text{State in Fourier Basis}\rangleQFTx=x~\text{QFT}|x\rangle = |\widetilde{x}\rangle

(We often note states in the Fourier basis using the tilde (~)).

2.1 Counting in the Fourier basis:

In the computational basis, we store numbers in binary using the states 0|0\rangle and 1|1\rangle:

zbasiscounting

Note the frequency with which the different qubits change; the leftmost qubit flips with every increment in the number, the next with every 2 increments, the third with every 4 increments, and so on. In the Fourier basis, we store numbers using different rotations around the Z-axis:

fbasiscounting

The number we want to store dictates the angle at which each qubit is rotated around the Z-axis. In the state 0~|\widetilde{0}\rangle, all qubits are in the state +|{+}\rangle. As seen in the example above, to encode the state 5~|\widetilde{5}\rangle on 4 qubits, we rotated the leftmost qubit by 52n=516\tfrac{5}{2^n} = \tfrac{5}{16} full turns (516×2π\tfrac{5}{16}\times 2\pi radians). The next qubit is turned double this (1016×2π\tfrac{10}{16}\times 2\pi radians, or 10/1610/16 full turns), this angle is then doubled for the qubit after, and so on.

Again, note the frequency with which each qubit changes. The leftmost qubit (qubit 0) in this case has the lowest frequency, and the rightmost the highest.

3. Example 1: 1-qubit QFT

Consider how the QFT operator as defined above acts on a single qubit state ψ=α0+β1\vert\psi\rangle = \alpha \vert 0 \rangle + \beta \vert 1 \rangle. In this case, x0=αx_0 = \alpha, x1=βx_1 = \beta, and N=2N = 2. Then,

y0=12(αexp(2πi0×02)+βexp(2πi1×02))=12(α+β)y_0 = \frac{1}{\sqrt{2}}\left( \alpha \exp\left(2\pi i\frac{0\times0}{2}\right) + \beta \exp\left(2\pi i\frac{1\times0}{2}\right) \right) = \frac{1}{\sqrt{2}}\left(\alpha + \beta\right)

and

y1=12(αexp(2πi0×12)+βexp(2πi1×12))=12(αβ)y_1 = \frac{1}{\sqrt{2}}\left( \alpha \exp\left(2\pi i\frac{0\times1}{2}\right) + \beta \exp\left(2\pi i\frac{1\times1}{2}\right) \right) = \frac{1}{\sqrt{2}}\left(\alpha - \beta\right)

such that the final result is the state

UQFTψ=12(α+β)0+12(αβ)1U_{QFT}\vert\psi\rangle = \frac{1}{\sqrt{2}}(\alpha + \beta) \vert 0 \rangle + \frac{1}{\sqrt{2}}(\alpha - \beta) \vert 1 \rangle

This operation is exactly the result of applying the Hadamard operator (HH) on the qubit:

H=12[1111]H = \frac{1}{\sqrt{2}}\begin{bmatrix} 1 & 1 \\ 1 & -1 \end{bmatrix}

If we apply the HH operator to the state ψ=α0+β1\vert\psi\rangle = \alpha \vert 0 \rangle + \beta \vert 1 \rangle, we obtain the new state:

12(α+β)0+12(αβ)1α~0+β~1\frac{1}{\sqrt{2}}(\alpha + \beta) \vert 0 \rangle + \frac{1}{\sqrt{2}}(\alpha - \beta) \vert 1 \rangle \equiv \tilde{\alpha}\vert 0 \rangle + \tilde{\beta}\vert 1 \rangle

Notice how the Hadamard gate performs the discrete Fourier transform for N=2N = 2 on the amplitudes of the state.

4. The Quantum Fourier transform

So what does the quantum Fourier transform look like for larger NN? Let's derive a transformation for N=2nN=2^n, QFTNQFT_N acting on the state x=x1xn\vert x \rangle = \vert x_1\ldots x_n \rangle where x1x_1 is the most significant bit. This maths is here for those that find it useful, if you struggle with it then don’t worry; as long as you understand the intuition in section 2 then you can continue straight to the next section.

QFTNx=1Ny=0N1ωNxyy=1Ny=0N1e2πixy/2ny sinceωNxy=e2πixyNandN=2n=1Ny=0N1e2πi(k=1nyk/2k)xy1ynrewriting in fractional binary notationy=y1yn,y/2n=k=1nyk/2k=1Ny=0N1k=1ne2πixyk/2ky1ynafter expanding the exponential of a sum to a product of exponentials=1Nk=1n(0+e2πix/2k1)after rearranging the sum and products, and expandingy=0N1=y1=01y2=01yn=01=1N(0+e2πi2x1)(0+e2πi22x1)(0+e2πi2n1x1)(0+e2πi2nx1)\begin{aligned} QFT_N\vert x \rangle & = \frac{1}{\sqrt{N}} \sum_{y=0}^{N-1}\omega_N^{xy} \vert y \rangle \\ & = \frac{1}{\sqrt{N}} \sum_{y=0}^{N-1} e^{2 \pi i xy / 2^n} \vert y \rangle ~\text{since}\: \omega_N^{xy} = e^{2\pi i \frac{xy}{N}} \:\text{and}\: N = 2^n \\ & = \frac{1}{\sqrt{N}} \sum_{y=0}^{N-1} e^{2 \pi i \left(\sum_{k=1}^n y_k/2^k\right) x} \vert y_1 \ldots y_n \rangle \:\text{rewriting in fractional binary notation}\: y = y_1\ldots y_n, y/2^n = \sum_{k=1}^n y_k/2^k \\ & = \frac{1}{\sqrt{N}} \sum_{y=0}^{N-1} \prod_{k=1}^n e^{2 \pi i x y_k/2^k } \vert y_1 \ldots y_n \rangle \:\text{after expanding the exponential of a sum to a product of exponentials} \\ & = \frac{1}{\sqrt{N}} \bigotimes_{k=1}^n \left(\vert0\rangle + e^{2 \pi i x /2^k } \vert1\rangle \right) \:\text{after rearranging the sum and products, and expanding} \sum_{y=0}^{N-1} = \sum_{y_1=0}^{1}\sum_{y_2=0}^{1}\ldots\sum_{y_n=0}^{1} \\ & = \frac{1}{\sqrt{N}} \left(\vert0\rangle + e^{\frac{2\pi i}{2}x} \vert1\rangle\right) \otimes \left(\vert0\rangle + e^{\frac{2\pi i}{2^2}x} \vert1\rangle\right) \otimes \ldots \otimes \left(\vert0\rangle + e^{\frac{2\pi i}{2^{n-1}}x} \vert1\rangle\right) \otimes \left(\vert0\rangle + e^{\frac{2\pi i}{2^n}x} \vert1\rangle\right) \end{aligned}

This is a mathematical description of the animation we saw in the intuition section:

fbasiscounting

5. The Circuit that Implements the QFT

The circuit that implements QFT makes use of two gates. The first one is a single-qubit Hadamard gate, HH, that you already know. From the discussion in Example 1 above, you have already seen that the action of HH on the single-qubit state xk\vert x_k\rangle is

Hxk=12(0+exp(2πi2xk)1)H\vert x_k \rangle = \frac{1}{\sqrt{2}}\left(\vert0\rangle + \exp\left(\frac{2\pi i}{2}x_k\right)\vert1\rangle\right)

The second is a two-qubit controlled rotation CROTkCROT_k given in block-diagonal form as

CROTk=[I00UROTk]CROT_k = \left[\begin{matrix} I&0\\ 0&UROT_k\\ \end{matrix}\right]

where

UROTk=[100exp(2πi2k)]UROT_k = \left[\begin{matrix} 1&0\\ 0&\exp\left(\frac{2\pi i}{2^k}\right)\\ \end{matrix}\right]

The action of CROTkCROT_k on a two-qubit state xlxj\vert x_l x_j\rangle where the first qubit is the control and the second is the target is given by

CROTk0xj=0xjCROT_k\vert 0x_j\rangle = \vert 0x_j\rangle

and

CROTk1xj=exp(2πi2kxj)1xjCROT_k\vert 1x_j\rangle = \exp\left( \frac{2\pi i}{2^k}x_j \right)\vert 1x_j\rangle

Given these two gates, a circuit that implements an n-qubit QFT is shown below.

image1

The circuit operates as follows. We start with an n-qubit input state x1x2xn\vert x_1x_2\ldots x_n\rangle.

  1. After the first Hadamard gate on qubit 1, the state is transformed from the input state to
H1x1x2xn=12[0+exp(2πi2x1)1]x2x3xnH_1\vert x_1x_2\ldots x_n\rangle = \frac{1}{\sqrt{2}} \left[\vert0\rangle + \exp\left(\frac{2\pi i}{2}x_1\right)\vert1\rangle\right] \otimes \vert x_2x_3\ldots x_n\rangle
  • After the UROT2UROT_2 gate on qubit 1 controlled by qubit 2, the state is transformed to
  • 12[0+exp(2πi22x2+2πi2x1)1]x2x3xn\frac{1}{\sqrt{2}} \left[\vert0\rangle + \exp\left(\frac{2\pi i}{2^2}x_2 + \frac{2\pi i}{2}x_1\right)\vert1\rangle\right] \otimes \vert x_2x_3\ldots x_n\rangle
  • After the application of the last UROTnUROT_n gate on qubit 1 controlled by qubit nn, the state becomes
  • 12[0+exp(2πi2nxn+2πi2n1xn1++2πi22x2+2πi2x1)1]x2x3xn\frac{1}{\sqrt{2}} \left[\vert0\rangle + \exp\left( \frac{2\pi i}{2^n}x_n + \frac{2\pi i}{2^{n-1}}x_{n-1} + \ldots + \frac{2\pi i}{2^2}x_2 + \frac{2\pi i}{2}x_1 \right) \vert1\rangle\right] \otimes \vert x_2x_3\ldots x_n\rangle

    Noting that

    x=2n1x1+2n2x2++21xn1+20xnx = 2^{n-1}x_1 + 2^{n-2}x_2 + \ldots + 2^1x_{n-1} + 2^0x_n

    we can write the above state as

    12[0+exp(2πi2nx)1]x2x3xn\frac{1}{\sqrt{2}} \left[\vert0\rangle + \exp\left( \frac{2\pi i}{2^n}x \right) \vert1\rangle\right] \otimes \vert x_2x_3\ldots x_n\rangle
  • After the application of a similar sequence of gates for qubits 2n2\ldots n, we find the final state to be:
  • 12[0+exp(2πi2nx)1]12[0+exp(2πi2n1x)1]12[0+exp(2πi22x)1]12[0+exp(2πi21x)1]\frac{1}{\sqrt{2}} \left[\vert0\rangle + \exp\left( \frac{2\pi i}{2^n}x \right) \vert1\rangle\right] \otimes \frac{1}{\sqrt{2}} \left[\vert0\rangle + \exp\left( \frac{2\pi i}{2^{n-1}}x \right) \vert1\rangle\right] \otimes \ldots \otimes \frac{1}{\sqrt{2}} \left[\vert0\rangle + \exp\left( \frac{2\pi i}{2^{2}}x \right) \vert1\rangle\right] \otimes \frac{1}{\sqrt{2}} \left[\vert0\rangle + \exp\left( \frac{2\pi i}{2^{1}}x \right) \vert1\rangle\right]

    which is exactly the QFT of the input state as derived above with the caveat that the order of the qubits is reversed in the output state.

    6. Example 2: 3-qubit QFT

    The steps to creating the circuit for y3y2y1=QFT8x3x2x1\vert y_3y_2y_1\rangle = QFT_8\vert x_3x_2x_1\rangle would be:

    1. Apply a Hadamard gate to x1\vert x_1 \rangle
    ψ1=x3x212[0+exp(2πi2x1)1]|\psi_1\rangle = \vert x_3\rangle \otimes \vert x_2\rangle \otimes \frac{1}{\sqrt{2}} \left[ \vert0\rangle + \exp\left(\frac{2\pi i}{2}x_1\right) \vert1\rangle\right]
  • Apply a UROT2UROT_2 gate to x1\vert x_1\rangle depending on x2\vert x_2\rangle
  • ψ2=x3x212[0+exp(2πi22x2+2πi2x1)1]|\psi_2\rangle = \vert x_3\rangle \otimes \vert x_2\rangle \otimes \frac{1}{\sqrt{2}} \left[ \vert0\rangle + \exp\left( \frac{2\pi i}{2^2}x_2 + \frac{2\pi i}{2}x_1 \right) \vert1\rangle\right]
  • Apply a UROT3UROT_3 gate to x1\vert x_1\rangle depending on x3\vert x_3\rangle
  • ψ3=x3x212[0+exp(2πi23x3+2πi22x2+2πi2x1)1]|\psi_3\rangle = \vert x_3\rangle \otimes \vert x_2\rangle \otimes \frac{1}{\sqrt{2}} \left[ \vert0\rangle + \exp\left( \frac{2\pi i}{2^3}x_3 + \frac{2\pi i}{2^2}x_2 + \frac{2\pi i}{2}x_1 \right) \vert1\rangle\right]
  • Apply a Hadamard gate to x2\vert x_2 \rangle
  • ψ4=x312[0+exp(2πi2x2)1]12[0+exp(2πi23x3+2πi22x2+2πi2x1)1]|\psi_4\rangle = \vert x_3\rangle \otimes \frac{1}{\sqrt{2}} \left[ \vert0\rangle + \exp\left( \frac{2\pi i}{2}x_2 \right) \vert1\rangle\right] \otimes \frac{1}{\sqrt{2}} \left[ \vert0\rangle + \exp\left( \frac{2\pi i}{2^3}x_3 + \frac{2\pi i}{2^2}x_2 + \frac{2\pi i}{2}x_1 \right) \vert1\rangle\right]
  • Apply a UROT2UROT_2 gate to x2\vert x_2\rangle depending on x3\vert x_3\rangle
  • ψ5=x312[0+exp(2πi22x3+2πi2x2)1]12[0+exp(2πi23x3+2πi22x2+2πi2x1)1]|\psi_5\rangle = \vert x_3\rangle \otimes \frac{1}{\sqrt{2}} \left[ \vert0\rangle + \exp\left( \frac{2\pi i}{2^2}x_3 + \frac{2\pi i}{2}x_2 \right) \vert1\rangle\right] \otimes \frac{1}{\sqrt{2}} \left[ \vert0\rangle + \exp\left( \frac{2\pi i}{2^3}x_3 + \frac{2\pi i}{2^2}x_2 + \frac{2\pi i}{2}x_1 \right) \vert1\rangle\right]
  • Apply a Hadamard gate to x3\vert x_3\rangle
  • ψ6=12[0+exp(2πi2x3)1]12[0+exp(2πi22x3+2πi2x2)1]12[0+exp(2πi23x3+2πi22x2+2πi2x1)1]|\psi_6\rangle = \frac{1}{\sqrt{2}} \left[ \vert0\rangle + \exp\left( \frac{2\pi i}{2}x_3 \right) \vert1\rangle\right] \otimes \frac{1}{\sqrt{2}} \left[ \vert0\rangle + \exp\left( \frac{2\pi i}{2^2}x_3 + \frac{2\pi i}{2}x_2 \right) \vert1\rangle\right] \otimes \frac{1}{\sqrt{2}} \left[ \vert0\rangle + \exp\left( \frac{2\pi i}{2^3}x_3 + \frac{2\pi i}{2^2}x_2 + \frac{2\pi i}{2}x_1 \right) \vert1\rangle\right]
  • Keep in mind the reverse order of the output state relative to the desired QFT. Therefore, we must reverse the order of the qubits (in this case swap y1y_1 and y3y_3).
  • 7. Some Notes About the Form of the QFT Circuit

    The example above demonstrates a very useful form of the QFT for N=2nN=2^n. Note that only the last qubit depends on the values of all the other input qubits and each further bit depends less and less on the input qubits. This becomes important in physical implementations of the QFT, where nearest-neighbor couplings are easier to achieve than distant couplings between qubits.

    Additionally, as the QFT circuit becomes large, an increasing amount of time is spent doing increasingly slight rotations. It turns out that we can ignore rotations below a certain threshold and still get decent results, this is known as the approximate QFT. This is also important in physical implementations, as reducing the number of operations can greatly reduce decoherence and potential gate errors.

    8. Qiskit Implementation

    In Qiskit, the implementation of the CROTCROT gate used in the discussion above is a controlled phase rotation gate. This gate is defined in OpenQASM as

    CP(θ)=[100001000010000eiθ]CP(\theta) = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & e^{i\theta}\end{bmatrix}

    Hence, the mapping from the CROTkCROT_k gate in the discussion above into the CPCP gate is found from the equation

    θ=2π/2k=π/2k1\theta = 2\pi/2^k = \pi/2^{k-1}

    8.1 Example on 3 Qubits

    import numpy as np from numpy import pi # importing Qiskit from qiskit import QuantumCircuit, transpile, Aer, IBMQ from qiskit.providers.ibmq import least_busy from qiskit.tools.monitor import job_monitor from qiskit.visualization import plot_histogram, plot_bloch_multivector

    It is useful to work out the relevant code for the 3-qubit case before generalizing to the nn-qubit case. First, we must define our quantum circuit:

    qc = QuantumCircuit(3)

    Note: Remember that Qiskit's least significant bit has the lowest index (0), thus the circuit will be mirrored through the horizontal in relation to the image in section 5. First, we apply a H-gate to qubit 2 :

    qc.h(2) qc.draw()
    Image in a Jupyter notebook

    Next, we want to turn this an extra quarter turn if qubit 1 is in the state 1|1\rangle:

    qc.cp(pi/2, 1, 2) # CROT from qubit 1 to qubit 2 qc.draw()
    Image in a Jupyter notebook

    And another eighth turn if the least significant qubit (0) is 1|1\rangle:

    qc.cp(pi/4, 0, 2) # CROT from qubit 2 to qubit 0 qc.draw()
    Image in a Jupyter notebook

    With that qubit taken care of, we can now ignore it and repeat the process, using the same logic for qubits 0 and 1:

    qc.h(1) qc.cp(pi/2, 0, 1) # CROT from qubit 0 to qubit 1 qc.h(0) qc.draw()
    Image in a Jupyter notebook

    Finally we must swap the qubits 0 and 2 to complete the QFT:

    qc.swap(0,2) qc.draw()
    Image in a Jupyter notebook

    8.2 General QFT Function

    We will now create a general circuit for the QFT in Qiskit. Creating large general circuits like this is really where Qiskit shines.

    It is easier to build a circuit that implements the QFT with the qubits upside down, then swap them afterwards; we will start off by creating the function that rotates our qubits correctly. Let’s start as we did with the 3 qubit example, by correctly rotating the most significant qubit (the qubit with the highest index):

    def qft_rotations(circuit, n): if n == 0: # Exit function if circuit is empty return circuit n -= 1 # Indexes start from 0 circuit.h(n) # Apply the H-gate to the most significant qubit for qubit in range(n): # For each less significant qubit, we need to do a # smaller-angled controlled rotation: circuit.cp(pi/2**(n-qubit), qubit, n)

    Let’s see how this looks:

    qc = QuantumCircuit(4) qft_rotations(qc,4) qc.draw()
    Image in a Jupyter notebook

    We can use the widget below to see how this circuit scales with the number of qubits in our circuit:

    from qiskit_textbook.widgets import scalable_circuit scalable_circuit(qft_rotations)

    Great! This is the first part of our QFT. Now we have correctly rotated the most significant qubit, we need to correctly rotate the second most significant qubit. Then we must deal with the third most significant, and so on. But why write more code? When we get to the end of our qft_rotations() function, we can use the same code to repeat the process on the next n-1 qubits:

    def qft_rotations(circuit, n): """Performs qft on the first n qubits in circuit (without swaps)""" if n == 0: return circuit n -= 1 circuit.h(n) for qubit in range(n): circuit.cp(pi/2**(n-qubit), qubit, n) # At the end of our function, we call the same function again on # the next qubits (we reduced n by one earlier in the function) qft_rotations(circuit, n) # Let's see how it looks: qc = QuantumCircuit(4) qft_rotations(qc,4) qc.draw()
    Image in a Jupyter notebook

    That was easy! Process in which a function calls itself directly or indirectly is called recursion. It can greatly simplify code. We can again see how this scales using the widget below:

    scalable_circuit(qft_rotations)

    Finally, we need to add the swaps at the end of the QFT function to match the definition of the QFT. We will combine this into the final function qft():

    def swap_registers(circuit, n): for qubit in range(n//2): circuit.swap(qubit, n-qubit-1) return circuit def qft(circuit, n): """QFT on the first n qubits in circuit""" qft_rotations(circuit, n) swap_registers(circuit, n) return circuit # Let's see how it looks: qc = QuantumCircuit(4) qft(qc,4) qc.draw()
    Image in a Jupyter notebook

    This is the generalised circuit for the quantum Fourier transform. We can again see how this scales using the widget below:

    scalable_circuit(qft)

    We now want to demonstrate this circuit works correctly. To do this we must first encode a number in the computational basis. We can see the number 5 in binary is 101:

    bin(5)
    '0b101'

    (The 0b just reminds us this is a binary number). Let's encode this into our qubits:

    # Create the circuit qc = QuantumCircuit(3) # Encode the state 5 qc.x(0) qc.x(2) qc.draw()
    Image in a Jupyter notebook

    And let's check the qubit's states using the aer simulator:

    sim = Aer.get_backend("aer_simulator") qc_init = qc.copy() qc_init.save_statevector() statevector = sim.run(qc_init).result().get_statevector() plot_bloch_multivector(statevector)
    /usr/local/anaconda3/envs/terra-unstable/lib/python3.9/site-packages/qiskit/visualization/bloch.py:69: MatplotlibDeprecationWarning: The M attribute was deprecated in Matplotlib 3.4 and will be removed two minor releases later. Use self.axes.M instead. x_s, y_s, _ = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M)
    Image in a Jupyter notebook

    Finally, let's use our QFT function and view the final state of our qubits:

    qft(qc,3) qc.draw()
    Image in a Jupyter notebook
    qc.save_statevector() statevector = sim.run(qc).result().get_statevector() plot_bloch_multivector(statevector)
    /usr/local/anaconda3/envs/terra-unstable/lib/python3.9/site-packages/qiskit/visualization/bloch.py:69: MatplotlibDeprecationWarning: The M attribute was deprecated in Matplotlib 3.4 and will be removed two minor releases later. Use self.axes.M instead. x_s, y_s, _ = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M)
    Image in a Jupyter notebook

    We can see out QFT function has worked correctly. Compared the state 0~=+++|\widetilde{0}\rangle = |{+}{+}{+}\rangle, Qubit 0 has been rotated by 58\tfrac{5}{8} of a full turn, qubit 1 by 108\tfrac{10}{8} full turns (equivalent to 14\tfrac{1}{4} of a full turn), and qubit 2 by 208\tfrac{20}{8} full turns (equivalent to 12\tfrac{1}{2} of a full turn).

    8.3 Running QFT on a Real Quantum Device

    If we tried running the circuit at the end of section 8.2 on a real device, the results would be completely random, since all qubits are in equal superposition of 0|0\rangle and 1|1\rangle. If we want to demonstrate and investigate the QFT working on real hardware, we can instead create the state 5~|\widetilde{5}\rangle seen at the end of section 8.2, run the QFT in reverse, and verify the output is the state 5|5\rangle as expected.

    Firstly, let’s use Qiskit to easily reverse our QFT operation:

    def inverse_qft(circuit, n): """Does the inverse QFT on the first n qubits in circuit""" # First we create a QFT circuit of the correct size: qft_circ = qft(QuantumCircuit(n), n) # Then we take the inverse of this circuit invqft_circ = qft_circ.inverse() # And add it to the first n qubits in our existing circuit circuit.append(invqft_circ, circuit.qubits[:n]) return circuit.decompose() # .decompose() allows us to see the individual gates

    Now let's put our qubits in the state 5~|\widetilde{5}\rangle:

    nqubits = 3 number = 5 qc = QuantumCircuit(nqubits) for qubit in range(nqubits): qc.h(qubit) qc.p(number*pi/4,0) qc.p(number*pi/2,1) qc.p(number*pi,2) qc.draw()
    Image in a Jupyter notebook

    And we can see this does indeed result in the Fourier state 5~|\widetilde{5}\rangle:

    qc_init = qc.copy() qc_init.save_statevector() sim = Aer.get_backend("aer_simulator") statevector = sim.run(qc_init).result().get_statevector() plot_bloch_multivector(statevector)
    /usr/local/anaconda3/envs/terra-unstable/lib/python3.9/site-packages/qiskit/visualization/bloch.py:69: MatplotlibDeprecationWarning: The M attribute was deprecated in Matplotlib 3.4 and will be removed two minor releases later. Use self.axes.M instead. x_s, y_s, _ = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M)
    Image in a Jupyter notebook

    Finally, let's apply our inverse QFT:

    qc = inverse_qft(qc, nqubits) qc.measure_all() qc.draw()
    Image in a Jupyter notebook
    # Load our saved IBMQ accounts and get the least busy backend device with less than or equal to nqubits IBMQ.load_account() provider = IBMQ.get_provider(hub='ibm-q') backend = least_busy(provider.backends(filters=lambda x: x.configuration().n_qubits >= nqubits and not x.configuration().simulator and x.status().operational==True)) print("least busy backend: ", backend)
    least busy backend: ibmq_bogota
    shots = 2048 transpiled_qc = transpile(qc, backend, optimization_level=3) job = backend.run(transpiled_qc, shots=shots) job_monitor(job)
    Job Status: job has successfully run
    counts = job.result().get_counts() plot_histogram(counts)
    Image in a Jupyter notebook

    We (hopefully) see that the highest probability outcome is 101101.

    9. Problems

    1. The above implementation of QFT was tested by preparing the Fourier state 5~|\widetilde{5}\rangle for which QFT5~=101\text{QFT}^{\dagger}|\widetilde{5}\rangle = |101\rangle. Try to find the state a|a\rangle such that QFTa=100\text{QFT}^{\dagger}|a\rangle = |100\rangle.

    2. Find the state b|b\rangle such that QFTb=011\text{QFT}^{\dagger}|b\rangle = |011\rangle.

    3. Try to write the QFT function without recursion. Use Qiskit's unitary simulator to verify your results.

    10. References

    1. M. Nielsen and I. Chuang, Quantum Computation and Quantum Information, Cambridge Series on Information and the Natural Sciences (Cambridge University Press, Cambridge, 2000).

    import qiskit.tools.jupyter %qiskit_version_table
    /usr/local/anaconda3/envs/terra-unstable/lib/python3.9/site-packages/qiskit/aqua/__init__.py:86: DeprecationWarning: The package qiskit.aqua is deprecated. It was moved/refactored to qiskit-terra For more information see <https://github.com/Qiskit/qiskit-aqua/blob/main/README.md#migration-guide> warn_package('aqua', 'qiskit-terra')