diff --git a/qiskit/transpiler/preset_passmanagers/builtin_plugins.py b/qiskit/transpiler/preset_passmanagers/builtin_plugins.py index 7360825b9747..fc01f6efaced 100644 --- a/qiskit/transpiler/preset_passmanagers/builtin_plugins.py +++ b/qiskit/transpiler/preset_passmanagers/builtin_plugins.py @@ -87,7 +87,7 @@ def pass_manager(self, pass_manager_config, optimization_level=None) -> PassMana pass_manager_config.unitary_synthesis_plugin_config, pass_manager_config.hls_config, ) - elif optimization_level in {1, 2}: + elif optimization_level == 1: init = PassManager() if ( pass_manager_config.initial_layout @@ -123,10 +123,8 @@ def pass_manager(self, pass_manager_config, optimization_level=None) -> PassMana ] ) ) - if optimization_level == 2: - init.append(CommutativeCancellation()) - elif optimization_level == 3: + elif optimization_level in {2, 3}: init = common.generate_unroll_3q( pass_manager_config.target, pass_manager_config.basis_gates, @@ -543,16 +541,13 @@ def _opt_control(property_set): ] ), ] + elif optimization_level == 2: - # Steps for optimization level 2 _opt = [ Optimize1qGatesDecomposition( basis=pass_manager_config.basis_gates, target=pass_manager_config.target ), - CommutativeCancellation( - basis_gates=pass_manager_config.basis_gates, - target=pass_manager_config.target, - ), + CommutativeCancellation(target=pass_manager_config.target), ] elif optimization_level == 3: # Steps for optimization level 3 @@ -598,6 +593,27 @@ def _unroll_condition(property_set): if optimization_level == 3: optimization.append(_minimum_point_check) + elif optimization_level == 2: + optimization.append( + [ + Collect2qBlocks(), + ConsolidateBlocks( + basis_gates=pass_manager_config.basis_gates, + target=pass_manager_config.target, + approximation_degree=pass_manager_config.approximation_degree, + ), + UnitarySynthesis( + pass_manager_config.basis_gates, + approximation_degree=pass_manager_config.approximation_degree, + coupling_map=pass_manager_config.coupling_map, + backend_props=pass_manager_config.backend_properties, + method=pass_manager_config.unitary_synthesis_method, + plugin_config=pass_manager_config.unitary_synthesis_plugin_config, + target=pass_manager_config.target, + ), + ] + ) + optimization.append(_depth_check + _size_check) else: optimization.append(_depth_check + _size_check) opt_loop = ( @@ -749,7 +765,7 @@ def _swap_mapped(property_set): call_limit=int(5e6), # Set call limit to ~10s with rustworkx 0.10.2 properties=pass_manager_config.backend_properties, target=pass_manager_config.target, - max_trials=25000, # Limits layout scoring to < 10s on ~400 qubit devices + max_trials=2500, # Limits layout scoring to < 600ms on ~400 qubit devices ) layout.append( ConditionalController(choose_layout_0, condition=_choose_layout_condition) @@ -758,8 +774,8 @@ def _swap_mapped(property_set): coupling_map, max_iterations=2, seed=pass_manager_config.seed_transpiler, - swap_trials=10, - layout_trials=10, + swap_trials=20, + layout_trials=20, skip_routing=pass_manager_config.routing_method is not None and pass_manager_config.routing_method != "sabre", ) @@ -911,8 +927,8 @@ def _swap_mapped(property_set): coupling_map, max_iterations=2, seed=pass_manager_config.seed_transpiler, - swap_trials=10, - layout_trials=10, + swap_trials=20, + layout_trials=20, skip_routing=pass_manager_config.routing_method is not None and pass_manager_config.routing_method != "sabre", ) diff --git a/qiskit/transpiler/preset_passmanagers/common.py b/qiskit/transpiler/preset_passmanagers/common.py index dcd9f27c2bc0..1b77e7dbd269 100644 --- a/qiskit/transpiler/preset_passmanagers/common.py +++ b/qiskit/transpiler/preset_passmanagers/common.py @@ -627,16 +627,11 @@ def get_vf2_limits( """ limits = VF2Limits(None, None) if layout_method is None and initial_layout is None: - if optimization_level == 1: + if optimization_level in {1, 2}: limits = VF2Limits( int(5e4), # Set call limit to ~100ms with rustworkx 0.10.2 2500, # Limits layout scoring to < 600ms on ~400 qubit devices ) - elif optimization_level == 2: - limits = VF2Limits( - int(5e6), # Set call limit to ~10 sec with rustworkx 0.10.2 - 25000, # Limits layout scoring to < 6 sec on ~400 qubit devices - ) elif optimization_level == 3: limits = VF2Limits( int(3e7), # Set call limit to ~60 sec with rustworkx 0.10.2 diff --git a/releasenotes/notes/optimization-level2-2c8c1488173aed31.yaml b/releasenotes/notes/optimization-level2-2c8c1488173aed31.yaml new file mode 100644 index 000000000000..20c9b1ed9cbb --- /dev/null +++ b/releasenotes/notes/optimization-level2-2c8c1488173aed31.yaml @@ -0,0 +1,10 @@ +--- +upgrade_transpiler: + - | + The preset :class:`.StagedPassManager` returned for optimization level 2 by + :func:`.generate_preset_pass_manager` and :func:`.level_2_pass_manager` have + been reworked to provide a better balance between runtime and optimization. + This means the output circuits will change compared to earlier releases. If + you need an exact pass manager from level 2 in earlier releases you can + either build it manually or use it from an earlier release and save the + circuits with :mod:`~qiskit.qpy` to load with a newer release. diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index d4e19da541a0..943de7b932e7 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -1831,11 +1831,12 @@ def test_synthesis_translation_method_with_gates_outside_basis(self, optimizatio optimization_level=optimization_level, seed_transpiler=42, ) - if optimization_level != 3: + if optimization_level not in {2, 3}: self.assertTrue(Operator(qc).equiv(res)) self.assertNotIn("swap", res.count_ops()) else: - # Optimization level 3 eliminates the pointless swap + # Optimization level 2 and 3 eliminates the swap by permuting the + # qubits self.assertEqual(res, QuantumCircuit(2)) @data(0, 1, 2, 3)