This page was generated from the notebook examples/notebooks/4_Quantum_Fourier_Transform.ipynb.

Quantum Fourier Transform

In this notebook we present how to extend the QCircuit to define a circuit representing the Quantum Fourier Transform (QFT) for \(n\)-qubits.

For a reminder about the QFT, one can check this medium article.

We first import the required objects.

[2]:
from mpqp.gates import *
from mpqp.execution.result import Result
from mpqp import QCircuit, Barrier
from mpqp.execution import run, IBMDevice
from math import floor
import numpy as np

We define the QFT class, extending from QCircuit, taking into parameter the number of qubits of the circuit, and a boolean indicating if the inverse of the QFT is needed.

[3]:
class QFT(QCircuit):

    def __init__(self,n_qubits,inverse=False):

        super().__init__(n_qubits, nb_cbits=n_qubits)
        self.inverse = inverse
        self._build()

    def _build(self):
        for j in range(self.nb_qubits):
            self.add(H(j))
            self.add([CRk(i+1, i, j) for i in range(j+1, self.nb_qubits)])
            self.add(Barrier())
        self.add([SWAP(i, self.nb_qubits-1-i) for i in range(int(floor(self.nb_qubits / 2)))])

        if self.inverse == True:
           self.inverse()

As a matter, we generate and print the Quantum Fourier Transform for 5-qubit systems.

[4]:
qft_5 = QFT(n_qubits=5)
print(qft_5)
     ┌───┐                                      ░                        »
q_0: ┤ H ├─■────────■────────■────────■─────────░────────────────────────»
     └───┘ │P(π/2)  │        │        │         ░ ┌───┐                  »
q_1: ──────■────────┼────────┼────────┼─────────░─┤ H ├─■────────■───────»
                    │P(π/4)  │        │         ░ └───┘ │P(π/4)  │       »
q_2: ───────────────■────────┼────────┼─────────░───────■────────┼───────»
                             │P(π/8)  │         ░                │P(π/8) »
q_3: ────────────────────────■────────┼─────────░────────────────■───────»
                                      │P(π/16)  ░                        »
q_4: ─────────────────────────────────■─────────░────────────────────────»
                                                ░                        »
c: 5/════════════════════════════════════════════════════════════════════»
                                                                         »
«                ░                          ░                 ░       ░
«q_0: ───────────░──────────────────────────░─────────────────░───────░──X────
«                ░                          ░                 ░       ░  │
«q_1: ─■─────────░──────────────────────────░─────────────────░───────░──┼──X─
«      │         ░ ┌───┐                    ░                 ░       ░  │  │
«q_2: ─┼─────────░─┤ H ├─■────────■─────────░─────────────────░───────░──┼──┼─
«      │         ░ └───┘ │P(π/8)  │         ░ ┌───┐           ░       ░  │  │
«q_3: ─┼─────────░───────■────────┼─────────░─┤ H ├─■─────────░───────░──┼──X─
«      │P(π/16)  ░                │P(π/16)  ░ └───┘ │P(π/16)  ░ ┌───┐ ░  │
«q_4: ─■─────────░────────────────■─────────░───────■─────────░─┤ H ├─░──X────
«                ░                          ░                 ░ └───┘ ░
«c: 5/════════════════════════════════════════════════════════════════════════
«

When applied on the basis state \(|0\rangle^{\otimes n}\), we retrieve as expected the fully-parallelized state \(|+\rangle^{\otimes n}\).

[5]:
result = run(qft_5, IBMDevice.AER_SIMULATOR_STATEVECTOR)
if isinstance(result, Result):
    print(result.amplitudes)
[0.1767767+0.j 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j
 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j
 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j
 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j
 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j
 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j 0.1767767+0.j
 0.1767767+0.j 0.1767767+0.j]

We then give a couple of example of application of the QFT, when appended at the end of a circuit defining a state.

[6]:
qc1 = QCircuit([H(1)]) + QFT(2)

print(qc1)

result1 = run(qc1, IBMDevice.AER_SIMULATOR_STATEVECTOR)
if isinstance(result1, Result):
    print(result1.amplitudes)
     ┌───┐          ░       ░
q_0: ┤ H ├─■────────░───────░──X─
     ├───┤ │P(π/2)  ░ ┌───┐ ░  │
q_1: ┤ H ├─■────────░─┤ H ├─░──X─
     └───┘          ░ └───┘ ░
[0.70710678-4.32978028e-17j 0.35355339+3.53553391e-01j
 0.        +4.32978028e-17j 0.35355339-3.53553391e-01j]
[7]:
W_circuit = QCircuit([Ry(2*np.arccos(1/np.sqrt(3)),0),Ry(-np.pi/4,1),CZ(0,1),Ry(np.pi/4,1),CNOT(1,2),CNOT(0,1),X(0)])

qc2 = W_circuit + QFT(3)
print(qc2)

result2 = run(qc2, IBMDevice.AER_SIMULATOR_STATEVECTOR)
if isinstance(result2, Result):
    print(result2.amplitudes)
     ┌────────────┐                        ┌───┐┌───┐                   ░      »
q_0: ┤ Ry(1.9106) ├─■───────────────────■──┤ X ├┤ H ├─■────────■────────░──────»
     └┬──────────┬┘ │ ┌─────────┐     ┌─┴─┐└───┘└───┘ │P(π/2)  │        ░ ┌───┐»
q_1: ─┤ Ry(-π/4) ├──■─┤ Ry(π/4) ├──■──┤ X ├───────────■────────┼────────░─┤ H ├»
      └──────────┘    └─────────┘┌─┴─┐└───┘                    │P(π/4)  ░ └───┘»
q_2: ────────────────────────────┤ X ├─────────────────────────■────────░──────»
                                 └───┘                                  ░      »
«               ░       ░
«q_0: ──────────░───────░──X─
«               ░       ░  │
«q_1: ─■────────░───────░──┼─
«      │P(π/4)  ░ ┌───┐ ░  │
«q_2: ─■────────░─┤ H ├─░──X─
«               ░ └───┘ ░
[ 0.61237244-7.49939943e-17j -0.05978658+3.48461713e-01j
  0.14433757+1.44337567e-01j -0.20412415+4.09474745e-17j
  0.20412415-2.49979981e-17j -0.34846171+5.97865779e-02j
 -0.14433757-1.44337567e-01j -0.20412415-4.08248290e-01j]