Skip to content

Commit

Permalink
Optimization stage as a plugin. (#10581)
Browse files Browse the repository at this point in the history
* Initial: Optimization stage as a plugin.

* CI: Added fix to preset_passmanager test

* Simplify inner translation stage creation logic

This commit changes the plugin construction logic slightly to adjust
how the embedded translation stage is created. After #10621 merged we
only need to use the plugin interface to get the translation stage pass
manager.

* Update documentation

---------

Co-authored-by: Matthew Treinish <[email protected]>
  • Loading branch information
raynelfss and mtreinish authored Aug 22, 2023
1 parent 4ab2ef8 commit e7808e7
Show file tree
Hide file tree
Showing 9 changed files with 160 additions and 179 deletions.
121 changes: 120 additions & 1 deletion qiskit/transpiler/preset_passmanagers/builtin_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,21 @@
from qiskit.transpiler.passes import CheckMap
from qiskit.transpiler.passes import BarrierBeforeFinalMeasurements
from qiskit.transpiler.preset_passmanagers import common
from qiskit.transpiler.preset_passmanagers.plugin import PassManagerStagePlugin
from qiskit.transpiler.preset_passmanagers.plugin import (
PassManagerStagePlugin,
PassManagerStagePluginManager,
)
from qiskit.transpiler.passes.optimization import (
Optimize1qGatesDecomposition,
CommutativeCancellation,
Collect2qBlocks,
ConsolidateBlocks,
CXCancellation,
)
from qiskit.transpiler.passes import Depth, Size, FixedPoint, MinimumPoint
from qiskit.transpiler.passes.utils.gates_basis import GatesInBasis
from qiskit.transpiler.passes.synthesis.unitary_synthesis import UnitarySynthesis
from qiskit.passmanager.flow_controllers import ConditionalController
from qiskit.transpiler.timing_constraints import TimingConstraints
from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason

Expand Down Expand Up @@ -378,6 +392,111 @@ def pass_manager(self, pass_manager_config, optimization_level=None) -> PassMana
)


class OptimizationPassManager(PassManagerStagePlugin):
"""Plugin class for optimization stage"""

def pass_manager(self, pass_manager_config, optimization_level=None) -> PassManager:
"""Build pass manager for optimization stage."""
# Obtain the translation method required for this pass to work
translation_method = pass_manager_config.translation_method or "translator"
optimization = PassManager()
if optimization_level != 0:
plugin_manager = PassManagerStagePluginManager()
_depth_check = [Depth(recurse=True), FixedPoint("depth")]
_size_check = [Size(recurse=True), FixedPoint("size")]
# Minimum point check for optimization level 3.
_minimum_point_check = [
Depth(recurse=True),
Size(recurse=True),
MinimumPoint(["depth", "size"], "optimization_loop"),
]

def _opt_control(property_set):
return (not property_set["depth_fixed_point"]) or (
not property_set["size_fixed_point"]
)

translation = plugin_manager.get_passmanager_stage(
"translation",
translation_method,
pass_manager_config,
optimization_level=optimization_level,
)
if optimization_level == 1:
# Steps for optimization level 1
_opt = [
Optimize1qGatesDecomposition(
basis=pass_manager_config.basis_gates, target=pass_manager_config.target
),
CXCancellation(),
]
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,
),
]
elif optimization_level == 3:
# Steps for optimization level 3
_opt = [
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,
),
Optimize1qGatesDecomposition(
basis=pass_manager_config.basis_gates, target=pass_manager_config.target
),
CommutativeCancellation(target=pass_manager_config.target),
]

def _opt_control(property_set):
return not property_set["optimization_loop_minimum_point"]

else:
raise TranspilerError(f"Invalid optimization_level: {optimization_level}")

unroll = [pass_ for x in translation.passes() for pass_ in x["passes"]]
# Build nested Flow controllers
def _unroll_condition(property_set):
return not property_set["all_gates_in_basis"]

# Check if any gate is not in the basis, and if so, run unroll passes
_unroll_if_out_of_basis = [
GatesInBasis(pass_manager_config.basis_gates, target=pass_manager_config.target),
ConditionalController(unroll, condition=_unroll_condition),
]

