diff --git a/qiskit/transpiler/preset_passmanagers/level0.py b/qiskit/transpiler/preset_passmanagers/level0.py index b178f97fe551..46cc34f8c0b5 100644 --- a/qiskit/transpiler/preset_passmanagers/level0.py +++ b/qiskit/transpiler/preset_passmanagers/level0.py @@ -94,7 +94,20 @@ def level_0_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: unitary_synthesis_method = pass_manager_config.unitary_synthesis_method unitary_synthesis_plugin_config = pass_manager_config.unitary_synthesis_plugin_config - # 1. Choose an initial layout if not set by user (default: trivial layout) + # 1. Decompose so only 1-qubit and 2-qubit gates remain + _unroll3q = [ + # Use unitary synthesis for basis aware decomposition of UnitaryGates + UnitarySynthesis( + basis_gates, + approximation_degree=approximation_degree, + method=unitary_synthesis_method, + min_qubits=3, + plugin_config=unitary_synthesis_plugin_config, + ), + Unroll3qOrMore(), + ] + + # 2. Choose an initial layout if not set by user (default: trivial layout) _given_layout = SetLayout(initial_layout) def _choose_layout_condition(property_set): @@ -111,24 +124,9 @@ def _choose_layout_condition(property_set): else: raise TranspilerError("Invalid layout method %s." % layout_method) - # 2. Extend dag/layout with ancillas using the full coupling map + # 3. Extend dag/layout with ancillas using the full coupling map _embed = [FullAncillaAllocation(coupling_map), EnlargeWithAncilla(), ApplyLayout()] - # 3. Decompose so only 1-qubit and 2-qubit gates remain - _unroll3q = [ - # Use unitary synthesis for basis aware decomposition of UnitaryGates - UnitarySynthesis( - basis_gates, - approximation_degree=approximation_degree, - coupling_map=coupling_map, - backend_props=backend_properties, - method=unitary_synthesis_method, - min_qubits=3, - plugin_config=unitary_synthesis_plugin_config, - ), - Unroll3qOrMore(), - ] - # 4. Swap to fit the coupling map _swap_check = CheckMap(coupling_map) @@ -247,9 +245,9 @@ def _contains_delay(property_set): pm0 = PassManager() if coupling_map or initial_layout: pm0.append(_given_layout) + pm0.append(_unroll3q) pm0.append(_choose_layout, condition=_choose_layout_condition) pm0.append(_embed) - pm0.append(_unroll3q) pm0.append(_swap_check) pm0.append(_swap, condition=_swap_condition) pm0.append(_unroll) diff --git a/qiskit/transpiler/preset_passmanagers/level1.py b/qiskit/transpiler/preset_passmanagers/level1.py index 7417fb650076..21c362044273 100644 --- a/qiskit/transpiler/preset_passmanagers/level1.py +++ b/qiskit/transpiler/preset_passmanagers/level1.py @@ -112,7 +112,20 @@ def level_1_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: def _choose_layout_condition(property_set): return not property_set["layout"] - # 2. Use a better layout on densely connected qubits, if circuit needs swaps + # 2. Decompose so only 1-qubit and 2-qubit gates remain + _unroll3q = [ + # Use unitary synthesis for basis aware decomposition of UnitaryGates + UnitarySynthesis( + basis_gates, + approximation_degree=approximation_degree, + method=unitary_synthesis_method, + min_qubits=3, + plugin_config=unitary_synthesis_plugin_config, + ), + Unroll3qOrMore(), + ] + + # 3. Use a better layout on densely connected qubits, if circuit needs swaps if layout_method == "trivial": _improve_layout = TrivialLayout(coupling_map) elif layout_method == "dense": @@ -130,24 +143,9 @@ def _not_perfect_yet(property_set): and property_set["trivial_layout_score"] != 0 ) - # 3. Extend dag/layout with ancillas using the full coupling map + # 4. Extend dag/layout with ancillas using the full coupling map _embed = [FullAncillaAllocation(coupling_map), EnlargeWithAncilla(), ApplyLayout()] - # 4. Decompose so only 1-qubit and 2-qubit gates remain - _unroll3q = [ - # Use unitary synthesis for basis aware decomposition of UnitaryGates - UnitarySynthesis( - basis_gates, - approximation_degree=approximation_degree, - coupling_map=coupling_map, - method=unitary_synthesis_method, - backend_props=backend_properties, - min_qubits=3, - plugin_config=unitary_synthesis_plugin_config, - ), - Unroll3qOrMore(), - ] - # 5. Swap to fit the coupling map _swap_check = CheckMap(coupling_map) @@ -279,10 +277,10 @@ def _contains_delay(property_set): pm1 = PassManager() if coupling_map or initial_layout: pm1.append(_given_layout) + pm1.append(_unroll3q) pm1.append(_choose_layout_and_score, condition=_choose_layout_condition) pm1.append(_improve_layout, condition=_not_perfect_yet) pm1.append(_embed) - pm1.append(_unroll3q) pm1.append(_swap_check) pm1.append(_swap, condition=_swap_condition) pm1.append(_unroll) diff --git a/qiskit/transpiler/preset_passmanagers/level2.py b/qiskit/transpiler/preset_passmanagers/level2.py index 5a492cd06fc5..d0a6396626d2 100644 --- a/qiskit/transpiler/preset_passmanagers/level2.py +++ b/qiskit/transpiler/preset_passmanagers/level2.py @@ -105,7 +105,20 @@ def level_2_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: timing_constraints = pass_manager_config.timing_constraints or TimingConstraints() unitary_synthesis_plugin_config = pass_manager_config.unitary_synthesis_plugin_config - # 1. Search for a perfect layout, or choose a dense layout, if no layout given + # 1. Unroll to 1q or 2q gates + _unroll3q = [ + # Use unitary synthesis for basis aware decomposition of UnitaryGates + UnitarySynthesis( + basis_gates, + approximation_degree=approximation_degree, + method=unitary_synthesis_method, + min_qubits=3, + plugin_config=unitary_synthesis_plugin_config, + ), + Unroll3qOrMore(), + ] + + # 2. Search for a perfect layout, or choose a dense layout, if no layout given _given_layout = SetLayout(initial_layout) def _choose_layout_condition(property_set): @@ -121,7 +134,7 @@ def _choose_layout_condition(property_set): Layout2qDistance(coupling_map, property_name="trivial_layout_score"), ] ) - # 1b. If a trivial layout wasn't perfect (ie no swaps are needed) then try using + # 2b. If a trivial layout wasn't perfect (ie no swaps are needed) then try using # CSP layout to find a perfect layout _choose_layout_1 = ( [] @@ -132,7 +145,7 @@ def _choose_layout_condition(property_set): def _trivial_not_perfect(property_set): # Verify that a trivial layout is perfect. If trivial_layout_score > 0 # the layout is not perfect. The layout is unconditionally set by trivial - # layout so we need to clear it before contuing. + # layout so we need to clear it before continuing. if property_set["trivial_layout_score"] is not None: if property_set["trivial_layout_score"] != 0: return True @@ -151,7 +164,7 @@ def _csp_not_found_match(property_set): return True return False - # 1c. if CSP layout doesn't converge on a solution use layout_method (dense) to get a layout + # 2c. if CSP layout doesn't converge on a solution use layout_method (dense) to get a layout if layout_method == "trivial": _choose_layout_2 = TrivialLayout(coupling_map) elif layout_method == "dense": @@ -163,24 +176,9 @@ def _csp_not_found_match(property_set): else: raise TranspilerError("Invalid layout method %s." % layout_method) - # 2. Extend dag/layout with ancillas using the full coupling map + # 3. Extend dag/layout with ancillas using the full coupling map _embed = [FullAncillaAllocation(coupling_map), EnlargeWithAncilla(), ApplyLayout()] - # 3. Unroll to 1q or 2q gates - _unroll3q = [ - # Use unitary synthesis for basis aware decomposition of UnitaryGates - UnitarySynthesis( - basis_gates, - approximation_degree=approximation_degree, - coupling_map=coupling_map, - backend_props=backend_properties, - method=unitary_synthesis_method, - min_qubits=3, - plugin_config=unitary_synthesis_plugin_config, - ), - Unroll3qOrMore(), - ] - # 4. Swap to fit the coupling map _swap_check = CheckMap(coupling_map) @@ -316,11 +314,11 @@ def _contains_delay(property_set): pm2 = PassManager() if coupling_map or initial_layout: pm2.append(_given_layout) + pm2.append(_unroll3q) pm2.append(_choose_layout_0, condition=_choose_layout_condition) pm2.append(_choose_layout_1, condition=_trivial_not_perfect) pm2.append(_choose_layout_2, condition=_csp_not_found_match) pm2.append(_embed) - pm2.append(_unroll3q) pm2.append(_swap_check) pm2.append(_swap, condition=_swap_condition) pm2.append(_unroll) diff --git a/qiskit/transpiler/preset_passmanagers/level3.py b/qiskit/transpiler/preset_passmanagers/level3.py index 28b59c0d3893..93fdd9ccbb7b 100644 --- a/qiskit/transpiler/preset_passmanagers/level3.py +++ b/qiskit/transpiler/preset_passmanagers/level3.py @@ -114,8 +114,6 @@ def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: UnitarySynthesis( basis_gates, approximation_degree=approximation_degree, - coupling_map=coupling_map, - backend_props=backend_properties, method=unitary_synthesis_method, plugin_config=unitary_synthesis_plugin_config, min_qubits=3, diff --git a/releasenotes/notes/7156-df1a60c608b93184.yaml b/releasenotes/notes/7156-df1a60c608b93184.yaml new file mode 100644 index 000000000000..86cefa690c7f --- /dev/null +++ b/releasenotes/notes/7156-df1a60c608b93184.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixed `#7156 `__ . + Many layout methods ignore 3-or-more qubit gates resulting in expected layout allocation decisions. + The pass :class:`qiskit.transpiler.passes.Unroll3qOrMore` is now being executed before the layout pass.