text: # -*- coding: utf-8 -*-
  
  # Copyright 2018, IBM.
  #
  # This source code is licensed under the Apache License, Version 2.0 found in
  # the LICENSE.txt file in the root directory of this source tree.
  
  """
  A pass implementing a basic mapper.
  
  The basic mapper is a minimum effort to insert swap gates to map the DAG into 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.
  """
  
  from qiskit.transpiler.basepasses import TransformationPass
  from qiskit.transpiler.exceptions import TranspilerError
  from qiskit.dagcircuit import DAGCircuit
  from qiskit.mapper import Layout
  from qiskit.extensions.standard import SwapGate
  from .barrier_before_final_measurements import BarrierBeforeFinalMeasurements
  
  
  class BasicSwap(TransformationPass):
      """
      Maps (with minimum effort) a DAGCircuit onto a `coupling_map` adding swap gates.
      """
  
      def __init__(self,
                   coupling_map,
                   initial_layout=None):
          """
          Maps a DAGCircuit onto a `coupling_map` using swap gates.
          Args:
              coupling_map (CouplingMap): Directed graph represented a coupling map.
              initial_layout (Layout): initial layout of qubits in mapping
          """
          super().__init__()
          self.coupling_map = coupling_map
          self.initial_layout = initial_layout
          self.swap_gate = SwapGate
          self.requires.append(BarrierBeforeFinalMeasurements())
  
      def run(self, dag):
          """
          Runs 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()
  
          if self.initial_layout is None:
              if self.property_set["layout"]:
                  self.initial_layout = self.property_set["layout"]
              else:
                  self.initial_layout = Layout.generate_trivial_layout(*dag.qregs.values())
  
          if len(dag.qubits()) != len(self.initial_layout):
              raise TranspilerError('The layout does not match the amount of qubits in the DAG')
  
          if len(self.coupling_map.physical_qubits) != len(self.initial_layout):
              raise TranspilerError(
                  "Mappers require to have the layout to be the same size as the coupling map")
  
          current_layout = self.initial_layout.copy()
  
          for layer in dag.serial_layers():
              subdag = layer['graph']
  
              for gate in subdag.twoQ_nodes():
                  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()
  
                      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 qregs
                          for qreg in current_layout.get_registers():
                              if qreg not in swap_layer.qregs.values():
                                  swap_layer.add_qreg(qreg)
  
                          # create the swap operation
                          swap_layer.apply_operation_back(self.swap_gate(qubit_1, qubit_2),
                                                          qargs=[qubit_1, qubit_2])
  
                      # layer insertion
                      edge_map = current_layout.combine_into_edge_map(self.initial_layout)
                      new_dag.compose_back(swap_layer, edge_map)
  
                      # update current_layout
                      for swap in range(len(path) - 2):
                          current_layout.swap(path[swap], path[swap + 1])
  
              edge_map = current_layout.combine_into_edge_map(self.initial_layout)
              new_dag.extend_back(subdag, edge_map)
  
          return new_dag
  