if optimization_level == 3:
optimization.append(_minimum_point_check)
else:
optimization.append(_depth_check + _size_check)
opt_loop = (
_opt + _unroll_if_out_of_basis + _minimum_point_check
if optimization_level == 3
else _opt + _unroll_if_out_of_basis + _depth_check + _size_check
)
optimization.append(opt_loop, do_while=_opt_control)
return optimization
else:
return None


class AlapSchedulingPassManager(PassManagerStagePlugin):
"""Plugin class for alap scheduling stage."""

Expand Down
10 changes: 4 additions & 6 deletions qiskit/transpiler/preset_passmanagers/level0.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def level_0_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
layout_method = pass_manager_config.layout_method or "default"
routing_method = pass_manager_config.routing_method or "stochastic"
translation_method = pass_manager_config.translation_method or "translator"
optimization_method = pass_manager_config.optimization_method
optimization_method = pass_manager_config.optimization_method or "default"
scheduling_method = pass_manager_config.scheduling_method or "default"
approximation_degree = pass_manager_config.approximation_degree
unitary_synthesis_method = pass_manager_config.unitary_synthesis_method
Expand Down Expand Up @@ -113,11 +113,9 @@ def level_0_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
)
elif unroll_3q is not None:
init += unroll_3q
optimization = None
if optimization_method is not None:
optimization = plugin_manager.get_passmanager_stage(
"optimization", optimization_method, pass_manager_config, optimization_level=0
)
optimization = plugin_manager.get_passmanager_stage(
"optimization", optimization_method, pass_manager_config, optimization_level=0
)

