def run(self, dag): """ Runs the BasicSwap pass on `dag`. Args: dag (DAGCircuit): DAG to map. Returns: DAGCircuit: A mapped 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()) current_layout = copy(self.initial_layout) for layer in dag.serial_layers(): subdag = layer['graph'] for gate in subdag.get_2q_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[0] not in swap_layer.qregs.values(): swap_layer.add_qreg(qreg[0]) # create the swap operation swap_layer.add_basis_element('swap', 2, 0, 0) 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
def run(self, dag): """ Flips the cx nodes to match the directed coupling map. Args: dag (DAGCircuit): DAG to map. Returns: DAGCircuit: The rearranged dag for the coupling map Raises: TranspilerError: If the circuit cannot be mapped just by flipping the cx nodes. """ new_dag = DAGCircuit() if self.layout is None: if self.property_set["layout"]: self.layout = self.property_set["layout"] else: self.layout = Layout.generate_trivial_layout( *dag.qregs.values()) for layer in dag.serial_layers(): subdag = layer['graph'] for cnot_id in subdag.named_nodes('cx', 'CX'): cnot_node = subdag.node(cnot_id) control = cnot_node['op'].qargs[0] target = cnot_node['op'].qargs[1] physical_q0 = self.layout[control] physical_q1 = self.layout[target] if self.coupling_map.distance(physical_q0, physical_q1) != 1: raise TranspilerError( 'The circuit requires a connection between physical ' 'qubits %s and %s' % (physical_q0, physical_q1)) if (physical_q0, physical_q1) not in self.coupling_map.get_edges(): # A flip needs to be done # Create the involved registers if control[0] not in subdag.qregs.values(): subdag.add_qreg(control[0]) if target[0] not in subdag.qregs.values(): subdag.add_qreg(target[0]) # Add H gates around subdag.apply_operation_back(HGate(target)) subdag.apply_operation_back(HGate(control)) subdag.apply_operation_front(HGate(target)) subdag.apply_operation_front(HGate(control)) # Flips the CX cnot_node['op'].qargs[0], cnot_node['op'].qargs[ 1] = target, control new_dag.extend_back(subdag) return new_dag
def run(self, dag): """ Flips the cx nodes to match the directed coupling map. Args: dag (DAGCircuit): DAG to map. Returns: DAGCircuit: The rearranged dag for the coupling map Raises: MapperError: If the circuit cannot be mapped just by flipping the cx nodes. """ new_dag = DAGCircuit() if self.layout is None: # create a one-to-one layout self.layout = Layout() wire_no = 0 for qreg in dag.qregs.values(): for index in range(qreg.size): self.layout[(qreg, index)] = wire_no wire_no += 1 for layer in dag.serial_layers(): subdag = layer['graph'] for cnot in subdag.get_cnot_nodes(): control = cnot['op'].qargs[0] target = cnot['op'].qargs[1] physical_q0 = self.layout[control] physical_q1 = self.layout[target] if self.coupling_map.distance(physical_q0, physical_q1) != 1: raise MapperError('The circuit requires a connectiontion between the phsycial ' 'qubits %s and %s' % (physical_q0, physical_q1)) if (physical_q0, physical_q1) not in self.coupling_map.get_edges(): # A flip needs to be done # Create the involved registers if control[0] not in subdag.qregs.values(): subdag.add_qreg(control[0]) if target[0] not in subdag.qregs.values(): subdag.add_qreg(target[0]) # Add H gates around subdag.add_basis_element('h', 1, 0, 0) subdag.apply_operation_back(HGate(target)) subdag.apply_operation_back(HGate(control)) subdag.apply_operation_front(HGate(target)) subdag.apply_operation_front(HGate(control)) # Flips the CX cnot['op'].qargs[0], cnot['op'].qargs[1] = target, control new_dag.extend_back(subdag) return new_dag
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, layout_dict_copy) layout_copy_copy = copy.copy(layout) self.assertTrue(isinstance(layout_copy_copy, Layout)) self.assertDictEqual(layout, layout_copy_copy) layout_copy_deepcopy = copy.deepcopy(layout) self.assertTrue(isinstance(layout_copy_deepcopy, Layout)) self.assertDictEqual(layout, layout_copy_deepcopy)
def create_passmanager(self, coupling_map, initial_layout=None): """Returns a PassManager using self.pass_class(coupling_map, initial_layout)""" passmanager = PassManager( self.pass_class(CouplingMap(coupling_map), # pylint: disable=not-callable **self.additional_args)) if initial_layout: passmanager.property_set['layout'] = Layout(initial_layout) return passmanager
def test_layout_combine(self): """combine_into_edge_map() method""" 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)) 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_idle_physical_bits(self): """Get physical_bits that are not mapped""" layout = Layout() layout.add((self.qr, 1), 2) layout.add(None, 4) layout.add(None, 6) self.assertEqual(layout.idle_physical_bits(), [4, 6])
def test_layout_swap(self): """swap() method""" layout = Layout() layout.add((self.qr, 0)) layout.add((self.qr, 1)) layout.swap(0, 1) self.assertDictEqual(layout.get_virtual_bits(), {(self.qr, 0): 1, (self.qr, 1): 0})
def create_passmanager(self, coupling_map, initial_layout=None): """Returns a PassManager using self.pass_class(coupling_map, initial_layout)""" passmanager = PassManager() if initial_layout: passmanager.append(SetLayout(Layout(initial_layout))) # pylint: disable=not-callable passmanager.append(self.pass_class(CouplingMap(coupling_map), **self.additional_args)) return passmanager
def test_layout_error_when_same_type(self): """Layout does not work when key and value are the same type""" layout = Layout() with self.assertRaises(LayoutError): layout[(self.qr, 0)] = (self.qr, 1) with self.assertRaises(LayoutError): layout[0] = 1
def test_layout_error_str_key(self): """Layout does not work with strings""" layout = Layout() with self.assertRaises(LayoutError): layout['a_string'] = 3 with self.assertRaises(LayoutError): layout[2] = 'a_string'
def run(self, dag): """ Pick a convenient layout depending on the best matching qubit connectivity, and set the property `layout`. Args: dag (DAGCircuit): DAG to find layout for. Raises: TranspilerError: if dag wider than self.coupling_map """ num_dag_qubits = sum([qreg.size for qreg in dag.qregs.values()]) if num_dag_qubits > self.coupling_map.size(): raise TranspilerError('Number of qubits greater than device.') layout = Layout() for qreg in dag.qregs.values(): layout.add_register(qreg) self.property_set['layout'] = layout
def run(self, dag): """Run one pass of the lookahead mapper on the provided DAG. Args: dag (DAGCircuit): the directed acyclic graph to be mapped Returns: DAGCircuit: A dag mapped to be compatible with the coupling_map in the property_set. Raises: MapperError: If the provided DAG has more qubits than are available in the coupling map. """ # Preserve fix for https://github.com/Qiskit/qiskit-terra/issues/674 removed_measures = remove_last_measurements(dag) coupling_map = self._coupling_map ordered_virtual_gates = list(dag.serial_layers()) if len(dag.get_qubits()) > len(coupling_map.physical_qubits): raise MapperError( 'DAG contains more qubits than are present in the coupling map.' ) dag_qubits = dag.get_qubits() coupling_qubits = coupling_map.physical_qubits starting_layout = [ dag_qubits[i] if i < len(dag_qubits) else None for i in range(len(coupling_qubits)) ] mapped_gates = [] layout = Layout(starting_layout) gates_remaining = ordered_virtual_gates.copy() while gates_remaining: best_step = _search_forward_n_swaps(layout, gates_remaining, coupling_map) layout = best_step['layout'] gates_mapped = best_step['gates_mapped'] gates_remaining = best_step['gates_remaining'] mapped_gates.extend(gates_mapped) # Preserve input DAG's name, regs, wire_map, etc. but replace the graph. mapped_dag = _copy_circuit_metadata(dag, coupling_map) for gate in mapped_gates: mapped_dag.apply_operation_back(**gate) return_last_measurements(mapped_dag, removed_measures, layout) return mapped_dag
def test_no_extension(self): """There are no virtual qubits to extend.""" layout = Layout({self.qr3[0]: 0, self.qr3[1]: 1, self.qr3[2]: 2}) pass_ = EnlargeWithAncilla(layout) after = pass_.run(self.dag) qregs = list(after.qregs.values()) self.assertEqual(1, len(qregs)) self.assertEqual(self.qr3, qregs[0])
def test_layout_from_dict(self): """Constructor from a dict""" layout = Layout({(self.qr, 0): 0, (self.qr, 1): 1, (self.qr, 2): 2}) self.assertEqual(layout[(self.qr, 0)], 0) self.assertEqual(layout[(self.qr, 1)], 1) self.assertEqual(layout[(self.qr, 2)], 2) self.assertEqual(layout[0], (self.qr, 0)) self.assertEqual(layout[1], (self.qr, 1)) self.assertEqual(layout[2], (self.qr, 2))
def test_no_extension(self): """There are no idle physical bits to extend.""" layout = Layout([(self.qr3, 0), (self.qr3, 1), (self.qr3, 2)]) pass_ = EnlargeWithAncilla(layout) after = pass_.run(self.dag) qregs = list(after.qregs.values()) self.assertEqual(1, len(qregs)) self.assertEqual(self.qr3, qregs[0])
def test_final_measurement_barrier_for_devices(self, mock_pass): """Verify BarrierBeforeFinalMeasurements pass is called in default pipeline for devices.""" circ = QuantumCircuit.from_qasm_file(self._get_resource_path('example.qasm', Path.QASMS)) dag_circuit = circuit_to_dag(circ) layout = Layout.generate_trivial_layout(*circ.qregs) transpile_dag(dag_circuit, coupling_map=FakeRueschlikon().configuration().coupling_map, initial_layout=layout) self.assertTrue(mock_pass.called)
def test_default_layout(self): """Static method generate_trivial_layout creates a Layout""" qr0 = QuantumRegister(3, 'q0') qr1 = QuantumRegister(2, 'q1') layout = Layout.generate_trivial_layout(qr0, qr1) self.assertEqual(layout[(qr0, 0)], 0) self.assertEqual(layout[(qr0, 1)], 1) self.assertEqual(layout[(qr0, 2)], 2) self.assertEqual(layout[(qr1, 0)], 3) self.assertEqual(layout[(qr1, 1)], 4)
def run(self, dag): """Run one pass of the lookahead mapper on the provided DAG. Args: dag (DAGCircuit): the directed acyclic graph to be mapped Returns: DAGCircuit: A dag mapped to be compatible with the coupling_map in the property_set. Raises: TranspilerError: if the coupling map or the layout are not compatible with the DAG """ coupling_map = self._coupling_map ordered_virtual_gates = list(dag.serial_layers()) 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" ) mapped_gates = [] layout = self.initial_layout.copy() gates_remaining = ordered_virtual_gates.copy() while gates_remaining: best_step = _search_forward_n_swaps(layout, gates_remaining, coupling_map) layout = best_step['layout'] gates_mapped = best_step['gates_mapped'] gates_remaining = best_step['gates_remaining'] mapped_gates.extend(gates_mapped) # Preserve input DAG's name, regs, wire_map, etc. but replace the graph. mapped_dag = _copy_circuit_metadata(dag, coupling_map) for node in mapped_gates: mapped_dag.apply_operation_back(op=node.op, qargs=node.qargs, cargs=node.cargs) return mapped_dag
def test_with_extension(self): """There are 2 idle physical bits to extend.""" layout = Layout([(self.qr3, 0), None, (self.qr3, 1), None, (self.qr3, 2)]) pass_ = EnlargeWithAncilla(layout) after = pass_.run(self.dag) final_layout = {0: (QuantumRegister(3, 'qr'), 0), 1: (QuantumRegister(2, 'ancilla'), 0), 2: (QuantumRegister(3, 'qr'), 1), 3: (QuantumRegister(2, 'ancilla'), 1), 4: (QuantumRegister(3, 'qr'), 2)} qregs = list(after.qregs.values()) self.assertEqual(2, len(qregs)) self.assertEqual(self.qr3, qregs[0]) self.assertEqual(QuantumRegister(2, name='ancilla'), qregs[1]) self.assertEqual(final_layout, layout.get_physical_bits())
def test_set_virtual_without_physical(self): """When adding a virtual without care in which physical is going""" layout = Layout() layout.add((self.qr, 1), 2) layout.add((self.qr, 0)) self.assertDictEqual(layout.get_virtual_bits(), { (self.qr, 0): 1, (self.qr, 1): 2 })
def test_layout_swap_error(self): """swap() method error""" layout = Layout() layout.add((self.qr, 0)) layout.add((self.qr, 1)) with self.assertRaises(LayoutError): layout.swap(0, (self.qr, 0))
class CheckMap(AnalysisPass): """ Checks if a DAGCircuit is mapped to `coupling_map`. """ def __init__(self, coupling_map, initial_layout=None): """ Checks if a DAGCircuit is mapped to `coupling_map`. Args: coupling_map (Coupling): Directed graph represented a coupling map. initial_layout (Layout): The initial layout of the DAG to analyze. """ super().__init__() self.layout = initial_layout self.coupling_map = coupling_map def run(self, dag): """ If `dag` is mapped to coupling_map, the property `is_mapped` is set to True (or to False otherwise). Args: dag (DAGCircuit): DAG to map. """ if self.layout is None: self.layout = Layout() for qreg in dag.qregs.values(): self.layout.add_register(qreg) self.property_set['is_mapped'] = None for layer in dag.serial_layers(): subdag = layer['graph'] for a_cx in subdag.get_cnot_nodes(): q = QuantumRegister(self.coupling_map.node_counter, 'q') physical_q0 = (q, self.layout[a_cx['op'].qargs[0]]) physical_q1 = (q, self.layout[a_cx['op'].qargs[1]]) if self.coupling_map.distance(physical_q0, physical_q1) != 1: self.property_set['is_mapped'] = False return self.property_set['is_mapped'] = True
def test_layout_len(self): """Length of the layout is the amount of physical bits""" layout = Layout() self.assertEqual(len(layout), 0) layout.add((self.qr, 0)) self.assertEqual(len(layout), 1) layout.add((self.qr, 1), 3) self.assertEqual(len(layout), 4)
def run(self, dag): """ Pick a layout by assigning n circuit qubits to device qubits 0, .., n-1. Args: dag (DAGCircuit): DAG to find layout for. Raises: TranspilerError: if dag wider than self.coupling_map """ num_dag_qubits = sum([qreg.size for qreg in dag.qregs.values()]) if num_dag_qubits > self.coupling_map.size(): raise TranspilerError('Number of qubits greater than device.') self.property_set['layout'] = Layout.generate_trivial_layout(*dag.qregs.values())
def run(self, dag): """ If `dag` is mapped to coupling_map, the property `is_mapped` is set to True (or to False otherwise). Args: dag (DAGCircuit): DAG to map. """ if self.layout is None: self.layout = Layout() for qreg in dag.qregs.values(): self.layout.add_register(qreg) self.property_set['is_mapped'] = None for layer in dag.serial_layers(): subdag = layer['graph'] for a_cx in subdag.get_cnot_nodes(): physical_q0 = ('q', self.layout[a_cx['op'].qargs[0]]) physical_q1 = ('q', self.layout[a_cx['op'].qargs[1]]) if self.coupling_map.distance(physical_q0, physical_q1) != 1: self.property_set['is_mapped'] = False return self.property_set['is_mapped'] = True
def run(self, dag): """Run one pass of the lookahead mapper on the provided DAG. Args: dag (DAGCircuit): the directed acyclic graph to be mapped Returns: DAGCircuit: A dag mapped to be compatible with the coupling_map in the property_set. Raises: TranspilerError: If the provided DAG has more qubits than are available in the coupling map. """ coupling_map = self._coupling_map ordered_virtual_gates = list(dag.serial_layers()) if len(dag.get_qubits()) > len(coupling_map.physical_qubits): raise TranspilerError('DAG contains more qubits than are ' 'present in the coupling map.') 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()) mapped_gates = [] layout = self.initial_layout.copy() gates_remaining = ordered_virtual_gates.copy() while gates_remaining: best_step = _search_forward_n_swaps(layout, gates_remaining, coupling_map) layout = best_step['layout'] gates_mapped = best_step['gates_mapped'] gates_remaining = best_step['gates_remaining'] mapped_gates.extend(gates_mapped) # Preserve input DAG's name, regs, wire_map, etc. but replace the graph. mapped_dag = _copy_circuit_metadata(dag, coupling_map) for gate in mapped_gates: mapped_dag.apply_operation_back(**gate) return mapped_dag
def test_name_collision(self): """Name collision during ancilla extension.""" qr_ancilla = QuantumRegister(3, 'ancilla') circuit = QuantumCircuit(qr_ancilla) circuit.h(qr_ancilla) dag = circuit_to_dag(circuit) layout = Layout([(qr_ancilla, 0), None, (qr_ancilla, 1), None, (qr_ancilla, 2)]) pass_ = EnlargeWithAncilla(layout) after = pass_.run(dag) qregs = list(after.qregs.values()) self.assertEqual(2, len(qregs)) self.assertEqual(qr_ancilla, qregs[0]) self.assertEqual(2, qregs[1].size) self.assertRegex(qregs[1].name, r'^ancilla\d+$')
def test_move_measurements(self): """Measurements applied AFTER swap mapping. """ backend = FakeRueschlikon() cmap = backend.configuration().coupling_map circ = QuantumCircuit.from_qasm_file( self._get_resource_path('move_measurements.qasm', Path.QASMS)) dag_circuit = circuit_to_dag(circ) lay = Layout({('qa', 0): ('q', 0), ('qa', 1): ('q', 1), ('qb', 0): ('q', 15), ('qb', 1): ('q', 2), ('qb', 2): ('q', 14), ('qN', 0): ('q', 3), ('qN', 1): ('q', 13), ('qN', 2): ('q', 4), ('qc', 0): ('q', 12), ('qNt', 0): ('q', 5), ('qNt', 1): ('q', 11), ('qt', 0): ('q', 6)}) out_dag = transpile_dag(dag_circuit, initial_layout=lay, coupling_map=cmap) meas_nodes = out_dag.named_nodes('measure') for meas_node in meas_nodes: is_last_measure = all([after_measure.type == 'out' for after_measure in out_dag.quantum_successors(meas_node)]) self.assertTrue(is_last_measure)
def run(self, dag): """Main run method for the noise adaptive layout.""" self._initialize_backend_prop() num_qubits = self._create_program_graph(dag) if num_qubits > len(self.swap_graph): raise TranspilerError('Number of qubits greater than device.') for end1, end2, _ in sorted(self.prog_graph.edges(data=True), key=lambda x: x[2]['weight'], reverse=True): self.pending_program_edges.append((end1, end2)) while self.pending_program_edges: edge = self._select_next_edge() q1_mapped = edge[0] in self.prog2hw q2_mapped = edge[1] in self.prog2hw if (not q1_mapped) and (not q2_mapped): best_hw_edge = self._select_best_remaining_cx() self.prog2hw[edge[0]] = best_hw_edge[0] self.prog2hw[edge[1]] = best_hw_edge[1] self.available_hw_qubits.remove(best_hw_edge[0]) self.available_hw_qubits.remove(best_hw_edge[1]) elif not q1_mapped: best_hw_qubit = self._select_best_remaining_qubit(edge[0]) self.prog2hw[edge[0]] = best_hw_qubit self.available_hw_qubits.remove(best_hw_qubit) else: best_hw_qubit = self._select_best_remaining_qubit(edge[1]) self.prog2hw[edge[1]] = best_hw_qubit self.available_hw_qubits.remove(best_hw_qubit) new_edges = [ x for x in self.pending_program_edges if not (x[0] in self.prog2hw and x[1] in self.prog2hw) ] self.pending_program_edges = new_edges for qid in self.qarg_to_id.values(): if qid not in self.prog2hw: self.prog2hw[qid] = self.available_hw_qubits[0] self.available_hw_qubits.remove(self.prog2hw[qid]) layout = Layout() for q in dag.qubits(): pid = self._qarg_to_id(q) hwid = self.prog2hw[pid] layout[(q[0], q[1])] = hwid self.property_set['layout'] = layout