Skip to content

Commit

Permalink
QFT circuit synthesis for linear nearest neighbor connectivity (#11236)
Browse files Browse the repository at this point in the history
* add basic code to synthesize QFT circuit for linear architecture

* replace cp and swap by 3 cx gates and p gates

* add do_swaps option

* add approximation_degree option

* update test: equal instead of equiv

* add docstrings

* add release notes

* fix approximation_degree code. updates following review

* updates following review

* minor updates follwing review
  • Loading branch information
ShellyGarion committed Dec 8, 2023
1 parent cc6fa8f commit 523ea74
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 0 deletions.
6 changes: 6 additions & 0 deletions qiskit/synthesis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@
.. autofunction:: generate_basic_approximations
Basis Change Synthesis
======================
.. autofunction:: synth_qft_line
"""

from .evolution import (
Expand Down Expand Up @@ -120,3 +125,4 @@
)
from .stabilizer import synth_stabilizer_layers, synth_stabilizer_depth_lnn
from .discrete_basis import SolovayKitaevDecomposition, generate_basic_approximations
from .qft import synth_qft_line
15 changes: 15 additions & 0 deletions qiskit/synthesis/qft/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2023.
#
# 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.

"""Module containing stabilizer QFT circuit synthesis."""

from .qft_decompose_lnn import synth_qft_line
74 changes: 74 additions & 0 deletions qiskit/synthesis/qft/qft_decompose_lnn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2023.
#
# 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.
"""

import numpy as np
from qiskit.circuit import QuantumCircuit
from qiskit.synthesis.linear_phase.cz_depth_lnn import _append_cx_stage1, _append_cx_stage2


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].
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.
Args:
num_qubits: The number of qubits on which the QFT acts.
approximation_degree: The degree of approximation (0 for no approximation).
do_swaps: Whether to include the final swaps in the QFT.
Return:
A circuit implementation of the QFT circuit.
Reference:
1. A. G. Fowler, S. J. Devitt, and L. C. L. Hollenberg,
*Implementation of Shor's algorithm on a linear nearest neighbour qubit array*,
Quantum Info. Comput. 4, 4 (July 2004), 237–251.
`arXiv:quant-ph/0402196 [quant-ph] <https://arxiv.org/abs/quant-ph/0402196>`_
"""

qc = QuantumCircuit(num_qubits)

for i in range(num_qubits):
qc.h(num_qubits - 1)

for j in range(i, num_qubits - 1):
if j - i + 2 < num_qubits - approximation_degree + 1:
qc.p(np.pi / 2 ** (j - i + 2), num_qubits - j + i - 1)
qc.cx(num_qubits - j + i - 1, num_qubits - j + i - 2)
qc.p(-np.pi / 2 ** (j - i + 2), num_qubits - j + i - 2)
qc.cx(num_qubits - j + i - 2, num_qubits - j + i - 1)
qc.cx(num_qubits - j + i - 1, num_qubits - j + i - 2)
qc.p(np.pi / 2 ** (j - i + 2), num_qubits - j + i - 1)
else:
qc.cx(num_qubits - j + i - 1, num_qubits - j + i - 2)
qc.cx(num_qubits - j + i - 2, num_qubits - j + i - 1)
qc.cx(num_qubits - j + i - 1, num_qubits - j + i - 2)

if not do_swaps:
# Add a reversal network for LNN connectivity in depth 2*n+2,
# based on Kutin at al., https://arxiv.org/abs/quant-ph/0701194, Section 5.
for _ in range((num_qubits + 1) // 2):
qc = _append_cx_stage1(qc, num_qubits)
qc = _append_cx_stage2(qc, num_qubits)
if (num_qubits % 2) == 0:
qc = _append_cx_stage1(qc, num_qubits)

return qc
6 changes: 6 additions & 0 deletions releasenotes/notes/qft_lnn_synthesis-c917dc00c3a8cabc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
features:
- |
Add a new synthesis method :func:`.synth_qft_line` of a QFT circuit
for linear nearest neighbor connectivity, which significantly reduces
the number of SWAPs for large numbers of qubits compared to SABRE.
62 changes: 62 additions & 0 deletions test/python/synthesis/test_qft_synthesis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2023.
#
# 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.

"""Tests for QFT synthesis methods."""


import unittest
from test import combine
from ddt import ddt

from qiskit.test import QiskitTestCase
from qiskit.circuit.library import QFT
from qiskit.synthesis.qft import synth_qft_line
from qiskit.quantum_info import Operator

from qiskit.synthesis.linear.linear_circuits_utils import check_lnn_connectivity


@ddt
class TestQFTLNN(QiskitTestCase):
"""Tests for QFT synthesis functions."""

@combine(num_qubits=[2, 3, 4, 5, 6, 7, 8], do_swaps=[True, False])
def test_qft_lnn(self, num_qubits, do_swaps):
"""Assert that the original and synthesized QFT circuits are the same."""
qft_circ = QFT(num_qubits, do_swaps=do_swaps)
qft_lnn = synth_qft_line(num_qubits, do_swaps=do_swaps)

with self.subTest(msg="original and synthesized QFT circuits are not the same"):
self.assertEqual(Operator(qft_circ), Operator(qft_lnn))

# Check that the output circuit has LNN connectivity
with self.subTest(msg="synthesized QFT circuit do not have LNN connectivity"):
self.assertTrue(check_lnn_connectivity(qft_lnn))

@combine(num_qubits=[5, 6, 7, 8], do_swaps=[True, False], approximation_degree=[2, 3])
def test_qft_lnn_approximated(self, num_qubits, do_swaps, approximation_degree):
"""Assert that the original and synthesized QFT circuits are the same with approximation."""
qft_circ = QFT(num_qubits, do_swaps=do_swaps, approximation_degree=approximation_degree)
qft_lnn = synth_qft_line(
num_qubits, do_swaps=do_swaps, approximation_degree=approximation_degree
)

with self.subTest(msg="original and synthesized QFT circuits are not the same"):
self.assertEqual(Operator(qft_circ), Operator(qft_lnn))

# Check that the output circuit has LNN connectivity
with self.subTest(msg="synthesized QFT circuit do not have LNN connectivity"):
self.assertTrue(check_lnn_connectivity(qft_lnn))


if __name__ == "__main__":
unittest.main()

0 comments on commit 523ea74

Please sign in to comment.