From cbd0973fc12b50d509e8f349f36bd446148f73af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elena=20Pe=C3=B1a=20Tapia?= Date: Fri, 1 Nov 2024 19:21:44 +0100 Subject: [PATCH] Cleanup --- .../passes/synthesis/high_level_synthesis.py | 2 ++ .../preset_passmanagers/builtin_plugins.py | 13 ++++++++++- .../generate_preset_pass_manager.py | 11 +++++----- .../transpiler/preset_passmanagers/level2.py | 1 - .../transpiler/preset_passmanagers/level3.py | 1 - qiskit/transpiler/target.py | 22 ++++++++++++++++--- test/python/compiler/test_transpiler.py | 16 ++------------ .../transpiler/test_preset_passmanagers.py | 17 +++----------- test/utils/base.py | 11 ---------- 9 files changed, 43 insertions(+), 51 deletions(-) diff --git a/qiskit/transpiler/passes/synthesis/high_level_synthesis.py b/qiskit/transpiler/passes/synthesis/high_level_synthesis.py index d34bde12556c..fc847a40a2c8 100644 --- a/qiskit/transpiler/passes/synthesis/high_level_synthesis.py +++ b/qiskit/transpiler/passes/synthesis/high_level_synthesis.py @@ -302,6 +302,8 @@ def __init__( self._basis_gates = basis_gates self._min_qubits = min_qubits + # include cases where target exists with no basis gates, or the basis gates + # are an empty list self._top_level_only = (self._basis_gates is None or len(self._basis_gates) == 0) and ( self._target is None or len(self._target.operation_names) == 0 ) diff --git a/qiskit/transpiler/preset_passmanagers/builtin_plugins.py b/qiskit/transpiler/preset_passmanagers/builtin_plugins.py index 8b60b16dfcf2..555dedef8c54 100644 --- a/qiskit/transpiler/preset_passmanagers/builtin_plugins.py +++ b/qiskit/transpiler/preset_passmanagers/builtin_plugins.py @@ -558,6 +558,9 @@ def _opt_control(property_set): ) if optimization_level == 1: # Steps for optimization level 1 + + # If there are no basis gates (None/empty list), don't run + # Optimize1qGatesDecomposition if ( pass_manager_config.basis_gates is not None and len(pass_manager_config.basis_gates) > 0 @@ -569,6 +572,7 @@ def _opt_control(property_set): ] else: _opt = [] + _opt += [ InverseCancellation( [ @@ -589,6 +593,10 @@ def _opt_control(property_set): ] elif optimization_level == 2: + # Steps for optimization level 2 + + # If there are no basis gates (None/empty list), don't run + # Optimize1qGatesDecomposition if ( pass_manager_config.basis_gates is not None and len(pass_manager_config.basis_gates) > 0 @@ -613,7 +621,8 @@ def _opt_control(property_set): approximation_degree=pass_manager_config.approximation_degree, ), ] - + # If there are no basis gates (None/empty list), don't run + # Optimize1qGatesDecomposition or UnitarySynthesis if ( pass_manager_config.basis_gates is not None and len(pass_manager_config.basis_gates) > 0 @@ -656,6 +665,8 @@ def _unroll_condition(property_set): if optimization_level == 3: optimization.append(_minimum_point_check) elif optimization_level == 2: + # If there are no basis gates (None/empty list), don't run + # UnitarySynthesis if ( pass_manager_config.basis_gates is not None and len(pass_manager_config.basis_gates) > 0 diff --git a/qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py b/qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py index 5e8c91a88072..de005506307d 100644 --- a/qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +++ b/qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py @@ -315,12 +315,11 @@ def generate_preset_pass_manager( and timing_constraints is None ) # If it's an edge case => do not build target - _skip_target = ( - target is None - and backend is None - # and (basis_gates is None or coupling_map is None or instruction_durations is not None) - and (instruction_durations is not None) - ) + # NOTE (1.3.0): we are skipping the target in the case where + # instruction_durations is provided without additional constraints + # instead of providing a target-based alternative because the argument + # will be removed in 2.0 as part of the Pulse deprecation efforts. + _skip_target = target is None and backend is None and instruction_durations is not None # Resolve loose constraints case-by-case against backend constraints. # The order of priority is loose constraints > backend. diff --git a/qiskit/transpiler/preset_passmanagers/level2.py b/qiskit/transpiler/preset_passmanagers/level2.py index aa5f33d67bbd..b22743883fbe 100644 --- a/qiskit/transpiler/preset_passmanagers/level2.py +++ b/qiskit/transpiler/preset_passmanagers/level2.py @@ -73,7 +73,6 @@ def level_2_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa else: layout = None routing = None - translation = plugin_manager.get_passmanager_stage( "translation", translation_method, pass_manager_config, optimization_level=2 ) diff --git a/qiskit/transpiler/preset_passmanagers/level3.py b/qiskit/transpiler/preset_passmanagers/level3.py index b51e4c0775be..c1393a0b7c6e 100644 --- a/qiskit/transpiler/preset_passmanagers/level3.py +++ b/qiskit/transpiler/preset_passmanagers/level3.py @@ -94,7 +94,6 @@ def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa optimization = plugin_manager.get_passmanager_stage( "optimization", optimization_method, pass_manager_config, optimization_level=3 ) - if (coupling_map and not coupling_map.is_symmetric) or ( target is not None and target.get_non_global_operation_names(strict_direction=True) ): diff --git a/qiskit/transpiler/target.py b/qiskit/transpiler/target.py index e074b96e74fb..4fe45ec2c7c8 100644 --- a/qiskit/transpiler/target.py +++ b/qiskit/transpiler/target.py @@ -867,7 +867,7 @@ def build_coupling_map(self, two_q_gate=None, filter_idle_qubits=False): if self._coupling_graph is None: self._build_coupling_graph() - # if there is no connectivity constraints in the coupling graph treat it as not + # if there are no connectivity constraints in the coupling graph, treat it as not # existing and return if self._coupling_graph is not None: cmap = CouplingMap() @@ -1068,6 +1068,10 @@ def from_configuration( qubit_properties = qubit_props_list_from_props(properties=backend_properties) if basis_gates is None: + # The Target class requires basis_gates. + # If there are no basis_gates, we can't build a proper Target instance, + # but we can generate a "pseudo" target that holds connectivity constraints + # and is compatible with our transpilation pipeline if num_qubits is None and coupling_map is not None: num_qubits = len(coupling_map.graph) target = FakeTarget( @@ -1323,7 +1327,12 @@ def target_to_backend_properties(target: Target): class FakeTarget(Target): - """Fake target that only contains a connectivity constraint.""" + """ + Pseudo-target class for internal use in the transpilation pipeline. + Differently to the :class:`.Target` class, this preudo-target is initialized + with a `coupling_map` argument that allows to store connectivity constraints + without basis gates. + """ def __init__(self, coupling_map=None, **kwargs): super().__init__(**kwargs) @@ -1333,4 +1342,11 @@ def build_coupling_map(self, two_q_gate=None, filter_idle_qubits=False): return self._coupling_map def instruction_supported(self, *args, **kwargs): - return True + """Checks whether an instruction is supported by the + Target based on instruction name and qargs. Note that if there are no + basis gates in the Target, this method will always return ``True``. + """ + if len(self.operation_names) == 0: + return True + else: + return super().instruction_supported(*args, **kwargs) diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index 03a7c74ab988..5241304a0db4 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -2097,8 +2097,7 @@ def _visit_block(circuit, qubit_mapping=None): qubit_mapping={qubit: index for index, qubit in enumerate(transpiled.qubits)}, ) - # @data(1, 2, 3) - @data(3) + @data(1, 2, 3) def test_transpile_identity_circuit_no_target(self, opt_level): """Test circuit equivalent to identity is optimized away for all optimization levels >0. @@ -2198,14 +2197,6 @@ def test_barrier_not_output_input_preservered(self, opt_level): @combine(opt_level=[0, 1, 2, 3]) def test_transpile_annotated_ops(self, opt_level): """Test transpilation of circuits with annotated operations.""" - passes = [] - kwargss = [] - - def callback_func(**kwargs): - t_pass = kwargs["pass_"].name() - kwargss.append(kwargs) - passes.append(t_pass) - qc = QuantumCircuit(3) qc.append(AnnotatedOperation(SGate(), InverseModifier()), [0]) qc.append(AnnotatedOperation(XGate(), ControlModifier(1)), [1, 2]) @@ -2214,10 +2205,7 @@ def callback_func(**kwargs): expected.sdg(0) expected.cx(1, 2) expected.h(2) - transpiled = transpile( - qc, optimization_level=opt_level, seed_transpiler=42, callback=callback_func - ) - print("Callback out:", passes) + transpiled = transpile(qc, optimization_level=opt_level, seed_transpiler=42) self.assertNotIn("annotated", transpiled.count_ops().keys()) self.assertEqual(Operator(qc), Operator(transpiled)) self.assertEqual(Operator(qc), Operator(expected)) diff --git a/test/python/transpiler/test_preset_passmanagers.py b/test/python/transpiler/test_preset_passmanagers.py index ec1d4836393b..4b36c6095ef0 100644 --- a/test/python/transpiler/test_preset_passmanagers.py +++ b/test/python/transpiler/test_preset_passmanagers.py @@ -91,8 +91,7 @@ def circuit_2532(): class TestPresetPassManager(QiskitTestCase): """Test preset passmanagers work as expected.""" - # @combine(level=[0, 1, 2, 3], name="level{level}") - @combine(level=[3], name="level{level}") + @combine(level=[0, 1, 2, 3], name="level{level}") def test_no_coupling_map_with_sabre(self, level): """Test that coupling_map can be None with Sabre (level={level})""" q = QuantumRegister(2, name="q") @@ -145,13 +144,7 @@ def test_no_basis_gates(self, level): circuit.h(q[0]) circuit.cz(q[0], q[1]) - def callback_func(**kwargs): - t_pass = kwargs["pass_"].name() - print("callback", t_pass) - - result = transpile( - circuit, basis_gates=None, optimization_level=level, callback=callback_func - ) + result = transpile(circuit, basis_gates=None, optimization_level=level) self.assertEqual(result, circuit) def test_level0_keeps_reset(self): @@ -1271,11 +1264,7 @@ def test_size_optimization(self, level): qc.cx(7, 6) qc.cx(6, 7) - def callback_func(**kwargs): - t_pass = kwargs["pass_"].name() - print("callback", t_pass) - - circ = transpile(qc, optimization_level=level, callback=callback_func).decompose() + circ = transpile(qc, optimization_level=level).decompose() circ_data = circ.data free_qubits = {0, 1, 2, 3} diff --git a/test/utils/base.py b/test/utils/base.py index a35d15bb1cd3..133666cfc7ad 100644 --- a/test/utils/base.py +++ b/test/utils/base.py @@ -324,17 +324,6 @@ def setUp(self): self.useFixture(fixtures.MonkeyPatch("sys.stderr", stderr)) self.useFixture(fixtures.LoggerFixture(nuke_handlers=False, level=None)) - # a dummy setting config to make sure it does not intervene - # with the test runner environment. See https://github.com/Qiskit/qiskit/pull/12463 - self._mock_setting = unittest.mock.patch.dict( - os.environ, {"QISKIT_SETTINGS": "dummy_setting.conf"} - ) - self._mock_setting.start() - - def tearDown(self): - super().tearDown() - self._mock_setting.stop() - def dicts_almost_equal(dict1, dict2, delta=None, places=None, default_value=0): """Test if two dictionaries with numeric values are almost equal.