return StagedPassManager(
init=init,
Expand Down
45 changes: 5 additions & 40 deletions qiskit/transpiler/preset_passmanagers/level1.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,8 @@
Level 1 pass manager: light optimization by simple adjacent gate collapsing.
"""
from __future__ import annotations
from qiskit.transpiler.basepasses import BasePass
from qiskit.transpiler.passmanager_config import PassManagerConfig
from qiskit.transpiler.passmanager import PassManager
from qiskit.transpiler.passmanager import StagedPassManager
from qiskit.transpiler import ConditionalController, FlowController
from qiskit.transpiler.passes import CXCancellation
from qiskit.transpiler.passes import FixedPoint
from qiskit.transpiler.passes import Depth
from qiskit.transpiler.passes import Size
from qiskit.transpiler.passes import Optimize1qGatesDecomposition
from qiskit.transpiler.passes import GatesInBasis
from qiskit.transpiler.preset_passmanagers import common
from qiskit.transpiler.preset_passmanagers.plugin import (
PassManagerStagePluginManager,
Expand Down Expand Up @@ -63,7 +54,7 @@ def level_1_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
layout_method = pass_manager_config.layout_method or "default"
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
optimization_method = pass_manager_config.optimization_method or "default"
scheduling_method = pass_manager_config.scheduling_method or "default"
approximation_degree = pass_manager_config.approximation_degree
unitary_synthesis_method = pass_manager_config.unitary_synthesis_method
Expand All @@ -76,16 +67,6 @@ def level_1_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
"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
_depth_check = [Depth(recurse=True), FixedPoint("depth")]
_size_check = [Size(recurse=True), FixedPoint("size")]

def _opt_control(property_set):
return (not property_set["depth_fixed_point"]) or (not property_set["size_fixed_point"])

_opt = [Optimize1qGatesDecomposition(basis=basis_gates, target=target), CXCancellation()]

unroll_3q = None
# Build full pass manager
if coupling_map or initial_layout:
Expand Down Expand Up @@ -118,26 +99,10 @@ def _opt_control(property_set):
)
else:
pre_optimization = common.generate_pre_op_passmanager(remove_reset_in_zero=True)
if optimization_method is None:
optimization = PassManager()
unroll = [pass_ for x in translation.passes() for pass_ in x["passes"]]
# Build nested Flow controllers
def _unroll_condition(property_set):
return not property_set["all_gates_in_basis"]

# Check if any gate is not in the basis, and if so, run unroll passes
_unroll_if_out_of_basis: list[BasePass | FlowController] = [
GatesInBasis(basis_gates, target=target),
ConditionalController(unroll, condition=_unroll_condition),
]

optimization.append(_depth_check + _size_check)
opt_loop = _opt + _unroll_if_out_of_basis + _depth_check + _size_check
optimization.append(opt_loop, do_while=_opt_control)
else:
optimization = plugin_manager.get_passmanager_stage(
"optimization", optimization_method, pass_manager_config, optimization_level=1
)

optimization = plugin_manager.get_passmanager_stage(
"optimization", optimization_method, pass_manager_config, optimization_level=1
)

sched = plugin_manager.get_passmanager_stage(
"scheduling", scheduling_method, pass_manager_config, optimization_level=1
Expand Down
47 changes: 5 additions & 42 deletions qiskit/transpiler/preset_passmanagers/level2.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,8 @@
gate cancellation using commutativity rules.
"""
from __future__ import annotations
from qiskit.transpiler.basepasses import BasePass
from qiskit.transpiler.passmanager_config import PassManagerConfig
from qiskit.transpiler.passmanager import PassManager
from qiskit.transpiler.passmanager import StagedPassManager
from qiskit.transpiler import ConditionalController, FlowController
from qiskit.transpiler.passes import FixedPoint
from qiskit.transpiler.passes import Depth
from qiskit.transpiler.passes import Size
from qiskit.transpiler.passes import Optimize1qGatesDecomposition
from qiskit.transpiler.passes import CommutativeCancellation
from qiskit.transpiler.passes import GatesInBasis
from qiskit.transpiler.preset_passmanagers import common
from qiskit.transpiler.preset_passmanagers.plugin import (
PassManagerStagePluginManager,
Expand Down Expand Up @@ -64,7 +55,7 @@ def level_2_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
layout_method = pass_manager_config.layout_method or "default"
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
optimization_method = pass_manager_config.optimization_method or "default"
scheduling_method = pass_manager_config.scheduling_method or "default"
approximation_degree = pass_manager_config.approximation_degree
unitary_synthesis_method = pass_manager_config.unitary_synthesis_method
Expand All @@ -77,19 +68,6 @@ def level_2_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
"routing", routing_method, pass_manager_config, optimization_level=2
)

# Build optimization loop: 1q rotation merge and commutative cancellation iteratively until
# no more change in depth
_depth_check = [Depth(recurse=True), FixedPoint("depth")]
_size_check = [Size(recurse=True), FixedPoint("size")]

def _opt_control(property_set):
return (not property_set["depth_fixed_point"]) or (not property_set["size_fixed_point"])

_opt: list[BasePass] = [
Optimize1qGatesDecomposition(basis=basis_gates, target=target),
CommutativeCancellation(basis_gates=basis_gates, target=target),
]

unroll_3q = None
# Build pass manager
if coupling_map or initial_layout:
Expand Down Expand Up @@ -118,25 +96,10 @@ def _opt_control(property_set):
pre_optimization = common.generate_pre_op_passmanager(target, coupling_map, True)
else:
pre_optimization = common.generate_pre_op_passmanager(remove_reset_in_zero=True)
if optimization_method is None:
optimization = PassManager()
unroll = [pass_ for x in translation.passes() for pass_ in x["passes"]]
# Build nested Flow controllers
def _unroll_condition(property_set):
return not property_set["all_gates_in_basis"]

# Check if any gate is not in the basis, and if so, run unroll passes
_unroll_if_out_of_basis: list[BasePass | FlowController] = [
GatesInBasis(basis_gates, target=target),
ConditionalController(unroll, condition=_unroll_condition),
]
optimization.append(_depth_check + _size_check)
opt_loop = _opt + _unroll_if_out_of_basis + _depth_check + _size_check
optimization.append(opt_loop, do_while=_opt_control)
else:
optimization = plugin_manager.get_passmanager_stage(
"optimization", optimization_method, pass_manager_config, optimization_level=2
)

optimization = plugin_manager.get_passmanager_stage(
"optimization", optimization_method, pass_manager_config, optimization_level=2
)

sched = plugin_manager.get_passmanager_stage(
"scheduling", scheduling_method, pass_manager_config, optimization_level=2
Expand Down
Loading

0 comments on commit e7808e7

Please sign in to comment.