-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add reverse permutation for LNN connectivity #12181
Changes from 5 commits
a4bcef3
9830b3c
bda1ca4
d08646f
83b43ab
2bb82ae
00c48e7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# 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. | ||
""" | ||
Synthesis of a reverse permutation for LNN connectivity. | ||
""" | ||
|
||
from qiskit.circuit import QuantumCircuit | ||
|
||
|
||
def _append_cx_stage1(qc, n): | ||
"""A single layer of CX gates.""" | ||
for i in range(n // 2): | ||
qc.cx(2 * i, 2 * i + 1) | ||
for i in range((n + 1) // 2 - 1): | ||
qc.cx(2 * i + 2, 2 * i + 1) | ||
return qc | ||
|
||
|
||
def _append_cx_stage2(qc, n): | ||
"""A single layer of CX gates.""" | ||
for i in range(n // 2): | ||
qc.cx(2 * i + 1, 2 * i) | ||
for i in range((n + 1) // 2 - 1): | ||
qc.cx(2 * i + 1, 2 * i + 2) | ||
return qc | ||
|
||
|
||
def synth_permutation_reverse_lnn_kms(num_qubits: int) -> QuantumCircuit: | ||
""" | ||
Synthesize reverse permutation for linear nearest-neighbor architectures using | ||
Kutin, Moulton, Smithline method. | ||
|
||
Synthesis algorithm for reverse permutation from [1], section 5. | ||
This algorithm synthesizes the reverse permutation on :math:`n` qubits over | ||
a linear nearest-neighbor architecture using CX gates with depth :math:`2 * n + 2`. | ||
|
||
Args: | ||
num_qubits: The number of qubits. | ||
|
||
Returns: | ||
The synthesized quantum circuit. | ||
|
||
References: | ||
1. Kutin, S., Moulton, D. P., Smithline, L., | ||
*Computation at a distance*, Chicago J. Theor. Comput. Sci., vol. 2007, (2007), | ||
`arXiv:quant-ph/0701194 <https://arxiv.org/abs/quant-ph/0701194>`_ | ||
""" | ||
|
||
qc = QuantumCircuit(num_qubits) | ||
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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,7 +15,7 @@ | |
|
||
import numpy as np | ||
from qiskit.circuit import QuantumCircuit | ||
from qiskit.synthesis.linear_phase.cz_depth_lnn import _append_cx_stage1, _append_cx_stage2 | ||
from qiskit.synthesis.permutation import synth_permutation_reverse_lnn_kms | ||
|
||
|
||
def synth_qft_line( | ||
|
@@ -65,10 +65,7 @@ def synth_qft_line( | |
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) | ||
qc_rev = synth_permutation_reverse_lnn_kms(num_qubits) | ||
qc = qc.compose(qc_rev) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks good, but I think we can do this more efficiently. While the current implementation using compose ensures correctness, it might not be the most efficient in terms of performance and memory usage, especially for larger circuits. Instead of composing two quantum circuits, we could consider enhancing efficiency by adding a function that directly appends the reverse permutation LNN to an existing circuit. This approach would modify the circuit in place, avoiding the overhead associated with creating and composing a new circuit instance. Here's a conceptual sketch of how this could be implemented: def append_reverse_permutation_lnn_kms(qc: QuantumCircuit, num_qubits: int) -> None:
for _ in range((num_qubits + 1) // 2):
_append_cx_stage1(qc, num_qubits)
_append_cx_stage2(qc, num_qubits)
if (num_qubits % 2) == 0:
_append_cx_stage1(qc, num_qubits) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that's a good suggestion, I added it as a helper function. |
||
|
||
return qc |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
--- | ||
features_synthesis: | ||
- | | ||
Add a new synthesis method :func:`.synth_permutation_reverse_lnn_kms` | ||
of reverse permutations for linear nearest-neighbor architectures using | ||
Kutin, Moulton, Smithline method. | ||
This algorithm synthesizes the reverse permutation on :math:`n` qubits over | ||
a linear nearest-neighbor architecture using CX gates with depth :math:`2 * n + 2`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,8 +19,12 @@ | |
|
||
from qiskit.quantum_info.operators import Operator | ||
from qiskit.circuit.library import LinearFunction, PermutationGate | ||
from qiskit.synthesis import synth_permutation_acg | ||
from qiskit.synthesis.permutation import synth_permutation_depth_lnn_kms, synth_permutation_basic | ||
from qiskit.synthesis.permutation import ( | ||
synth_permutation_acg, | ||
synth_permutation_depth_lnn_kms, | ||
synth_permutation_basic, | ||
synth_permutation_reverse_lnn_kms, | ||
) | ||
from qiskit.synthesis.permutation.permutation_utils import _get_ordered_swap | ||
from test import QiskitTestCase # pylint: disable=wrong-import-order | ||
|
||
|
@@ -108,6 +112,26 @@ def test_synth_permutation_depth_lnn_kms(self, width): | |
synthesized_pattern = LinearFunction(qc).permutation_pattern() | ||
self.assertTrue(np.array_equal(synthesized_pattern, pattern)) | ||
|
||
@data(4, 5, 10, 15, 20) | ||
def test_synth_permutation_reverse_lnn_kms(self, num_qubits): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great work on the implementation and testing. The current tests effectively assess the basic functionality and correct usage scenarios. However, I suggest adding tests that focus on:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added test cases for 1,2 and 3 qubits. |
||
"""Test synth_permutation_reverse_lnn_kms function produces the correct | ||
circuit.""" | ||
pattern = list(reversed(range(num_qubits))) | ||
qc = synth_permutation_reverse_lnn_kms(num_qubits) | ||
self.assertListEqual((LinearFunction(qc).permutation_pattern()).tolist(), pattern) | ||
|
||
# Check that the CX depth of the circuit is at 2*n+2 | ||
self.assertEqual(qc.depth(), 2 * num_qubits + 2) | ||
|
||
# Check that the synthesized circuit consists of CX gates only, | ||
# and that these CXs adhere to the LNN connectivity. | ||
for instruction in qc.data: | ||
self.assertEqual(instruction.operation.name, "cx") | ||
q0 = qc.find_bit(instruction.qubits[0]).index | ||
q1 = qc.find_bit(instruction.qubits[1]).index | ||
dist = abs(q0 - q1) | ||
self.assertEqual(dist, 1) | ||
|
||
@data(4, 5, 6, 7) | ||
def test_permutation_matrix(self, width): | ||
"""Test that the unitary matrix constructed from permutation pattern | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed
_append_cx_stage1
and_append_cx_stage2
functions were moved fromqiskit/synthesis/linear_phase/cz_depth_lnn.py
toqiskit/synthesis/permutation/permutation_reverse_lnn.py
. Could you share the reasoning behind this change?While I understand these are private functions and the move does not impact their functionality, I am curious if the new location makes more sense and better aligns with their specific use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These functions are helper functions to construct a reverse permutation, and this is the reason that they have been moved. CZ circuit synthesis for LNN is basically constructing a reverse permutation with phase gates in between.