From 9b1dad553ee527540d983a3b36da16091cf618f5 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 25 Jan 2023 01:19:57 +0000 Subject: [PATCH] Add back qiskit.transpiler.passes.synthesis.graysynth module (#9445) (#9446) * Add back qiskit.transpiler.passes.synthesis.graysynth module This commit reverts a breaking change made in #8568, in that PR the graysynth module was moved to the qiskit.synthesis package and the cnot_synth function was also renamed as part of the move. However, this change would break any existing users of the module without any warning. To fix this for the 0.23.0 release this commit adds back the graysynth module and just exports the contents of the module in its new location. Additionally, a small wrapper function is added so that the legacy cnot_synth function name can continue to be used for the time being. In the 0.24.0 cycle we can deprecate the old module and remove them after we've giving users a warning about the change. * Restore root qiskit.transpiler.synthesis exports * Fix import issues (cherry picked from commit bf8d6fa615f650b93dcfe33e03935065aaf53b75) Co-authored-by: Matthew Treinish --- qiskit/transpiler/synthesis/__init__.py | 12 +++++ qiskit/transpiler/synthesis/graysynth.py | 54 ++++++++++++++++++++ test/python/synthesis/test_gray_synthesis.py | 16 ++++-- 3 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 qiskit/transpiler/synthesis/graysynth.py 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: