# Quantum Fourier Transform

Hey I am new to PennyLanne and Quantum Computing. I am trying to implement quantum Fourier transform on using PennyLane. The following code was adapted from Qiskit at: https://qiskit.org/textbook/ch-algorithms/quantum-fourier-transform.html

My goal is the replicate the code for QFT in this link using PennyLane. I got error when I tried, I am not sure what I am missing. Below is the code:

import pennylane as qml
from pennylane import numpy as np

n_register = 3
dev = qml.device(‘default.qubit’, wires=(n_register), analytic=True)

@qml.qnode(dev)

def qft_rotations(qml, n):
“”“Performs qft on the first n qubits in circuit (without swaps)”""
n = int(n)
if n == 0:
return qml
n -= 1
for qubit in range(n):
qml.CRZ(pi/2**(n-qubit), wires=[qubit, n])
qft_rotations(n)

def swap_registers(qml, n):
for qubit in range(n//2):
qml.SWAP(wires = [qubit, n-qubit-1])
return qml

def qft(qml, n):
“”“QFT on the first n qubits in circuit”""
qft_rotations(qml, n)
swap_registers(qml, n)
return qml

result = qft(qml,3)
print(result.draw())

Hi @gidu — Welcome to the forum.

Before being able to help, could I ask you to

• Adjust the formatting of the code (e.g., enclosing strings with `""` and `''` instead of `““` , double-checking that imports are correct and the code snippet can be executed independently)
• Place code into a highlighted code blocks so that the code renders and indentation is correct

Overall this helps with quickly recreating the case that is shared and also helps other users easily get up to speed with parts of the solution.

Thanks!

Thanks you very much @Nicolas_Quesada, here is the edited version:

Hey I am new to PennyLanne and Quantum Computing. I am trying to implement quantum Fourier transform on using PennyLane. The following code was adapted from Qiskit at: https://qiskit.org/textbook/ch-algorithms/quantum-fourier-transform.html

My goal is the replicate the code for QFT in this link using PennyLane. I got error when I tried, I am not sure what I am missing. Below is the code:

``````import pennylane as qml
from pennylane import numpy as np

n_register = 3
dev = qml.device('default.qubit', wires=(n_register), analytic=True)

@qml.qnode(dev)

def qft_rotations(qml, n):
"""Performs qft on the first n qubits in circuit (without swaps)"""
n = int(n)
if n == 0:
return qml
n -= 1
for qubit in range(n):
qml.CRZ(pi/2**(n-qubit), wires=[qubit, n])
qft_rotations(n)

def swap_registers(qml, n):
for qubit in range(n//2):
qml.SWAP(wires = [qubit, n-qubit-1])
return qml

def qft(qml, n):
"""QFT on the first n qubits in circuit"""
qft_rotations(qml, n)
swap_registers(qml, n)
return qml

result = qft(qml,3)
print(result.draw())
``````

Thanks @gidu. Could you also tell us which error are you getting?

From looking at you code, one problem is that you are importing pennylane as qml but you are also using this name for the input variable of one of your functions.

Hello @Nicolas_Quesada, even without qml in the input argument, when I run the function: `qft_rotations(3)` :

``````import pennylane as qml
from pennylane import numpy as np

n_register = 3
dev = qml.device('default.qubit', wires=(n_register), analytic=True)

@qml.qnode(dev)

def qft_rotations(n):
"""Performs qft on the first n qubits in circuit (without swaps)"""
n = int(n)
if n == 0:
return qml
n -= 1
for qubit in range(n):
qml.CRZ(pi/2**(n-qubit), wires=[qubit, n])
qft_rotations(n)

``````

I got the following error:

``````---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-f25d837ec086> in <module>()
----> 1 qft_rotations(3)

67             self.set_trainable(args)
68             args = autograd.builtins.tuple(args)  # pylint: disable=no-member
---> 69             return self.evaluate(args, kwargs)
70
71         @staticmethod

46             return new_box(ans, trace, node)
47         else:
---> 48             return f_raw(*args, **kwargs)
49     f_wrapped.fun = f_raw

~\Anaconda3\lib\site-packages\pennylane\qnodes\base.py in evaluate(self, args, kwargs)
819
820         if self.circuit is None or self.mutable:
--> 821             self._construct(args, kwargs)
822
823         self.device.reset()

~\Anaconda3\lib\site-packages\pennylane\qnodes\jacobian.py in _construct(self, args, kwargs)
88         for each positional parameter.
89         """
---> 90         super()._construct(args, kwargs)
91         self.par_to_grad_method = {k: self._best_method(k) for k in self.variable_deps}
92

~\Anaconda3\lib\site-packages\pennylane\qnodes\base.py in _construct(self, args, kwargs)
564                     # it's ok to directly pass auxiliary arguments since the circuit is re-constructed each time
565                     # (positional args must be replaced because parameter-shift differentiation requires Variables)
--> 566                     res = self.func(*self.arg_vars, **kwargs)
567                 else:
568                     # TODO: Maybe we should only convert the kwarg_vars that were actually given

<ipython-input-2-fe55010aff02> in qft_rotations(n)
10 def qft_rotations(n):
11     """Performs qft on the first n qubits in circuit (without swaps)"""
---> 12     n = int(n)
13     if n == 0:
14         return qml

TypeError: int() argument must be a string, a bytes-like object or a number, not 'Variable'

``````

Running the following code without `qml` in the argument:

``````import pennylane as qml
from pennylane import numpy as np

n_register = 3
dev = qml.device('default.qubit', wires=(n_register), analytic=True)

@qml.qnode(dev)

def qft_rotations(n):
"""Performs qft on the first n qubits in circuit (without swaps)"""
n = int(n)
if n == 0:
return qml
n -= 1
for qubit in range(n):
qml.CRZ(pi/2**(n-qubit), wires=[qubit, n])
qft_rotations(n)

def swap_registers(n):
for qubit in range(n//2):
qml.SWAP(wires = [qubit, n-qubit-1])
return qml

def qft(n):
"""QFT on the first n qubits in circuit"""
qft_rotations(qml, n)
swap_registers(qml, n)
return qml

result = qft(3)
print(result.draw())

``````

gives this error:

``````TypeError                                 Traceback (most recent call last)
<ipython-input-2-fe55010aff02> in <module>()
30     return qml
31
---> 32 result = qft(3)
33 print(result.draw())

<ipython-input-2-fe55010aff02> in qft(n)
26 def qft(n):
27     """QFT on the first n qubits in circuit"""
---> 28     qft_rotations(qml, n)
29     swap_registers(qml, n)
30     return qml

67             self.set_trainable(args)
68             args = autograd.builtins.tuple(args)  # pylint: disable=no-member
---> 69             return self.evaluate(args, kwargs)
70
71         @staticmethod

46             return new_box(ans, trace, node)
47         else:
---> 48             return f_raw(*args, **kwargs)
49     f_wrapped.fun = f_raw

~\Anaconda3\lib\site-packages\pennylane\qnodes\base.py in evaluate(self, args, kwargs)
819
820         if self.circuit is None or self.mutable:
--> 821             self._construct(args, kwargs)
822
823         self.device.reset()

~\Anaconda3\lib\site-packages\pennylane\qnodes\jacobian.py in _construct(self, args, kwargs)
88         for each positional parameter.
89         """
---> 90         super()._construct(args, kwargs)
91         self.par_to_grad_method = {k: self._best_method(k) for k in self.variable_deps}
92

~\Anaconda3\lib\site-packages\pennylane\qnodes\base.py in _construct(self, args, kwargs)
550         # pylint: disable=attribute-defined-outside-init, too-many-branches, too-many-statements
551
--> 552         self.arg_vars, self.kwarg_vars = self._make_variables(args, kwargs)
553
554         # temporary queues for operations and observables

~\Anaconda3\lib\site-packages\pennylane\qnodes\base.py in _make_variables(self, args, kwargs)
482         arg_vars = [
483             i.item() if isinstance(i, np.ndarray) and i.ndim == 0 else i
--> 484             for i in unflatten(arg_vars, args)
485         ]
486

~\Anaconda3\lib\site-packages\pennylane\utils.py in unflatten(flat, model)
176     """
177     # pylint:disable=len-as-condition
--> 178     res, tail = _unflatten(np.asarray(flat), model)
179     if len(tail) != 0:
180         raise ValueError("Flattened iterable has more elements than the model.")

~\Anaconda3\lib\site-packages\pennylane\utils.py in _unflatten(flat, model)
158         res = []
159         for x in model:
--> 160             val, flat = _unflatten(flat, x)
161             res.append(val)
162         return res, flat

~\Anaconda3\lib\site-packages\pennylane\utils.py in _unflatten(flat, model)
162         return res, flat
163
--> 164     raise TypeError("Unsupported type in the model: {}".format(type(model)))
165
166

TypeError: Unsupported type in the model: <class 'module'>
``````

Hi @gidu — I think you misunderstood my suggestion. It is not that you should remove your first argument is that you are using the word qml to mean two different things.

Hi @Nicolas_Quesada, I am trying to return the circuit (qml) if a given condition is met, I changed the code to return the circuit (dev) as follows (the equivalent implementation in qiskit is below):

``````def qft_rotations(n):
"""Performs qft on the first n qubits in circuit (without swaps)"""
n = int(n)
if n == 0:
return dev
n -= 1
for qubit in range(n):
qml.CRZ(np.pi/2**(n-qubit), wires=[qubit, n])
qft_rotations(n)

result = qft_rotations(3)
print(result.draw())

``````

Error Obtained:

``````AttributeError                            Traceback (most recent call last)
<ipython-input-17-48eea1b84893> in <module>()
11
12 result = qft_rotations(3)
---> 13 print(result.draw())

AttributeError: 'NoneType' object has no attribute 'draw'

``````

Qiskit Implementation:

``````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.cu1(pi/2**(n-qubit), qubit, n)

``````

Hi @gidu — Could you post a complete code snippet that produces the error you are getting?

Hi @Nicolas_Quesada, here is the code:

``````import pennylane as qml
from pennylane import numpy as np

n_register = 3
dev = qml.device('default.qubit', wires=(n_register), analytic=True)

def qft_rotations(n):
"""Performs qft on the first n qubits in circuit (without swaps)"""
n = int(n)
if n == 0:
return dev
n -= 1
for qubit in range(n):
qml.CRZ(np.pi/2**(n-qubit), wires=[qubit, n])
qft_rotations(n)

result = qft_rotations(n_register)
print(result.draw())

``````

Hi @gidu — As written you function `qft_rotations` is returning `None`, which is why you are getting an error. Seems like this function is missing a return statement.

1 Like

How can I make the function return the circuit when n get to zero `(n=0)`? And I would like to see how the circuit is drawn. Thanks.

Hi @gidu,

Sure thing! There are two related characteristics to keep in mind when creating a `QNode` in PennyLane:

1. Every QNode needs to have a return statement specifying the type of the statistics to use (e.g., `qml.expval` for obtaining the expectation value, `qml.samples` to obtain samples by running the circuit, etc.) and the observable (e.g., `qml.PauliZ(0)` for PauliZ to act on the first qubit)
2. Arguments to the circuit that are passed as positional arguments will be regarded as differentiable parameters. Non-differntiable parameters should be passed as keyword arguments to the quantum function (and should have a default value in the signature)

For the sake of the example, added `qml.expval(qml.PauliZ(0))` to satisfy the 1. point and made `n` a keyword argument (specified a default value) to satisfy the 2. point.

Further note that the `return` statement for `qft_rotations` was made “empty” (returning `None` implicitly), as calls to `qft_rotations` will build up the `circuit` quantum function which has `return qml.expval(qml.PauliZ(0))` as the return.

The snippet looks as follows with this modifications:

``````import pennylane as qml
from pennylane import numpy as np

n_register = 3
dev = qml.device('default.qubit', wires=(n_register), analytic=True)

def qft_rotations(n=0):
"""Performs qft on the first n qubits in circuit (without swaps)"""
n = int(n)
if n == 0:
return
n -= 1
for qubit in range(n):
qml.CRZ(np.pi/2**(n-qubit), wires=[qubit, n])
qft_rotations(n=n)

def circuit(n=0):
qft_rotations(n=n)
return qml.expval(qml.PauliZ(0))

circuit = qml.QNode(circuit, dev)
circuit(n=3)
print(circuit.draw())
``````

One way to draw the circuit is to specify the `QNode` explicitly, evaluate the quantum function (`circuit(n=3)`) and print the drawn circuit (`print(circuit.draw())`).

Let us know if you have further questions!

Thank you very much @antalszava. Your explanation and code give me some great insights. I adapted your code to implement QFT for n-qubits, but I am not sure if this is correct. I would appreciate your feedback. Also, please how can I extract the probabilities for the different bases?

``````import pennylane as qml
from pennylane import numpy as np

n_register = 3
dev = qml.device('default.qubit', wires=(n_register), analytic=True)

def qft_rotations(n=0):
"""Performs qft on the first n qubits in circuit (without swaps)"""
n = int(n)
if n == 0:
return
n -= 1
for qubit in range(n):
qml.CRZ(np.pi/2**(n-qubit), wires=[qubit, n])
qft_rotations(n=n)

def swap_registers(n):
for qubit in range(n//2):
qml.SWAP(wires = [qubit, n-qubit-1])
#return

def qft(n=0):
"""QFT on the first n qubits in circuit"""
qft_rotations(n=n)
swap_registers(n=n)
return qml.probs(wires=[0, 1, 2])

circuit = qml.QNode(qft, dev)
circuit(n=3)
print(circuit.draw())

qft(n=3)

``````

When I run the above `QFT` function for `n = 3` I get the following: `probs(wires=[0, 1, 2])` as my output. I would like to get the actual probabilities displayed. Is there a way around this, please?

@antalszava I think I figured it out. Here is the code (Your feedback will be appreciated):

``````import pennylane as qml
from pennylane import numpy as np

n_register = 3
dev = qml.device('default.qubit', wires=(n_register), analytic=True)
def qft_rotations(n=0):
"""Performs qft on the first n qubits in circuit (without swaps)"""
n = int(n)
if n == 0:
return
n -= 1
for qubit in range(n):
qml.CRZ(np.pi/2**(n-qubit), wires=[qubit, n])
qft_rotations(n=n)

def swap_registers(n):
for qubit in range(n//2):
qml.SWAP(wires = [qubit, n-qubit-1])

def qft(n=0):
"""QFT on the first n qubits in circuit"""
qft_rotations(n=n)
swap_registers(n=n)
return qml.probs(wires=[0, 1, 2])

circuit = qml.QNode(qft, dev)
circuit(n=3)
print(circuit.draw())

circuit(n=3)

``````

Hi @gidu,

Also, please how can I extract the probabilities for the different bases?

`qml.probs` returns probabilities of computational bases states. If you’d like to extract probabilities of states in another basis, then one approach is to apply rotations to the circuit followed by using `qml.probs`. The needed rotations can be obtained for an observable by calling the `diagonalizing_gates` method:

``````print(qml.Hadamard(wires=[0]).diagonalizing_gates())

[RY(-0.7853981633974483, wires=[0])]
``````

This forum thread shares more details on how we obtain these rotations.

The code snippet seems to be using PennyLane well indeed. One thing to note, is that for `n>3`, `qft` would still only extract `qml.probs(wires=[0, 1, 2])` (might be worth parametrizing the `wires` based on the value of `n`).

Hi @antalszava, thank you very much for your help and suggestions so far. I find the last point you raised very important and I would like to implement it in my code. Please could you give an example or share a link where I can find something that relates to that? I would like to be able to pass the circuit as a parameter to account for variations in the `wires`. Thank you once again.

Hi @gidu,

Sure thing! You could try going with `qml.probs(wires=range(n))` . This will create the indices based on the definition of `n`. Note, that it assumes a trivial wire indexing (that is, there are no custom wire labels and wires are indexed from `0`). (This would become important if you’d create a device with specific wire labels.)

Hope this helps!

1 Like