def q_add_one_mod_5(self, n): qasm = """ OPENQASM 2.0; include "qelib1.inc"; qreg q[5]; creg c[3]; // Inputs. {}x q[0]; {}x q[1]; {}x q[2]; cx q[2],q[3]; cx q[1],q[4]; x q[2]; ccx q[1],q[2],q[4]; cx q[3],q[1]; cx q[4],q[0]; reset q[3]; reset q[4]; ccx q[0],q[1],q[3]; cx q[3],q[1]; cx q[3],q[0]; ccx q[2],q[3],q[1]; cx q[3],q[2]; reset q[3]; x q[0]; x q[1]; x q[2]; ccx q[0],q[1],q[3]; ccx q[2],q[3],q[4]; x q[0]; x q[1]; x q[2]; reset q[3]; cx q[4],q[2]; cx q[4],q[1]; measure q[0] -> c[2]; measure q[1] -> c[1]; measure q[2] -> c[0]; """ binary = bin(n)[2:].zfill(3) comments = ['' if int(bi) else '//' for bi in binary] qasm = qasm.format(*comments) qp = QuantumProgram() qp.load_qasm_text(qasm, name='circuit') qobj = qp.compile(['circuit']) result = qp.run(qobj, wait=2, timeout=240) counted_result = Counter(result.get_counts('circuit')) # Turn binary back to decimal. output = int(counted_result.most_common()[0][0], 2) return output
def test_load_qasm_text(self): """Test load_qasm_text and get_circuit. If all is correct we should get the qasm file loaded from the string Previusly: Libraries: from qiskit import QuantumProgram """ QP_program = QuantumProgram() QASM_string = "// A simple 8 qubit example\nOPENQASM 2.0;\n" QASM_string += "include \"qelib1.inc\";\nqreg a[4];\n" QASM_string += "qreg b[4];\ncreg c[4];\ncreg d[4];\nh a;\ncx a, b;\n" QASM_string += "barrier a;\nbarrier b;\nmeasure a[0]->c[0];\n" QASM_string += "measure a[1]->c[1];\nmeasure a[2]->c[2];\n" QASM_string += "measure a[3]->c[3];\nmeasure b[0]->d[0];\n" QASM_string += "measure b[1]->d[1];\nmeasure b[2]->d[2];\n" QASM_string += "measure b[3]->d[3];" name = QP_program.load_qasm_text(QASM_string, verbose=False) result = QP_program.get_circuit(name) to_check = result.qasm() # print(to_check) self.assertEqual(len(to_check), 554)
def test_load_qasm_text(self): """Test load_qasm_text and get_circuit. If all is correct we should get the qasm file loaded from the string Previusly: Libraries: from qiskit import QuantumProgram """ QP_program = QuantumProgram() QASM_string = "// A simple 8 qubit example\nOPENQASM 2.0;\n" QASM_string += "include \"qelib1.inc\";\nqreg a[4];\n" QASM_string += "qreg b[4];\ncreg c[4];\ncreg d[4];\nh a;\ncx a, b;\n" QASM_string += "barrier a;\nbarrier b;\nmeasure a[0]->c[0];\n" QASM_string += "measure a[1]->c[1];\nmeasure a[2]->c[2];\n" QASM_string += "measure a[3]->c[3];\nmeasure b[0]->d[0];\n" QASM_string += "measure b[1]->d[1];\nmeasure b[2]->d[2];\n" QASM_string += "measure b[3]->d[3];" name = QP_program.load_qasm_text(QASM_string, verbose=False) result = QP_program.get_circuit(name) to_check = result.qasm() # print(to_check) self.assertEqual(len(to_check), 554)
def evaluate(compiler_function=None, test_circuits=None, verbose=False, backend='local_qiskit_simulator', seed=19): """ Evaluates the given complier_function with the circuits in test_circuits and compares the output circuit and quantum state with the original and a reference obtained with the qiskit compiler. Args: compiler_function (function): reference to user compiler function test_circuits (dict): named dict of circuits for which the compiler performance is evaluated test_circuits: { "name": { "qasm": 'qasm_str', "coupling_map": 'target_coupling_map } } verbose (bool): specifies if performance of basic QISKit unroler and mapper circuit is shown for each circuit backend (string): backend to use. For Windows Systems you should specify 'local_qasm_simulator' until 'local_qiskit_simulator' is available. Returns: dict { "name": circuit name { "optimizer_time": time taken by user compiler, "reference_time": reference time taken by qiskit circuit mapper/unroler (if verbose), "cost_original": original circuit cost function value (if verbose), "cost_reference": reference circuit cost function value (if verbose), "cost_optimized": optimized circuit cost function value, "coupling_correct_original": (bool) does original circuit satisfy the coupling map (if verbose), "coupling_correct_reference": (bool) does circuit produced by the qiskit mapper/unroler satisfy the coupling map (if verbose), "coupling_correct_optimized": (bool) does optimized circuit satisfy the coupling map, "state_correct_optimized": (bool) does optimized circuit return correct state } } """ # Initial Setup basis_gates = 'u1,u2,u3,cx,id' # or use "U,CX?" gate_costs = {'id': 0, 'u1': 0, 'measure': 0, 'reset': 0, 'barrier': 0, 'u2': 1, 'u3': 1, 'U': 1, 'cx': 10, 'CX': 10, 'seed': seed} # pass the seed through gate costs # Results data structure results = {} fileJSONExists = False # paler json if os.path.isfile("run_once_results.json"): with open("run_once_results.json", "r") as f: fileJSONExists = True results = json.load(f) print("Paler: Loaded JSON") # end paler json # Load QASM files and extract DAG circuits for name, circuit in test_circuits.items(): print("....name " + name) qp = QuantumProgram() qp.load_qasm_text( circuit["qasm"], name, basis_gates=basis_gates) circuit["dag_original"] = qasm_to_dag_circuit(circuit["qasm"], basis_gates=basis_gates) test_circuits[name] = circuit if not fileJSONExists: results[name] = {} # build empty result dict to be filled later # Only return results if a valid compiler function is provided if compiler_function is not None: # step through all the test circuits using multiprocessing compile_jobs = [[name, circuit, 0, compiler_function, gate_costs] for name, circuit in test_circuits.items()] with Pool(len(compile_jobs)) as job: res_values_opt = job.map(_compile_circuits, compile_jobs) # stash the results in the respective dicts print("..... [compiled optimised]") for job in range(len(compile_jobs)): name = res_values_opt[job].pop("name") test_circuits[name].update( res_values_opt[job].pop("circuit")) # remove the circuit from the results and store it # results[name] = res_values_opt[job] results[name].update(res_values_opt[job]) # do the same for the reference compiler in qiskit if verbose == True # paler json if verbose and (not fileJSONExists): compile_jobs = [[name, circuit, 1, _qiskit_compiler, gate_costs] for name, circuit in test_circuits.items()] with Pool(len(compile_jobs)) as job: res_values = job.map(_compile_circuits, compile_jobs) # also stash this but use update so we don't overwrite anything print("..... [compiled reference]") for job in range(len(compile_jobs)): name = res_values[job].pop("name") test_circuits[name].update( res_values[job].pop("circuit")) # remove the circuit from the results and store it results[name].update(res_values[job]) # determine the final permutation of the qubits # this is done by analyzing the measurements on the qubits compile_jobs = [[name, circuit, verbose] for name, circuit in test_circuits.items()] with Pool(len(compile_jobs)) as job: res_values = job.map(_prep_sim, compile_jobs) for job in range(len(compile_jobs)): name = res_values[job].pop("name") test_circuits[name].update( res_values[job].pop("circuit")) # remove the circuit from the results and store it results[name].update(res_values[job]) # Compose qobj for simulation config = { 'data': ['quantum_state'], } # generate qobj for original circuit qobj_original = _compose_qobj("original", test_circuits, backend=backend, config=config, basis_gates=basis_gates, shots=1, seed=None) # Compute original cost and check original coupling map if verbose and (not fileJSONExists): for circuit in qobj_original["circuits"]: name = circuit["name"] coupling_map = test_circuits[name].get("coupling_map", None) coupling_map_passes = True cost = 0 for op in circuit["compiled_circuit"]["operations"]: cost += gate_costs.get(op["name"]) # compute cost if op["name"] in ["cx", "CX"] \ and coupling_map is not None: # check coupling map coupling_map_passes &= ( op["qubits"][0] in coupling_map) if op["qubits"][0] in coupling_map: coupling_map_passes &= ( op["qubits"][1] in coupling_map[op["qubits"][0]] ) results[name]["cost_original"] = cost results[name]["coupling_correct_original"] = coupling_map_passes # Run simulation if not skipVerif: time_start = time.process_time() res_original = qp.run(qobj_original, timeout=GLOBAL_TIMEOUT) print("..... [executed original]") results[name]["sim_time_orig"] = time.process_time() - time_start # Generate qobj for optimized circuit qobj_optimized = _compose_qobj("optimized", test_circuits, backend=backend, config=config, basis_gates=basis_gates, shots=1, seed=None) # Compute compiled circuit cost and check coupling map for circuit in qobj_optimized["circuits"]: name = circuit["name"] coupling_map = test_circuits[name].get("coupling_map", None) coupling_map_passes = True cost = 0 for op in circuit["compiled_circuit"]["operations"]: cost += gate_costs.get(op["name"]) # compute cost if op["name"] in ["cx", "CX"] \ and coupling_map is not None: # check coupling map coupling_map_passes &= ( op["qubits"][0] in coupling_map) if op["qubits"][0] in coupling_map: coupling_map_passes &= ( op["qubits"][1] in coupling_map[op["qubits"][0]] ) results[name]["cost_optimized"] = cost results[name]["coupling_correct_optimized"] = coupling_map_passes # Run simulation if not skipVerif: time_start = time.process_time() res_optimized = qp.run(qobj_optimized, timeout=GLOBAL_TIMEOUT) results[name]["sim_time_opti"] = time.process_time() - time_start print("..... [executed optimised]") # paler json if verbose and (not fileJSONExists): # Generate qobj for reference circuit optimized by qiskit compiler qobj_reference = _compose_qobj("reference", test_circuits, backend=backend, config=config, basis_gates=basis_gates, shots=1, seed=None) # Compute reference cost and check reference coupling map for circuit in qobj_reference["circuits"]: name = circuit["name"] coupling_map = test_circuits[name].get("coupling_map", None) coupling_map_passes = True cost = 0 for op in circuit["compiled_circuit"]["operations"]: cost += gate_costs.get(op["name"]) # compute cost if op["name"] in ["cx", "CX"] \ and coupling_map is not None: # check coupling map coupling_map_passes &= ( op["qubits"][0] in coupling_map) if op["qubits"][0] in coupling_map: coupling_map_passes &= ( op["qubits"][1] in coupling_map[op["qubits"][0]] ) results[name]["cost_reference"] = cost results[name]["coupling_correct_reference"] = coupling_map_passes # Skip simulation of reference State to speed things up! # time_start = time.process_time() # res_reference = qp.run(qobj_reference, timeout=GLOBAL_TIMEOUT) # results[name]["sim_time_ref"] = time.process_time() - time_start # Check output quantum state of optimized circuit is correct in comparison to original for name in results.keys(): # handle errors here if skipVerif: results[name]["state_correct_optimized"] = True continue data_original = res_original.get_data(name) if test_circuits[name]["dag_optimized"] is not None: data_optimized = res_optimized.get_data(name) correct = _compare_outputs(data_original, data_optimized, test_circuits[name]["perm_optimized"]) # paler transform np.bool_ to bool results[name]["state_correct_optimized"] = bool(correct) print(name, bool(correct)) # skip verification # results[name]["state_correct_optimized"] = True else: results[name]["state_correct_optimized"] = False # Skip verification of the reference State to speed things up! # if verbose: # if test_circuits[name]["dag_reference"] is not None: # data_reference = res_reference.get_data(name) # correct = _compare_outputs(data_original, data_reference, test_circuits[name]["perm_reference"]) # results[name]["state_correct_reference"] = correct # else: # results[name]["state_correct_reference"] = False # paler json with open("run_once_results.json", "w") as f: json.dump(results, f) print("Paler: Wrote JSON") # end paler json return results
def compiler_function(dag_circuit, coupling_map=None, gate_costs=None): """ Modify a DAGCircuit based on a gate cost function. Instructions: Your submission involves filling in the implementation of this function. The function takes as input a DAGCircuit object, which can be generated from a QASM file by using the function 'qasm_to_dag_circuit' from the included 'submission_evaluation.py' module. For more information on the DAGCircuit object see the or QISKit documentation (eg. 'help(DAGCircuit)'). Args: dag_circuit (DAGCircuit): DAGCircuit object to be compiled. coupling_circuit (list): Coupling map for device topology. A coupling map of None corresponds an all-to-all connected topology. gate_costs (dict) : dictionary of gate names and costs. Returns: A modified DAGCircuit object that satisfies an input coupling_map and has as low a gate_cost as possible. """ qasm_in = dag_circuit.qasm() Q_program = QuantumProgram() qcircuit_name = Q_program.load_qasm_text(qasm_in) qcircuit = Q_program.get_circuit(qcircuit_name) tuple_map = {} if coupling_map is None: # todo: make all-to-all map raise ValueError else: for key in coupling_map.keys(): tuple_map[key] = tuple(coupling_map[key]) result, cost = Embed(qcircuit, tuple_map) compiled_dag = DAGCircuit.fromQuantumCircuit(result) return compiled_dag if False: # Example using mapper passes in Qiskit import copy from qiskit.mapper import swap_mapper, direction_mapper, cx_cancellation, optimize_1q_gates, Coupling from qiskit import qasm, unroll initial_layout = None coupling = Coupling(coupling_map) compiled_dag, final_layout = swap_mapper(copy.deepcopy(dag_circuit), coupling, initial_layout, trials=40, seed=19) # Expand swaps basis_gates = "u1,u2,u3,cx,id" # QE target basis program_node_circuit = qasm.Qasm(data=compiled_dag.qasm()).parse() unroller_circuit = unroll.Unroller( program_node_circuit, unroll.DAGBackend(basis_gates.split(","))) compiled_dag = unroller_circuit.execute() # Change cx directions compiled_dag = direction_mapper(compiled_dag, coupling) # Simplify cx gates cx_cancellation(compiled_dag) # Simplify single qubit gates compiled_dag = optimize_1q_gates(compiled_dag) # Return the compiled dag circuit return compiled_dag