diff --git a/qiskit/transpiler/passes/routing/layout_transformation.py b/qiskit/transpiler/passes/routing/layout_transformation.py index 536b282d9135..61494a5e515b 100644 --- a/qiskit/transpiler/passes/routing/layout_transformation.py +++ b/qiskit/transpiler/passes/routing/layout_transformation.py @@ -117,8 +117,5 @@ def run(self, dag): perm_circ = self.token_swapper.permutation_circuit(permutation, self.trials) qubits = [dag.qubits[i[0]] for i in sorted(perm_circ.inputmap.items(), key=lambda x: x[0])] - self.property_set["perm_circ"] = perm_circ - self.property_set["perm_qubits"] = qubits - dag.compose(perm_circ.circuit, qubits=qubits, inplace=self.inplace) return dag diff --git a/qiskit/transpiler/passes/routing/utils.py b/qiskit/transpiler/passes/routing/utils.py index 31ac452384a0..e128fcec414e 100644 --- a/qiskit/transpiler/passes/routing/utils.py +++ b/qiskit/transpiler/passes/routing/utils.py @@ -16,6 +16,8 @@ from qiskit.transpiler.layout import Layout from qiskit.dagcircuit import DAGCircuit from qiskit.circuit import QuantumRegister +from qiskit.transpiler import CouplingMap +from qiskit.transpiler.exceptions import TranspilerError def route_cf_multiblock(tpass, cf_opnode, current_layout, qregs, root_dag, seed=None): @@ -38,7 +40,6 @@ def route_cf_multiblock(tpass, cf_opnode, current_layout, qregs, root_dag, seed= list(Qubit): list of idle qubits in controlflow layer. """ # pylint: disable=cyclic-import - from qiskit.transpiler.passes.routing.layout_transformation import LayoutTransformation from qiskit.converters import dag_to_circuit, circuit_to_dag if current_layout is None: @@ -67,18 +68,13 @@ def route_cf_multiblock(tpass, cf_opnode, current_layout, qregs, root_dag, seed= if i == deepest_index: block_circuits[i] = dag_to_circuit(updated_dag_block) else: - layout_xform = LayoutTransformation( - coupling, block_layouts[i], block_layouts[deepest_index], seed=seed, inplace=False + swap_circuit, swap_qubits = _get_swap_map_dag( + root_dag, coupling, block_layouts[i], block_layouts[deepest_index], seed=seed ) - layout_xform.run(updated_dag_block) - physical_swap_dag = layout_xform.property_set["perm_circ"].circuit - if physical_swap_dag.depth(): + if swap_circuit.depth(): virtual_swap_dag = updated_dag_block.copy_empty_like() - order = [ - p2v[virtual_swap_dag.qubits.index(qubit)] - for qubit in layout_xform.property_set["perm_qubits"] - ] - virtual_swap_dag.compose(physical_swap_dag, qubits=order) + order = [p2v[virtual_swap_dag.qubits.index(qubit)] for qubit in swap_qubits] + virtual_swap_dag.compose(swap_circuit, qubits=order) updated_dag_block.compose(virtual_swap_dag) idle_qubits &= set(updated_dag_block.idle_wires()) # contract idle bits from full width post routing @@ -100,7 +96,7 @@ def route_cf_multiblock(tpass, cf_opnode, current_layout, qregs, root_dag, seed= def route_cf_looping(tpass, cf_opnode, current_layout, root_dag, seed=None): - """For looping this pass adds a swap layer using LayoutTransformation + """For looping this pass adds a swap layer using ApproximateTokenSwapper to the end of the loop body to bring the layout back to the starting layout. This prevents reapplying layout changing swaps for every iteration of the loop. @@ -119,7 +115,6 @@ def route_cf_looping(tpass, cf_opnode, current_layout, root_dag, seed=None): list(Qubit): list of idle qubits in controlflow layer. """ # pylint: disable=cyclic-import - from qiskit.transpiler.passes.routing.layout_transformation import LayoutTransformation from qiskit.converters import dag_to_circuit, circuit_to_dag cf_op = cf_opnode.op # control flow operation @@ -133,19 +128,15 @@ def route_cf_looping(tpass, cf_opnode, current_layout, root_dag, seed=None): full_dag_block.compose(dag_block, qubits=order) updated_dag_block = tpass.run(full_dag_block) updated_layout = tpass.property_set["final_layout"].copy() - layout_xform = LayoutTransformation( - coupling, updated_layout, start_layout, seed=seed, inplace=False + swap_circuit, swap_qubits = _get_swap_map_dag( + root_dag, coupling, updated_layout, start_layout, seed=seed ) - layout_xform.run(updated_dag_block) - physical_swap_dag = layout_xform.property_set["perm_circ"].circuit - if physical_swap_dag.depth(): + + if swap_circuit.depth(): p2v = current_layout.get_physical_bits() virtual_swap_dag = updated_dag_block.copy_empty_like() - order = [ - p2v[virtual_swap_dag.qubits.index(qubit)] - for qubit in layout_xform.property_set["perm_qubits"] - ] - virtual_swap_dag.compose(physical_swap_dag, qubits=order) + order = [p2v[virtual_swap_dag.qubits.index(qubit)] for qubit in swap_qubits] + virtual_swap_dag.compose(swap_circuit, qubits=order) updated_dag_block.compose(virtual_swap_dag) # contract from full width post routing idle_qubits = set(root_dag.qubits) & set(updated_dag_block.idle_wires()) @@ -178,3 +169,32 @@ def combine_permutations(*permutations): for this_order in permutations[1:]: order = [order[i] for i in this_order] return order + + +def _get_swap_map_dag(dag, coupling_map, from_layout, to_layout, seed, trials=4): + """Gets the circuit of swaps to go from from_layout to to_layout.""" + from qiskit.transpiler.passes.routing.algorithms import ApproximateTokenSwapper + + if len(dag.qregs) != 1 or dag.qregs.get("q", None) is None: + raise TranspilerError("layout transformation runs on physical circuits only") + + if len(dag.qubits) > len(coupling_map.physical_qubits): + raise TranspilerError("The layout does not match the amount of qubits in the DAG") + + if coupling_map: + graph = coupling_map.graph.to_undirected() + else: + coupling_map = CouplingMap.from_full(len(to_layout)) + graph = coupling_map.graph.to_undirected() + + token_swapper = ApproximateTokenSwapper(graph, seed) + # Find the permutation between the initial physical qubits and final physical qubits. + permutation = { + pqubit: to_layout.get_virtual_bits()[vqubit] + for vqubit, pqubit in from_layout.get_virtual_bits().items() + } + permutation_circ = token_swapper.permutation_circuit(permutation, trials) + permutation_qubits = [ + dag.qubits[i[0]] for i in sorted(permutation_circ.inputmap.items(), key=lambda x: x[0]) + ] + return permutation_circ.circuit, permutation_qubits