From 2d8fa90b8da78b3c68ffb558a3145c89c23a258d Mon Sep 17 00:00:00 2001 From: Ali Javadi Date: Thu, 19 Mar 2020 20:30:01 -0400 Subject: [PATCH 1/6] add ability to select layout and routing method from top transpile function --- qiskit/compiler/transpile.py | 37 +++++++++++++++---- .../transpiler/preset_passmanagers/level0.py | 30 +++++++++++++-- .../transpiler/preset_passmanagers/level1.py | 26 +++++++++++-- .../transpiler/preset_passmanagers/level2.py | 28 ++++++++++++-- .../transpiler/preset_passmanagers/level3.py | 30 ++++++++++++--- 5 files changed, 127 insertions(+), 24 deletions(-) diff --git a/qiskit/compiler/transpile.py b/qiskit/compiler/transpile.py index d92b7ff3253d..bbf7e81d3436 100644 --- a/qiskit/compiler/transpile.py +++ b/qiskit/compiler/transpile.py @@ -40,6 +40,8 @@ def transpile(circuits: Union[QuantumCircuit, List[QuantumCircuit]], coupling_map: Optional[Union[CouplingMap, List[List[int]]]] = None, backend_properties: Optional[BackendProperties] = None, initial_layout: Optional[Union[Layout, Dict, List]] = None, + layout_method: Optional[str] = None, + routing_method: Optional[str] = None, seed_transpiler: Optional[int] = None, optimization_level: Optional[int] = None, pass_manager: Optional[PassManager] = None, @@ -108,6 +110,8 @@ def transpile(circuits: Union[QuantumCircuit, List[QuantumCircuit]], [qr[0], None, None, qr[1], None, qr[2]] + layout_method: Name of layout selection pass ('trivial', 'dense', 'noise_adaptive') + routing_method: Name of routing pass ('basic', 'lookahead', 'stochastic') seed_transpiler: Sets random seed for the stochastic parts of the transpiler optimization_level: How much optimization to perform on the circuits. Higher levels generate more optimized circuits, @@ -170,6 +174,7 @@ def callback_func(**kwargs): circuits = circuits if isinstance(circuits, list) else [circuits] transpile_args = _parse_transpile_args(circuits, backend, basis_gates, coupling_map, backend_properties, initial_layout, + layout_method, routing_method, seed_transpiler, optimization_level, pass_manager, callback, output_name) # Check circuit width against number of qubits in coupling_map(s) @@ -263,7 +268,8 @@ def _transpile_circuit(circuit_config_tuple: Tuple[QuantumCircuit, Dict]) -> Qua def _parse_transpile_args(circuits, backend, basis_gates, coupling_map, backend_properties, - initial_layout, seed_transpiler, optimization_level, + initial_layout, layout_method, routing_method, + seed_transpiler, optimization_level, pass_manager, callback, output_name) -> List[Dict]: """Resolve the various types of args allowed to the transpile() function through duck typing, overriding args, etc. Refer to the transpile() docstring for details on @@ -284,6 +290,8 @@ def _parse_transpile_args(circuits, backend, coupling_map = _parse_coupling_map(coupling_map, backend, num_circuits) backend_properties = _parse_backend_properties(backend_properties, backend, num_circuits) initial_layout = _parse_initial_layout(initial_layout, circuits) + layout_method = _parse_layout_method(layout_method, num_circuits) + routing_method = _parse_routing_method(routing_method, num_circuits) seed_transpiler = _parse_seed_transpiler(seed_transpiler, num_circuits) optimization_level = _parse_optimization_level(optimization_level, num_circuits) pass_manager = _parse_pass_manager(pass_manager, num_circuits) @@ -292,17 +300,20 @@ def _parse_transpile_args(circuits, backend, list_transpile_args = [] for args in zip(basis_gates, coupling_map, backend_properties, - initial_layout, seed_transpiler, optimization_level, + initial_layout, layout_method, routing_method, + seed_transpiler, optimization_level, pass_manager, output_name, callback): transpile_args = {'pass_manager_config': PassManagerConfig(basis_gates=args[0], coupling_map=args[1], backend_properties=args[2], initial_layout=args[3], - seed_transpiler=args[4]), - 'optimization_level': args[5], - 'pass_manager': args[6], - 'output_name': args[7], - 'callback': args[8]} + layout_method=args[4], + routing_method=args[5], + seed_transpiler=args[6]), + 'optimization_level': args[7], + 'pass_manager': args[8], + 'output_name': args[9], + 'callback': args[10]} list_transpile_args.append(transpile_args) return list_transpile_args @@ -388,6 +399,18 @@ def _layout_from_raw(initial_layout, circuit): return initial_layout +def _parse_layout_method(layout_method, num_circuits): + if not isinstance(layout_method, list): + layout_method = [layout_method] * num_circuits + return layout_method + + +def _parse_routing_method(routing_method, num_circuits): + if not isinstance(routing_method, list): + routing_method = [routing_method] * num_circuits + return routing_method + + def _parse_seed_transpiler(seed_transpiler, num_circuits): if not isinstance(seed_transpiler, list): seed_transpiler = [seed_transpiler] * num_circuits diff --git a/qiskit/transpiler/preset_passmanagers/level0.py b/qiskit/transpiler/preset_passmanagers/level0.py index 53e024df7669..c19c50c888b2 100644 --- a/qiskit/transpiler/preset_passmanagers/level0.py +++ b/qiskit/transpiler/preset_passmanagers/level0.py @@ -26,7 +26,11 @@ from qiskit.transpiler.passes import CXDirection from qiskit.transpiler.passes import SetLayout from qiskit.transpiler.passes import TrivialLayout +from qiskit.transpiler.passes import DenseLayout +from qiskit.transpiler.passes import NoiseAdaptiveLayout from qiskit.transpiler.passes import BarrierBeforeFinalMeasurements +from qiskit.transpiler.passes import BasicSwap +from qiskit.transpiler.passes import LookaheadSwap from qiskit.transpiler.passes import StochasticSwap from qiskit.transpiler.passes import FullAncillaAllocation from qiskit.transpiler.passes import EnlargeWithAncilla @@ -34,6 +38,8 @@ from qiskit.transpiler.passes import ApplyLayout from qiskit.transpiler.passes import CheckCXDirection +from qiskit.transpiler import TranspilerError + def level_0_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: """Level 0 pass manager: no explicit optimization other than mapping to backend. @@ -58,15 +64,24 @@ def level_0_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: basis_gates = pass_manager_config.basis_gates coupling_map = pass_manager_config.coupling_map initial_layout = pass_manager_config.initial_layout + layout_method = pass_manager_config.layout_method or 'dense' + routing_method = pass_manager_config.routing_method or 'stochastic' seed_transpiler = pass_manager_config.seed_transpiler - # 1. Use trivial layout if no layout given + # 1. Choose an initial layout if not set by user (default: trivial layout) _given_layout = SetLayout(initial_layout) def _choose_layout_condition(property_set): return not property_set['layout'] - _choose_layout = TrivialLayout(coupling_map) + if layout_method == 'trivial': + _choose_layout = TrivialLayout(coupling_map) + elif layout_method == 'dense': + _choose_layout = DenseLayout(coupling_map) + elif layout_method == 'noise_adaptive': + _choose_layout = NoiseAdaptiveLayout(backend_properties) + else: + raise TranspilerError("Invalid layout method %s.", layout_method) # 2. Extend dag/layout with ancillas using the full coupling map _embed = [FullAncillaAllocation(coupling_map), EnlargeWithAncilla(), ApplyLayout()] @@ -80,8 +95,15 @@ def _choose_layout_condition(property_set): def _swap_condition(property_set): return not property_set['is_swap_mapped'] - _swap = [BarrierBeforeFinalMeasurements(), - StochasticSwap(coupling_map, trials=20, seed=seed_transpiler)] + _swap = [BarrierBeforeFinalMeasurements()] + if routing_method == 'basic': + _swap += [BasicSwap(coupling_map)] + elif routing_method == 'stochastic': + _swap += [StochasticSwap(coupling_map, trials=20, seed=seed_transpiler)] + elif routing_method == 'lookahead': + _swap += [LookaheadSwap(coupling_map)] + else: + raise TranspilerError("Invalid routing method %s.", routing_method) # 5. Unroll to the basis _unroll = Unroller(basis_gates) diff --git a/qiskit/transpiler/preset_passmanagers/level1.py b/qiskit/transpiler/preset_passmanagers/level1.py index 9b05eeb318a5..b682caeefc03 100644 --- a/qiskit/transpiler/preset_passmanagers/level1.py +++ b/qiskit/transpiler/preset_passmanagers/level1.py @@ -27,7 +27,11 @@ from qiskit.transpiler.passes import CXDirection from qiskit.transpiler.passes import SetLayout from qiskit.transpiler.passes import TrivialLayout +from qiskit.transpiler.passes import DenseLayout +from qiskit.transpiler.passes import NoiseAdaptiveLayout from qiskit.transpiler.passes import BarrierBeforeFinalMeasurements +from qiskit.transpiler.passes import BasicSwap +from qiskit.transpiler.passes import LookaheadSwap from qiskit.transpiler.passes import StochasticSwap from qiskit.transpiler.passes import FullAncillaAllocation from qiskit.transpiler.passes import EnlargeWithAncilla @@ -65,6 +69,8 @@ def level_1_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: basis_gates = pass_manager_config.basis_gates coupling_map = pass_manager_config.coupling_map initial_layout = pass_manager_config.initial_layout + layout_method = pass_manager_config.layout_method or 'dense' + routing_method = pass_manager_config.routing_method or 'stochastic' seed_transpiler = pass_manager_config.seed_transpiler backend_properties = pass_manager_config.backend_properties @@ -79,7 +85,14 @@ def _choose_layout_condition(property_set): return not property_set['layout'] # 2. Use a better layout on densely connected qubits, if circuit needs swaps - _improve_layout = DenseLayout(coupling_map, backend_properties) + if layout_method == 'trivial': + _improve_layout = TrivialLayout(coupling_map) + elif layout_method == 'dense': + _improve_layout = DenseLayout(coupling_map, backend_properties) + elif layout_method == 'noise_adaptive': + _improve_layout = NoiseAdaptiveLayout(backend_properties) + else: + raise TranspilerError("Invalid layout method %s.", layout_method) def _not_perfect_yet(property_set): return property_set['trivial_layout_score'] is not None and \ @@ -97,8 +110,15 @@ def _not_perfect_yet(property_set): def _swap_condition(property_set): return not property_set['is_swap_mapped'] - _swap = [BarrierBeforeFinalMeasurements(), - StochasticSwap(coupling_map, trials=20, seed=seed_transpiler)] + _swap = [BarrierBeforeFinalMeasurements()] + if routing_method == 'basic': + _swap += [BasicSwap(coupling_map)] + elif routing_method == 'stochastic': + _swap += [StochasticSwap(coupling_map, trials=50, seed=seed_transpiler)] + elif routing_method == 'lookahead': + _swap += [LookaheadSwap(coupling_map)] + else: + raise TranspilerError("Invalid routing method %s.", routing_method) # 6. Unroll to the basis _unroll = Unroller(basis_gates) diff --git a/qiskit/transpiler/preset_passmanagers/level2.py b/qiskit/transpiler/preset_passmanagers/level2.py index 09e161628d2f..d954dbcf8cb4 100644 --- a/qiskit/transpiler/preset_passmanagers/level2.py +++ b/qiskit/transpiler/preset_passmanagers/level2.py @@ -26,9 +26,13 @@ from qiskit.transpiler.passes import CheckMap from qiskit.transpiler.passes import CXDirection from qiskit.transpiler.passes import SetLayout -from qiskit.transpiler.passes import DenseLayout from qiskit.transpiler.passes import CSPLayout +from qiskit.transpiler.passes import TrivialLayout +from qiskit.transpiler.passes import DenseLayout +from qiskit.transpiler.passes import NoiseAdaptiveLayout from qiskit.transpiler.passes import BarrierBeforeFinalMeasurements +from qiskit.transpiler.passes import BasicSwap +from qiskit.transpiler.passes import LookaheadSwap from qiskit.transpiler.passes import StochasticSwap from qiskit.transpiler.passes import FullAncillaAllocation from qiskit.transpiler.passes import EnlargeWithAncilla @@ -68,6 +72,8 @@ def level_2_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: basis_gates = pass_manager_config.basis_gates coupling_map = pass_manager_config.coupling_map initial_layout = pass_manager_config.initial_layout + layout_method = pass_manager_config.layout_method or 'dense' + routing_method = pass_manager_config.routing_method or 'stochastic' seed_transpiler = pass_manager_config.seed_transpiler backend_properties = pass_manager_config.backend_properties @@ -78,7 +84,14 @@ def _choose_layout_condition(property_set): return not property_set['layout'] _choose_layout_1 = CSPLayout(coupling_map, call_limit=1000, time_limit=10) - _choose_layout_2 = DenseLayout(coupling_map, backend_properties) + if layout_method == 'trivial': + _choose_layout_2 = TrivialLayout(coupling_map) + elif layout_method == 'dense': + _choose_layout_2 = DenseLayout(coupling_map, backend_properties) + elif layout_method == 'noise_adaptive': + _choose_layout_2 = NoiseAdaptiveLayout(backend_properties) + else: + raise TranspilerError("Invalid layout method %s.", layout_method) # 2. Extend dag/layout with ancillas using the full coupling map _embed = [FullAncillaAllocation(coupling_map), EnlargeWithAncilla(), ApplyLayout()] @@ -92,8 +105,15 @@ def _choose_layout_condition(property_set): def _swap_condition(property_set): return not property_set['is_swap_mapped'] - _swap = [BarrierBeforeFinalMeasurements(), - StochasticSwap(coupling_map, trials=20, seed=seed_transpiler)] + _swap = [BarrierBeforeFinalMeasurements()] + if routing_method == 'basic': + _swap += [BasicSwap(coupling_map)] + elif routing_method == 'stochastic': + _swap += [StochasticSwap(coupling_map, trials=100, seed=seed_transpiler)] + elif routing_method == 'lookahead': + _swap += [LookaheadSwap(coupling_map)] + else: + raise TranspilerError("Invalid routing method %s.", routing_method) # 5. Unroll to the basis _unroll = Unroller(basis_gates) diff --git a/qiskit/transpiler/preset_passmanagers/level3.py b/qiskit/transpiler/preset_passmanagers/level3.py index 994bc4c8fdf1..d45b2f8cea55 100644 --- a/qiskit/transpiler/preset_passmanagers/level3.py +++ b/qiskit/transpiler/preset_passmanagers/level3.py @@ -27,9 +27,13 @@ from qiskit.transpiler.passes import CXDirection from qiskit.transpiler.passes import SetLayout from qiskit.transpiler.passes import CSPLayout +from qiskit.transpiler.passes import TrivialLayout from qiskit.transpiler.passes import DenseLayout -from qiskit.transpiler.passes import StochasticSwap +from qiskit.transpiler.passes import NoiseAdaptiveLayout from qiskit.transpiler.passes import BarrierBeforeFinalMeasurements +from qiskit.transpiler.passes import BasicSwap +from qiskit.transpiler.passes import LookaheadSwap +from qiskit.transpiler.passes import StochasticSwap from qiskit.transpiler.passes import FullAncillaAllocation from qiskit.transpiler.passes import EnlargeWithAncilla from qiskit.transpiler.passes import FixedPoint @@ -72,6 +76,8 @@ def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: basis_gates = pass_manager_config.basis_gates coupling_map = pass_manager_config.coupling_map initial_layout = pass_manager_config.initial_layout + layout_method = pass_manager_config.layout_method or 'dense' + routing_method = pass_manager_config.routing_method or 'stochastic' seed_transpiler = pass_manager_config.seed_transpiler backend_properties = pass_manager_config.backend_properties @@ -85,8 +91,14 @@ def _choose_layout_condition(property_set): return not property_set['layout'] _choose_layout_1 = CSPLayout(coupling_map, call_limit=10000, time_limit=60) - # TODO: benchmark DenseLayout vs. NoiseAdaptiveLayout in terms of noise aware mapping - _choose_layout_2 = DenseLayout(coupling_map, backend_properties) + if layout_method == 'trivial': + _choose_layout_2 = TrivialLayout(coupling_map) + elif layout_method == 'dense': + _choose_layout_2 = DenseLayout(coupling_map, backend_properties) + elif layout_method == 'noise_adaptive': + _choose_layout_2 = NoiseAdaptiveLayout(backend_properties) + else: + raise TranspilerError("Invalid layout method %s.", layout_method) # 3. Extend dag/layout with ancillas using the full coupling map _embed = [FullAncillaAllocation(coupling_map), EnlargeWithAncilla(), ApplyLayout()] @@ -97,9 +109,15 @@ def _choose_layout_condition(property_set): def _swap_condition(property_set): return not property_set['is_swap_mapped'] - _swap = [BarrierBeforeFinalMeasurements(), - Unroll3qOrMore(), - StochasticSwap(coupling_map, trials=20, seed=seed_transpiler)] + _swap = [BarrierBeforeFinalMeasurements(), Unroll3qOrMore()] + if routing_method == 'basic': + _swap += [BasicSwap(coupling_map)] + elif routing_method == 'stochastic': + _swap += [StochasticSwap(coupling_map, trials=200, seed=seed_transpiler)] + elif routing_method == 'lookahead': + _swap += [LookaheadSwap(coupling_map)] + else: + raise TranspilerError("Invalid routing method %s.", routing_method) # 5. 1q rotation merge and commutative cancellation iteratively until no more change in depth _depth_check = [Depth(), FixedPoint('depth')] From c2d15fbf38c3788865c94f5dff988b82807a471a Mon Sep 17 00:00:00 2001 From: Ali Javadi Date: Thu, 19 Mar 2020 21:21:16 -0400 Subject: [PATCH 2/6] set lookahead width/depth in increasing order --- qiskit/transpiler/preset_passmanagers/level0.py | 2 +- qiskit/transpiler/preset_passmanagers/level1.py | 2 +- qiskit/transpiler/preset_passmanagers/level2.py | 2 +- qiskit/transpiler/preset_passmanagers/level3.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/qiskit/transpiler/preset_passmanagers/level0.py b/qiskit/transpiler/preset_passmanagers/level0.py index c19c50c888b2..9d097f2fd7ba 100644 --- a/qiskit/transpiler/preset_passmanagers/level0.py +++ b/qiskit/transpiler/preset_passmanagers/level0.py @@ -101,7 +101,7 @@ def _swap_condition(property_set): elif routing_method == 'stochastic': _swap += [StochasticSwap(coupling_map, trials=20, seed=seed_transpiler)] elif routing_method == 'lookahead': - _swap += [LookaheadSwap(coupling_map)] + _swap += [LookaheadSwap(coupling_map, search_depth=2, search_width=2)] else: raise TranspilerError("Invalid routing method %s.", routing_method) diff --git a/qiskit/transpiler/preset_passmanagers/level1.py b/qiskit/transpiler/preset_passmanagers/level1.py index b682caeefc03..81f47217fc10 100644 --- a/qiskit/transpiler/preset_passmanagers/level1.py +++ b/qiskit/transpiler/preset_passmanagers/level1.py @@ -116,7 +116,7 @@ def _swap_condition(property_set): elif routing_method == 'stochastic': _swap += [StochasticSwap(coupling_map, trials=50, seed=seed_transpiler)] elif routing_method == 'lookahead': - _swap += [LookaheadSwap(coupling_map)] + _swap += [LookaheadSwap(coupling_map, search_depth=4, search_width=4)] else: raise TranspilerError("Invalid routing method %s.", routing_method) diff --git a/qiskit/transpiler/preset_passmanagers/level2.py b/qiskit/transpiler/preset_passmanagers/level2.py index d954dbcf8cb4..1646937eac94 100644 --- a/qiskit/transpiler/preset_passmanagers/level2.py +++ b/qiskit/transpiler/preset_passmanagers/level2.py @@ -111,7 +111,7 @@ def _swap_condition(property_set): elif routing_method == 'stochastic': _swap += [StochasticSwap(coupling_map, trials=100, seed=seed_transpiler)] elif routing_method == 'lookahead': - _swap += [LookaheadSwap(coupling_map)] + _swap += [LookaheadSwap(coupling_map, search_depth=5, search_width=5)] else: raise TranspilerError("Invalid routing method %s.", routing_method) diff --git a/qiskit/transpiler/preset_passmanagers/level3.py b/qiskit/transpiler/preset_passmanagers/level3.py index d45b2f8cea55..2b4ed1ba5848 100644 --- a/qiskit/transpiler/preset_passmanagers/level3.py +++ b/qiskit/transpiler/preset_passmanagers/level3.py @@ -115,7 +115,7 @@ def _swap_condition(property_set): elif routing_method == 'stochastic': _swap += [StochasticSwap(coupling_map, trials=200, seed=seed_transpiler)] elif routing_method == 'lookahead': - _swap += [LookaheadSwap(coupling_map)] + _swap += [LookaheadSwap(coupling_map, search_depth=5, search_width=6)] else: raise TranspilerError("Invalid routing method %s.", routing_method) From 0143d4d37efc9fd52e8caadbb1d8e91ea94b201e Mon Sep 17 00:00:00 2001 From: Ali Javadi Date: Thu, 26 Mar 2020 11:09:52 -0400 Subject: [PATCH 3/6] releasenote --- .../transpile-method-selectors-1c426457743a6fa7.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 releasenotes/notes/transpile-method-selectors-1c426457743a6fa7.yaml diff --git a/releasenotes/notes/transpile-method-selectors-1c426457743a6fa7.yaml b/releasenotes/notes/transpile-method-selectors-1c426457743a6fa7.yaml new file mode 100644 index 000000000000..829a98fdf899 --- /dev/null +++ b/releasenotes/notes/transpile-method-selectors-1c426457743a6fa7.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + ``qiskit.transpile()`` now allows you to pass ``layout_method`` + and ``routing_method`` to select a particular method for placement and + routing of circuits on constrained architectures. + e.g. ``transpile(circ, backend, + layout_method='dense', routing_method='lookahead')`` From a41896097b799e9803f991fa9321364e4e38d3d7 Mon Sep 17 00:00:00 2001 From: Ali Javadi Date: Thu, 26 Mar 2020 22:10:04 -0400 Subject: [PATCH 4/6] review comments --- qiskit/compiler/transpile.py | 8 ++++++- qiskit/transpiler/pass_manager_config.py | 22 ++++++++----------- .../transpiler/preset_passmanagers/level0.py | 12 ++++++---- .../transpiler/preset_passmanagers/level1.py | 19 ++++++++++------ .../transpiler/preset_passmanagers/level2.py | 9 ++++++-- .../transpiler/preset_passmanagers/level3.py | 9 ++++++-- 6 files changed, 50 insertions(+), 29 deletions(-) diff --git a/qiskit/compiler/transpile.py b/qiskit/compiler/transpile.py index bbf7e81d3436..aa902489b293 100644 --- a/qiskit/compiler/transpile.py +++ b/qiskit/compiler/transpile.py @@ -13,6 +13,7 @@ # that they have been altered from the originals. """Circuit transpile function""" +import warnings from typing import List, Union, Dict, Callable, Any, Optional, Tuple from qiskit.circuit.quantumcircuit import QuantumCircuit from qiskit.providers import BaseBackend @@ -111,6 +112,8 @@ def transpile(circuits: Union[QuantumCircuit, List[QuantumCircuit]], [qr[0], None, None, qr[1], None, qr[2]] layout_method: Name of layout selection pass ('trivial', 'dense', 'noise_adaptive') + Sometimes a perfect layout can be available in which case the layout_method + may not run. routing_method: Name of routing pass ('basic', 'lookahead', 'stochastic') seed_transpiler: Sets random seed for the stochastic parts of the transpiler optimization_level: How much optimization to perform on the circuits. @@ -282,6 +285,9 @@ def _parse_transpile_args(circuits, backend, Returns: list[dicts]: a list of transpile parameters. """ + if initial_layout is not None and layout_method is not None: + warnings.warn("initial_layout provided; layout_method is ignored.", + UserWarning) # Each arg could be single or a list. If list, it must be the same size as # number of circuits. If single, duplicate to create a list of that size. num_circuits = len(circuits) @@ -300,7 +306,7 @@ def _parse_transpile_args(circuits, backend, list_transpile_args = [] for args in zip(basis_gates, coupling_map, backend_properties, - initial_layout, layout_method, routing_method, + initial_layout, layout_method, routing_method, seed_transpiler, optimization_level, pass_manager, output_name, callback): transpile_args = {'pass_manager_config': PassManagerConfig(basis_gates=args[0], diff --git a/qiskit/transpiler/pass_manager_config.py b/qiskit/transpiler/pass_manager_config.py index 4848207e98cc..b9d349d69854 100644 --- a/qiskit/transpiler/pass_manager_config.py +++ b/qiskit/transpiler/pass_manager_config.py @@ -2,7 +2,7 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2019. +# (C) Copyright IBM 2017, 2020. # # 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 @@ -17,24 +17,14 @@ class PassManagerConfig: """Pass Manager Configuration. - - Attributes: - initial_layout (Layout): Initial position of virtual qubits on physical - qubits. - basis_gates (list): List of basis gate names to unroll to. - coupling_map (CouplingMap): Directed graph represented a coupling map. - backend_properties (BackendProperties): Properties returned by a - backend, including - information on gate errors, readout errors, qubit coherence times, - etc. - seed_transpiler (int): Sets random seed for the stochastic parts of the - transpiler. """ def __init__(self, initial_layout=None, basis_gates=None, coupling_map=None, + layout_method=None, + routing_method=None, backend_properties=None, seed_transpiler=None): """Initialize a PassManagerConfig object @@ -45,6 +35,10 @@ def __init__(self, basis_gates (list): List of basis gate names to unroll to. coupling_map (CouplingMap): Directed graph represented a coupling map. + layout_method (str): the pass to use for choosing initial qubit + placement. + routing_method (str): the pass to use for routing qubits on the + architecture. backend_properties (BackendProperties): Properties returned by a backend, including information on gate errors, readout errors, qubit coherence times, etc. @@ -54,5 +48,7 @@ def __init__(self, self.initial_layout = initial_layout self.basis_gates = basis_gates self.coupling_map = coupling_map + self.layout_method = layout_method + self.routing_method=routing_method, self.backend_properties = backend_properties self.seed_transpiler = seed_transpiler diff --git a/qiskit/transpiler/preset_passmanagers/level0.py b/qiskit/transpiler/preset_passmanagers/level0.py index 9d097f2fd7ba..688774b92c6d 100644 --- a/qiskit/transpiler/preset_passmanagers/level0.py +++ b/qiskit/transpiler/preset_passmanagers/level0.py @@ -60,13 +60,17 @@ def level_0_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: Returns: a level 0 pass manager. + + Raises: + TranspilerError: if the passmanager config is invalid. """ basis_gates = pass_manager_config.basis_gates coupling_map = pass_manager_config.coupling_map initial_layout = pass_manager_config.initial_layout - layout_method = pass_manager_config.layout_method or 'dense' + layout_method = pass_manager_config.layout_method or 'trivial' routing_method = pass_manager_config.routing_method or 'stochastic' seed_transpiler = pass_manager_config.seed_transpiler + backend_properties = pass_manager_config.backend_properties # 1. Choose an initial layout if not set by user (default: trivial layout) _given_layout = SetLayout(initial_layout) @@ -77,11 +81,11 @@ def _choose_layout_condition(property_set): if layout_method == 'trivial': _choose_layout = TrivialLayout(coupling_map) elif layout_method == 'dense': - _choose_layout = DenseLayout(coupling_map) + _choose_layout = DenseLayout(coupling_map, backend_properties) elif layout_method == 'noise_adaptive': _choose_layout = NoiseAdaptiveLayout(backend_properties) else: - raise TranspilerError("Invalid layout method %s.", layout_method) + raise TranspilerError("Invalid layout method %s." % layout_method) # 2. Extend dag/layout with ancillas using the full coupling map _embed = [FullAncillaAllocation(coupling_map), EnlargeWithAncilla(), ApplyLayout()] @@ -103,7 +107,7 @@ def _swap_condition(property_set): elif routing_method == 'lookahead': _swap += [LookaheadSwap(coupling_map, search_depth=2, search_width=2)] else: - raise TranspilerError("Invalid routing method %s.", routing_method) + raise TranspilerError("Invalid routing method %s." % routing_method) # 5. Unroll to the basis _unroll = Unroller(basis_gates) diff --git a/qiskit/transpiler/preset_passmanagers/level1.py b/qiskit/transpiler/preset_passmanagers/level1.py index 81f47217fc10..1cfc9a721365 100644 --- a/qiskit/transpiler/preset_passmanagers/level1.py +++ b/qiskit/transpiler/preset_passmanagers/level1.py @@ -42,16 +42,18 @@ from qiskit.transpiler.passes import ApplyLayout from qiskit.transpiler.passes import CheckCXDirection from qiskit.transpiler.passes import Layout2qDistance -from qiskit.transpiler.passes import DenseLayout + +from qiskit.transpiler import TranspilerError def level_1_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: """Level 1 pass manager: light optimization by simple adjacent gate collapsing. - This pass manager applies the user-given initial layout. If none is given, and a trivial - layout (i-th virtual -> i-th physical) makes the circuit fit the coupling map, that is used. - Otherwise, the circuit is mapped to the most densely connected coupling subgraph, and swaps - are inserted to map. Any unused physical qubit is allocated as ancilla space. + This pass manager applies the user-given initial layout. If none is given, + and a trivial layout (i-th virtual -> i-th physical) makes the circuit fit + the coupling map, that is used. + Otherwise, the circuit is mapped to the most densely connected coupling subgraph, + and swaps are inserted to map. Any unused physical qubit is allocated as ancilla space. The pass manager then unrolls the circuit to the desired basis, and transforms the circuit to match the coupling map. Finally, optimizations in the form of adjacent gate collapse and redundant reset removal are performed. @@ -65,6 +67,9 @@ def level_1_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: Returns: a level 1 pass manager. + + Raises: + TranspilerError: if the passmanager config is invalid. """ basis_gates = pass_manager_config.basis_gates coupling_map = pass_manager_config.coupling_map @@ -92,7 +97,7 @@ def _choose_layout_condition(property_set): elif layout_method == 'noise_adaptive': _improve_layout = NoiseAdaptiveLayout(backend_properties) else: - raise TranspilerError("Invalid layout method %s.", layout_method) + raise TranspilerError("Invalid layout method %s." % layout_method) def _not_perfect_yet(property_set): return property_set['trivial_layout_score'] is not None and \ @@ -118,7 +123,7 @@ def _swap_condition(property_set): elif routing_method == 'lookahead': _swap += [LookaheadSwap(coupling_map, search_depth=4, search_width=4)] else: - raise TranspilerError("Invalid routing method %s.", routing_method) + raise TranspilerError("Invalid routing method %s." % routing_method) # 6. Unroll to the basis _unroll = Unroller(basis_gates) diff --git a/qiskit/transpiler/preset_passmanagers/level2.py b/qiskit/transpiler/preset_passmanagers/level2.py index 1646937eac94..ea25f5ae442e 100644 --- a/qiskit/transpiler/preset_passmanagers/level2.py +++ b/qiskit/transpiler/preset_passmanagers/level2.py @@ -44,6 +44,8 @@ from qiskit.transpiler.passes import ApplyLayout from qiskit.transpiler.passes import CheckCXDirection +from qiskit.transpiler import TranspilerError + def level_2_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: """Level 2 pass manager: medium optimization by initial layout selection and @@ -68,6 +70,9 @@ def level_2_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: Returns: a level 2 pass manager. + + Raises: + TranspilerError: if the passmanager config is invalid. """ basis_gates = pass_manager_config.basis_gates coupling_map = pass_manager_config.coupling_map @@ -91,7 +96,7 @@ def _choose_layout_condition(property_set): elif layout_method == 'noise_adaptive': _choose_layout_2 = NoiseAdaptiveLayout(backend_properties) else: - raise TranspilerError("Invalid layout method %s.", layout_method) + raise TranspilerError("Invalid layout method %s." % layout_method) # 2. Extend dag/layout with ancillas using the full coupling map _embed = [FullAncillaAllocation(coupling_map), EnlargeWithAncilla(), ApplyLayout()] @@ -113,7 +118,7 @@ def _swap_condition(property_set): elif routing_method == 'lookahead': _swap += [LookaheadSwap(coupling_map, search_depth=5, search_width=5)] else: - raise TranspilerError("Invalid routing method %s.", routing_method) + raise TranspilerError("Invalid routing method %s." % routing_method) # 5. Unroll to the basis _unroll = Unroller(basis_gates) diff --git a/qiskit/transpiler/preset_passmanagers/level3.py b/qiskit/transpiler/preset_passmanagers/level3.py index 2b4ed1ba5848..6b7f6a490456 100644 --- a/qiskit/transpiler/preset_passmanagers/level3.py +++ b/qiskit/transpiler/preset_passmanagers/level3.py @@ -48,6 +48,8 @@ from qiskit.transpiler.passes import ApplyLayout from qiskit.transpiler.passes import CheckCXDirection +from qiskit.transpiler import TranspilerError + def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: """Level 3 pass manager: heavy optimization by noise adaptive qubit mapping and @@ -72,6 +74,9 @@ def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: Returns: a level 3 pass manager. + + Raises: + TranspilerError: if the passmanager config is invalid. """ basis_gates = pass_manager_config.basis_gates coupling_map = pass_manager_config.coupling_map @@ -98,7 +103,7 @@ def _choose_layout_condition(property_set): elif layout_method == 'noise_adaptive': _choose_layout_2 = NoiseAdaptiveLayout(backend_properties) else: - raise TranspilerError("Invalid layout method %s.", layout_method) + raise TranspilerError("Invalid layout method %s." % layout_method) # 3. Extend dag/layout with ancillas using the full coupling map _embed = [FullAncillaAllocation(coupling_map), EnlargeWithAncilla(), ApplyLayout()] @@ -117,7 +122,7 @@ def _swap_condition(property_set): elif routing_method == 'lookahead': _swap += [LookaheadSwap(coupling_map, search_depth=5, search_width=6)] else: - raise TranspilerError("Invalid routing method %s.", routing_method) + raise TranspilerError("Invalid routing method %s." % routing_method) # 5. 1q rotation merge and commutative cancellation iteratively until no more change in depth _depth_check = [Depth(), FixedPoint('depth')] From e88c19f9aef251bc9282e04688a2bf0ae10f4932 Mon Sep 17 00:00:00 2001 From: Ali Javadi Date: Fri, 27 Mar 2020 11:25:07 -0400 Subject: [PATCH 5/6] lint --- .../notes/transpile-method-selectors-1c426457743a6fa7.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/releasenotes/notes/transpile-method-selectors-1c426457743a6fa7.yaml b/releasenotes/notes/transpile-method-selectors-1c426457743a6fa7.yaml index 829a98fdf899..8acec639d927 100644 --- a/releasenotes/notes/transpile-method-selectors-1c426457743a6fa7.yaml +++ b/releasenotes/notes/transpile-method-selectors-1c426457743a6fa7.yaml @@ -3,6 +3,5 @@ features: - | ``qiskit.transpile()`` now allows you to pass ``layout_method`` and ``routing_method`` to select a particular method for placement and - routing of circuits on constrained architectures. - e.g. ``transpile(circ, backend, - layout_method='dense', routing_method='lookahead')`` + routing of circuits on constrained architectures. e.g. + ``transpile(circ, backend, layout_method='dense', routing_method='lookahead')`` From b4a4ed7d7b8492b0735ccb3f9405a9edd4b1c2b4 Mon Sep 17 00:00:00 2001 From: Ali Javadi Date: Sat, 28 Mar 2020 00:54:06 -0400 Subject: [PATCH 6/6] lint --- qiskit/transpiler/pass_manager_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/transpiler/pass_manager_config.py b/qiskit/transpiler/pass_manager_config.py index b9d349d69854..392d5ac09b6f 100644 --- a/qiskit/transpiler/pass_manager_config.py +++ b/qiskit/transpiler/pass_manager_config.py @@ -49,6 +49,6 @@ def __init__(self, self.basis_gates = basis_gates self.coupling_map = coupling_map self.layout_method = layout_method - self.routing_method=routing_method, + self.routing_method = routing_method self.backend_properties = backend_properties self.seed_transpiler = seed_transpiler