Skip to content

Commit

Permalink
Enable Sabre for control flow circuits at O1 (#10371)
Browse files Browse the repository at this point in the history
* Enable Sabre for control flow circuits in O1.

* Add release note.

* Update preset pass manager tests.
  • Loading branch information
kevinhartman authored Jul 19, 2023
1 parent a804df5 commit 026d60a
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 46 deletions.
42 changes: 5 additions & 37 deletions qiskit/transpiler/preset_passmanagers/level1.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ def level_1_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
init_method = pass_manager_config.init_method
# Unlike other presets, the layout and routing defaults aren't set here because they change
# based on whether the input circuit has control flow.
layout_method = pass_manager_config.layout_method
routing_method = pass_manager_config.routing_method
layout_method = pass_manager_config.layout_method or "sabre"
routing_method = pass_manager_config.routing_method or "sabre"
translation_method = pass_manager_config.translation_method or "translator"
optimization_method = pass_manager_config.optimization_method
scheduling_method = pass_manager_config.scheduling_method
Expand Down Expand Up @@ -157,43 +157,11 @@ def _vf2_match_not_found(property_set):
skip_routing=pass_manager_config.routing_method is not None
and routing_method != "sabre",
)
elif layout_method is None:
_improve_layout = common.if_has_control_flow_else(
DenseLayout(coupling_map, backend_properties, target=target),
SabreLayout(
coupling_map_layout,
max_iterations=2,
seed=seed_transpiler,
swap_trials=5,
layout_trials=5,
skip_routing=pass_manager_config.routing_method is not None
and routing_method != "sabre",
),
).to_flow_controller()

# Choose routing pass
routing_pm = None
if routing_method is None:
_stochastic_routing = plugin_manager.get_passmanager_stage(
"routing",
"stochastic",
pass_manager_config,
optimization_level=1,
)
_sabre_routing = plugin_manager.get_passmanager_stage(
"routing",
"sabre",
pass_manager_config,
optimization_level=1,
)
routing_pm = common.if_has_control_flow_else(_stochastic_routing, _sabre_routing)
else:
routing_pm = plugin_manager.get_passmanager_stage(
"routing",
routing_method,
pass_manager_config,
optimization_level=1,
)
routing_pm = plugin_manager.get_passmanager_stage(
"routing", routing_method, pass_manager_config, optimization_level=1
)

# Build optimization loop: merge 1q rotations and cancel CNOT gates iteratively
# until no more change in depth
Expand Down
11 changes: 11 additions & 0 deletions releasenotes/notes/sabre-ctrl-flow-o1-431cd25a19adbcdc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
upgrade:
- |
The Sabre family of transpiler passes (namely :class:`.SabreLayout`
and :class:`.SabreSwap`) are now used by default for all circuits
when invoking the transpiler at optimization level 1 (e.g. calling
:func:`.transpile` or :func:`.generate_preset_pass_manager` with
keyword argument ``optimization_level=1``). Previously, circuits
with control flow operations used :class:`.DenseLayout` and
:class:`.StochasticSwap` with this profile.
17 changes: 8 additions & 9 deletions test/python/transpiler/test_preset_passmanagers.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ def test_no_coupling_map(self, level):
self.assertNotIn("TrivialLayout", self.passes)
self.assertNotIn("ApplyLayout", self.passes)
self.assertNotIn("StochasticSwap", self.passes)
self.assertNotIn("SabreSwap", self.passes)
self.assertNotIn("CheckGateDirection", self.passes)

@data(0, 1, 2, 3)
Expand Down Expand Up @@ -568,13 +569,11 @@ def test_level1_runs_vf2post_layout_when_routing_required_control_flow(self):
# Expected call path for layout and routing is:
# 1. TrivialLayout (no perfect match)
# 2. VF2Layout (no perfect match)
# 3. DenseLayout (heuristic layout)
# 4. StochasticSwap
# 3. SabreLayout (heuristic layout)
# 4. VF2PostLayout (applies a better layout)
self.assertIn("TrivialLayout", self.passes)
self.assertIn("VF2Layout", self.passes)
self.assertIn("DenseLayout", self.passes)
self.assertIn("StochasticSwap", self.passes)
self.assertIn("SabreLayout", self.passes)
self.assertIn("VF2PostLayout", self.passes)

def test_level1_not_runs_vf2post_layout_when_layout_method_set_control_flow(self):
Expand All @@ -599,7 +598,7 @@ def test_level1_not_runs_vf2post_layout_when_layout_method_set_control_flow(self
self.assertNotIn("SabreLayout", self.passes)
self.assertNotIn("VF2PostLayout", self.passes)
self.assertIn("DenseLayout", self.passes)
self.assertIn("StochasticSwap", self.passes)
self.assertIn("SabreSwap", self.passes)

def test_level1_not_run_vf2post_layout_when_trivial_is_perfect_control_flow(self):
"""Test that if we find a trivial perfect layout we don't run vf2post."""
Expand All @@ -615,8 +614,8 @@ def test_level1_not_run_vf2post_layout_when_trivial_is_perfect_control_flow(self
_ = transpile(qc, target, optimization_level=1, callback=self.callback)
self.assertIn("TrivialLayout", self.passes)
self.assertNotIn("VF2Layout", self.passes)
self.assertNotIn("DenseLayout", self.passes)
self.assertNotIn("StochasticSwap", self.passes)
self.assertNotIn("SabreLayout", self.passes)
self.assertNotIn("SabreSwap", self.passes)
self.assertNotIn("VF2PostLayout", self.passes)

def test_level1_not_run_vf2post_layout_when_vf2layout_is_perfect_control_flow(self):
Expand All @@ -635,9 +634,9 @@ def test_level1_not_run_vf2post_layout_when_vf2layout_is_perfect_control_flow(se
_ = transpile(qc, target, optimization_level=1, callback=self.callback)
self.assertIn("TrivialLayout", self.passes)
self.assertIn("VF2Layout", self.passes)
self.assertNotIn("DenseLayout", self.passes)
self.assertNotIn("SabreLayout", self.passes)
self.assertNotIn("VF2PostLayout", self.passes)
self.assertNotIn("StochasticSwap", self.passes)
self.assertNotIn("SabreSwap", self.passes)


@ddt
Expand Down

0 comments on commit 026d60a

Please sign in to comment.