def _remap_circuit_faulty_backend(circuit, num_qubits, backend_prop, faulty_qubits_map): faulty_qubits = backend_prop.faulty_qubits() if backend_prop else [] disconnected_qubits = {k for k, v in faulty_qubits_map.items() if v is None}.difference( faulty_qubits ) faulty_qubits_map_reverse = {v: k for k, v in faulty_qubits_map.items()} if faulty_qubits: faulty_qreg = circuit._create_qreg(len(faulty_qubits), "faulty") else: faulty_qreg = [] if disconnected_qubits: disconnected_qreg = circuit._create_qreg(len(disconnected_qubits), "disconnected") else: disconnected_qreg = [] new_layout = Layout() faulty_qubit = 0 disconnected_qubit = 0 for real_qubit in range(num_qubits): if faulty_qubits_map[real_qubit] is not None: new_layout[real_qubit] = circuit._layout[faulty_qubits_map[real_qubit]] else: if real_qubit in faulty_qubits: new_layout[real_qubit] = faulty_qreg[faulty_qubit] faulty_qubit += 1 else: new_layout[real_qubit] = disconnected_qreg[disconnected_qubit] disconnected_qubit += 1 physical_layout_dict = {} for index, qubit in enumerate(circuit.qubits): physical_layout_dict[qubit] = faulty_qubits_map_reverse[index] for qubit in faulty_qreg[:] + disconnected_qreg[:]: physical_layout_dict[qubit] = new_layout[qubit] dag_circuit = circuit_to_dag(circuit) apply_layout_pass = ApplyLayout() apply_layout_pass.property_set["layout"] = Layout(physical_layout_dict) circuit = dag_to_circuit(apply_layout_pass.run(dag_circuit)) circuit._layout = new_layout return circuit
def _layout_from_raw(initial_layout, circuit): if initial_layout is None or isinstance(initial_layout, Layout): return initial_layout elif isinstancelist(initial_layout): if all(isinstanceint(elem) for elem in initial_layout): initial_layout = Layout.from_intlist(initial_layout, *circuit.qregs) elif all(elem is None or isinstance(elem, Qubit) for elem in initial_layout): initial_layout = Layout.from_qubit_list(initial_layout) elif isinstance(initial_layout, dict): initial_layout = Layout(initial_layout) else: raise TranspilerError("The initial_layout parameter could not be parsed") return initial_layout
def test_no_cx(self): """Empty Circuit CouplingMap map: None. Result: 0""" qr = QuantumRegister(3, "qr") circuit = QuantumCircuit(qr) coupling = CouplingMap() layout = Layout().generate_trivial_layout(qr) dag = circuit_to_dag(circuit) pass_ = Layout2qDistance(coupling) pass_.property_set["layout"] = layout pass_.run(dag) self.assertEqual(pass_.property_set["layout_score"], 0)
def test_all_1q_score(self): """Test error rate for all 1q input.""" bit_map = {Qubit(): 0, Qubit(): 1} reverse_bit_map = {v: k for k, v in bit_map.items()} im_graph = retworkx.PyDiGraph() im_graph.add_node({"sx": 1}) im_graph.add_node({"sx": 1}) backend = FakeYorktownV2() vf2_pass = VF2PostLayout(target=backend.target) layout = Layout(bit_map) score = vf2_pass._score_layout(layout, bit_map, reverse_bit_map, im_graph) self.assertAlmostEqual(0.002925, score, places=5)
def test_plot_circuit_layout(self, backend): """ tests plot_circuit_layout for each device""" layout_length = int(backend._configuration.n_qubits / 2) qr = QuantumRegister(layout_length, 'qr') circuit = QuantumCircuit(qr) circuit._layout = Layout({qr[i]: i * 2 for i in range(layout_length)}) n = backend.configuration().n_qubits img_ref = path_to_diagram_reference(str(n) + "_plot_circuit_layout.png") filename = str(n) + "_plot_circuit_layout_result.png" fig = plot_circuit_layout(circuit, backend) fig.savefig(filename) self.assertImagesAreEqual(filename, img_ref, 0.1) os.remove(filename)
def test_plot_circuit_layout(self, backend): """tests plot_circuit_layout for each device""" layout_length = int(backend._configuration.n_qubits / 2) qr = QuantumRegister(layout_length, "qr") circuit = QuantumCircuit(qr) circuit._layout = Layout({qr[i]: i * 2 for i in range(layout_length)}) circuit._layout.add_register(qr) n = backend.configuration().n_qubits img_ref = path_to_diagram_reference(str(n) + "_plot_circuit_layout.png") fig = plot_circuit_layout(circuit, backend) with BytesIO() as img_buffer: fig.savefig(img_buffer, format="png") img_buffer.seek(0) self.assertImagesAreEqual(Image.open(img_buffer), img_ref, 0.1) plt.close(fig)
def unroll_and_map_circuit(self, circuit: QuantumCircuit, mapping, backend) -> QuantumCircuit: layout = Layout({q: i for q, i in zip(circuit.qubits, mapping)}) pm = PassManager([ SetLayout(layout), ApplyLayout(), Unroller(self._backend.configuration().basis_gates), ]) # pm = level_0_pass_manager(PassManagerConfig( # initial_layout = layout, # basis_gates=backend.configuration().basis_gates, # coupling_map=CouplingMap(backend.configuration().coupling_map), # backend_properties=backend.properties() # )) return pm.run(circuit)
def test_with_extension(self): """There are 2 virtual qubit to extend.""" ancilla = QuantumRegister(2, 'ancilla') layout = Layout({0: self.qr3[0], 1: ancilla[0], 2: self.qr3[1], 3: ancilla[1], 4: self.qr3[2]}) pass_ = EnlargeWithAncilla(layout) after = pass_.run(self.dag) qregs = list(after.qregs.values()) self.assertEqual(2, len(qregs)) self.assertEqual(self.qr3, qregs[0]) self.assertEqual(ancilla, qregs[1])
def test_all_1q_avg_score(self): """Test average scoring for all 1q input.""" bit_map = {Qubit(): 0, Qubit(): 1} reverse_bit_map = {v: k for k, v in bit_map.items()} im_graph = retworkx.PyDiGraph() im_graph.add_node({"sx": 1}) im_graph.add_node({"sx": 1}) backend = FakeYorktownV2() vf2_pass = VF2PostLayout(target=backend.target) vf2_pass.avg_error_map = vf2_utils.build_average_error_map( vf2_pass.target, vf2_pass.properties, vf2_pass.coupling_map) layout = Layout(bit_map) score = vf2_utils.score_layout(vf2_pass.avg_error_map, layout, bit_map, reverse_bit_map, im_graph) self.assertAlmostEqual(0.02054, score, places=5)
def setUp(self): coupling = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6]] coupling_map = CouplingMap(couplinglist=coupling) basis_gates = ['u1', 'u3', 'u2', 'cx'] qr = QuantumRegister(7, 'q') layout = Layout({qr[i]: i for i in range(coupling_map.size())}) # Create a pass manager with a variety of passes and flow control structures self.pass_manager = PassManager() self.pass_manager.append(SetLayout(layout)) self.pass_manager.append(TrivialLayout(coupling_map), condition=lambda x: True) self.pass_manager.append(FullAncillaAllocation(coupling_map)) self.pass_manager.append(EnlargeWithAncilla()) self.pass_manager.append(Unroller(basis_gates)) self.pass_manager.append(CheckMap(coupling_map)) self.pass_manager.append(BarrierBeforeFinalMeasurements(), do_while=lambda x: False) self.pass_manager.append(CXDirection(coupling_map)) self.pass_manager.append(RemoveResetInZeroState())
def test_map_with_layout(self): """Test using an initial layout.""" coupling = CouplingMap([[0, 1], [1, 2]]) qra = QuantumRegister(2, 'qa') qrb = QuantumRegister(1, 'qb') cr = ClassicalRegister(3, 'r') circ = QuantumCircuit(qra, qrb, cr) circ.cx(qra[0], qrb[0]) circ.measure(qra[0], cr[0]) circ.measure(qra[1], cr[1]) circ.measure(qrb[0], cr[2]) dag = circuit_to_dag(circ) layout = Layout({qra[0]: 0, qra[1]: 1, qrb[0]: 2}) pass_ = StochasticSwap(coupling, layout, 20, 13) after = pass_.run(dag) self.assertEqual(dag, after)
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)) 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 = transpile(circ, initial_layout=lay, coupling_map=cmap) out_dag = circuit_to_dag(out) 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 test_len_layout_vs_dag(self): """Test error if the layout and dag are not the same size.""" coupling = CouplingMap([[0, 1], [1, 2], [2, 3]]) qr = QuantumRegister(4, 'q') cr = ClassicalRegister(4, 'c') circuit = QuantumCircuit(qr, cr) circuit.h(qr[0]) circuit.cx(qr[0], qr[1]) circuit.cx(qr[0], qr[2]) circuit.cx(qr[0], qr[3]) circuit.measure(qr, cr) dag = circuit_to_dag(circuit) layout = Layout({qr[0]: 0, qr[1]: 1, qr[2]: 2}) pass_ = StochasticSwap(coupling, layout) with self.assertRaises(TranspilerError): _ = pass_.run(dag)
def run(self, quantum_circuit): dag_circuit = circuit_to_dag(quantum_circuit) init_time = time.time() self.parameters["TIME_START"] = init_time initial_mapping = [] if self.parameters["initial_map"] == K7MInitialMapping.RANDOM: # Only the first positions which correspond to the circuit qubits initial_mapping = numpy.random.permutation( self.parameters["nisq_qubits"]) initial_mapping = initial_mapping[:dag_circuit.num_qubits()] elif self.parameters["initial_map"] == K7MInitialMapping.LINEAR: initial_mapping = list(range(dag_circuit.num_qubits())) elif self.parameters["initial_map"] == K7MInitialMapping.HEURISTIC: initial_mapping = cuthill_order(dag_circuit, self.coupling_obj, self.parameters) init_time = time.time() - init_time if initial_mapping is None: return None, init_time, None # print(initial_mapping) # # return quantum_circuit print(" .......") original_pm = PassManager() optimal_layout = Layout() for c_idx, p_idx in enumerate(initial_mapping): optimal_layout.add(quantum_circuit.qregs[0][c_idx], p_idx) original_pm.append([ SetLayout(optimal_layout), ApplyLayout(), StochasticSwap(self.coupling_obj.coupling, seed=0), Decompose(gate=qiskit.extensions.SwapGate) ]) return original_pm.run(quantum_circuit), init_time, initial_mapping
def test_bad_layout(self): """Layout referes to a register that do not exist in the circuit """ qr = QuantumRegister(3, 'q') circ = QuantumCircuit(qr) dag = circuit_to_dag(circ) initial_layout = Layout() initial_layout[0] = QuantumRegister(4, 'q')[0] initial_layout[1] = QuantumRegister(4, 'q')[1] initial_layout[2] = QuantumRegister(4, 'q')[2] pass_ = FullAncillaAllocation(self.cmap5) pass_.property_set['layout'] = initial_layout with self.assertRaises(TranspilerError) as cm: pass_.run(dag) self.assertEqual( "FullAncillaAllocation: The layout refers to a qubit that does " "not exist in circuit.", cm.exception.message)
def test_swap_mapped_false(self): """ Needs [0]-[1] in a [0]--[2]--[1] Result:1 qr0:--(+)-- | qr1:---.--- CouplingMap map: [0]--[2]--[1] """ qr = QuantumRegister(2, 'qr') circuit = QuantumCircuit(qr) circuit.cx(qr[0], qr[1]) coupling = CouplingMap([[0, 2], [2, 1]]) layout = Layout().generate_trivial_layout(qr) dag = circuit_to_dag(circuit) pass_ = Layout2qDistance(coupling) pass_.property_set['layout'] = layout pass_.run(dag) self.assertEqual(pass_.property_set['layout_score'], 1)
def test_schedule_length2(self): """Testing with no crosstalk between CNOT 0,1 and CNOT 2,3""" bprop = create_fake_machine() crosstalk_prop = {} crosstalk_prop[(0, 1)] = {(2, 3): 0.05} crosstalk_prop[(2, 3)] = {(0, 1): 0.05, (4, 5): 0.05} crosstalk_prop[(4, 5)] = {(2, 3): 0.05} crosstalk_prop[(1, 2)] = {(3, 4): 0.05} crosstalk_prop[(3, 4)] = {(1, 2): 0.05} qr = QuantumRegister(6, 'q') circuit = QuantumCircuit(qr) circuit.cx(qr[0], qr[1]) circuit.cx(qr[2], qr[3]) mapping = [0, 1, 2, 3, 4, 5] layout = Layout({qr[i]: mapping[i] for i in range(6)}) new_circ = transpile(circuit, initial_layout=layout, basis_gates=['u1', 'u2', 'u3', 'cx']) dag = circuit_to_dag(new_circ) pass_ = CrosstalkAdaptiveSchedule(bprop, crosstalk_prop) scheduled_dag = pass_.run(dag) assert scheduled_dag.depth() == 1
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
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.') best_sub = self._best_subset(num_dag_qubits) layout = Layout() map_iter = 0 for qreg in dag.qregs.values(): for i in range(qreg.size): layout[(qreg, i)] = int(best_sub[map_iter]) map_iter += 1 self.property_set['layout'] = layout
def test_swap_mapped_true(self): """ Mapped circuit. Good Layout qr0 (0):--(+)---(+)- | | qr1 (1):---.-----|-- | qr2 (2):---------.-- CouplingMap map: [1]--[0]--[2] """ qr = QuantumRegister(3, 'qr') circuit = QuantumCircuit(qr) circuit.cx(qr[0], qr[1]) circuit.cx(qr[0], qr[2]) coupling = CouplingMap([[0, 1], [0, 2]]) layout = Layout().generate_trivial_layout(qr) dag = circuit_to_dag(circuit) pass_ = Layout2qDistance(coupling) pass_.property_set['layout'] = layout pass_.run(dag) self.assertEqual(pass_.property_set['layout_score'], 0)
def test_multiple_registers_with_good_layout(self): """ Test two registers + measurements using a layout. The layout makes all gates nearest neighbor. """ coupling = CouplingMap([[0, 1], [1, 2]]) qr_q = QuantumRegister(2, 'q') qr_a = QuantumRegister(1, 'a') cr_c = ClassicalRegister(3, 'c') circ = QuantumCircuit(qr_q, qr_a, cr_c) circ.cx(qr_q[0], qr_a[0]) circ.cx(qr_q[1], qr_a[0]) circ.measure(qr_q[0], cr_c[0]) circ.measure(qr_q[1], cr_c[1]) circ.measure(qr_a[0], cr_c[2]) dag = circuit_to_dag(circ) layout = Layout({qr_q[0]: 0, qr_a[0]: 1, qr_q[1]: 2}) pass_ = StochasticSwap(coupling, layout, 20, 13) after = pass_.run(dag) self.assertEqual(dag, after)
def test_schedule_length3(self): """Testing with repeated calls to run""" bprop = create_fake_machine() crosstalk_prop = {} crosstalk_prop[(0, 1)] = {(2, 3): 0.2} crosstalk_prop[(2, 3)] = {(0, 1): 0.05, (4, 5): 0.05} crosstalk_prop[(4, 5)] = {(2, 3): 0.05} crosstalk_prop[(1, 2)] = {(3, 4): 0.05} crosstalk_prop[(3, 4)] = {(1, 2): 0.05} qr = QuantumRegister(6, "q") circuit = QuantumCircuit(qr) circuit.cx(qr[0], qr[1]) circuit.cx(qr[2], qr[3]) mapping = [0, 1, 2, 3, 4, 5] layout = Layout({qr[i]: mapping[i] for i in range(6)}) new_circ = transpile(circuit, initial_layout=layout, basis_gates=["u1", "u2", "u3", "cx"]) dag = circuit_to_dag(new_circ) pass_ = CrosstalkAdaptiveSchedule(bprop, crosstalk_prop) scheduled_dag1 = pass_.run(dag) scheduled_dag2 = pass_.run(dag) self.assertEqual(scheduled_dag1.depth(), 3) self.assertEqual(scheduled_dag2.depth(), 3)
def run(self, dag): """Sets the layout property set. Args: dag (DAGCircuit): DAG to find layout for. Raises: TranspilerError: if dag wider than the 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.') # get the chain of qubits as list of integers chain = self.chain(num_dag_qubits) logger.info('Chain: %s' % str(chain)) layout = Layout() chain_iter = 0 # produce a layout from the chain for qreg in dag.qregs.values(): for i in range(qreg.size): layout[qreg[i]] = chain[chain_iter] chain_iter += 1 self.property_set['layout'] = layout logger.info(self.property_set['layout'])
def test_only_output_cx_and_swaps_in_coupling_map(self): """Test that output DAG contains only 2q gates from the the coupling map.""" coupling = CouplingMap([[0, 1], [1, 2], [2, 3]]) qr = QuantumRegister(4, 'q') cr = ClassicalRegister(4, 'c') circuit = QuantumCircuit(qr, cr) circuit.h(qr[0]) circuit.cx(qr[0], qr[1]) circuit.cx(qr[0], qr[2]) circuit.cx(qr[0], qr[3]) circuit.measure(qr, cr) dag = circuit_to_dag(circuit) layout = Layout({qr[0]: 0, qr[1]: 1, qr[2]: 2, qr[3]: 3}) pass_ = StochasticSwap(coupling, layout, 20, 5) after = pass_.run(dag) valid_couplings = [set([layout[a], layout[b]]) for (a, b) in coupling.get_edges()] for _2q_gate in after.twoQ_gates(): self.assertIn(set(_2q_gate.qargs), valid_couplings)
def test_name_collision(self): """Name collision during ancilla allocation.""" qr_ancilla = QuantumRegister(3, 'ancilla') circuit = QuantumCircuit(qr_ancilla) circuit.h(qr_ancilla) dag = circuit_to_dag(circuit) initial_layout = Layout() initial_layout[0] = qr_ancilla[0] initial_layout[1] = qr_ancilla[1] initial_layout[2] = qr_ancilla[2] pass_ = FullAncillaAllocation(self.cmap5) pass_.property_set['layout'] = initial_layout pass_.run(dag) after_layout = pass_.property_set['layout'] qregs = set(v[0] for v in after_layout.get_virtual_bits().keys()) self.assertEqual(2, len(qregs)) self.assertIn(qr_ancilla, qregs) qregs.remove(qr_ancilla) other_reg = qregs.pop() self.assertEqual(len(other_reg), 2) self.assertRegex(other_reg.name, r'^ancilla\d+$')
def _mapper(self, circuit_graph, coupling_graph, trials=20): """Map a DAGCircuit onto a CouplingMap using swap gates. Use self.initial_layout for the initial layout. Args: circuit_graph (DAGCircuit): input DAG circuit coupling_graph (CouplingMap): coupling graph to map onto trials (int): number of trials. Returns: DAGCircuit: object containing a circuit equivalent to circuit_graph that respects couplings in coupling_graph Layout: a layout object mapping qubits of circuit_graph into qubits of coupling_graph. The layout may differ from the initial_layout if the first layer of gates cannot be executed on the initial_layout, since in this case it is more efficient to modify the layout instead of swapping Dict: a final-layer qubit permutation Raises: TranspilerError: if there was any error during the mapping or with the parameters. """ # Schedule the input circuit by calling layers() layerlist = list(circuit_graph.layers()) logger.debug("schedule:") for i, v in enumerate(layerlist): logger.debug(" %d: %s", i, v["partition"]) if self.initial_layout is not None: qubit_subset = self.initial_layout.get_virtual_bits().keys() else: # Supply a default layout for this dag self.initial_layout = Layout() physical_qubit = 0 for qreg in circuit_graph.qregs.values(): for index in range(qreg.size): self.initial_layout[(qreg, index)] = physical_qubit physical_qubit += 1 qubit_subset = self.initial_layout.get_virtual_bits().keys() # Restrict the coupling map to the image of the layout coupling_graph = coupling_graph.subgraph( self.initial_layout.get_physical_bits().keys()) if coupling_graph.size() < len(self.initial_layout): raise TranspilerError( "Coupling map too small for default layout") self.input_layout = self.initial_layout.copy() # Find swap circuit to preceed to each layer of input circuit layout = self.initial_layout.copy() # Construct an empty DAGCircuit with the same set of # qregs and cregs as the input circuit dagcircuit_output = DAGCircuit() dagcircuit_output.name = circuit_graph.name for qreg in circuit_graph.qregs.values(): dagcircuit_output.add_qreg(qreg) for creg in circuit_graph.cregs.values(): dagcircuit_output.add_creg(creg) # Make a trivial wire mapping between the subcircuits # returned by _layer_update and the circuit we build identity_wire_map = {} for qubit in circuit_graph.qubits(): identity_wire_map[qubit] = qubit for bit in circuit_graph.clbits(): identity_wire_map[bit] = bit first_layer = True # True until first layer is output logger.debug("initial_layout = %s", layout) # Iterate over layers for i, layer in enumerate(layerlist): # Attempt to find a permutation for this layer success_flag, best_circuit, best_depth, best_layout, trivial_flag \ = self._layer_permutation(layer["partition"], layout, qubit_subset, coupling_graph, trials) logger.debug("mapper: layer %d", i) logger.debug( "mapper: success_flag=%s,best_depth=%s,trivial_flag=%s", success_flag, str(best_depth), trivial_flag) # If this fails, try one gate at a time in this layer if not success_flag: logger.debug( "mapper: failed, layer %d, " "retrying sequentially", i) serial_layerlist = list(layer["graph"].serial_layers()) # Go through each gate in the layer for j, serial_layer in enumerate(serial_layerlist): success_flag, best_circuit, best_depth, best_layout, trivial_flag = \ self._layer_permutation( serial_layer["partition"], layout, qubit_subset, coupling_graph, trials) logger.debug("mapper: layer %d, sublayer %d", i, j) logger.debug( "mapper: success_flag=%s,best_depth=%s," "trivial_flag=%s", success_flag, str(best_depth), trivial_flag) # Give up if we fail again if not success_flag: raise TranspilerError("swap mapper failed: " + "layer %d, sublayer %d" % (i, j)) # If this layer is only single-qubit gates, # and we have yet to see multi-qubit gates, # continue to the next inner iteration if trivial_flag and first_layer: logger.debug("mapper: skip to next sublayer") continue if first_layer: self.initial_layout = layout # Update the record of qubit positions # for each inner iteration layout = best_layout # Update the DAG dagcircuit_output.extend_back( self._layer_update(j, first_layer, best_layout, best_depth, best_circuit, serial_layerlist), identity_wire_map) if first_layer: first_layer = False else: # Update the record of qubit positions for each iteration layout = best_layout if first_layer: self.initial_layout = layout # Update the DAG dagcircuit_output.extend_back( self._layer_update(i, first_layer, best_layout, best_depth, best_circuit, layerlist), identity_wire_map) if first_layer: first_layer = False # This is the final edgemap. We might use it to correctly replace # any measurements that needed to be removed earlier. logger.debug("mapper: self.initial_layout = %s", pformat(self.initial_layout)) logger.debug("mapper: layout = %s", pformat(layout)) last_edgemap = layout.combine_into_edge_map(self.initial_layout) logger.debug("mapper: last_edgemap = %s", pformat(last_edgemap)) # If first_layer is still set, the circuit only has single-qubit gates # so we can use the initial layout to output the entire circuit # This code is dead due to changes to first_layer above. if first_layer: logger.debug("mapper: first_layer flag still set") layout = self.initial_layout for i, layer in enumerate(layerlist): edge_map = layout.combine_into_edge_map(self.initial_layout) dagcircuit_output.compose_back(layer["graph"], edge_map) return dagcircuit_output
def test_congestion(self): """Test code path that falls back to serial layers.""" coupling = CouplingMap([[0, 1], [1, 2], [1, 3]]) qr = QuantumRegister(2, 'q') ar = QuantumRegister(2, 'a') cr = ClassicalRegister(4, 'c') circ = QuantumCircuit(qr, ar, cr) circ.cx(qr[1], ar[0]) circ.cx(qr[0], ar[1]) circ.measure(qr[0], cr[0]) circ.h(qr) circ.h(ar) circ.cx(qr[0], qr[1]) circ.cx(ar[0], ar[1]) circ.measure(qr[0], cr[0]) circ.measure(qr[1], cr[1]) circ.measure(ar[0], cr[2]) circ.measure(ar[1], cr[3]) dag = circuit_to_dag(circ) # ┌─┐┌───┐ ┌─┐ # q_0: |0>─────────────────■──────────────────┤M├┤ H ├──■─────┤M├ # ┌───┐ │ └╥┘└───┘┌─┴─┐┌─┐└╥┘ # q_1: |0>──■───────┤ H ├──┼───────────────────╫──────┤ X ├┤M├─╫─ # ┌─┴─┐┌───┐└───┘ │ ┌─┐ ║ └───┘└╥┘ ║ # a_0: |0>┤ X ├┤ H ├───────┼─────────■─────┤M├─╫────────────╫──╫─ # └───┘└───┘ ┌─┴─┐┌───┐┌─┴─┐┌─┐└╥┘ ║ ║ ║ # a_1: |0>───────────────┤ X ├┤ H ├┤ X ├┤M├─╫──╫────────────╫──╫─ # └───┘└───┘└───┘└╥┘ ║ ║ ║ ║ # c_0: 0 ═══════════════════════════════╬══╬══╩════════════╬══╩═ # ║ ║ ║ # c_1: 0 ═══════════════════════════════╬══╬═══════════════╩════ # ║ ║ # c_2: 0 ═══════════════════════════════╬══╩════════════════════ # ║ # c_3: 0 ═══════════════════════════════╩═══════════════════════ # # ┌─┐┌───┐ ┌─┐ # q_0: |0>────────────────────■──┤M├┤ H ├──────────────────■──┤M├────── # ┌─┴─┐└╥┘└───┘┌───┐┌───┐ ┌─┴─┐└╥┘┌─┐ # q_1: |0>──■───X───────────┤ X ├─╫──────┤ H ├┤ X ├─X────┤ X ├─╫─┤M├─── # ┌─┴─┐ │ ┌───┐└───┘ ║ └───┘└─┬─┘ │ └───┘ ║ └╥┘┌─┐ # a_0: |0>┤ X ├─┼──────┤ H ├──────╫─────────────■───┼──────────╫──╫─┤M├ # └───┘ │ ┌───┐└───┘ ║ │ ┌─┐ ║ ║ └╥┘ # a_1: |0>──────X─┤ H ├───────────╫─────────────────X─┤M├──────╫──╫──╫─ # └───┘ ║ └╥┘ ║ ║ ║ # c_0: 0 ════════════════════════╩════════════════════╬═══════╩══╬══╬═ # ║ ║ ║ # c_1: 0 ═════════════════════════════════════════════╬══════════╩══╬═ # ║ ║ # c_2: 0 ═════════════════════════════════════════════╬═════════════╩═ # ║ # c_3: 0 ═════════════════════════════════════════════╩═══════════════ # # Layout from mapper: # {qr[0]: 0, # qr[1]: 1, # ar[0]: 2, # ar[1]: 3} # # 2 # | # 0 - 1 - 3 expected = QuantumCircuit(qr, ar, cr) expected.cx(qr[1], ar[0]) expected.swap(qr[0], qr[1]) expected.cx(qr[1], ar[1]) expected.h(ar[1]) expected.h(ar[0]) expected.measure(qr[1], cr[0]) expected.h(qr[0]) expected.swap(qr[1], ar[1]) expected.h(ar[1]) expected.cx(ar[0], qr[1]) expected.measure(ar[0], cr[2]) expected.swap(qr[1], ar[1]) expected.measure(ar[1], cr[3]) expected.cx(qr[1], qr[0]) expected.measure(qr[1], cr[0]) expected.measure(qr[0], cr[1]) expected_dag = circuit_to_dag(expected) layout = Layout({qr[0]: 0, qr[1]: 1, ar[0]: 2, ar[1]: 3}) pass_ = StochasticSwap(coupling, layout, 20, 13) after = pass_.run(dag) self.assertEqual(expected_dag, after)
def benchmark(depth, trail, varying_param): # qasm_file_name = "_private_benchmark/BNTF/16QBT_{:02}CYC_{}_{}.qasm".format( # depth, gdv_name, trail) # # solution_file_name = "_private_benchmark/meta/16QBT_{:02}CYC_{}_{}_solution.csv".format( # depth, gdv_name, trail) if gdv_name == "TFL": folder = "BNTF" depth_string = "{:02}".format(depth) name_end = "TFL" if nr_qubits == 54: name_end = "QSE" elif gdv_name == "QSE": folder = "BSS" depth_string = "{:03}".format(depth) name_end = "QSE" # if nr_qubits==54: # gdv_name = "QSE" qasm_file_name = "_private_benchmark/{}/{}QBT_{}CYC_{}_{}.qasm".format( folder, nr_qubits, depth_string, name_end, trail) solution_file_name = "_private_benchmark/meta/{}QBT_{}CYC_{}_{}_solution.csv".format( nr_qubits, depth_string, name_end, trail) # print("qiskit", depth) # input qasm file as circuit test_circuit = qiskit.QuantumCircuit.from_qasm_file(qasm_file_name) """ Construct the optimal initial mapping """ qiskit_layout_dict = dict() original_nodes = list() with open(solution_file_name, 'r') as csvfile: for original_node in csv.reader(csvfile, delimiter=','): original_nodes.append(literal_eval(original_node[0])) csvfile.close() print(original_nodes) for i in range(len(original_nodes)): qiskit_layout_dict[test_circuit.qregs[0][i]] = original_nodes[i] # construct passes that use the optimal initial mapping and BasicSwap # however, no swapping gates should be ever necessary original_pm = PassManager() # print(original_nodes) qiskit_coupling_map = CouplingMap(couplinglist=connection_list[qubits[nr_qubits]]) optimal_layout = Layout() optimal_layout.from_dict(qiskit_layout_dict) original_pm.append([SetLayout(optimal_layout), ApplyLayout(), BasicSwap(qiskit_coupling_map)]) map_original_circuit = original_pm.run(test_circuit) optimal_depth = map_original_circuit.depth() print("optimal mapping: the circuit has", optimal_depth, "cycles") # print(map_original_circuit.draw(style="text")) # construct passes that use the DenseLayout+StochasticSwap without initial mapping """ K7M """ gate_costs = {'id': 0, 'u1': 0, 'measure': 0, 'reset': 0, 'barrier': 0, 'u2': 1, 'u3': 1, 'U': 1, "ok": 0, # update the costs "rev_cnot": 4 * 1 + 10, # 4 u2/hadamard + 1 cnot "swap": 3 * 10 + 4, # 4 u2/hadamard + 3 cnot 'seed': 19} # pass the seed through gate costs """ 20 secunde 4.093154 :: attr_b=5.00,attr_c=0.61,edge_cost=0.20,max_breadth=4,max_depth=9,movement_factor=2 5 secunde 4.138454 :: attr_b=17.30,attr_c=0.25,edge_cost=0.20,max_breadth=3,max_depth=9,movement_factor=4 0.5 secunde 4.322774 :: attr_b=8.00,attr_c=0.02,edge_cost=0.20,max_breadth=2,max_depth=9,movement_factor=2 0.05 secunde 4.464655 :: attr_b=3.50,attr_c=0.31,edge_cost=0.90,max_breadth=2,max_depth=6,movement_factor=6 # Lucian 2.424873 for [-w9 -d9 -b1.50 -c0.32 -e0.80 -m10] """ parameters = { "att_b": 15, "att_c": 0, "cx": 0.8, "max_children": 2, "max_depth": 9, "div_dist": 10, # UNUSED "opt_att": True, "opt_max_t_min": False, "qubit_increase_factor": 3, "option_skip_cx": False, "penalty_skip_cx": 20, "opt_div_by_act": False, "TIME_LIMIT": 600 # seconds } parameters_string = str(parameters) # the number of qubits in the device parameters["nisq_qubits"] = qiskit_coupling_map.size() # Add the gate costs parameters["gate_costs"] = gate_costs # Should the initial mapping be chosen random? parameters["initial_map"] = K7MInitialMapping.HEURISTIC parameters["unidirectional_coupling"]=False parameters["dry_run"] = False k7mcomp = K7MCompiler(connection_list[qubits[nr_qubits]], parameters) execution_time = time.time() map_test_circuit, init_time, init_map = k7mcomp.run(test_circuit) execution_time = time.time() - execution_time if (map_test_circuit is None) and (init_map is None): # this happens when the execution was interrupted # Will not write to file of results. So the averages are not affected # by the interrupted experiments return optimal_depth, -1, execution_time, init_time, -1, -1 depth_result = map_test_circuit.depth() print("k7m mapping: the circuit has", depth_result, "cycles") # print(map_test_circuit.draw(style="text")) # accumulate result print("----") file_op_type = "a" global first_run if first_run: file_op_type = "w" first_run = False with open( "_private_data/BNTF/_{}_{}.csv".format(name_end, qubits[nr_qubits], ), file_op_type) as csvFile: writer = csv.writer(csvFile) writer.writerow([trail, "k7m", optimal_depth, depth_result, execution_time]) return optimal_depth, depth_result, execution_time, init_time
def __init__(self, backend, shots=1024, seed_simulator=None, max_credits=10, basis_gates=None, coupling_map=None, initial_layout=None, pass_manager=None, seed_transpiler=None, backend_options=None, noise_model=None, timeout=None, wait=5, circuit_caching=True, cache_file=None, skip_qobj_deepcopy=True, skip_qobj_validation=True, measurement_error_mitigation_cls=None, cals_matrix_refresh_period=30): """Constructor. Args: backend (BaseBackend): instance of selected backend shots (int, optional): number of repetitions of each circuit, for sampling seed_simulator (int, optional): random seed for simulators max_credits (int, optional): maximum credits to use basis_gates (list[str], optional): list of basis gate names supported by the target. Default: ['u1','u2','u3','cx','id'] coupling_map (list[list]): coupling map (perhaps custom) to target in mapping initial_layout (dict, optional): initial layout of qubits in mapping pass_manager (PassManager, optional): pass manager to handle how to compile the circuits seed_transpiler (int, optional): the random seed for circuit mapper backend_options (dict, optional): all running options for backend, please refer to the provider. noise_model (qiskit.provider.aer.noise.noise_model.NoiseModel, optional): noise model for simulator timeout (float, optional): seconds to wait for job. If None, wait indefinitely. wait (float, optional): seconds between queries to result circuit_caching (bool, optional): USe CircuitCache when calling compile_and_run_circuits cache_file(str, optional): filename into which to store the cache as a pickle file skip_qobj_deepcopy (bool, optional): Reuses the same qobj object over and over to avoid deepcopying skip_qobj_validation (bool, optional): Bypass Qobj validation to decrease submission time measurement_error_mitigation_cls (callable, optional): the approach to mitigate measurement error, CompleteMeasFitter or TensoredMeasFitter cals_matrix_refresh_period (int): how long to refresh the calibration matrix in measurement mitigation, unit in minutes """ self._backend = backend # setup run config run_config = RunConfig(shots=shots, max_credits=max_credits) if seed_simulator: run_config.seed_simulator = seed_simulator if getattr(run_config, 'shots', None) is not None: if self.is_statevector and run_config.shots != 1: logger.info( "statevector backend only works with shot=1, change " "shots from {} to 1.".format(run_config.shots)) run_config.shots = 1 self._run_config = run_config # setup backend config basis_gates = basis_gates or backend.configuration().basis_gates coupling_map = coupling_map or getattr(backend.configuration(), 'coupling_map', None) self._backend_config = { 'basis_gates': basis_gates, 'coupling_map': coupling_map } # setup noise config noise_config = None if noise_model is not None: if is_aer_provider(self._backend): if not self.is_statevector: noise_config = noise_model else: logger.info( "The noise model can be only used with Aer qasm simulator. " "Change it to None.") else: logger.info( "The noise model can be only used with Qiskit Aer. " "Please install it.") self._noise_config = {} if noise_config is None else { 'noise_model': noise_config } # setup compile config if initial_layout is not None and not isinstance( initial_layout, Layout): initial_layout = Layout(initial_layout) self._compile_config = { 'pass_manager': pass_manager, 'initial_layout': initial_layout, 'seed_transpiler': seed_transpiler } # setup job config self._qjob_config = {'timeout': timeout} if self.is_local \ else {'timeout': timeout, 'wait': wait} # setup backend options for run self._backend_options = {} if is_ibmq_provider(self._backend): logger.info( "backend_options can not used with the backends in IBMQ provider." ) else: self._backend_options = {} if backend_options is None \ else {'backend_options': backend_options} self._shared_circuits = False self._circuit_summary = False self._circuit_cache = CircuitCache( skip_qobj_deepcopy=skip_qobj_deepcopy, cache_file=cache_file) if circuit_caching else None self._skip_qobj_validation = skip_qobj_validation self._measurement_error_mitigation_cls = None if self.is_statevector: if measurement_error_mitigation_cls is not None: logger.info( "Measurement error mitigation does not work with statevector simulation, disable it." ) else: self._measurement_error_mitigation_cls = measurement_error_mitigation_cls self._measurement_error_mitigation_fitter = None self._measurement_error_mitigation_method = 'least_squares' self._cals_matrix_refresh_period = cals_matrix_refresh_period self._prev_timestamp = 0 if self._measurement_error_mitigation_cls is not None: logger.info( "The measurement error mitigation is enable. " "It will automatically submit an additional job to help calibrate the result of other jobs. " "The current approach will submit a job with 2^N circuits to build the calibration matrix, " "where N is the number of measured qubits. " "Furthermore, Aqua will re-use the calibration matrix for {} minutes " "and re-build it after that.".format( self._cals_matrix_refresh_period)) logger.info(self)
def benchmark(depth, trail, parameters): if gdv_name == "TFL": folder = "BNTF" depth_string = "{:02}".format(depth) name_end = "TFL" if nr_qubits == 54: name_end = "QSE" elif gdv_name == "QSE": folder = "BSS" depth_string = "{:03}".format(depth) name_end = "QSE" # if nr_qubits==54: # gdv_name = "QSE" qasm_file_name = "_private_benchmark/{}/{}QBT_{}CYC_{}_{}.qasm".format( folder, nr_qubits, depth_string, name_end, trail) solution_file_name = "_private_benchmark/meta/{}QBT_{}CYC_{}_{}_solution.csv".format( nr_qubits, depth_string, name_end, trail) # print("qiskit", depth) # input qasm file as circuit test_circuit = qiskit.QuantumCircuit.from_qasm_file(qasm_file_name) """ Construct the optimal initial mapping """ qiskit_layout_dict = dict() original_nodes = list() with open(solution_file_name, 'r') as csvfile: for original_node in csv.reader(csvfile, delimiter=','): original_nodes.append(literal_eval(original_node[0])) csvfile.close() # print(original_nodes) for i in range(len(original_nodes)): qiskit_layout_dict[test_circuit.qregs[0][i]] = original_nodes[i] # construct passes that use the optimal initial mapping and BasicSwap # however, no swapping gates should be ever necessary original_pm = PassManager() # print(original_nodes) qiskit_coupling_map = CouplingMap( couplinglist=connection_list[qubits[nr_qubits]]) optimal_layout = Layout() optimal_layout.from_dict(qiskit_layout_dict) original_pm.append([ SetLayout(optimal_layout), ApplyLayout(), BasicSwap(qiskit_coupling_map) ]) map_original_circuit = original_pm.run(test_circuit) optimal_depth = map_original_circuit.depth() # print("optimal mapping: the circuit has", optimal_depth, "cycles") # print(map_original_circuit.draw(style="text")) # construct passes that use the DenseLayout+StochasticSwap without initial mapping """ K7M """ gate_costs = { 'id': 0, 'u1': 0, 'measure': 0, 'reset': 0, 'barrier': 0, 'u2': 1, 'u3': 1, 'U': 1, "ok": 0, # update the costs "rev_cnot": 4 * 1 + 10, # 4 u2/hadamard + 1 cnot "swap": 3 * 10 + 4, # 4 u2/hadamard + 3 cnot 'seed': 19 } # pass the seed through gate costs # parameters_string = str(parameters) # the number of qubits in the device parameters["nisq_qubits"] = qiskit_coupling_map.size() # Add the gate costs parameters["gate_costs"] = gate_costs # Should the initial mapping be chosen random? parameters["initial_map"] = K7MInitialMapping.HEURISTIC parameters["unidirectional_coupling"] = False parameters["dry_run"] = False k7mcomp = K7MCompiler(connection_list[qubits[nr_qubits]], parameters) execution_time = time.time() map_test_circuit, init_time, init_map = k7mcomp.run(test_circuit) execution_time = time.time() - execution_time if (map_test_circuit is None) and (init_map is None): # this happens when the execution was interrupted return optimal_depth, -1, execution_time, init_time, -1, -1 # print(map_test_circuit.draw(output="text", fold=-1)) # tmp_circuit = map_test_circuit.decompose() tmp_circuit = map_test_circuit # print(tmp_circuit.draw(output="text", fold=-1)) # tmp_circuit = qiskit_to_tk(map_test_circuit) # Transform.RebaseToQiskit().DecomposeSWAPtoCX().apply(tmp_circuit) depth_result = tmp_circuit.depth() # print("k7m mapping: the circuit has", depth_result, "cycles") # print(map_test_circuit.draw(style="text")) # accumulate result # print("----") nr_t1 = noOfTranspositions(list(range(nr_qubits)), original_nodes, nr_qubits) nr_t2 = noOfTranspositions(original_nodes, init_map, nr_qubits) return optimal_depth, depth_result, execution_time, init_time, nr_t1, nr_t2