Ejemplo n.º 1
0
    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)
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
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