From cfb13c98b58394673cbaf746cae96a2733fa79d4 Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 30 Jan 2024 12:37:42 -0500 Subject: [PATCH] Remove deprecated feature in 0.45 in unroller (#11581) * Removed unroller * Additional removals where unroller appears * Fix lint and remove unroller test * Fixed test_controlled_gate * Fix test_preset_passmanagers * Fixed lint * Fixed test_circuit_methods * Fixed lint * Fixed lint again * Fixed test_circuit_methods again * Fixed test_pass_manager_drawer * Undo change in requirements.txt * Fix test_controlled_gate * Updated release note * Fix test_circuit_methods * Update releasenotes/notes/remove-deprecated-unroller-4693330708c681e0.yaml Co-authored-by: Julien Gacon * Reverted change to requirements * Added seperate function for equality check to test_controlled_gate * Fixed requirements.txt --------- Co-authored-by: Julien Gacon --- qiskit/compiler/transpiler.py | 9 - qiskit/transpiler/passes/__init__.py | 2 - qiskit/transpiler/passes/basis/__init__.py | 1 - qiskit/transpiler/passes/basis/unroller.py | 145 ---- .../preset_passmanagers/__init__.py | 19 +- .../preset_passmanagers/builtin_plugins.py | 17 - .../transpiler/preset_passmanagers/common.py | 7 +- ...-deprecated-unroller-4693330708c681e0.yaml | 22 + requirements.txt | 2 +- test/benchmarks/passes.py | 22 - test/python/circuit/test_controlled_gate.py | 69 +- .../python/circuit/test_instruction_repeat.py | 38 +- test/python/qasm2/test_circuit_methods.py | 13 +- .../transpiler/test_optimize_1q_gates.py | 12 +- test/python/transpiler/test_pass_call.py | 19 - test/python/transpiler/test_passmanager.py | 12 +- .../transpiler/test_preset_passmanagers.py | 23 +- .../transpiler/test_staged_passmanager.py | 27 +- test/python/transpiler/test_unroller.py | 780 ------------------ .../references/pass_manager_standard.dot | 54 +- .../references/pass_manager_style.dot | 54 +- .../visualization/test_pass_manager_drawer.py | 9 +- 22 files changed, 179 insertions(+), 1177 deletions(-) delete mode 100644 qiskit/transpiler/passes/basis/unroller.py create mode 100644 releasenotes/notes/remove-deprecated-unroller-4693330708c681e0.yaml delete mode 100644 test/python/transpiler/test_unroller.py diff --git a/qiskit/compiler/transpiler.py b/qiskit/compiler/transpiler.py index f79bd6b22428..eaed6744ff06 100644 --- a/qiskit/compiler/transpiler.py +++ b/qiskit/compiler/transpiler.py @@ -347,15 +347,6 @@ def callback_func(**kwargs): target = copy.deepcopy(target) target.update_from_instruction_schedule_map(inst_map) - if translation_method == "unroller": - warnings.warn( - "The 'unroller' translation_method plugin is deprecated as of Qiskit 0.45.0 and " - "will be removed in a future release. Instead you should use the default " - "'translator' method or another plugin.", - DeprecationWarning, - stacklevel=2, - ) - if not ignore_backend_supplied_default_methods: if scheduling_method is None and hasattr(backend, "get_scheduling_stage_plugin"): scheduling_method = backend.get_scheduling_stage_plugin() diff --git a/qiskit/transpiler/passes/__init__.py b/qiskit/transpiler/passes/__init__.py index 19925f3fe147..297588f69d36 100644 --- a/qiskit/transpiler/passes/__init__.py +++ b/qiskit/transpiler/passes/__init__.py @@ -58,7 +58,6 @@ TranslateParameterizedGates Unroll3qOrMore UnrollCustomDefinitions - Unroller Optimizations ============= @@ -204,7 +203,6 @@ # basis change from .basis import Decompose -from .basis import Unroller from .basis import UnrollCustomDefinitions from .basis import Unroll3qOrMore from .basis import BasisTranslator diff --git a/qiskit/transpiler/passes/basis/__init__.py b/qiskit/transpiler/passes/basis/__init__.py index 57c094a2ae7a..9d9d0989f2c3 100644 --- a/qiskit/transpiler/passes/basis/__init__.py +++ b/qiskit/transpiler/passes/basis/__init__.py @@ -13,7 +13,6 @@ """Module containing basis change passes.""" from .decompose import Decompose -from .unroller import Unroller from .unroll_custom_definitions import UnrollCustomDefinitions from .unroll_3q_or_more import Unroll3qOrMore from .basis_translator import BasisTranslator diff --git a/qiskit/transpiler/passes/basis/unroller.py b/qiskit/transpiler/passes/basis/unroller.py deleted file mode 100644 index 918c9324f91e..000000000000 --- a/qiskit/transpiler/passes/basis/unroller.py +++ /dev/null @@ -1,145 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017, 2018. -# -# 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. - -"""Unroll a circuit to a given basis.""" - -from qiskit.transpiler.basepasses import TransformationPass -from qiskit.transpiler.passes.utils import control_flow -from qiskit.exceptions import QiskitError -from qiskit.circuit import ControlledGate, ControlFlowOp -from qiskit.converters.circuit_to_dag import circuit_to_dag -from qiskit.utils.deprecation import deprecate_func - - -class Unroller(TransformationPass): - """Unroll a circuit to a given basis. - - Unroll (expand) non-basis, non-opaque instructions recursively - to a desired basis, using decomposition rules defined for each instruction. - """ - - @deprecate_func( - since="0.45.0", - additional_msg="This has been replaced by the `BasisTranslator` pass " - "and is going to be removed in Qiskit 1.0.", - ) - def __init__(self, basis=None, target=None): - """Unroller initializer. - - Args: - basis (list[str] or None): Target basis names to unroll to, e.g. `['u3', 'cx']` . If - None, does not unroll any gate. - target (Target): The :class:`~.Target` representing the target backend, if both - ``basis`` and this are specified then this argument will take - precedence and ``basis`` will be ignored. - """ - super().__init__() - self.basis = basis - self.target = target - - def run(self, dag): - """Run the Unroller pass on `dag`. - - Args: - dag (DAGCircuit): input dag - - Raises: - QiskitError: if unable to unroll given the basis due to undefined - decomposition rules (such as a bad basis) or excessive recursion. - - Returns: - DAGCircuit: output unrolled dag - """ - if self.basis is None and self.target is None: - return dag - # Walk through the DAG and expand each non-basis node - basic_insts = ["measure", "reset", "barrier", "snapshot", "delay"] - for node in dag.op_nodes(): - if getattr(node.op, "_directive", False): - continue - - run_qubits = None - if self.target is not None: - run_qubits = tuple(dag.find_bit(x).index for x in node.qargs) - if ( - self.target.instruction_supported(node.op.name, qargs=run_qubits) - or node.op.name == "barrier" - ): - if isinstance(node.op, ControlledGate) and node.op._open_ctrl: - pass - else: - continue - else: - if node.name in basic_insts: - # TODO: this is legacy behavior.Basis_insts should be removed that these - # instructions should be part of the device-reported basis. Currently, no - # backend reports "measure", for example. - continue - - if node.name in self.basis: # If already a base, ignore. - if isinstance(node.op, ControlledGate) and node.op._open_ctrl: - pass - else: - continue - - if isinstance(node.op, ControlFlowOp): - node.op = control_flow.map_blocks(self.run, node.op) - continue - - try: - phase = node.op.definition.global_phase - rule = node.op.definition.data - except (TypeError, AttributeError) as err: - raise QiskitError( - f"Error decomposing node of instruction '{node.name}': {err}. " - f"Unable to define instruction '{node.name}' in the given basis." - ) from err - - # Isometry gates definitions can have widths smaller than that of the - # original gate, in which case substitute_node will raise. Fall back - # to substitute_node_with_dag if an the width of the definition is - # different that the width of the node. - while rule and len(rule) == 1 and len(node.qargs) == len(rule[0].qubits) == 1: - if self.target is not None: - if self.target.instruction_supported(rule[0].operation.name, run_qubits): - dag.global_phase += phase - dag.substitute_node(node, rule[0].operation, inplace=True) - break - else: - if rule[0].operation.name in self.basis: - dag.global_phase += phase - dag.substitute_node(node, rule[0].operation, inplace=True) - break - try: - phase += rule[0].operation.definition.global_phase - rule = rule[0].operation.definition.data - except (TypeError, AttributeError) as err: - raise QiskitError( - f"Error decomposing node of instruction '{node.name}': {err}. " - f"Unable to define instruction '{rule[0].operation.name}' in the basis." - ) from err - - else: - if not rule: - if rule == []: # empty node - dag.remove_op_node(node) - dag.global_phase += phase - continue - # opaque node - raise QiskitError( - "Cannot unroll the circuit to the given basis, %s. " - "No rule to expand instruction %s." % (str(self.basis), node.op.name) - ) - decomposition = circuit_to_dag(node.op.definition) - unrolled_dag = self.run(decomposition) # recursively unroll ops - dag.substitute_node_with_dag(node, unrolled_dag) - return dag diff --git a/qiskit/transpiler/preset_passmanagers/__init__.py b/qiskit/transpiler/preset_passmanagers/__init__.py index a889021b279d..9b6efe661b2e 100644 --- a/qiskit/transpiler/preset_passmanagers/__init__.py +++ b/qiskit/transpiler/preset_passmanagers/__init__.py @@ -154,12 +154,11 @@ def generate_preset_pass_manager( You can see a list of installed plugins by using :func:`~.list_stage_plugins` with ``"routing"`` for the ``stage_name`` argument. translation_method (str): The method to use for translating gates to - basis gates. Valid choices ``'unroller'``, ``'translator'``, ``'synthesis'`` - representing :class:`~.Unroller`, :class:`~.BasisTranslator`, and - :class:`~.UnitarySynthesis` respectively. This can also be the external plugin - name to use for the ``translation`` stage of the output :class:`~.StagedPassManager`. - You can see a list of installed plugins by using :func:`~.list_stage_plugins` with - ``"translation"`` for the ``stage_name`` argument. + basis gates. Valid choices ``'translator'``, ``'synthesis'`` representing + :class:`~.BasisTranslator`, and :class:`~.UnitarySynthesis` respectively. This can + also be the external plugin name to use for the ``translation`` stage of the output + :class:`~.StagedPassManager`. You can see a list of installed plugins by using + :func:`~.list_stage_plugins` with ``"translation"`` for the ``stage_name`` argument. scheduling_method (str): The pass to use for scheduling instructions. Valid choices are ``'alap'`` and ``'asap'``. This can also be the external plugin name to use for the ``scheduling`` stage of the output :class:`~.StagedPassManager`. You can @@ -205,14 +204,6 @@ def generate_preset_pass_manager( Raises: ValueError: if an invalid value for ``optimization_level`` is passed in. """ - if translation_method == "unroller": - warnings.warn( - "The 'unroller' translation_method plugin is deprecated as of Qiskit 0.45.0 and " - "will be removed in a future release. Instead you should use the default " - "'translator' method or another plugin.", - DeprecationWarning, - stacklevel=2, - ) if coupling_map is not None and not isinstance(coupling_map, CouplingMap): coupling_map = CouplingMap(coupling_map) diff --git a/qiskit/transpiler/preset_passmanagers/builtin_plugins.py b/qiskit/transpiler/preset_passmanagers/builtin_plugins.py index d24fdca64885..cc19c4621295 100644 --- a/qiskit/transpiler/preset_passmanagers/builtin_plugins.py +++ b/qiskit/transpiler/preset_passmanagers/builtin_plugins.py @@ -176,23 +176,6 @@ def pass_manager(self, pass_manager_config, optimization_level=None) -> PassMana ) -class UnrollerPassManager(PassManagerStagePlugin): - """Plugin class for translation stage with :class:`~.BasisTranslator`""" - - def pass_manager(self, pass_manager_config, optimization_level=None) -> PassManager: - return common.generate_translation_passmanager( - pass_manager_config.target, - basis_gates=pass_manager_config.basis_gates, - method="unroller", - approximation_degree=pass_manager_config.approximation_degree, - coupling_map=pass_manager_config.coupling_map, - backend_props=pass_manager_config.backend_properties, - unitary_synthesis_method=pass_manager_config.unitary_synthesis_method, - unitary_synthesis_plugin_config=pass_manager_config.unitary_synthesis_plugin_config, - hls_config=pass_manager_config.hls_config, - ) - - class UnitarySynthesisPassManager(PassManagerStagePlugin): """Plugin class for translation stage with :class:`~.BasisTranslator`""" diff --git a/qiskit/transpiler/preset_passmanagers/common.py b/qiskit/transpiler/preset_passmanagers/common.py index 2795ec585931..8fc1402d322c 100644 --- a/qiskit/transpiler/preset_passmanagers/common.py +++ b/qiskit/transpiler/preset_passmanagers/common.py @@ -22,7 +22,6 @@ from qiskit.passmanager.flow_controllers import ConditionalController from qiskit.transpiler.passmanager import PassManager from qiskit.transpiler.passes import Error -from qiskit.transpiler.passes import Unroller from qiskit.transpiler.passes import BasisTranslator from qiskit.transpiler.passes import Unroll3qOrMore from qiskit.transpiler.passes import Collect2qBlocks @@ -65,7 +64,7 @@ working={"none", "stochastic", "sabre"}, not_working={"lookahead", "basic"} ), "translation_method": _ControlFlowState( - working={"translator", "synthesis", "unroller"}, + working={"translator", "synthesis"}, not_working=set(), ), "optimization_method": _ControlFlowState(working=set(), not_working=set()), @@ -447,9 +446,7 @@ def generate_translation_passmanager( Raises: TranspilerError: If the ``method`` kwarg is not a valid value """ - if method == "unroller": - unroll = [Unroller(basis=basis_gates, target=target)] - elif method == "translator": + if method == "translator": unroll = [ # Use unitary synthesis for basis aware decomposition of # UnitaryGates before custom unrolling diff --git a/releasenotes/notes/remove-deprecated-unroller-4693330708c681e0.yaml b/releasenotes/notes/remove-deprecated-unroller-4693330708c681e0.yaml new file mode 100644 index 000000000000..fbb25bb27f98 --- /dev/null +++ b/releasenotes/notes/remove-deprecated-unroller-4693330708c681e0.yaml @@ -0,0 +1,22 @@ +--- +upgrade: + - | + Removes the deprecated ``Unroller`` class in :mod:`qiskit.transpiler.passes.basis`. + This class was deprecated in Qiskit Terra 0.45 and has been replaced by + the combination usage of :class:`.BasisTranslator` and :class:`.UnrollCustomDefinitions`. + + Note that :class:`.BasisTranslator` and :class:`.UnrollCustomDefinitions` take different + arguments than ``Unroller``, as they requires a `EquivalenceLibrary` object to be passed in. + + Where previously ``Unroller(basis_gates)`` could be used, + you can now use:: + + from qiskit.circuit.library.standard_gates.equivalence_library import ( + StandardEquivalenceLibrary as std_eqlib, + ) + pm = PassManager([ + UnrollCustomDefinitions(std_eqlib, basis_gates) + BasisTranslator(std_eqlib, basis_gates), + ]) + translated = pm.run(circuit) + \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 5c3dd9c879b6..7c40a75e0b83 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,4 +6,4 @@ dill>=0.3 python-dateutil>=2.8.0 stevedore>=3.0.0 typing-extensions -symengine>=0.11 +symengine>=0.11 \ No newline at end of file diff --git a/test/benchmarks/passes.py b/test/benchmarks/passes.py index 1f93fcd9956e..19fb4f265c0e 100644 --- a/test/benchmarks/passes.py +++ b/test/benchmarks/passes.py @@ -66,25 +66,6 @@ def time_commutative_cancellation(self, _, __): _pass.run(self.dag) -class UnrolledPassBenchmarks: - params = ([5, 14, 20], [1024]) - - param_names = ["n_qubits", "depth"] - timeout = 300 - - def setup(self, n_qubits, depth): - seed = 42 - self.circuit = random_circuit( - n_qubits, depth, measure=True, conditional=True, reset=True, seed=seed - ) - self.dag = circuit_to_dag(self.circuit) - self.basis_gates = ["u1", "u2", "u3", "cx", "id"] - self.unrolled_dag = Unroller(self.basis_gates).run(self.dag) - - def time_optimize_1q(self, _, __): - Optimize1qGates().run(self.unrolled_dag) - - class MultipleBasisPassBenchmarks: params = ( [5, 14, 20], @@ -125,9 +106,6 @@ def setup(self, n_qubits, depth): self.dag = circuit_to_dag(self.circuit) self.basis_gates = ["u1", "u2", "u3", "cx", "id"] - def time_unroller(self, _, __): - Unroller(self.basis_gates).run(self.dag) - def time_depth_pass(self, _, __): Depth().run(self.dag) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 39042ae3d3ac..b7e08b83fe93 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -28,7 +28,7 @@ from qiskit.quantum_info.random import random_unitary from qiskit.quantum_info.states import Statevector import qiskit.circuit.add_control as ac -from qiskit.transpiler.passes import Unroller +from qiskit.transpiler.passes import UnrollCustomDefinitions, BasisTranslator from qiskit.converters.circuit_to_dag import circuit_to_dag from qiskit.converters.dag_to_circuit import dag_to_circuit from qiskit.quantum_info import Operator @@ -79,6 +79,9 @@ from qiskit.circuit._utils import _compute_control_matrix import qiskit.circuit.library.standard_gates as allGates from qiskit.circuit.library.standard_gates.multi_control_rotation_gates import _mcsu2_real_diagonal +from qiskit.circuit.library.standard_gates.equivalence_library import ( + StandardEquivalenceLibrary as std_eqlib, +) from .gate_utils import _get_free_params @@ -120,9 +123,11 @@ def test_controlled_u1(self): circ = QuantumCircuit(1) circ.append(U1Gate(theta), circ.qregs[0]) - with self.assertWarns(DeprecationWarning): - unroller = Unroller(["cx", "u", "p"]) - ctrl_circ_gate = dag_to_circuit(unroller.run(circuit_to_dag(circ))).control() + unroller = UnrollCustomDefinitions(std_eqlib, ["cx", "u", "p"]) + basis_translator = BasisTranslator(std_eqlib, ["cx", "u", "p"]) + ctrl_circ_gate = dag_to_circuit( + basis_translator.run(unroller.run(circuit_to_dag(circ))) + ).control() ctrl_circ = QuantumCircuit(2) ctrl_circ.append(ctrl_circ_gate, ctrl_circ.qregs[0]) ctrl_circ = ctrl_circ.decompose().decompose() @@ -169,9 +174,11 @@ def test_controlled_u3(self): circ = QuantumCircuit(1) circ.append(U3Gate(theta, phi, lamb), circ.qregs[0]) - with self.assertWarns(DeprecationWarning): - unroller = Unroller(["cx", "u", "p"]) - ctrl_circ_gate = dag_to_circuit(unroller.run(circuit_to_dag(circ))).control() + unroller = UnrollCustomDefinitions(std_eqlib, ["cx", "u", "p"]) + basis_translator = BasisTranslator(std_eqlib, ["cx", "u", "p"]) + ctrl_circ_gate = dag_to_circuit( + basis_translator.run(unroller.run(circuit_to_dag(circ))) + ).control() ctrl_circ = QuantumCircuit(2) ctrl_circ.append(ctrl_circ_gate, ctrl_circ.qregs[0]) ctrl_circ = ctrl_circ.decompose().decompose() @@ -927,31 +934,21 @@ def test_open_control_cx_unrolling(self): """test unrolling of open control gates when gate is in basis""" qc = QuantumCircuit(2) qc.cx(0, 1, ctrl_state=0) - dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - unroller = Unroller(["u3", "cx"]) - uqc = dag_to_circuit(unroller.run(dag)) - ref_circuit = QuantumCircuit(2) ref_circuit.append(U3Gate(np.pi, 0, np.pi), [0]) ref_circuit.cx(0, 1) ref_circuit.append(U3Gate(np.pi, 0, np.pi), [0]) - self.assertEqual(uqc, ref_circuit) + self.assertEqualTranslated(qc, ref_circuit, ["u3", "cx"]) def test_open_control_cy_unrolling(self): """test unrolling of open control gates when gate is in basis""" qc = QuantumCircuit(2) qc.cy(0, 1, ctrl_state=0) - dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - unroller = Unroller(["u3", "cy"]) - uqc = dag_to_circuit(unroller.run(dag)) - ref_circuit = QuantumCircuit(2) ref_circuit.append(U3Gate(np.pi, 0, np.pi), [0]) ref_circuit.cy(0, 1) ref_circuit.append(U3Gate(np.pi, 0, np.pi), [0]) - self.assertEqual(uqc, ref_circuit) + self.assertEqualTranslated(qc, ref_circuit, ["u3", "cy"]) def test_open_control_ccx_unrolling(self): """test unrolling of open control gates when gate is in basis""" @@ -959,11 +956,6 @@ def test_open_control_ccx_unrolling(self): qc = QuantumCircuit(qreg) ccx = CCXGate(ctrl_state=0) qc.append(ccx, [0, 1, 2]) - dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - unroller = Unroller(["x", "ccx"]) - unrolled_dag = unroller.run(dag) - # ┌───┐ ┌───┐ # q0_0: ┤ X ├──■──┤ X ├ # ├───┤ │ ├───┤ @@ -977,8 +969,7 @@ def test_open_control_ccx_unrolling(self): ref_circuit.ccx(qreg[0], qreg[1], qreg[2]) ref_circuit.x(qreg[0]) ref_circuit.x(qreg[1]) - ref_dag = circuit_to_dag(ref_circuit) - self.assertEqual(unrolled_dag, ref_dag) + self.assertEqualTranslated(qc, ref_circuit, ["x", "ccx"]) def test_ccx_ctrl_state_consistency(self): """Test the consistency of parameters ctrl_state in CCX @@ -1005,17 +996,12 @@ def test_open_control_composite_unrolling(self): cqreg = QuantumRegister(3) qc = QuantumCircuit(cqreg) qc.append(bell.control(ctrl_state=0), qc.qregs[0][:]) - dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - unroller = Unroller(["x", "u1", "cbell"]) - unrolled_dag = unroller.run(dag) # create reference circuit ref_circuit = QuantumCircuit(cqreg) ref_circuit.x(cqreg[0]) ref_circuit.append(bell.control(), [cqreg[0], cqreg[1], cqreg[2]]) ref_circuit.x(cqreg[0]) - ref_dag = circuit_to_dag(ref_circuit) - self.assertEqual(unrolled_dag, ref_dag) + self.assertEqualTranslated(qc, ref_circuit, ["x", "u1", "cbell"]) @data(*ControlledGate.__subclasses__()) def test_standard_base_gate_setting(self, gate_class): @@ -1372,6 +1358,13 @@ def test_control_zero_operand_gate(self, num_ctrl_qubits): target.flat[-1] = -1 self.assertEqual(Operator(controlled), Operator(target)) + def assertEqualTranslated(self, circuit, unrolled_reference, basis): + """Assert that the circuit is equal to the unrolled reference circuit.""" + unroller = UnrollCustomDefinitions(std_eqlib, basis) + basis_translator = BasisTranslator(std_eqlib, basis) + unrolled = basis_translator(unroller(circuit)) + self.assertEqual(unrolled, unrolled_reference) + @ddt class TestOpenControlledToMatrix(QiskitTestCase): @@ -1446,9 +1439,9 @@ def test_single_controlled_rotation_gates(self, gate, cgate): cqc = QuantumCircuit(self.num_ctrl + self.num_target) cqc.append(cgate, cqc.qregs[0]) dag = circuit_to_dag(cqc) - with self.assertWarns(DeprecationWarning): - unroller = Unroller(["u", "cx"]) - uqc = dag_to_circuit(unroller.run(dag)) + unroller = UnrollCustomDefinitions(std_eqlib, ["u", "cx"]) + basis_translator = BasisTranslator(std_eqlib, ["u", "cx"]) + uqc = dag_to_circuit(basis_translator.run(unroller.run(dag))) self.log.info("%s gate count: %d", cgate.name, uqc.size()) self.log.info("\n%s", str(uqc)) # these limits could be changed @@ -1469,9 +1462,9 @@ def test_composite(self): qc.append(self.grz.control(self.num_ctrl), qreg) dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - unroller = Unroller(["u", "cx"]) - uqc = dag_to_circuit(unroller.run(dag)) + unroller = UnrollCustomDefinitions(std_eqlib, ["u", "cx"]) + basis_translator = BasisTranslator(std_eqlib, ["u", "cx"]) + uqc = dag_to_circuit(basis_translator.run(unroller.run(dag))) self.log.info("%s gate count: %d", uqc.name, uqc.size()) self.assertLessEqual(uqc.size(), 96, f"\n{uqc}") # this limit could be changed diff --git a/test/python/circuit/test_instruction_repeat.py b/test/python/circuit/test_instruction_repeat.py index c276b91dba5b..9cf50787d58d 100644 --- a/test/python/circuit/test_instruction_repeat.py +++ b/test/python/circuit/test_instruction_repeat.py @@ -14,14 +14,11 @@ """Test Qiskit's repeat instruction operation.""" import unittest -from numpy import pi -from qiskit.transpiler import PassManager from qiskit import QuantumRegister, QuantumCircuit, ClassicalRegister from qiskit.test import QiskitTestCase -from qiskit.circuit.library import SGate, U3Gate, CXGate, UnitaryGate +from qiskit.circuit.library import SGate, CXGate, UnitaryGate from qiskit.circuit import Instruction, Measure, Gate -from qiskit.transpiler.passes import Unroller from qiskit.circuit.exceptions import CircuitError @@ -122,39 +119,6 @@ def test_measure_one(self): self.assertNotIsInstance(result, Gate) -class TestRepeatUnroller(QiskitTestCase): - """Test unrolling Gate.repeat""" - - def test_unroller_two(self): - """Test unrolling gate.repeat(2).""" - qr = QuantumRegister(1, "qr") - - circuit = QuantumCircuit(qr) - circuit.append(SGate().repeat(2), [qr[0]]) - with self.assertWarns(DeprecationWarning): - result = PassManager(Unroller("u3")).run(circuit) - - expected = QuantumCircuit(qr) - expected.append(U3Gate(0, 0, pi / 2), [qr[0]]) - expected.append(U3Gate(0, 0, pi / 2), [qr[0]]) - - self.assertEqual(result, expected) - - def test_unroller_one(self): - """Test unrolling gate.repeat(1).""" - qr = QuantumRegister(1, "qr") - - circuit = QuantumCircuit(qr) - circuit.append(SGate().repeat(1), [qr[0]]) - with self.assertWarns(DeprecationWarning): - result = PassManager(Unroller("u3")).run(circuit) - - expected = QuantumCircuit(qr) - expected.append(U3Gate(0, 0, pi / 2), [qr[0]]) - - self.assertEqual(result, expected) - - class TestRepeatErrors(QiskitTestCase): """Test when Gate.repeat() should raise.""" diff --git a/test/python/qasm2/test_circuit_methods.py b/test/python/qasm2/test_circuit_methods.py index e6b35e582ccb..78839de14455 100644 --- a/test/python/qasm2/test_circuit_methods.py +++ b/test/python/qasm2/test_circuit_methods.py @@ -19,10 +19,14 @@ from qiskit.circuit import Gate, Parameter from qiskit.exceptions import QiskitError from qiskit.test import QiskitTestCase -from qiskit.transpiler.passes import Unroller +from qiskit.transpiler.passes import UnrollCustomDefinitions, BasisTranslator from qiskit.converters.circuit_to_dag import circuit_to_dag from qiskit.qasm2 import dumps +from qiskit.circuit.library.standard_gates.equivalence_library import ( + StandardEquivalenceLibrary as std_eqlib, +) + class LoadFromQasmTest(QiskitTestCase): """Test circuit.from_qasm_* set of methods.""" @@ -501,8 +505,9 @@ def assertEqualUnroll(self, basis, circuit, expected): """Compares the dags after unrolling to basis""" circuit_dag = circuit_to_dag(circuit) expected_dag = circuit_to_dag(expected) - with self.assertWarns(DeprecationWarning): - circuit_result = Unroller(basis).run(circuit_dag) - expected_result = Unroller(basis).run(expected_dag) + unroller = UnrollCustomDefinitions(std_eqlib, basis) + basis_translator = BasisTranslator(std_eqlib, basis) + circuit_result = basis_translator.run(unroller.run(circuit_dag)) + expected_result = basis_translator.run(unroller.run(expected_dag)) self.assertEqual(circuit_result, expected_result) diff --git a/test/python/transpiler/test_optimize_1q_gates.py b/test/python/transpiler/test_optimize_1q_gates.py index 41c43bd88a66..86714159e53e 100644 --- a/test/python/transpiler/test_optimize_1q_gates.py +++ b/test/python/transpiler/test_optimize_1q_gates.py @@ -17,7 +17,7 @@ from qiskit import QuantumRegister, QuantumCircuit, ClassicalRegister from qiskit.transpiler import PassManager -from qiskit.transpiler.passes import Optimize1qGates, Unroller +from qiskit.transpiler.passes import Optimize1qGates, BasisTranslator from qiskit.converters import circuit_to_dag from qiskit.test import QiskitTestCase from qiskit.circuit import Parameter @@ -25,6 +25,10 @@ from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.target import Target +from qiskit.circuit.library.standard_gates.equivalence_library import ( + StandardEquivalenceLibrary as std_eqlib, +) + class TestOptimize1qGates(QiskitTestCase): """Test for 1q gate optimizations.""" @@ -58,8 +62,7 @@ def test_optimize_h_gates_pass_manager(self): expected.append(U2Gate(0, np.pi), [qr[0]]) passmanager = PassManager() - with self.assertWarns(DeprecationWarning): - passmanager.append(Unroller(["u2"])) + passmanager.append(BasisTranslator(std_eqlib, ["u2"])) passmanager.append(Optimize1qGates()) result = passmanager.run(circuit) @@ -695,8 +698,7 @@ def test_optimize_u3_with_parameters(self): qc.ry(alpha, qr[0]) qc.ry(0.1, qr[0]) qc.ry(0.2, qr[0]) - with self.assertWarns(DeprecationWarning): - passmanager = PassManager([Unroller(["u3"]), Optimize1qGates()]) + passmanager = PassManager([BasisTranslator(std_eqlib, ["u3"]), Optimize1qGates()]) result = passmanager.run(qc) expected = QuantumCircuit(qr) diff --git a/test/python/transpiler/test_pass_call.py b/test/python/transpiler/test_pass_call.py index 6598abe8929b..a33481c26169 100644 --- a/test/python/transpiler/test_pass_call.py +++ b/test/python/transpiler/test_pass_call.py @@ -13,10 +13,7 @@ """Test calling passes (passmanager-less)""" from qiskit import QuantumRegister, QuantumCircuit -from qiskit.circuit.library import ZGate -from qiskit.transpiler.passes import Unroller from qiskit.test import QiskitTestCase -from qiskit.exceptions import QiskitError from qiskit.transpiler import PropertySet from ._dummy_passes import PassD_TP_NR_NP, PassE_AP_NR_NP, PassN_AP_NR_NP @@ -93,19 +90,3 @@ def test_analysis_pass_remove_property(self): self.assertEqual(property_set, PropertySet({"to none": None})) self.assertIsInstance(property_set, dict) self.assertEqual(circuit, result) - - def test_error_unknown_defn_unroller_pass(self): - """Check for proper error message when unroller cannot find the definition - of a gate.""" - circuit = ZGate().control(2).definition - basis = ["u1", "u2", "u3", "cx"] - with self.assertWarns(DeprecationWarning): - unroller = Unroller(basis) - with self.assertRaises(QiskitError) as cm: - unroller(circuit) - exp_msg = ( - "Error decomposing node of instruction 'u': " - "'NoneType' object has no attribute 'global_phase'. " - "Unable to define instruction 'u' in the given basis." - ) - self.assertEqual(exp_msg, cm.exception.message) diff --git a/test/python/transpiler/test_passmanager.py b/test/python/transpiler/test_passmanager.py index 181dace29acf..151f478016f3 100644 --- a/test/python/transpiler/test_passmanager.py +++ b/test/python/transpiler/test_passmanager.py @@ -28,10 +28,15 @@ ) from qiskit.transpiler import PassManager, PropertySet, TransformationPass from qiskit.transpiler.passes import CommutativeCancellation -from qiskit.transpiler.passes import Optimize1qGates, Unroller +from qiskit.transpiler.passes import Optimize1qGates, BasisTranslator from qiskit.test import QiskitTestCase +from qiskit.circuit.library.standard_gates.equivalence_library import ( + StandardEquivalenceLibrary as std_eqlib, +) + + class TestPassManager(QiskitTestCase): """Test Pass manager logic.""" @@ -60,14 +65,13 @@ def callback(**kwargs): calls.append(out_dict) passmanager = PassManager() - with self.assertWarns(DeprecationWarning): - passmanager.append(Unroller(["u2"])) + passmanager.append(BasisTranslator(std_eqlib, ["u2"])) passmanager.append(Optimize1qGates()) passmanager.run(circuit, callback=callback) self.assertEqual(len(calls), 2) self.assertEqual(len(calls[0]), 5) self.assertEqual(calls[0]["count"], 0) - self.assertEqual(calls[0]["pass_"].name(), "Unroller") + self.assertEqual(calls[0]["pass_"].name(), "BasisTranslator") self.assertEqual(expected_start_dag, calls[0]["dag"]) self.assertIsInstance(calls[0]["time"], float) self.assertEqual(calls[0]["property_set"], PropertySet()) diff --git a/test/python/transpiler/test_preset_passmanagers.py b/test/python/transpiler/test_preset_passmanagers.py index cf6b216743cf..dbfef944c1ea 100644 --- a/test/python/transpiler/test_preset_passmanagers.py +++ b/test/python/transpiler/test_preset_passmanagers.py @@ -1523,22 +1523,21 @@ def test_allow_overriding_defaults(self, optimization_level): def callback(pass_, **_): calls.add(pass_.name()) - with self.assertWarns(DeprecationWarning): - transpiled = transpile( - circuit, - basis_gates=["u3", "cx", "if_else", "for_loop", "while_loop"], - layout_method="trivial", - translation_method="unroller", - coupling_map=coupling_map, - optimization_level=optimization_level, - seed_transpiler=2022_10_04, - callback=callback, - ) + transpiled = transpile( + circuit, + basis_gates=["u3", "cx", "if_else", "for_loop", "while_loop"], + layout_method="trivial", + translation_method="translator", + coupling_map=coupling_map, + optimization_level=optimization_level, + seed_transpiler=2022_10_04, + callback=callback, + ) self.assertIsInstance(transpiled, QuantumCircuit) self.assertIsNot(getattr(transpiled, "_layout", None), None) self.assertIn("TrivialLayout", calls) - self.assertIn("Unroller", calls) + self.assertIn("BasisTranslator", calls) self.assertNotIn("DenseLayout", calls) self.assertNotIn("SabreLayout", calls) diff --git a/test/python/transpiler/test_staged_passmanager.py b/test/python/transpiler/test_staged_passmanager.py index 33bec0f4f913..00d95747b1c2 100644 --- a/test/python/transpiler/test_staged_passmanager.py +++ b/test/python/transpiler/test_staged_passmanager.py @@ -19,9 +19,13 @@ from qiskit.transpiler import PassManager, StagedPassManager from qiskit.transpiler.exceptions import TranspilerError -from qiskit.transpiler.passes import Optimize1qGates, Unroller, Depth, BasicSwap +from qiskit.transpiler.passes import Optimize1qGates, Depth, BasicSwap, BasisTranslator from qiskit.test import QiskitTestCase +from qiskit.circuit.library.standard_gates.equivalence_library import ( + StandardEquivalenceLibrary as std_eqlib, +) + @ddt class TestStagedPassManager(QiskitTestCase): @@ -30,15 +34,14 @@ def test_default_stages(self): self.assertEqual( spm.stages, ("init", "layout", "routing", "translation", "optimization", "scheduling") ) - with self.assertWarns(DeprecationWarning): - spm = StagedPassManager( - init=PassManager([Optimize1qGates()]), - routing=PassManager([Unroller(["u", "cx"])]), - scheduling=PassManager([Depth()]), - ) + spm = StagedPassManager( + init=PassManager([Optimize1qGates()]), + routing=PassManager([BasisTranslator(std_eqlib, ["u", "cx"])]), + scheduling=PassManager([Depth()]), + ) self.assertEqual( [x.__class__.__name__ for x in spm.to_flow_controller().tasks], - ["Optimize1qGates", "Unroller", "Depth"], + ["Optimize1qGates", "BasisTranslator", "Depth"], ) def test_inplace_edit(self): @@ -48,12 +51,11 @@ def test_inplace_edit(self): [x.__class__.__name__ for x in spm.to_flow_controller().tasks], ["Optimize1qGates", "Depth"], ) - with self.assertWarns(DeprecationWarning): - spm.single_stage.append(Unroller(["u"])) + spm.single_stage.append(BasisTranslator(std_eqlib, ["u"])) spm.single_stage.append(Depth()) self.assertEqual( [x.__class__.__name__ for x in spm.to_flow_controller().tasks], - ["Optimize1qGates", "Depth", "Unroller", "Depth"], + ["Optimize1qGates", "Depth", "BasisTranslator", "Depth"], ) def test_invalid_stage(self): @@ -103,8 +105,7 @@ def test_invalid_stages(self): def test_repeated_stages(self): stages = ["alpha", "omega", "alpha"] - with self.assertWarns(DeprecationWarning): - pre_alpha = PassManager(Unroller(["u", "cx"])) + pre_alpha = PassManager(BasisTranslator(std_eqlib, ["u", "cx"])) alpha = PassManager(Depth()) post_alpha = PassManager(BasicSwap([[0, 1], [1, 2]])) omega = PassManager(Optimize1qGates()) diff --git a/test/python/transpiler/test_unroller.py b/test/python/transpiler/test_unroller.py deleted file mode 100644 index c43953f221d9..000000000000 --- a/test/python/transpiler/test_unroller.py +++ /dev/null @@ -1,780 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017, 2018. -# -# 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. - - -"""Test the Unroller pass""" - -from numpy import pi - -from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit -from qiskit.transpiler.passes import Unroller -from qiskit.converters import circuit_to_dag, dag_to_circuit -from qiskit.quantum_info import Operator -from qiskit.test import QiskitTestCase -from qiskit.exceptions import QiskitError -from qiskit.circuit import Parameter, Qubit, Clbit -from qiskit.circuit.library import U1Gate, U2Gate, U3Gate, CU1Gate, CU3Gate -from qiskit.transpiler.target import Target - - -class TestUnroller(QiskitTestCase): - """Tests the Unroller pass.""" - - def test_basic_unroll(self): - """Test decompose a single H into u2.""" - qr = QuantumRegister(1, "qr") - circuit = QuantumCircuit(qr) - circuit.h(qr[0]) - dag = circuit_to_dag(circuit) - with self.assertWarns(DeprecationWarning): - pass_ = Unroller(["u2"]) - unrolled_dag = pass_.run(dag) - op_nodes = unrolled_dag.op_nodes() - self.assertEqual(len(op_nodes), 1) - self.assertEqual(op_nodes[0].name, "u2") - - def test_basic_unroll_target(self): - """Test decompose a single H into U2 from target.""" - qc = QuantumCircuit(1) - qc.h(0) - target = Target(num_qubits=1) - phi = Parameter("phi") - lam = Parameter("lam") - target.add_instruction(U2Gate(phi, lam)) - dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - pass_ = Unroller(target=target) - unrolled_dag = pass_.run(dag) - op_nodes = unrolled_dag.op_nodes() - self.assertEqual(len(op_nodes), 1) - self.assertEqual(op_nodes[0].name, "u2") - - def test_unroll_toffoli(self): - """Test unroll toffoli on multi regs to h, t, tdg, cx.""" - qr1 = QuantumRegister(2, "qr1") - qr2 = QuantumRegister(1, "qr2") - circuit = QuantumCircuit(qr1, qr2) - circuit.ccx(qr1[0], qr1[1], qr2[0]) - dag = circuit_to_dag(circuit) - with self.assertWarns(DeprecationWarning): - pass_ = Unroller(["h", "t", "tdg", "cx"]) - unrolled_dag = pass_.run(dag) - op_nodes = unrolled_dag.op_nodes() - self.assertEqual(len(op_nodes), 15) - for node in op_nodes: - self.assertIn(node.name, ["h", "t", "tdg", "cx"]) - - def test_unroll_1q_chain_conditional(self): - """Test unroll chain of 1-qubit gates interrupted by conditional.""" - qr = QuantumRegister(1, "qr") - cr = ClassicalRegister(1, "cr") - circuit = QuantumCircuit(qr, cr) - circuit.h(qr) - circuit.tdg(qr) - circuit.z(qr) - circuit.t(qr) - circuit.ry(0.5, qr) - circuit.rz(0.3, qr) - circuit.rx(0.1, qr) - circuit.measure(qr, cr) - circuit.x(qr).c_if(cr, 1) - circuit.y(qr).c_if(cr, 1) - circuit.z(qr).c_if(cr, 1) - dag = circuit_to_dag(circuit) - with self.assertWarns(DeprecationWarning): - pass_ = Unroller(["u1", "u2", "u3"]) - unrolled_dag = pass_.run(dag) - - # Pick up -1 * 0.3 / 2 global phase for one RZ -> U1. - ref_circuit = QuantumCircuit(qr, cr, global_phase=-0.3 / 2) - ref_circuit.append(U2Gate(0, pi), [qr[0]]) - ref_circuit.append(U1Gate(-pi / 4), [qr[0]]) - ref_circuit.append(U1Gate(pi), [qr[0]]) - ref_circuit.append(U1Gate(pi / 4), [qr[0]]) - ref_circuit.append(U3Gate(0.5, 0, 0), [qr[0]]) - ref_circuit.append(U1Gate(0.3), [qr[0]]) - ref_circuit.append(U3Gate(0.1, -pi / 2, pi / 2), [qr[0]]) - ref_circuit.measure(qr[0], cr[0]) - ref_circuit.append(U3Gate(pi, 0, pi), [qr[0]]).c_if(cr, 1) - ref_circuit.append(U3Gate(pi, pi / 2, pi / 2), [qr[0]]).c_if(cr, 1) - ref_circuit.append(U1Gate(pi), [qr[0]]).c_if(cr, 1) - ref_dag = circuit_to_dag(ref_circuit) - - self.assertEqual(unrolled_dag, ref_dag) - - def test_unroll_no_basis(self): - """Test when a given gate has no decompositions.""" - qr = QuantumRegister(1, "qr") - cr = ClassicalRegister(1, "cr") - circuit = QuantumCircuit(qr, cr) - circuit.h(qr) - dag = circuit_to_dag(circuit) - with self.assertWarns(DeprecationWarning): - pass_ = Unroller(basis=[]) - - with self.assertRaises(QiskitError): - pass_.run(dag) - - def test_simple_unroll_parameterized_without_expressions(self): - """Verify unrolling parameterized gates without expressions.""" - qr = QuantumRegister(1) - qc = QuantumCircuit(qr) - - theta = Parameter("theta") - - qc.rz(theta, qr[0]) - dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - unrolled_dag = Unroller(["u1", "u3", "cx"]).run(dag) - - expected = QuantumCircuit(qr, global_phase=-theta / 2) - expected.append(U1Gate(theta), [qr[0]]) - - self.assertEqual(circuit_to_dag(expected), unrolled_dag) - - def test_simple_unroll_parameterized_with_expressions(self): - """Verify unrolling parameterized gates with expressions.""" - qr = QuantumRegister(1) - qc = QuantumCircuit(qr) - - theta = Parameter("theta") - phi = Parameter("phi") - sum_ = theta + phi - - qc.rz(sum_, qr[0]) - dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - unrolled_dag = Unroller(["u1", "u3", "cx"]).run(dag) - - expected = QuantumCircuit(qr, global_phase=-sum_ / 2) - expected.append(U1Gate(sum_), [qr[0]]) - - self.assertEqual(circuit_to_dag(expected), unrolled_dag) - - def test_definition_unroll_parameterized(self): - """Verify that unrolling complex gates with parameters does not raise.""" - qr = QuantumRegister(2) - qc = QuantumCircuit(qr) - - theta = Parameter("theta") - - qc.append(CU1Gate(theta), [qr[1], qr[0]]) - qc.append(CU1Gate(theta * theta), [qr[0], qr[1]]) - dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - out_dag = Unroller(["u1", "cx"]).run(dag) - - self.assertEqual(out_dag.count_ops(), {"u1": 6, "cx": 4}) - - def test_unrolling_parameterized_composite_gates(self): - """Verify unrolling circuits with parameterized composite gates.""" - qr1 = QuantumRegister(2) - subqc = QuantumCircuit(qr1) - - theta = Parameter("theta") - - subqc.rz(theta, qr1[0]) - subqc.cx(qr1[0], qr1[1]) - subqc.rz(theta, qr1[1]) - - # Expanding across register with shared parameter - qr2 = QuantumRegister(4) - qc = QuantumCircuit(qr2) - - qc.append(subqc.to_instruction(), [qr2[0], qr2[1]]) - qc.append(subqc.to_instruction(), [qr2[2], qr2[3]]) - - dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - out_dag = Unroller(["u1", "u3", "cx"]).run(dag) - - # Pick up -1 * theta / 2 global phase four twice (once for each RZ -> P - # in each of the two sub_instr instructions). - expected = QuantumCircuit(qr2, global_phase=-1 * 4 * theta / 2.0) - expected.append(U1Gate(theta), [qr2[0]]) - expected.cx(qr2[0], qr2[1]) - expected.append(U1Gate(theta), [qr2[1]]) - - expected.append(U1Gate(theta), [qr2[2]]) - expected.cx(qr2[2], qr2[3]) - expected.append(U1Gate(theta), [qr2[3]]) - self.assertEqual(circuit_to_dag(expected), out_dag) - - # Expanding across register with shared parameter - qc = QuantumCircuit(qr2) - - phi = Parameter("phi") - gamma = Parameter("gamma") - - qc.append(subqc.to_instruction({theta: phi}), [qr2[0], qr2[1]]) - qc.append(subqc.to_instruction({theta: gamma}), [qr2[2], qr2[3]]) - - dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - out_dag = Unroller(["u1", "u3", "cx"]).run(dag) - - expected = QuantumCircuit(qr2, global_phase=-1 * (2 * phi + 2 * gamma) / 2.0) - expected.append(U1Gate(phi), [qr2[0]]) - expected.cx(qr2[0], qr2[1]) - expected.append(U1Gate(phi), [qr2[1]]) - - expected.append(U1Gate(gamma), [qr2[2]]) - expected.cx(qr2[2], qr2[3]) - expected.append(U1Gate(gamma), [qr2[3]]) - - self.assertEqual(circuit_to_dag(expected), out_dag) - - def test_unrolling_preserves_qregs_order(self): - """Test unrolling a gate preseveres it's definition registers order""" - qr = QuantumRegister(2, "qr1") - qc = QuantumCircuit(qr) - qc.cx(1, 0) - gate = qc.to_gate() - - qr2 = QuantumRegister(2, "qr2") - qc2 = QuantumCircuit(qr2) - qc2.append(gate, qr2) - - dag = circuit_to_dag(qc2) - with self.assertWarns(DeprecationWarning): - out_dag = Unroller(["cx"]).run(dag) - - expected = QuantumCircuit(qr2) - expected.cx(1, 0) - - self.assertEqual(circuit_to_dag(expected), out_dag) - - def test_unrolling_nested_gates_preserves_qregs_order(self): - """Test unrolling a nested gate preseveres it's definition registers order.""" - qr = QuantumRegister(2, "qr1") - qc = QuantumCircuit(qr) - qc.cx(1, 0) - gate_level_1 = qc.to_gate() - - qr2 = QuantumRegister(2, "qr2") - qc2 = QuantumCircuit(qr2) - qc2.append(gate_level_1, [1, 0]) - qc2.cp(pi, 1, 0) - gate_level_2 = qc2.to_gate() - - qr3 = QuantumRegister(2, "qr3") - qc3 = QuantumCircuit(qr3) - qc3.append(gate_level_2, [1, 0]) - qc3.cu(pi, pi, pi, 0, 1, 0) - gate_level_3 = qc3.to_gate() - - qr4 = QuantumRegister(2, "qr4") - qc4 = QuantumCircuit(qr4) - qc4.append(gate_level_3, [0, 1]) - - dag = circuit_to_dag(qc4) - with self.assertWarns(DeprecationWarning): - out_dag = Unroller(["cx", "cp", "cu"]).run(dag) - - expected = QuantumCircuit(qr4) - expected.cx(1, 0) - expected.cp(pi, 0, 1) - expected.cu(pi, pi, pi, 0, 1, 0) - - self.assertEqual(circuit_to_dag(expected), out_dag) - - def test_unrolling_global_phase_1q(self): - """Test unrolling a circuit with global phase in a composite gate.""" - circ = QuantumCircuit(1, global_phase=pi / 2) - circ.x(0) - circ.h(0) - v = circ.to_gate() - - qc = QuantumCircuit(1) - qc.append(v, [0]) - - dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - out_dag = Unroller(["cx", "x", "h"]).run(dag) - qcd = dag_to_circuit(out_dag) - - self.assertEqual(Operator(qc), Operator(qcd)) - - def test_unrolling_global_phase_nested_gates(self): - """Test unrolling a nested gate preseveres global phase.""" - qc = QuantumCircuit(1, global_phase=pi) - qc.x(0) - gate = qc.to_gate() - - qc = QuantumCircuit(1) - qc.append(gate, [0]) - gate = qc.to_gate() - - qc = QuantumCircuit(1) - qc.append(gate, [0]) - dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - out_dag = Unroller(["x", "u"]).run(dag) - qcd = dag_to_circuit(out_dag) - - self.assertEqual(Operator(qc), Operator(qcd)) - - def test_if_simple(self): - """Test a simple if statement unrolls correctly.""" - qubits = [Qubit(), Qubit()] - clbits = [Clbit(), Clbit()] - - qc = QuantumCircuit(qubits, clbits) - qc.h(0) - qc.measure(0, 0) - with qc.if_test((clbits[0], 0)): - qc.x(0) - qc.h(0) - qc.measure(0, 1) - with qc.if_test((clbits[1], 0)): - qc.h(1) - qc.cx(1, 0) - dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - unrolled_dag = Unroller(["u", "cx"]).run(dag) - - expected = QuantumCircuit(qubits, clbits) - expected.u(pi / 2, 0, pi, 0) - expected.measure(0, 0) - with expected.if_test((clbits[0], 0)): - expected.u(pi, 0, pi, 0) - expected.u(pi / 2, 0, pi, 0) - expected.measure(0, 1) - with expected.if_test((clbits[1], 0)): - expected.u(pi / 2, 0, pi, 1) - expected.cx(1, 0) - expected_dag = circuit_to_dag(expected) - self.assertEqual(unrolled_dag, expected_dag) - - def test_if_else_simple(self): - """Test a simple if-else statement unrolls correctly.""" - qubits = [Qubit(), Qubit()] - clbits = [Clbit(), Clbit()] - - qc = QuantumCircuit(qubits, clbits) - qc.h(0) - qc.measure(0, 0) - with qc.if_test((clbits[0], 0)) as else_: - qc.x(0) - with else_: - qc.z(0) - qc.h(0) - qc.measure(0, 1) - with qc.if_test((clbits[1], 0)) as else_: - qc.h(1) - qc.cx(1, 0) - with else_: - qc.h(0) - qc.cx(0, 1) - dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - unrolled_dag = Unroller(["u", "cx"]).run(dag) - - expected = QuantumCircuit(qubits, clbits) - expected.u(pi / 2, 0, pi, 0) - expected.measure(0, 0) - with expected.if_test((clbits[0], 0)) as else_: - expected.u(pi, 0, pi, 0) - with else_: - expected.u(0, 0, pi, 0) - expected.u(pi / 2, 0, pi, 0) - expected.measure(0, 1) - with expected.if_test((clbits[1], 0)) as else_: - expected.u(pi / 2, 0, pi, 1) - expected.cx(1, 0) - with else_: - expected.u(pi / 2, 0, pi, 0) - expected.cx(0, 1) - expected_dag = circuit_to_dag(expected) - self.assertEqual(unrolled_dag, expected_dag) - - def test_nested_control_flow(self): - """Test unrolling nested control flow blocks.""" - qr = QuantumRegister(2) - cr1 = ClassicalRegister(1) - cr2 = ClassicalRegister(1) - cr3 = ClassicalRegister(1) - qc = QuantumCircuit(qr, cr1, cr2, cr3) - with qc.for_loop(range(3)): - with qc.while_loop((cr1, 0)): - qc.x(0) - with qc.while_loop((cr2, 0)): - qc.y(0) - with qc.while_loop((cr3, 0)): - qc.z(0) - dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - unrolled_dag = Unroller(["u", "cx"]).run(dag) - - expected = QuantumCircuit(qr, cr1, cr2, cr3) - with expected.for_loop(range(3)): - with expected.while_loop((cr1, 0)): - expected.u(pi, 0, pi, 0) - with expected.while_loop((cr2, 0)): - expected.u(pi, pi / 2, pi / 2, 0) - with expected.while_loop((cr3, 0)): - expected.u(0, 0, pi, 0) - expected_dag = circuit_to_dag(expected) - self.assertEqual(unrolled_dag, expected_dag) - - def test_parameterized_angle(self): - """Test unrolling with parameterized angle""" - qc = QuantumCircuit(1) - index = Parameter("index") - with qc.for_loop((0, 0.5 * pi), index) as param: - qc.rx(param, 0) - dag = circuit_to_dag(qc) - with self.assertWarns(DeprecationWarning): - unrolled_dag = Unroller(["u", "cx"]).run(dag) - - expected = QuantumCircuit(1) - with expected.for_loop((0, 0.5 * pi), index) as param: - expected.u(param, -pi / 2, pi / 2, 0) - expected_dag = circuit_to_dag(expected) - self.assertEqual(unrolled_dag, expected_dag) - - -class TestUnrollAllInstructions(QiskitTestCase): - """Test unrolling a circuit containing all standard instructions.""" - - def setUp(self): - super().setUp() - qr = self.qr = QuantumRegister(3, "qr") - cr = self.cr = ClassicalRegister(3, "cr") - self.circuit = QuantumCircuit(qr, cr) - self.ref_circuit = QuantumCircuit(qr, cr) - with self.assertWarns(DeprecationWarning): - self.pass_ = Unroller(basis=["u3", "cx", "id"]) - - def compare_dags(self): - """compare dags in class tests""" - dag = circuit_to_dag(self.circuit) - unrolled_dag = self.pass_.run(dag) - ref_dag = circuit_to_dag(self.ref_circuit) - self.assertEqual(unrolled_dag, ref_dag) - - def test_unroll_crx(self): - """test unroll crx""" - # qr_1: ─────■───── qr_1: ─────────────────■─────────────────────■───────────────────── - # ┌────┴────┐ = ┌─────────────┐┌─┴─┐┌───────────────┐┌─┴─┐┌─────────────────┐ - # qr_2: ┤ Rx(0.5) ├ qr_2: ┤ U3(0,0,π/2) ├┤ X ├┤ U3(-0.25,0,0) ├┤ X ├┤ U3(0.25,-π/2,0) ├ - # └─────────┘ └─────────────┘└───┘└───────────────┘└───┘└─────────────────┘ - self.circuit.crx(0.5, 1, 2) - self.ref_circuit.append(U3Gate(0, 0, pi / 2), [2]) - self.ref_circuit.cx(1, 2) - self.ref_circuit.append(U3Gate(-0.25, 0, 0), [2]) - self.ref_circuit.cx(1, 2) - self.ref_circuit.append(U3Gate(0.25, -pi / 2, 0), [2]) - self.compare_dags() - - def test_unroll_cry(self): - """test unroll cry""" - # qr_1: ─────■───── qr_1: ──────────────────■─────────────────────■── - # ┌────┴────┐ = ┌──────────────┐┌─┴─┐┌───────────────┐┌─┴─┐ - # qr_2: ┤ Ry(0.5) ├ qr_2: ┤ U3(0.25,0,0) ├┤ X ├┤ U3(-0.25,0,0) ├┤ X ├ - # └─────────┘ └──────────────┘└───┘└───────────────┘└───┘ - self.circuit.cry(0.5, 1, 2) - self.ref_circuit.append(U3Gate(0.25, 0, 0), [2]) - self.ref_circuit.cx(1, 2) - self.ref_circuit.append(U3Gate(-0.25, 0, 0), [2]) - self.ref_circuit.cx(1, 2) - self.compare_dags() - - def test_unroll_ccx(self): - """test unroll ccx""" - - # qr_0: ──■── qr_0: ──────────────────────────────────────■──────────────────────» - # │ │ » - # qr_1: ──■── = qr_1: ─────────────────■────────────────────┼───────────────────■──» - # ┌─┴─┐ ┌─────────────┐┌─┴─┐┌──────────────┐┌─┴─┐┌─────────────┐┌─┴─┐» - # qr_2: ┤ X ├ qr_2: ┤ U3(π/2,0,π) ├┤ X ├┤ U3(0,0,-π/4) ├┤ X ├┤ U3(0,0,π/4) ├┤ X ├» - # └───┘ └─────────────┘└───┘└──────────────┘└───┘└─────────────┘└───┘» - # « ┌─────────────┐ - # «qr_0: ──────────────────■─────────■───────┤ U3(0,0,π/4) ├───■── - # « ┌─────────────┐ │ ┌─┴─┐ ├─────────────┴┐┌─┴─┐ - # «qr_1: ┤ U3(0,0,π/4) ├───┼───────┤ X ├─────┤ U3(0,0,-π/4) ├┤ X ├ - # « ├─────────────┴┐┌─┴─┐┌────┴───┴────┐├─────────────┬┘└───┘ - # «qr_2: ┤ U3(0,0,-π/4) ├┤ X ├┤ U3(0,0,π/4) ├┤ U3(π/2,0,π) ├────── - # « └──────────────┘└───┘└─────────────┘└─────────────┘ - self.circuit.ccx(0, 1, 2) - self.ref_circuit.append(U3Gate(pi / 2, 0, pi), [2]) - self.ref_circuit.cx(1, 2) - self.ref_circuit.append(U3Gate(0, 0, -pi / 4), [2]) - self.ref_circuit.cx(0, 2) - self.ref_circuit.append(U3Gate(0, 0, pi / 4), [2]) - self.ref_circuit.cx(1, 2) - self.ref_circuit.append(U3Gate(0, 0, pi / 4), [1]) - self.ref_circuit.append(U3Gate(0, 0, -pi / 4), [2]) - self.ref_circuit.cx(0, 2) - self.ref_circuit.cx(0, 1) - self.ref_circuit.append(U3Gate(0, 0, pi / 4), [0]) - self.ref_circuit.append(U3Gate(0, 0, -pi / 4), [1]) - self.ref_circuit.cx(0, 1) - self.ref_circuit.append(U3Gate(0, 0, pi / 4), [2]) - self.ref_circuit.append(U3Gate(pi / 2, 0, pi), [2]) - self.compare_dags() - - def test_unroll_ch(self): - """test unroll ch""" - - # qr_0: ──■── qr_0: ───────────────────────────────────────────────■──────────────────» - # ┌─┴─┐ = ┌─────────────┐┌─────────────┐┌─────────────┐┌─┴─┐┌──────────────┐» - # qr_2: ┤ H ├ qr_2: ┤ U3(0,0,π/2) ├┤ U3(π/2,0,π) ├┤ U3(0,0,π/4) ├┤ X ├┤ U3(0,0,-π/4) ├» - # └───┘ └─────────────┘└─────────────┘└─────────────┘└───┘└──────────────┘» - # « - # «qr_0: ─────────────────────────────── - # « ┌─────────────┐┌──────────────┐ - # «qr_2: ┤ U3(π/2,0,π) ├┤ U3(0,0,-π/2) ├ - # « └─────────────┘└──────────────┘ - self.circuit.ch(0, 2) - self.ref_circuit.append(U3Gate(0, 0, pi / 2), [2]) - self.ref_circuit.append(U3Gate(pi / 2, 0, pi), [2]) - self.ref_circuit.append(U3Gate(0, 0, pi / 4), [2]) - self.ref_circuit.cx(0, 2) - self.ref_circuit.append(U3Gate(0, 0, -pi / 4), [2]) - self.ref_circuit.append(U3Gate(pi / 2, 0, pi), [2]) - self.ref_circuit.append(U3Gate(0, 0, -pi / 2), [2]) - self.compare_dags() - - def test_unroll_crz(self): - """test unroll crz""" - - # qr_1: ─────■───── qr_1: ──────────────────■─────────────────────■── - # ┌────┴────┐ = ┌──────────────┐┌─┴─┐┌───────────────┐┌─┴─┐ - # qr_2: ┤ Rz(0.5) ├ qr_2: ┤ U3(0,0,0.25) ├┤ X ├┤ U3(0,0,-0.25) ├┤ X ├ - # └─────────┘ └──────────────┘└───┘└───────────────┘└───┘ - self.circuit.crz(0.5, 1, 2) - self.ref_circuit.append(U3Gate(0, 0, 0.25), [2]) - self.ref_circuit.cx(1, 2) - self.ref_circuit.append(U3Gate(0, 0, -0.25), [2]) - self.ref_circuit.cx(1, 2) - - def test_unroll_cswap(self): - """test unroll cswap""" - # ┌───┐ » - # qr_0: ─X─ qr_0: ┤ X ├─────────────────■────────────────────────────────────────■──» - # │ └─┬─┘ │ │ » - # qr_1: ─■─ = qr_1: ──┼───────────────────┼────────────────────■───────────────────┼──» - # │ │ ┌─────────────┐┌─┴─┐┌──────────────┐┌─┴─┐┌─────────────┐┌─┴─┐» - # qr_2: ─X─ qr_2: ──■──┤ U3(π/2,0,π) ├┤ X ├┤ U3(0,0,-π/4) ├┤ X ├┤ U3(0,0,π/4) ├┤ X ├» - # └─────────────┘└───┘└──────────────┘└───┘└─────────────┘└───┘» - # « ┌─────────────┐ ┌───┐ ┌──────────────┐┌───┐┌───┐ - # «qr_0: ┤ U3(0,0,π/4) ├───────────┤ X ├─────┤ U3(0,0,-π/4) ├┤ X ├┤ X ├ - # « └─────────────┘ └─┬─┘ ├─────────────┬┘└─┬─┘└─┬─┘ - # «qr_1: ──────────────────■─────────■───────┤ U3(0,0,π/4) ├───■────┼── - # « ┌──────────────┐┌─┴─┐┌─────────────┐├─────────────┤ │ - # «qr_2: ┤ U3(0,0,-π/4) ├┤ X ├┤ U3(0,0,π/4) ├┤ U3(π/2,0,π) ├────────■── - # « └──────────────┘└───┘└─────────────┘└─────────────┘ - self.circuit.cswap(1, 0, 2) - self.ref_circuit.cx(2, 0) - self.ref_circuit.append(U3Gate(pi / 2, 0, pi), [2]) - self.ref_circuit.cx(0, 2) - self.ref_circuit.append(U3Gate(0, 0, -pi / 4), [2]) - self.ref_circuit.cx(1, 2) - self.ref_circuit.append(U3Gate(0, 0, pi / 4), [2]) - self.ref_circuit.cx(0, 2) - self.ref_circuit.append(U3Gate(0, 0, pi / 4), [0]) - self.ref_circuit.append(U3Gate(0, 0, -pi / 4), [2]) - self.ref_circuit.cx(1, 2) - self.ref_circuit.cx(1, 0) - self.ref_circuit.append(U3Gate(0, 0, -pi / 4), [0]) - self.ref_circuit.append(U3Gate(0, 0, pi / 4), [1]) - self.ref_circuit.cx(1, 0) - self.ref_circuit.append(U3Gate(0, 0, pi / 4), [2]) - self.ref_circuit.append(U3Gate(pi / 2, 0, pi), [2]) - self.ref_circuit.cx(2, 0) - self.compare_dags() - - def test_unroll_cu1(self): - """test unroll cu1""" - # ┌──────────────┐ - # qr_0: ─■──────── qr_0: ┤ U3(0,0,0.05) ├──■─────────────────────■────────────────── - # │U1(0.1) = └──────────────┘┌─┴─┐┌───────────────┐┌─┴─┐┌──────────────┐ - # qr_2: ─■──────── qr_2: ────────────────┤ X ├┤ U3(0,0,-0.05) ├┤ X ├┤ U3(0,0,0.05) ├ - # └───┘└───────────────┘└───┘└──────────────┘ - self.circuit.append(CU1Gate(0.1), [0, 2]) - self.ref_circuit.append(U3Gate(0, 0, 0.05), [0]) - self.ref_circuit.cx(0, 2) - self.ref_circuit.append(U3Gate(0, 0, -0.05), [2]) - self.ref_circuit.cx(0, 2) - self.ref_circuit.append(U3Gate(0, 0, 0.05), [2]) - self.compare_dags() - - def test_unroll_cu3(self): - """test unroll cu3""" - # ┌──────────────┐ - # q_1: ────────■──────── q_1: ─┤ U3(0,0,0.05) ├──■────────────────────────■─────────────────── - # ┌───────┴───────┐ = ┌┴──────────────┤┌─┴─┐┌──────────────────┐┌─┴─┐┌───────────────┐ - # q_2: ┤ U3(0.2,0.1,0) ├ q_2: ┤ U3(0,0,-0.05) ├┤ X ├┤ U3(-0.1,0,-0.05) ├┤ X ├┤ U3(0.1,0.1,0) ├ - # └───────────────┘ └───────────────┘└───┘└──────────────────┘└───┘└───────────────┘ - self.circuit.append(CU3Gate(0.2, 0.1, 0.0), [1, 2]) - self.ref_circuit.append(U3Gate(0, 0, 0.05), [1]) - self.ref_circuit.append(U3Gate(0, 0, -0.05), [2]) - self.ref_circuit.cx(1, 2) - self.ref_circuit.append(U3Gate(-0.1, 0, -0.05), [2]) - self.ref_circuit.cx(1, 2) - self.ref_circuit.append(U3Gate(0.1, 0.1, 0), [2]) - self.compare_dags() - - def test_unroll_cx(self): - """test unroll cx""" - self.circuit.cx(1, 0) - self.ref_circuit.cx(1, 0) - self.compare_dags() - - def test_unroll_cy(self): - """test unroll cy""" - # qr_1: ──■── qr_1: ──────────────────■───────────────── - # ┌─┴─┐ = ┌──────────────┐┌─┴─┐┌─────────────┐ - # qr_2: ┤ Y ├ qr_2: ┤ U3(0,0,-π/2) ├┤ X ├┤ U3(0,0,π/2) ├ - # └───┘ └──────────────┘└───┘└─────────────┘ - self.circuit.cy(1, 2) - self.ref_circuit.append(U3Gate(0, 0, -pi / 2), [2]) - self.ref_circuit.cx(1, 2) - self.ref_circuit.append(U3Gate(0, 0, pi / 2), [2]) - self.compare_dags() - - def test_unroll_cz(self): - """test unroll cz""" - # ┌─────────────┐┌───┐┌─────────────┐ - # qr_0: ─■─ qr_0: ┤ U3(π/2,0,π) ├┤ X ├┤ U3(π/2,0,π) ├ - # │ = └─────────────┘└─┬─┘└─────────────┘ - # qr_2: ─■─ qr_2: ─────────────────■───────────────── - self.circuit.cz(2, 0) - self.ref_circuit.append(U3Gate(pi / 2, 0, pi), [0]) - self.ref_circuit.cx(2, 0) - self.ref_circuit.append(U3Gate(pi / 2, 0, pi), [0]) - self.compare_dags() - - def test_unroll_h(self): - """test unroll h""" - self.circuit.h(1) - self.ref_circuit.append(U3Gate(pi / 2, 0, pi), [1]) - self.compare_dags() - - def test_unroll_i(self): - """test unroll i""" - self.circuit.id(0) - self.ref_circuit.id(0) - self.compare_dags() - - def test_unroll_rx(self): - """test unroll rx""" - self.circuit.rx(0.1, 0) - self.ref_circuit.append(U3Gate(0.1, -pi / 2, pi / 2), [0]) - self.compare_dags() - - def test_unroll_ry(self): - """test unroll ry""" - self.circuit.ry(0.2, 1) - self.ref_circuit.append(U3Gate(0.2, 0, 0), [1]) - self.compare_dags() - - def test_unroll_rz(self): - """test unroll rz""" - self.circuit.rz(0.3, 2) - self.ref_circuit.global_phase = -1 * 0.3 / 2 - self.ref_circuit.append(U3Gate(0, 0, 0.3), [2]) - self.compare_dags() - - def test_unroll_rzz(self): - """test unroll rzz""" - # global phase: 5.9832 - # ┌───┐┌─────────────┐┌───┐ - # qr_0: ─■──────── qr_0: ┤ X ├┤ U3(0,0,0.6) ├┤ X ├ - # │ZZ(0.6) = └─┬─┘└─────────────┘└─┬─┘ - # qr_1: ─■──────── qr_1: ──■───────────────────■── - self.circuit.rzz(0.6, 1, 0) - self.ref_circuit.global_phase = -1 * 0.6 / 2 - self.ref_circuit.cx(1, 0) - self.ref_circuit.append(U3Gate(0, 0, 0.6), [0]) - self.ref_circuit.cx(1, 0) - self.compare_dags() - - def test_unroll_s(self): - """test unroll s""" - self.circuit.s(0) - self.ref_circuit.append(U3Gate(0, 0, pi / 2), [0]) - self.compare_dags() - - def test_unroll_sdg(self): - """test unroll sdg""" - self.circuit.sdg(1) - self.ref_circuit.append(U3Gate(0, 0, -pi / 2), [1]) - self.compare_dags() - - def test_unroll_swap(self): - """test unroll swap""" - # ┌───┐ - # qr_1: ─X─ qr_1: ──■──┤ X ├──■── - # │ = ┌─┴─┐└─┬─┘┌─┴─┐ - # qr_2: ─X─ qr_2: ┤ X ├──■──┤ X ├ - # └───┘ └───┘ - self.circuit.swap(1, 2) - self.ref_circuit.cx(1, 2) - self.ref_circuit.cx(2, 1) - self.ref_circuit.cx(1, 2) - self.compare_dags() - - def test_unroll_t(self): - """test unroll t""" - self.circuit.t(2) - self.ref_circuit.append(U3Gate(0, 0, pi / 4), [2]) - self.compare_dags() - - def test_unroll_tdg(self): - """test unroll tdg""" - self.circuit.tdg(0) - self.ref_circuit.append(U3Gate(0, 0, -pi / 4), [0]) - self.compare_dags() - - def test_unroll_u1(self): - """test unroll u1""" - self.circuit.append(U1Gate(0.1), [1]) - self.ref_circuit.append(U3Gate(0, 0, 0.1), [1]) - self.compare_dags() - - def test_unroll_u2(self): - """test unroll u2""" - self.circuit.append(U2Gate(0.2, -0.1), [0]) - self.ref_circuit.append(U3Gate(pi / 2, 0.2, -0.1), [0]) - self.compare_dags() - - def test_unroll_u3(self): - """test unroll u3""" - self.circuit.append(U3Gate(0.3, 0.0, -0.1), [2]) - self.ref_circuit.append(U3Gate(0.3, 0.0, -0.1), [2]) - self.compare_dags() - - def test_unroll_x(self): - """test unroll x""" - self.circuit.x(2) - self.ref_circuit.append(U3Gate(pi, 0, pi), [2]) - self.compare_dags() - - def test_unroll_y(self): - """test unroll y""" - self.circuit.y(1) - self.ref_circuit.append(U3Gate(pi, pi / 2, pi / 2), [1]) - self.compare_dags() - - def test_unroll_z(self): - """test unroll z""" - self.circuit.z(0) - self.ref_circuit.append(U3Gate(0, 0, pi), [0]) - self.compare_dags() - - def test_unroll_measure(self): - """test unroll measure""" - self.circuit.measure(self.qr, self.cr) - self.ref_circuit.measure(self.qr, self.cr) - self.compare_dags() diff --git a/test/python/visualization/references/pass_manager_standard.dot b/test/python/visualization/references/pass_manager_standard.dot index bdb2137f33a3..5d6fa5ff713c 100644 --- a/test/python/visualization/references/pass_manager_standard.dot +++ b/test/python/visualization/references/pass_manager_standard.dot @@ -40,50 +40,58 @@ subgraph cluster_11 { fontname=helvetica; label="[4] "; labeljust=l; -12 [color=blue, fontname=helvetica, label=Unroller, shape=rectangle]; +12 [color=blue, fontname=helvetica, label=BasisTranslator, shape=rectangle]; +13 [color=black, fontname=helvetica, fontsize=10, label=equivalence_library, shape=ellipse, style=solid]; +13 -> 12; +14 [color=black, fontname=helvetica, fontsize=10, label=target_basis, shape=ellipse, style=solid]; +14 -> 12; +15 [color=black, fontname=helvetica, fontsize=10, label=target, shape=ellipse, style=dashed]; +15 -> 12; +16 [color=black, fontname=helvetica, fontsize=10, label=min_qubits, shape=ellipse, style=dashed]; +16 -> 12; 10 -> 12; } -subgraph cluster_13 { +subgraph cluster_17 { fontname=helvetica; label="[5] "; labeljust=l; -14 [color=red, fontname=helvetica, label=CheckMap, shape=rectangle]; -15 [color=black, fontname=helvetica, fontsize=10, label=coupling_map, shape=ellipse, style=solid]; -15 -> 14; -16 [color=black, fontname=helvetica, fontsize=10, label=property_set_field, shape=ellipse, style=dashed]; -16 -> 14; -12 -> 14; +18 [color=red, fontname=helvetica, label=CheckMap, shape=rectangle]; +19 [color=black, fontname=helvetica, fontsize=10, label=coupling_map, shape=ellipse, style=solid]; +19 -> 18; +20 [color=black, fontname=helvetica, fontsize=10, label=property_set_field, shape=ellipse, style=dashed]; +20 -> 18; +12 -> 18; } -subgraph cluster_17 { +subgraph cluster_21 { fontname=helvetica; label="[6] DoWhileController"; labeljust=l; -18 [color=blue, fontname=helvetica, label=BarrierBeforeFinalMeasurements, shape=rectangle]; -19 [color=black, fontname=helvetica, fontsize=10, label=label, shape=ellipse, style=dashed]; -19 -> 18; -14 -> 18; +22 [color=blue, fontname=helvetica, label=BarrierBeforeFinalMeasurements, shape=rectangle]; +23 [color=black, fontname=helvetica, fontsize=10, label=label, shape=ellipse, style=dashed]; +23 -> 22; +18 -> 22; } -subgraph cluster_20 { +subgraph cluster_24 { fontname=helvetica; label="[7] "; labeljust=l; -21 [color=blue, fontname=helvetica, label=GateDirection, shape=rectangle]; -22 [color=black, fontname=helvetica, fontsize=10, label=coupling_map, shape=ellipse, style=solid]; -22 -> 21; -23 [color=black, fontname=helvetica, fontsize=10, label=target, shape=ellipse, style=dashed]; -23 -> 21; -18 -> 21; +25 [color=blue, fontname=helvetica, label=GateDirection, shape=rectangle]; +26 [color=black, fontname=helvetica, fontsize=10, label=coupling_map, shape=ellipse, style=solid]; +26 -> 25; +27 [color=black, fontname=helvetica, fontsize=10, label=target, shape=ellipse, style=dashed]; +27 -> 25; +22 -> 25; } -subgraph cluster_24 { +subgraph cluster_28 { fontname=helvetica; label="[8] "; labeljust=l; -25 [color=blue, fontname=helvetica, label=RemoveResetInZeroState, shape=rectangle]; -21 -> 25; +29 [color=blue, fontname=helvetica, label=RemoveResetInZeroState, shape=rectangle]; +25 -> 29; } } diff --git a/test/python/visualization/references/pass_manager_style.dot b/test/python/visualization/references/pass_manager_style.dot index 3de498c4ada7..159bb6590a05 100644 --- a/test/python/visualization/references/pass_manager_style.dot +++ b/test/python/visualization/references/pass_manager_style.dot @@ -40,50 +40,58 @@ subgraph cluster_11 { fontname=helvetica; label="[4] "; labeljust=l; -12 [color=blue, fontname=helvetica, label=Unroller, shape=rectangle]; +12 [color=blue, fontname=helvetica, label=BasisTranslator, shape=rectangle]; +13 [color=black, fontname=helvetica, fontsize=10, label=equivalence_library, shape=ellipse, style=solid]; +13 -> 12; +14 [color=black, fontname=helvetica, fontsize=10, label=target_basis, shape=ellipse, style=solid]; +14 -> 12; +15 [color=black, fontname=helvetica, fontsize=10, label=target, shape=ellipse, style=dashed]; +15 -> 12; +16 [color=black, fontname=helvetica, fontsize=10, label=min_qubits, shape=ellipse, style=dashed]; +16 -> 12; 10 -> 12; } -subgraph cluster_13 { +subgraph cluster_17 { fontname=helvetica; label="[5] "; labeljust=l; -14 [color=green, fontname=helvetica, label=CheckMap, shape=rectangle]; -15 [color=black, fontname=helvetica, fontsize=10, label=coupling_map, shape=ellipse, style=solid]; -15 -> 14; -16 [color=black, fontname=helvetica, fontsize=10, label=property_set_field, shape=ellipse, style=dashed]; -16 -> 14; -12 -> 14; +18 [color=green, fontname=helvetica, label=CheckMap, shape=rectangle]; +19 [color=black, fontname=helvetica, fontsize=10, label=coupling_map, shape=ellipse, style=solid]; +19 -> 18; +20 [color=black, fontname=helvetica, fontsize=10, label=property_set_field, shape=ellipse, style=dashed]; +20 -> 18; +12 -> 18; } -subgraph cluster_17 { +subgraph cluster_21 { fontname=helvetica; label="[6] DoWhileController"; labeljust=l; -18 [color=blue, fontname=helvetica, label=BarrierBeforeFinalMeasurements, shape=rectangle]; -19 [color=black, fontname=helvetica, fontsize=10, label=label, shape=ellipse, style=dashed]; -19 -> 18; -14 -> 18; +22 [color=blue, fontname=helvetica, label=BarrierBeforeFinalMeasurements, shape=rectangle]; +23 [color=black, fontname=helvetica, fontsize=10, label=label, shape=ellipse, style=dashed]; +23 -> 22; +18 -> 22; } -subgraph cluster_20 { +subgraph cluster_24 { fontname=helvetica; label="[7] "; labeljust=l; -21 [color=blue, fontname=helvetica, label=GateDirection, shape=rectangle]; -22 [color=black, fontname=helvetica, fontsize=10, label=coupling_map, shape=ellipse, style=solid]; -22 -> 21; -23 [color=black, fontname=helvetica, fontsize=10, label=target, shape=ellipse, style=dashed]; -23 -> 21; -18 -> 21; +25 [color=blue, fontname=helvetica, label=GateDirection, shape=rectangle]; +26 [color=black, fontname=helvetica, fontsize=10, label=coupling_map, shape=ellipse, style=solid]; +26 -> 25; +27 [color=black, fontname=helvetica, fontsize=10, label=target, shape=ellipse, style=dashed]; +27 -> 25; +22 -> 25; } -subgraph cluster_24 { +subgraph cluster_28 { fontname=helvetica; label="[8] "; labeljust=l; -25 [color=grey, fontname=helvetica, label=RemoveResetInZeroState, shape=rectangle]; -21 -> 25; +29 [color=grey, fontname=helvetica, label=RemoveResetInZeroState, shape=rectangle]; +25 -> 29; } } diff --git a/test/python/visualization/test_pass_manager_drawer.py b/test/python/visualization/test_pass_manager_drawer.py index 6e53a895f67d..d4488e34b785 100644 --- a/test/python/visualization/test_pass_manager_drawer.py +++ b/test/python/visualization/test_pass_manager_drawer.py @@ -19,7 +19,7 @@ from qiskit.transpiler.passmanager import PassManager from qiskit import QuantumRegister from qiskit.passmanager.flow_controllers import ConditionalController, DoWhileController -from qiskit.transpiler.passes import GateDirection, Unroller +from qiskit.transpiler.passes import GateDirection, BasisTranslator from qiskit.transpiler.passes import CheckMap from qiskit.transpiler.passes import SetLayout from qiskit.transpiler.passes import TrivialLayout @@ -29,6 +29,10 @@ from qiskit.transpiler.passes import RemoveResetInZeroState from qiskit.utils import optionals +from qiskit.circuit.library.standard_gates.equivalence_library import ( + StandardEquivalenceLibrary as std_eqlib, +) + from .visualization import QiskitVisualizationTestCase, path_to_diagram_reference @@ -54,8 +58,7 @@ def setUp(self): ) self.pass_manager.append(FullAncillaAllocation(coupling_map)) self.pass_manager.append(EnlargeWithAncilla()) - with self.assertWarns(DeprecationWarning): - self.pass_manager.append(Unroller(basis_gates)) + self.pass_manager.append(BasisTranslator(std_eqlib, basis_gates)) self.pass_manager.append(CheckMap(coupling_map)) self.pass_manager.append( DoWhileController(BarrierBeforeFinalMeasurements(), do_while=lambda x: False)