Skip to content

Commit

Permalink
Adding QFT gate to natively reason about Quantum Fourier Transforms (#…
Browse files Browse the repository at this point in the history
…11463)

* initial commit

* release notes

* fixing synthesis plugin options

* finalize merge conflicts

* fixing default option values for qft plugins'

* additional tests for qft plugins

* renaming QftGate to QFTGate

* Also renaming Qft to QFT in synthesis method names

* appplying Jake's suggestion from code review

* inlining _basic_definition into _define

* docstring improvements

* more docstring improvements

* renaming do_swaps to reverse_qubits in the new code

* typos

* adding synth_qft_full to __init__

* round of suggestions from code review

* another round of code review suggestions

* fixes

* also adding QFTGate plugins to the docs
  • Loading branch information
alexanderivrii committed Jul 10, 2024
1 parent d86f995 commit fa3d6df
Show file tree
Hide file tree
Showing 15 changed files with 510 additions and 28 deletions.
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ sk = "qiskit.transpiler.passes.synthesis.solovay_kitaev_synthesis:SolovayKitaevS
"permutation.kms" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:KMSSynthesisPermutation"
"permutation.basic" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:BasicSynthesisPermutation"
"permutation.acg" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:ACGSynthesisPermutation"
"qft.full" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:QFTSynthesisFull"
"qft.line" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:QFTSynthesisLine"
"qft.default" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:QFTSynthesisFull"
"permutation.token_swapper" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:TokenSwapperSynthesisPermutation"

[project.entry-points."qiskit.transpiler.init"]
Expand Down
3 changes: 2 additions & 1 deletion qiskit/circuit/library/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@
:template: autosummary/class_no_inherited_members.rst
QFT
QFTGate
Arithmetic Circuits
===================
Expand Down Expand Up @@ -523,7 +524,7 @@
XOR,
InnerProduct,
)
from .basis_change import QFT
from .basis_change import QFT, QFTGate
from .arithmetic import (
FunctionalPauliRotations,
LinearPauliRotations,
Expand Down
2 changes: 1 addition & 1 deletion qiskit/circuit/library/basis_change/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@

"""The basis change circuits."""

from .qft import QFT
from .qft import QFT, QFTGate
46 changes: 40 additions & 6 deletions qiskit/circuit/library/basis_change/qft.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Quantum Fourier Transform Circuit."""
"""Define a Quantum Fourier Transform circuit (QFT) and a native gate (QFTGate)."""

from typing import Optional
from __future__ import annotations
import warnings
import numpy as np

from qiskit.circuit import QuantumCircuit, QuantumRegister, CircuitInstruction

from qiskit.circuit.quantumcircuit import QuantumCircuit, QuantumRegister, CircuitInstruction, Gate
from ..blueprintcircuit import BlueprintCircuit


Expand Down Expand Up @@ -75,12 +74,12 @@ class QFT(BlueprintCircuit):

def __init__(
self,
num_qubits: Optional[int] = None,
num_qubits: int | None = None,
approximation_degree: int = 0,
do_swaps: bool = True,
inverse: bool = False,
insert_barriers: bool = False,
name: Optional[str] = None,
name: str | None = None,
) -> None:
"""Construct a new QFT circuit.
Expand Down Expand Up @@ -293,3 +292,38 @@ def _build(self) -> None:

wrapped = circuit.to_instruction() if self.insert_barriers else circuit.to_gate()
self.compose(wrapped, qubits=self.qubits, inplace=True)


class QFTGate(Gate):
r"""Quantum Fourier Transform Gate.
The Quantum Fourier Transform (QFT) on :math:`n` qubits is the operation
.. math::
|j\rangle \mapsto \frac{1}{2^{n/2}} \sum_{k=0}^{2^n - 1} e^{2\pi ijk / 2^n} |k\rangle
"""

def __init__(
self,
num_qubits: int,
):
"""
Args:
num_qubits: The number of qubits on which the QFT acts.
"""
super().__init__(name="qft", num_qubits=num_qubits, params=[])

def __array__(self, dtype=complex):
"""Return a numpy array for the QFTGate."""
n = self.num_qubits
nums = np.arange(2**n)
outer = np.outer(nums, nums)
return np.exp(2j * np.pi * outer * (0.5**n), dtype=dtype) * (0.5 ** (n / 2))

def _define(self):
"""Provide a specific decomposition of the QFTGate into a quantum circuit."""
from qiskit.synthesis.qft import synth_qft_full

self.definition = synth_qft_full(num_qubits=self.num_qubits)
2 changes: 2 additions & 0 deletions qiskit/qpy/binary_io/circuits.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,8 @@ def _read_instruction(
"DiagonalGate",
}:
gate = gate_class(params)
elif gate_name == "QFTGate":
gate = gate_class(len(qargs), *params)
else:
if gate_name == "Barrier":
params = [len(qargs)]
Expand Down
3 changes: 2 additions & 1 deletion qiskit/synthesis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
======================
.. autofunction:: synth_qft_line
.. autofunction:: synth_qft_full
Unitary Synthesis
=================
Expand Down Expand Up @@ -162,7 +163,7 @@
synth_circuit_from_stabilizers,
)
from .discrete_basis import SolovayKitaevDecomposition, generate_basic_approximations
from .qft import synth_qft_line
from .qft import synth_qft_line, synth_qft_full
from .unitary.qsd import qs_decomposition
from .unitary import aqc
from .one_qubit import OneQubitEulerDecomposer
Expand Down
1 change: 1 addition & 0 deletions qiskit/synthesis/qft/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
"""Module containing stabilizer QFT circuit synthesis."""

from .qft_decompose_lnn import synth_qft_line
from .qft_decompose_full import synth_qft_full
79 changes: 79 additions & 0 deletions qiskit/synthesis/qft/qft_decompose_full.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2024.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""
Circuit synthesis for a QFT circuit.
"""

from __future__ import annotations
import numpy as np
from qiskit.circuit.quantumcircuit import QuantumCircuit


def synth_qft_full(
num_qubits: int,
do_swaps: bool = True,
approximation_degree: int = 0,
insert_barriers: bool = False,
inverse: bool = False,
name: str | None = None,
) -> QuantumCircuit:
"""Construct a circuit for the Quantum Fourier Transform using all-to-all connectivity.
.. note::
With the default value of ``do_swaps = True``, this synthesis algorithm creates a
circuit that faithfully implements the QFT operation. This circuit contains a sequence
of swap gates at the end, corresponding to reversing the order of its output qubits.
In some applications this reversal permutation can be avoided. Setting ``do_swaps = False``
creates a circuit without this reversal permutation, at the expense that this circuit
implements the "QFT-with-reversal" instead of QFT. Alternatively, the
:class:`~.ElidePermutations` transpiler pass is able to remove these swap gates.
Args:
num_qubits: The number of qubits on which the Quantum Fourier Transform acts.
do_swaps: Whether to synthesize the "QFT" or the "QFT-with-reversal" operation.
approximation_degree: The degree of approximation (0 for no approximation).
It is possible to implement the QFT approximately by ignoring
controlled-phase rotations with the angle beneath a threshold. This is discussed
in more detail in https://arxiv.org/abs/quant-ph/9601018 or
https://arxiv.org/abs/quant-ph/0403071.
insert_barriers: If ``True``, barriers are inserted for improved visualization.
inverse: If ``True``, the inverse Quantum Fourier Transform is constructed.
name: The name of the circuit.
Returns:
A circuit implementing the QFT operation.
"""

circuit = QuantumCircuit(num_qubits, name=name)

for j in reversed(range(num_qubits)):
circuit.h(j)
num_entanglements = max(0, j - max(0, approximation_degree - (num_qubits - j - 1)))
for k in reversed(range(j - num_entanglements, j)):
# Use negative exponents so that the angle safely underflows to zero, rather than
# using a temporary variable that overflows to infinity in the worst case.
lam = np.pi * (2.0 ** (k - j))
circuit.cp(lam, j, k)

if insert_barriers:
circuit.barrier()

if do_swaps:
for i in range(num_qubits // 2):
circuit.swap(i, num_qubits - i - 1)

if inverse:
circuit = circuit.inverse()

return circuit
26 changes: 17 additions & 9 deletions qiskit/synthesis/qft/qft_decompose_lnn.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,29 @@
def synth_qft_line(
num_qubits: int, do_swaps: bool = True, approximation_degree: int = 0
) -> QuantumCircuit:
"""Synthesis of a QFT circuit for a linear nearest neighbor connectivity.
Based on Fig 2.b in Fowler et al. [1].
"""Construct a circuit for the Quantum Fourier Transform using linear
neighbor connectivity.
Note that this method *reverts* the order of qubits in the circuit,
compared to the original :class:`.QFT` code.
Hence, the default value of the ``do_swaps`` parameter is ``True``
since it produces a circuit with fewer CX gates.
The construction is based on Fig 2.b in Fowler et al. [1].
.. note::
With the default value of ``do_swaps = True``, this synthesis algorithm creates a
circuit that faithfully implements the QFT operation. When ``do_swaps = False``,
this synthesis algorithm creates a circuit that corresponds to "QFT-with-reversal":
applying the QFT and reversing the order of its output qubits.
Args:
num_qubits: The number of qubits on which the QFT acts.
num_qubits: The number of qubits on which the Quantum Fourier Transform acts.
approximation_degree: The degree of approximation (0 for no approximation).
do_swaps: Whether to include the final swaps in the QFT.
It is possible to implement the QFT approximately by ignoring
controlled-phase rotations with the angle beneath a threshold. This is discussed
in more detail in https://arxiv.org/abs/quant-ph/9601018 or
https://arxiv.org/abs/quant-ph/0403071.
do_swaps: Whether to synthesize the "QFT" or the "QFT-with-reversal" operation.
Returns:
A circuit implementation of the QFT circuit.
A circuit implementing the QFT operation.
References:
1. A. G. Fowler, S. J. Devitt, and L. C. L. Hollenberg,
Expand Down
Loading

0 comments on commit fa3d6df

Please sign in to comment.