diff --git a/qiskit/transpiler/synthesis/__init__.py b/qiskit/transpiler/synthesis/__init__.py index bf4e7e4888a5..62dcdfc0c74c 100644 --- a/qiskit/transpiler/synthesis/__init__.py +++ b/qiskit/transpiler/synthesis/__init__.py @@ -10,4 +10,16 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. +# pylint: disable=undefined-all-variable + """Module containing transpiler synthesize.""" + +import importlib + +__all__ = ["graysynth", "cnot_synth"] + + +def __getattr__(name): + if name in __all__: + return getattr(importlib.import_module(".graysynth", __name__), name) + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/qiskit/transpiler/synthesis/graysynth.py b/qiskit/transpiler/synthesis/graysynth.py new file mode 100644 index 000000000000..249335d27a73 --- /dev/null +++ b/qiskit/transpiler/synthesis/graysynth.py @@ -0,0 +1,54 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2017, 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. + +# pylint: disable=unused-wildcard-import, wildcard-import + +""" +Implementation of the GraySynth algorithm for synthesizing CNOT-Phase +circuits with efficient CNOT cost, and the Patel-Hayes-Markov algorithm +for optimal synthesis of linear (CNOT-only) reversible circuits. +""" + + +# Redirect getattrs to modules new location +# TODO: Deprecate in 0.24.0 and remove in 0.26.0 +from qiskit.synthesis.linear.graysynth import * + + +def cnot_synth(state, section_size=2): + """ + Synthesize linear reversible circuits for all-to-all architecture + using Patel, Markov and Hayes method. + + This function is an implementation of the Patel, Markov and Hayes algorithm from [1] + for optimal synthesis of linear reversible circuits for all-to-all architecture, + as specified by an n x n matrix. + + Args: + state (list[list] or ndarray): n x n boolean invertible matrix, describing the state + of the input circuit + section_size (int): the size of each section, used in the + Patel–Markov–Hayes algorithm [1]. section_size must be a factor of num_qubits. + + Returns: + QuantumCircuit: a CX-only circuit implementing the linear transformation. + + Raises: + QiskitError: when variable "state" isn't of type numpy.ndarray + + References: + 1. Patel, Ketan N., Igor L. Markov, and John P. Hayes, + *Optimal synthesis of linear reversible circuits*, + Quantum Information & Computation 8.3 (2008): 282-294. + `arXiv:quant-ph/0302002 [quant-ph] `_ + """ + return synth_cnot_count_full_pmh(state, section_size=section_size) diff --git a/test/python/synthesis/test_gray_synthesis.py b/test/python/synthesis/test_gray_synthesis.py index 738567df0d86..3d2ffbb38ccd 100644 --- a/test/python/synthesis/test_gray_synthesis.py +++ b/test/python/synthesis/test_gray_synthesis.py @@ -14,17 +14,23 @@ import unittest +import ddt + from qiskit.circuit import QuantumCircuit, QuantumRegister from qiskit.quantum_info.operators import Operator from qiskit.extensions.unitary import UnitaryGate from qiskit.synthesis.linear import graysynth, synth_cnot_count_full_pmh +from qiskit.transpiler.synthesis import cnot_synth # pylint: disable=no-name-in-module +from qiskit.transpiler.synthesis.graysynth import graysynth as legacy_graysynth from qiskit.test import QiskitTestCase +@ddt.ddt class TestGraySynth(QiskitTestCase): """Test the Gray-Synth algorithm.""" - def test_gray_synth(self): + @ddt.data(graysynth, legacy_graysynth) + def test_gray_synth(self, synth_func): """Test synthesis of a small parity network via gray_synth. The algorithm should take the following matrix as an input: @@ -66,7 +72,7 @@ def test_gray_synth(self): [0, 1, 0, 0, 1, 0], ] angles = ["s", "t", "z", "s", "t", "t"] - c_gray = graysynth(cnots, angles) + c_gray = synth_func(cnots, angles) unitary_gray = UnitaryGate(Operator(c_gray)) # Create the circuit displayed above: @@ -200,11 +206,13 @@ def test_ccz(self): self.assertEqual(unitary_gray, unitary_compare) +@ddt.ddt class TestPatelMarkovHayes(QiskitTestCase): """Test the Patel-Markov-Hayes algorithm for synthesizing linear CNOT-only circuits.""" - def test_patel_markov_hayes(self): + @ddt.data(cnot_synth, synth_cnot_count_full_pmh) + def test_patel_markov_hayes(self, synth_func): """Test synthesis of a small linear circuit (example from paper, Figure 3). @@ -239,7 +247,7 @@ def test_patel_markov_hayes(self): [1, 1, 0, 1, 1, 1], [0, 0, 1, 1, 1, 0], ] - c_patel = synth_cnot_count_full_pmh(state) + c_patel = synth_func(state) unitary_patel = UnitaryGate(Operator(c_patel)) # Create the circuit displayed above: