def get_circuits(self, format='dag'): """Get the compiled circuits generated. Args: format (str, optional): "qasm" | "json" | "QuantumCircuit" Returns: List of Compiled QuantumCircuit objects. """ if format is 'qasm': qasm_list = [] for circuit in self.circuit_list: qasm_list.append(circuit.qasm()) return qasm_list elif format is 'json': json_list = [] for circuit in self.circuit_list: node_circuit = qasm.Qasm(data=circuit.qasm()).parse() unrolled_circuit = unroll.Unroller( node_circuit, unroll.JsonBackend(self.basis_gates)) json_list.append(unrolled_circuit.execute().decode()) return json_list elif format is 'QuantumCircuit': qc_list = [] for circuit in self.circuit_list: node_circuit = qasm.Qasm(data=circuit.qasm()).parse() unrolled_circuit = unroll.Unroller( node_circuit, unroll.CircuitBackend(self.basis_gates)) qc_list.append(unrolled_circuit.execute()) return qc_list
def direction_mapper(circuit_graph, coupling_graph, verbose=False): """Change the direction of CNOT gates to conform to CouplingGraph. circuit_graph = input Circuit coupling_graph = corresponding CouplingGraph verbose = optional flag to print more information Adds "h" to the circuit basis. Returns a Circuit object containing a circuit equivalent to circuit_graph but with CNOT gate directions matching the edges of coupling_graph. Raises an exception if the circuit_graph does not conform to the coupling_graph. """ if "cx" not in circuit_graph.basis: return circuit_graph if circuit_graph.basis["cx"] != (2, 0, 0): raise QISKitException("cx gate has unexpected signature %s" % circuit_graph.basis["cx"]) flipped_qasm = "OPENQASM 2.0;\n" + \ "gate cx c,t { CX c,t; }\n" + \ "gate u2(phi,lambda) q { U(pi/2,phi,lambda) q; }\n" + \ "gate h a { u2(0,pi) a; }\n" + \ "gate cx_flipped a,b { h a; h b; cx b, a; h a; h b; }\n" + \ "qreg q[2];\n" + \ "cx_flipped q[0],q[1];\n" u = unroll.Unroller(Qasm(data=flipped_qasm).parse(), unroll.CircuitBackend(["cx", "h"])) u.execute() flipped_cx_circuit = u.backend.circuit cx_node_list = circuit_graph.get_named_nodes("cx") cg_edges = coupling_graph.get_edges() for cx_node in cx_node_list: nd = circuit_graph.multi_graph.node[cx_node] cxedge = tuple(nd["qargs"]) if cxedge in cg_edges: if verbose: print("cx %s[%d], %s[%d] -- OK" % (cxedge[0][0], cxedge[0][1], cxedge[1][0], cxedge[1][1])) continue elif (cxedge[1], cxedge[0]) in cg_edges: circuit_graph.substitute_circuit_one(cx_node, flipped_cx_circuit, wires=[("q", 0), ("q", 1)]) if verbose: print("cx %s[%d], %s[%d] -FLIP" % (cxedge[0][0], cxedge[0][1], cxedge[1][0], cxedge[1][1])) else: raise QISKitException("circuit incompatible with CouplingGraph: " + "cx on %s" % cxedge) return circuit_graph
def load_unroll_qasm_file(filename, basis_gates='u1,u2,u3,cx,id'): """Load qasm file and return unrolled circuit Args: filename (str): a string for the filename including its location. basis_gates (str): basis to unroll circuit to. Returns: Returns a unrolled QuantumCircuit object """ # create Program object Node (AST) program_node_circuit = qasm.Qasm(filename=filename).parse() unrolled_circuit = unroll.Unroller( program_node_circuit, unroll.CircuitBackend(basis_gates.split(","))) circuit_unrolled = unrolled_circuit.execute() return circuit_unrolled
def get_circuits(self, format_='dag'): """Get the compiled circuits generated. Args: format_ (str, optional): "qasm" | "qobj" | "QuantumCircuit" Returns: list: List of Compiled QuantumCircuit objects. Raises: NameError: if the output format is not valid. """ if format_ == 'qasm': qasm_list = [] for circuit in self.circuit_list: qasm_list.append(circuit.qasm()) return qasm_list elif format_ == 'qobj': json_list = [] for circuit in self.circuit_list: node_circuit = qasm.Qasm(data=circuit.qasm()).parse() unrolled_circuit = unroll.Unroller( node_circuit, unroll.JsonBackend(self.basis_gates)) json_list.append(unrolled_circuit.execute()) return json_list elif format_ == 'QuantumCircuit': qc_list = [] for circuit in self.circuit_list: node_circuit = qasm.Qasm(data=circuit.qasm()).parse() unrolled_circuit = unroll.Unroller( node_circuit, unroll.CircuitBackend(self.basis_gates)) qc_list.append(unrolled_circuit.execute()) return qc_list # elif format is 'dag': # qc_list = [] # for circuit in self.circuit_list: # node_circuit = qasm.Qasm(data=circuit.qasm()).parse() # unrolled_circuit = unroll.Unroller( # node_circuit, # unroll.DAGBackend(self.basis_gates)) # qc_list.append(unrolled_circuit.execute()) # return qc_list else: raise NameError('Unrecognized circuit output format: "{}"'.format( format_))
def setUp(self): self.seed = 88 self.qasm_filename = self._get_resource_path('qasm/example.qasm') with open(self.qasm_filename, 'r') as qasm_file: self.qasm_text = qasm_file.read() self.qasm_ast = qasm.Qasm(data=self.qasm_text).parse() self.qasm_be = unroll.CircuitBackend( ['u1', 'u2', 'u3', 'id', 'cx']) self.qasm_circ = unroll.Unroller(self.qasm_ast, self.qasm_be).execute() qr = QuantumRegister(2, 'q') cr = ClassicalRegister(2, 'c') qc = QuantumCircuit(qr, cr) qc.h(qr[0]) qc.measure(qr[0], cr[0]) self.qc = qc # create qobj compiled_circuit1 = QobjExperiment.from_dict( transpile_dag(DAGCircuit.fromQuantumCircuit(self.qc), format='json')) compiled_circuit2 = QobjExperiment.from_dict( transpile_dag(DAGCircuit.fromQuantumCircuit(self.qasm_circ), format='json')) self.qobj = Qobj(qobj_id='test_qobj', config=QobjConfig(shots=2000, memory_slots=1, max_credits=3, seed=1111), experiments=[compiled_circuit1, compiled_circuit2], header=QobjHeader(backend_name='qasm_simulator')) self.qobj.experiments[0].header.name = 'test_circuit1' self.qobj.experiments[0].config = QobjItem( basis_gates='u1,u2,u3,cx,id') self.qobj.experiments[1].header.name = 'test_circuit2' self.qobj.experiments[1].config = QobjItem( basis_gates='u1,u2,u3,cx,id') self.backend = QasmSimulator()
def optimize_1q_gates(circuit): """Simplify runs of single qubit gates in the QX basis. Return a new circuit that has been optimized. """ qx_basis = ["u1", "u2", "u3", "cx", "id"] urlr = unroll.Unroller(Qasm(data=circuit.qasm(qeflag=True)).parse(), unroll.CircuitBackend(qx_basis)) urlr.execute() unrolled = urlr.backend.circuit runs = unrolled.collect_runs(["u1", "u2", "u3", "id"]) for run in runs: qname = unrolled.multi_graph.node[run[0]]["qargs"][0] right_name = "u1" right_parameters = (0.0, 0.0, 0.0) # (theta, phi, lambda) for node in run: nd = unrolled.multi_graph.node[node] assert nd["condition"] is None, "internal error" assert len(nd["qargs"]) == 1, "internal error" assert nd["qargs"][0] == qname, "internal error" left_name = nd["name"] assert left_name in ["u1", "u2", "u3", "id"], "internal error" if left_name == "u1": left_parameters = (0.0, 0.0, float(nd["params"][0])) elif left_name == "u2": left_parameters = (math.pi / 2, float(nd["params"][0]), float(nd["params"][1])) elif left_name == "u3": left_parameters = tuple(map(float, nd["params"])) else: left_name = "u1" # replace id with u1 left_parameters = (0.0, 0.0, 0.0) # Compose gates name_tuple = (left_name, right_name) if name_tuple == ("u1", "u1"): # u1(lambda1) * u1(lambda2) = u1(lambda1 + lambda2) right_parameters = (0.0, 0.0, right_parameters[2] + left_parameters[2]) elif name_tuple == ("u1", "u2"): # u1(lambda1) * u2(phi2, lambda2) = u2(phi2 + lambda1, lambda2) right_parameters = (math.pi / 2, right_parameters[1] + left_parameters[2], right_parameters[2]) elif name_tuple == ("u2", "u1"): # u2(phi1, lambda1) * u1(lambda2) = u2(phi1, lambda1 + lambda2) right_name = "u2" right_parameters = (math.pi / 2, left_parameters[1], right_parameters[2] + left_parameters[2]) elif name_tuple == ("u1", "u3"): # u1(lambda1) * u3(theta2, phi2, lambda2) = # u3(theta2, phi2 + lambda1, lambda2) right_parameters = (right_parameters[0], right_parameters[1] + left_parameters[2], right_parameters[2]) elif name_tuple == ("u3", "u1"): # u3(theta1, phi1, lambda1) * u1(lambda2) = # u3(theta1, phi1, lambda1 + lambda2) right_name = "u3" right_parameters = (left_parameters[0], left_parameters[1], right_parameters[2] + left_parameters[2]) elif name_tuple == ("u2", "u2"): # Using Ry(pi/2).Rz(2*lambda).Ry(pi/2) = # Rz(pi/2).Ry(pi-2*lambda).Rz(pi/2), # u2(phi1, lambda1) * u2(phi2, lambda2) = # u3(pi - lambda1 - phi2, phi1 + pi/2, lambda2 + pi/2) right_name = "u3" right_parameters = (math.pi - left_parameters[2] - right_parameters[1], left_parameters[1] + math.pi / 2, right_parameters[2] + math.pi / 2) else: # For composing u3's or u2's with u3's, use # u2(phi, lambda) = u3(pi/2, phi, lambda) # together with the qiskit.mapper.compose_u3 method. right_name = "u3" right_parameters = compose_u3(left_parameters[0], left_parameters[1], left_parameters[2], right_parameters[0], right_parameters[1], right_parameters[2]) # Here down, when we simplify, we add f(theta) to lambda to correct # the global phase when f(theta) is 2*pi. This isn't necessary but # the other steps preserve the global phase, so we continue. epsilon = 1e-9 # for comparison with zero # Y rotation is 0 mod 2*pi, so the gate is a u1 if abs(right_parameters[0] % 2.0 * math.pi) < epsilon \ and right_name != "u1": right_name = "u1" right_parameters = (0.0, 0.0, right_parameters[1] + right_parameters[2] + right_parameters[0]) # Y rotation is pi/2 or -pi/2 mod 2*pi, so the gate is a u2 if right_name == "u3": # theta = pi/2 + 2*k*pi if abs((right_parameters[0] - math.pi / 2) % 2.0 * math.pi) \ < epsilon: right_name = "u2" right_parameters = (math.pi / 2, right_parameters[1], right_parameters[2] + (right_parameters[0] - math.pi / 2)) # theta = -pi/2 + 2*k*pi if abs((right_parameters[0] + math.pi / 2) % 2.0 * math.pi) \ < epsilon: right_name = "u2" right_parameters = (math.pi / 2, right_parameters[1] + math.pi, right_parameters[2] - math.pi + (right_parameters[0] + math.pi / 2)) # u1 and lambda is 0 mod 4*pi so gate is nop if right_name == "u1" and \ abs(right_parameters[2] % 4.0 * math.pi) < epsilon: right_name = "nop" # Replace the data of the first node in the run new_params = [] if right_name == "u1": new_params.append(right_parameters[2]) if right_name == "u2": new_params = [right_parameters[1], right_parameters[2]] if right_name == "u3": new_params = list(right_parameters) nx.set_node_attributes(unrolled.multi_graph, 'name', {run[0]: right_name}) nx.set_node_attributes(unrolled.multi_graph, 'params', {run[0]: tuple(map(str, new_params))}) # Delete the other nodes in the run for node in run[1:]: unrolled._remove_op_node(node) if right_name == "nop": unrolled._remove_op_node(run[0]) return unrolled
def swap_mapper(circuit_graph, coupling_graph, initial_layout=None, basis="cx,u1,u2,u3,id", verbose=False): """Map a Circuit onto a CouplingGraph using swap gates. circuit_graph = input Circuit coupling_graph = CouplingGraph to map onto initial_layout = dict from qubits of circuit_graph to qubits of coupling_graph (optional) basis = basis string specifying basis of output Circuit verbose = optional flag to print more information Returns a Circuit object containing a circuit equivalent to circuit_graph that respects couplings in coupling_graph, and a layout dict 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. """ if circuit_graph.width() > coupling_graph.size(): raise QISKitException("Not enough qubits in CouplingGraph") # Schedule the input circuit layerlist = circuit_graph.layers() if verbose: print("schedule:") for i in range(len(layerlist)): print(" %d: %s" % (i, layerlist[i]["partition"])) # Check input layout and create default layout if necessary if initial_layout is not None: circ_qubits = circuit_graph.get_qubits() coup_qubits = coupling_graph.get_qubits() qubit_subset = [] for k, v in initial_layout.values(): qubit_subset.append(v) if k not in circ_qubits: raise QISKitException("initial_layout qubit %s[%d] not " + "in input Circuit" % (k[0], k[1])) if v not in coup_qubits: raise QISKitException("initial_layout qubit %s[%d] not " + " in input CouplingGraph" % (v[0], v[1])) else: # Supply a default layout qubit_subset = coupling_graph.get_qubits() qubit_subset = qubit_subset[0:circuit_graph.width()] initial_layout = {a: b for a, b in zip(circuit_graph.get_qubits(), qubit_subset)} # Find swap circuit to preceed to each layer of input circuit layout = copy.deepcopy(initial_layout) openqasm_output = "" first_layer = True # True until first layer is output first_swapping_layer = True # True until first swap layer is output # Iterate over layers for i in range(len(layerlist)): # Attempt to find a permutation for this layer success_flag, best_circ, best_d, best_layout, trivial_flag \ = layer_permutation(layerlist[i]["partition"], layout, qubit_subset, coupling_graph, 20) # If this fails, try one gate at a time in this layer if not success_flag: if verbose: print("swap_mapper: failed, layer %d, " % i, " retrying sequentially") serial_layerlist = layerlist[i]["graph"].serial_layers() # Go through each gate in the layer for j in range(len(serial_layerlist)): success_flag, best_circ, best_d, best_layout, trivial_flag \ = layer_permutation(serial_layerlist[j]["partition"], layout, qubit_subset, coupling_graph, 20) # Give up if we fail again if not success_flag: raise QISKitException("swap_mapper failed: " + "layer %d, sublayer %d" % (i, j) + ", \"%s\"" % serial_layerlist[j]["graph"].qasm( no_decls=True, aliases=layout)) else: # Update the qubit positions each iteration layout = best_layout if best_d == 0: # Output qasm without swaps if first_layer: openqasm_output += circuit_graph.qasm( add_swap=True, decls_only=True, aliases=layout) first_layer = False if not trivial_flag and first_swapping_layer: initial_layout = layout first_swapping_layer = False else: # Output qasm with swaps if first_layer: openqasm_output += circuit_graph.qasm( add_swap=True, decls_only=True, aliases=layout) first_layer = False initial_layout = layout first_swapping_layer = False else: if not first_swapping_layer: if verbose: print("swap_mapper: layer %d (%d), depth %d" % (i, j, best_d)) openqasm_output += best_circ else: initial_layout = layout first_swapping_layer = False openqasm_output += serial_layerlist[j]["graph"].qasm( no_decls=True, aliases=layout) else: # Update the qubit positions each iteration layout = best_layout if best_d == 0: # Output qasm without swaps if first_layer: openqasm_output += circuit_graph.qasm( add_swap=True, decls_only=True, aliases=layout) first_layer = False if not trivial_flag and first_swapping_layer: initial_layout = layout first_swapping_layer = False else: # Output qasm with swaps if first_layer: openqasm_output += circuit_graph.qasm( add_swap=True, decls_only=True, aliases=layout) first_layer = False initial_layout = layout first_swapping_layer = False else: if not first_swapping_layer: if verbose: print("swap_mapper: layer %d, depth %d" % (i, best_d)) openqasm_output += best_circ else: initial_layout = layout first_swapping_layer = False openqasm_output += layerlist[i]["graph"].qasm( no_decls=True, aliases=layout) # Parse openqasm_output into Circuit object basis += ",swap" ast = Qasm(data=openqasm_output).parse() u = unroll.Unroller(ast, unroll.CircuitBackend(basis.split(","))) u.execute() return u.backend.circuit, initial_layout