Source code for qiskit.transpiler.passes.routing.basic_swap

# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2018.
#
# 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
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Map (with minimum effort) a DAGCircuit onto a `coupling_map` adding swap gates."""

from qiskit.transpiler.basepasses import TransformationPass
from qiskit.transpiler.exceptions import TranspilerError
from qiskit.dagcircuit import DAGCircuit
from qiskit.transpiler.layout import Layout
from qiskit.circuit.library.standard_gates import SwapGate


[docs]class BasicSwap(TransformationPass): """Map (with minimum effort) a DAGCircuit onto a `coupling_map` adding swap gates. The basic mapper is a minimum effort to insert swap gates to map the DAG onto a coupling map. When a cx is not in the coupling map possibilities, it inserts one or more swaps in front to make it compatible. """ def __init__(self, coupling_map): """BasicSwap initializer. Args: coupling_map (CouplingMap): Directed graph represented a coupling map. """ super().__init__() self.coupling_map = coupling_map
[docs] def run(self, dag): """Run the BasicSwap pass on `dag`. Args: dag (DAGCircuit): DAG to map. Returns: DAGCircuit: A mapped DAG. Raises: TranspilerError: if the coupling map or the layout are not compatible with the DAG. """ new_dag = DAGCircuit() for qreg in dag.qregs.values(): new_dag.add_qreg(qreg) for creg in dag.cregs.values(): new_dag.add_creg(creg) if len(dag.qregs) != 1 or dag.qregs.get('q', None) is None: raise TranspilerError('Basic swap runs on physical circuits only') if len(dag.qubits) > len(self.coupling_map.physical_qubits): raise TranspilerError('The layout does not match the amount of qubits in the DAG') canonical_register = dag.qregs['q'] trivial_layout = Layout.generate_trivial_layout(canonical_register) current_layout = trivial_layout.copy() for layer in dag.serial_layers(): subdag = layer['graph'] for gate in subdag.two_qubit_ops(): physical_q0 = current_layout[gate.qargs[0]] physical_q1 = current_layout[gate.qargs[1]] if self.coupling_map.distance(physical_q0, physical_q1) != 1: # Insert a new layer with the SWAP(s). swap_layer = DAGCircuit() swap_layer.add_qreg(canonical_register) path = self.coupling_map.shortest_undirected_path(physical_q0, physical_q1) for swap in range(len(path) - 2): connected_wire_1 = path[swap] connected_wire_2 = path[swap + 1] qubit_1 = current_layout[connected_wire_1] qubit_2 = current_layout[connected_wire_2] # create the swap operation swap_layer.apply_operation_back(SwapGate(), qargs=[qubit_1, qubit_2], cargs=[]) # layer insertion order = current_layout.reorder_bits(new_dag.qubits) new_dag.compose(swap_layer, qubits=order) # update current_layout for swap in range(len(path) - 2): current_layout.swap(path[swap], path[swap + 1]) order = current_layout.reorder_bits(new_dag.qubits) new_dag.compose(subdag, qubits=order) return new_dag