def transpile_dag(dag, basis_gates=None, coupling_map=None, initial_layout=None, seed_mapper=None, pass_manager=None): """Transform a dag circuit into another dag circuit (transpile), through consecutive passes on the dag. Args: dag (DAGCircuit): dag circuit to transform via transpilation basis_gates (list[str]): list of basis gate names supported by the target. Default: ['u1','u2','u3','cx','id'] coupling_map (list): A graph of coupling:: [ [control0(int), target0(int)], [control1(int), target1(int)], ] eg. [[0, 2], [1, 2], [1, 3], [3, 4]} initial_layout (Layout or None): A layout object seed_mapper (int): random seed_mapper for the swap mapper pass_manager (PassManager): pass manager instance for the transpilation process If None, a default set of passes are run. Otherwise, the passes defined in it will run. If contains no passes in it, no dag transformations occur. Returns: DAGCircuit: transformed dag """ # TODO: `basis_gates` will be removed after we have the unroller pass. # TODO: `coupling_map`, `initial_layout`, `seed_mapper` removed after mapper pass. # TODO: move this to the mapper pass num_qubits = sum([qreg.size for qreg in dag.qregs.values()]) if num_qubits == 1: coupling_map = None if basis_gates is None: basis_gates = ['u1', 'u2', 'u3', 'cx', 'id'] if isinstance(basis_gates, str): warnings.warn( "The parameter basis_gates is now a list of strings. " "For example, this basis ['u1','u2','u3','cx'] should be used " "instead of 'u1,u2,u3,cx'. The string format will be " "removed after 0.9", DeprecationWarning, 2) basis_gates = basis_gates.split(',') if initial_layout is None: initial_layout = Layout.generate_trivial_layout(*dag.qregs.values()) if pass_manager: # run the passes specified by the pass manager # TODO return the property set too. See #1086 dag = pass_manager.run_passes(dag) else: # default set of passes # TODO: move each step here to a pass, and use a default passmanager below name = dag.name dag = Unroller(basis_gates).run(dag) dag = BarrierBeforeFinalMeasurements().run(dag) # if a coupling map is given compile to the map if coupling_map: logger.info("pre-mapping properties: %s", dag.properties()) coupling = CouplingMap(coupling_map) # Extend and enlarge the the dag/layout with ancillas using the full coupling map logger.info("initial layout: %s", initial_layout) pass_ = ExtendLayout(coupling) pass_.property_set['layout'] = initial_layout pass_.run(dag) initial_layout = pass_.property_set['layout'] pass_ = EnlargeWithAncilla(initial_layout) dag = pass_.run(dag) initial_layout = pass_.property_set['layout'] logger.info("initial layout (ancilla extended): %s", initial_layout) # temporarily build old-style layout dict # (TODO: remove after transition to StochasticSwap pass) virtual_qubits = initial_layout.get_virtual_bits() initial_layout = {(v[0].name, v[1]): ('q', initial_layout[v]) for v in virtual_qubits} # Swap mapper dag, final_layout = swap_mapper(dag, coupling, initial_layout, trials=20, seed=seed_mapper) logger.info("final layout: %s", final_layout) # Expand swaps dag = Decompose(SwapGate).run(dag) # Change cx directions dag = CXDirection(coupling).run(dag) # Unroll to the basis dag = Unroller(['u1', 'u2', 'u3', 'id', 'cx']).run(dag) # Simplify single qubit gates and CXs pm_4_optimization = PassManager() pm_4_optimization.append( [Optimize1qGates(), CXCancellation(), DAGFixedPoint()], do_while=lambda property_set: not property_set[ 'dag_fixed_point']) dag = transpile_dag(dag, pass_manager=pm_4_optimization) dag.name = name return dag
def transpile(circuits, backend=None, basis_gates=None, coupling_map=None, initial_layout=None, seed_mapper=None, pass_manager=None): """transpile one or more circuits. Args: circuits (QuantumCircuit or list[QuantumCircuit]): circuits to compile backend (BaseBackend): a backend to compile for basis_gates (list[str]): list of basis gate names supported by the target. Default: ['u1','u2','u3','cx','id'] coupling_map (list): coupling map (perhaps custom) to target in mapping initial_layout (list): initial layout of qubits in mapping seed_mapper (int): random seed for the swap_mapper pass_manager (PassManager): a pass_manager for the transpiler stages Returns: QuantumCircuit or list[QuantumCircuit]: transpiled circuit(s). Raises: TranspilerError: if args are not complete for the transpiler to function """ return_form_is_single = False if isinstance(circuits, QuantumCircuit): circuits = [circuits] return_form_is_single = True # Check for valid parameters for the experiments. basis_gates = basis_gates or backend.configuration().basis_gates if coupling_map: coupling_map = coupling_map elif backend: # This needs to be removed once Aer 0.2 is out coupling_map = getattr(backend.configuration(), 'coupling_map', None) else: coupling_map = None if not basis_gates: raise TranspilerError('no basis_gates or backend to compile to') # Convert integer list format to Layout if isinstance(initial_layout, list) and \ all(isinstance(elem, int) for elem in initial_layout): if isinstance(circuits, list): circ = circuits[0] else: circ = circuits initial_layout = Layout.generate_from_intlist(initial_layout, *circ.qregs) if initial_layout is not None and not isinstance(initial_layout, Layout): initial_layout = Layout(initial_layout) circuits = parallel_map(_transpilation, circuits, task_kwargs={ 'basis_gates': basis_gates, 'coupling_map': coupling_map, 'initial_layout': initial_layout, 'seed_mapper': seed_mapper, 'pass_manager': pass_manager }) if return_form_is_single: return circuits[0] return circuits
def test_layout_set(self): """Setter""" layout = Layout() layout[(self.qr, 0)] = 0 self.assertEqual(layout[(self.qr, 0)], 0) self.assertEqual(layout[0], (self.qr, 0))
def test_copy(self): """Test copy methods return equivalent layouts.""" layout = Layout() layout.add((self.qr, 0)) layout.add((self.qr, 1)) layout_dict_copy = layout.copy() self.assertTrue(isinstance(layout_dict_copy, Layout)) self.assertDictEqual(layout.get_physical_bits(), layout_dict_copy.get_physical_bits()) self.assertDictEqual(layout.get_virtual_bits(), layout_dict_copy.get_virtual_bits()) layout_copy_copy = copy.copy(layout) self.assertTrue(isinstance(layout_copy_copy, Layout)) self.assertDictEqual(layout.get_physical_bits(), layout_dict_copy.get_physical_bits()) self.assertDictEqual(layout.get_virtual_bits(), layout_dict_copy.get_virtual_bits()) layout_copy_deepcopy = copy.deepcopy(layout) self.assertTrue(isinstance(layout_copy_deepcopy, Layout)) self.assertDictEqual(layout.get_physical_bits(), layout_dict_copy.get_physical_bits()) self.assertDictEqual(layout.get_virtual_bits(), layout_dict_copy.get_virtual_bits())
def test_layout_combine_smaller(self): """combine_into_edge_map() method with another_layout is smaller and raises an Error""" layout = Layout() layout.add((self.qr, 0)) layout.add((self.qr, 1)) layout.add((self.qr, 2)) another_layout = Layout() another_layout.add((self.qr, 1)) another_layout.add((self.qr, 0)) with self.assertRaises(LayoutError): _ = layout.combine_into_edge_map(another_layout)
def test_layout_combine_bigger(self): """combine_into_edge_map() method with another_layout is bigger""" layout = Layout() layout.add((self.qr, 0)) layout.add((self.qr, 1)) another_layout = Layout() another_layout.add((self.qr, 1)) another_layout.add((self.qr, 0)) another_layout.add((self.qr, 2)) edge_map = layout.combine_into_edge_map(another_layout) self.assertDictEqual(edge_map, { (self.qr, 0): (self.qr, 1), (self.qr, 1): (self.qr, 0) })
def test_layout_get_bits(self): """Get the map from the (qu)bits view""" layout_dict = {(self.qr, 0): 0, (self.qr, 1): 1, (self.qr, 2): 2} layout = Layout(layout_dict) self.assertDictEqual(layout_dict, layout.get_virtual_bits())