コード例 #1
0
def my_transpile(old_circuit):
    new_circuit = QuantumCircuit(*old_circuit.qregs,
                                 *old_circuit.cregs,
                                 name=old_circuit.name + '_transpiled')

    for inst, qargs, cargs in old_circuit._data:
        # print(inst.name)
        if inst.name == "id":
            # print("my_I removes id")
            my_I(new_circuit, qargs)
        elif inst.name == "x":
            # print("my_x used")
            my_x(new_circuit, qargs)
        elif inst.name == "y":
            # print("my_y used")
            my_y(new_circuit, qargs)
        elif inst.name == "z":
            # print("my_z used")
            my_z(new_circuit, qargs)
        elif inst.name == "h":
            # print("my_h used")
            my_h(new_circuit, qargs)
        elif inst.name == "cx":
            # print("my_cx used")
            my_cx(new_circuit, *qargs)
        elif inst.name == "ry":
            # print("my_ry used")
            my_ry(new_circuit, qargs)
        elif inst.name == "barrier":
            # print("barrier kept")
            new_circuit._append(inst, qargs, cargs)
        else:
            new_circuit._append(inst, qargs, cargs)

    return new_circuit
コード例 #2
0
 def clifford_2_qubit_circuit(self, num):
     """Return the 2-qubit clifford circuit corresponding to `num`
     where `num` is between 0 and 11519.
     """
     vals = self._unpack_num_multi_sigs(num, self.CLIFFORD_2_QUBIT_SIGS)
     qr = QuantumRegister(2)
     qc = QuantumCircuit(qr)
     if vals[0] == 0 or vals[0] == 3:
         (form, i0, i1, j0, j1, p0, p1) = vals
     else:
         (form, i0, i1, j0, j1, k0, k1, p0, p1) = vals
     if i0 == 1:
         qc.h(0)
     if i1 == 1:
         qc.h(1)
     if j0 == 1:
         qc.sxdg(0)
     if j0 == 2:
         qc.s(0)
     if j1 == 1:
         qc.sxdg(1)
     if j1 == 2:
         qc.s(1)
     if form in (1, 2, 3):
         qc.cx(0, 1)
     if form in (2, 3):
         qc.cx(1, 0)
     if form == 3:
         qc.cx(0, 1)
     if form in (1, 2):
         if k0 == 1:
             qc._append(VGate(), [qr[0]], [])
         if k0 == 2:
             qc._append(WGate(), [qr[0]], [])
         if k1 == 1:
             qc._append(VGate(), [qr[1]], [])
         if k1 == 2:
             qc._append(VGate(), [qr[1]], [])
             qc._append(VGate(), [qr[1]], [])
     if p0 == 1:
         qc.x(0)
     if p0 == 2:
         qc.y(0)
     if p0 == 3:
         qc.z(0)
     if p1 == 1:
         qc.x(1)
     if p1 == 2:
         qc.y(1)
     if p1 == 3:
         qc.z(1)
     return qc
コード例 #3
0
 def clifford_1_qubit_circuit(self, num):
     """Return the 1-qubit clifford circuit corresponding to `num`
     where `num` is between 0 and 23.
     """
     # pylint: disable=unbalanced-tuple-unpacking
     # This is safe since `_unpack_num` returns list the size of the sig
     (i, j, p) = self._unpack_num(num, self.CLIFFORD_1_QUBIT_SIG)
     qr = QuantumRegister(1)
     qc = QuantumCircuit(qr)
     if i == 1:
         qc.h(0)
     if j == 1:
         qc._append(SXdgGate(), [qr[0]], [])
     if j == 2:
         qc._append(SGate(), [qr[0]], [])
     if p == 1:
         qc.x(0)
     if p == 2:
         qc.y(0)
     if p == 3:
         qc.z(0)
     return qc
コード例 #4
0
def my_transpile_optimized(old_circuit):
    """
    Implements following optimizations:

    1. Skip I
    2. Deletes RX, RX, RX, RX on same qubit
    3. Deletes RZ, RZ, RZ, RZ on same qubit 
    4. Deletes CZ, CZ on same qubits
    5. Deletes CX, CX on same qubits
    6. Deletes H, H on same qubit
    7. Deletes X, X on same qubit
    8. Deletes Y, Y on same qubit

    More identities could probably used to optimized further...
    """
    optimized_circuit = QuantumCircuit(*old_circuit.qregs,
                                       *old_circuit.cregs,
                                       name=old_circuit.name + '_optimized')
    optimized_circuit_new_set = QuantumCircuit(*old_circuit.qregs,
                                               *old_circuit.cregs,
                                               name=old_circuit.name +
                                               '_optimized_new_set')

    # Implement rules 5, 6, 7, 8, as these are on the old set

    # list counts consecutively gates by number of elements for every qubit
    # (qubitwise because gates on different qubits do not cancel:
    # e.g: q1: Rx Rx, q2: Rx Rx, do not cancel
    cx_list = [[] for i in old_circuit._qubits]
    h_list = [[] for i in old_circuit._qubits]
    x_list = [[] for i in old_circuit._qubits]
    y_list = [[] for i in old_circuit._qubits]
    delete_list = [[] for i in old_circuit._qubits]
    # gate index
    i = 0
    # counts deleted rx, rz, cz gates
    number_deleted_gates_new_set = 0
    for inst, qargs, cargs in old_circuit._data:
        print(inst, qargs)
        print("cx_list:", cx_list)
        # print("qargs:", qargs[0].index)
        if inst.name == "h":
            # clear other gates list as its not consecutive anymore
            cx_list = [[] for i in old_circuit._qubits]
            x_list = [[] for i in old_circuit._qubits]
            y_list = [[] for i in old_circuit._qubits]

            h_list[qargs[0].index].append(i)

        elif inst.name == "x":
            # clear other gates list as its not consecutive anymore
            cx_list = [[] for i in old_circuit._qubits]
            h_list = [[] for i in old_circuit._qubits]
            y_list = [[] for i in old_circuit._qubits]

            x_list[qargs[0].index].append(i)

        elif inst.name == "y":
            # clear other gates list as its not consecutive anymore
            cx_list = [[] for i in old_circuit._qubits]
            h_list = [[] for i in old_circuit._qubits]
            x_list = [[] for i in old_circuit._qubits]

            y_list[qargs[0].index].append(i)

        elif inst.name == "z":
            # WARNING: No z_list as Z Z will be removed trough step 2
            # clear other gates list as its not consecutive anymore
            cx_list = [[] for i in old_circuit._qubits]
            h_list = [[] for i in old_circuit._qubits]
            x_list = [[] for i in old_circuit._qubits]
            y_list = [[] for i in old_circuit._qubits]

        # id does not change the unitary, so does not break a sequence
#         elif inst.name == "i":
#             # WARNING: No z_list as Z Z will be removed trough step 2
#             # clear other gates list as its not consecutive anymore
#             cx_list = [[] for i in old_circuit._qubits]
#             h_list = [[] for i in old_circuit._qubits]
#             x_list = [[] for i in old_circuit._qubits]
#             y_list = [[] for i in old_circuit._qubits]

        elif inst.name == "cx":
            # clear other gates list as its not consecutive anymore
            h_list = [[] for i in old_circuit._qubits]
            x_list = [[] for i in old_circuit._qubits]
            y_list = [[] for i in old_circuit._qubits]

            # As CZ is a symmetric qubit gate both cz(0, 1)
            # and cz(1, 0) need to be count
            cx_list[qargs[0].index].append(i)
            cx_list[qargs[1].index].append(i)

        # Rule 5: delete if 2 consecutive Cx
        if len(cx_list[qargs[0].index]) == 2:
            delete_list[qargs[0].index].append(cx_list[qargs[0].index])
            number_deleted_gates_new_set += 2 * CXGATES

            # reset to empty list for that qubit
            cx_list = [[] for i in old_circuit._qubits]

        # Rule 6: delete if 2 consecutive H
        if len(h_list[qargs[0].index]) == 2:
            delete_list[qargs[0].index].append(h_list[qargs[0].index])
            number_deleted_gates_new_set += 2 * HGATES

            # reset to empty list for that qubit
            h_list = [[] for i in old_circuit._qubits]

        # Rule 7: delete if 2 consecutive x
        if len(x_list[qargs[0].index]) == 2:
            delete_list[qargs[0].index].append(x_list[qargs[0].index])
            number_deleted_gates_new_set += 2 * XGATES

            # reset to empty list for that qubit
            x_list = [[] for i in old_circuit._qubits]

        # Rule 8: delete if 2 consecutive y
        if len(y_list[qargs[0].index]) == 2:
            delete_list[qargs[0].index].append(y_list[qargs[0].index])
            number_deleted_gates_new_set += 2 * YGATES

            # reset to empty list for that qubit
            y_list = [[] for i in old_circuit._qubits]

        i += 1
    # flatten the lists for different qubits
    for x, _ in enumerate(old_circuit._qubits):
        delete_list[x] = [element for line in delete_list[x] \
            for element in line]
        print("delete[" + str(x) + "]: ", delete_list[x])

    # flatten the lists for all qubits, as seperation is not needed anymore
    delete_list_flatten = [element for line in delete_list \
        for element in line]
    print("delete_list_flatten: ", delete_list_flatten)

    counter = 0
    for inst, qargs, cargs in old_circuit._data:
        # print(inst.name)
        # if gate should be deleted skip it
        # (do not insert it into optimized circ)
        if counter in delete_list_flatten:
            pass
        elif inst.name == "id":
            print("my_I removes id")
            # my_I(optimized_circuit, qargs)
        elif inst.name == "x":
            # print("my_x used")
            optimized_circuit.x(qargs)
        elif inst.name == "y":
            # print("my_y used")
            optimized_circuit.y(qargs)
        elif inst.name == "z":
            # print("my_z used")
            optimized_circuit.z(qargs)
        elif inst.name == "h":
            # print("my_h used")
            optimized_circuit.h(qargs)
        elif inst.name == "cx":
            # print("my_cx used")
            optimized_circuit.cx(*qargs)
        elif inst.name == "ry":
            # print("my_ry used")
            optimized_circuit.ry(np.pi / 2, qargs)
        elif inst.name == "barrier":
            # print("barrier kept")
            optimized_circuit._append(inst, qargs, cargs)
        else:
            optimized_circuit._append(inst, qargs, cargs)

        counter += 1

    number_deleted_gates = sum([len(qubit_list) \
        for qubit_list in delete_list])
    print("Optimization deleted " + str(number_deleted_gates) +
          " gates in first step (gates from old basis set)" + " and " +
          str(number_deleted_gates_new_set) + " gates in terms of new set.")

    # Implement rules 1, 2, 3, 4, as these are on the new set

    # list counts consecutively gates by number of elements for every qubit
    # (qubitwise because gates on different qubits do not cancel:
    # e.g: q1: Rx Rx, q2: Rx Rx, do not cancel
    rx_list = [[] for i in old_circuit._qubits]
    rz_list = [[] for i in old_circuit._qubits]
    cz_list = [[] for i in old_circuit._qubits]
    delete_list = [[] for i in old_circuit._qubits]
    # gate index
    i = 0
    for inst, qargs, cargs in old_circuit._data:
        # print(inst, qargs)
        # print("qargs:", qargs[0].index)
        if inst.name == "rx":
            # clear other gates list as its not consecutive anymore
            rz_list = [[] for i in old_circuit._qubits]
            cz_list = [[] for i in old_circuit._qubits]

            rx_list[qargs[0].index].append(i)

        elif inst.name == "rz":
            # clear other gates list as its not consecutive anymore
            rx_list = [[] for i in old_circuit._qubits]
            cz_list = [[] for i in old_circuit._qubits]

            rz_list[qargs[0].index].append(i)

        elif inst.name == "cz":
            # clear other gates list as its not consecutive anymore
            rx_list = [[] for i in old_circuit._qubits]
            rz_list = [[] for i in old_circuit._qubits]

            # As CZ is a symmetric qubit gate both cz(0, 1)
            # and cz(1, 0) need to be count
            cz_list[qargs[0].index].append(i)
            cz_list[qargs[1].index].append(i)

        # Rule 2: delete if 4 consecutive Rx
        if len(rx_list[qargs[0].index]) == 4:
            delete_list[qargs[0].index].append(rx_list[qargs[0].index])

            # reset to empty list for that qubit
            rx_list = [[] for i in old_circuit._qubits]

        # Rule 3: delete if 4 consecutive Rz
        if len(rz_list[qargs[0].index]) == 4:
            delete_list[qargs[0].index].append(rz_list[qargs[0].index])

            # reset to empty list for that qubit
            rz_list = [[] for i in old_circuit._qubits]

        # Rule 4: delete if 2 consecutive Cz
        if len(cz_list[qargs[0].index]) == 2:
            delete_list[qargs[0].index].append(cz_list[qargs[0].index])

            # reset to empty list for that qubit
            cz_list = [[] for i in old_circuit._qubits]

        i += 1

    # flatten the lists for different qubits
    for x, _ in enumerate(old_circuit._qubits):
        delete_list[x] = [element for line in delete_list[x] \
            for element in line]
        print("delete[" + str(x) + "]: ", delete_list[x])

    # flatten the lists for all qubits, as seperation is not needed anymore
    delete_list_flatten = [element for line in delete_list \
        for element in line]
    print("delete_list_flatten: ", delete_list_flatten)

    counter = 0
    for inst, qargs, cargs in optimized_circuit._data:
        # print(inst.name)
        # if gate should be deleted skip it
        # (do not insert it into optimized circ)
        if counter in delete_list_flatten:
            pass
        elif inst.name == "id":
            print("my_I removes id")
            # my_I(optimized_circuit_new_set, qargs)
        elif inst.name == "x":
            # print("my_x used")
            my_x(optimized_circuit_new_set, qargs)
        elif inst.name == "y":
            # print("my_y used")
            my_y(optimized_circuit_new_set, qargs)
        elif inst.name == "z":
            # print("my_z used")
            my_z(optimized_circuit_new_set, qargs)
        elif inst.name == "h":
            # print("my_h used")
            my_h(optimized_circuit_new_set, qargs)
        elif inst.name == "cx":
            # print("my_cx used")
            my_cx(optimized_circuit_new_set, *qargs)
        elif inst.name == "ry":
            # print("my_ry used")
            my_ry(optimized_circuit_new_set, qargs)
        elif inst.name == "barrier":
            # print("barrier kept")
            optimized_circuit_new_set._append(inst, qargs, cargs)
        else:
            optimized_circuit_new_set._append(inst, qargs, cargs)

        counter += 1

    number_deleted_gates = sum([len(qubit_list) \
        for qubit_list in delete_list])
    print("Optimization deleted " + str(number_deleted_gates) +
          " gates in second step (gates from new basis set).")

    return optimized_circuit_new_set
コード例 #5
0
    def circuits(self):

        sub_circuits = []
        sub_qubits = []
        sub_maps = []
        sub_size = []
        num_qubits = 0

        # Generate data for combination
        for sub_exp in self._experiments:

            # Generate transpiled subcircuits
            circuits = sub_exp._transpiled_circuits()

            # Add subcircuits
            sub_circuits.append(circuits)
            sub_size.append(len(circuits))

            # Sub experiment logical qubits in the combined circuits full qubits
            qubits = list(range(num_qubits, num_qubits + sub_exp.num_qubits))
            sub_qubits.append(qubits)
            # Construct mapping for the sub-experiments logical qubits to physical qubits
            # in the full combined circuits
            sub_maps.append(
                {q: qubits[i]
                 for i, q in enumerate(sub_exp.physical_qubits)})
            num_qubits += sub_exp.num_qubits

        # Generate empty joint circuits
        num_circuits = max(sub_size)
        joint_circuits = []
        for circ_idx in range(num_circuits):
            # Create joint circuit
            circuit = QuantumCircuit(self.num_qubits,
                                     name=f"parallel_exp_{circ_idx}")
            circuit.metadata = {
                "experiment_type": self._type,
                "composite_index": [],
                "composite_metadata": [],
                "composite_qubits": [],
                "composite_clbits": [],
            }
            for exp_idx in range(self._num_experiments):
                if circ_idx < sub_size[exp_idx]:
                    # Add subcircuits to joint circuit
                    sub_circ = sub_circuits[exp_idx][circ_idx]
                    num_clbits = circuit.num_clbits
                    qubits = sub_qubits[exp_idx]
                    qargs_map = sub_maps[exp_idx]
                    clbits = list(
                        range(num_clbits, num_clbits + sub_circ.num_clbits))
                    circuit.add_register(ClassicalRegister(
                        sub_circ.num_clbits))

                    # Apply transpiled subcircuit
                    # Note that this assumes the circuit was not expanded to use
                    # any qubits outside the specified physical qubits
                    for inst, qargs, cargs in sub_circ.data:
                        try:
                            mapped_qargs = [
                                circuit.qubits[qargs_map[sub_circ.find_bit(
                                    i).index]] for i in qargs
                            ]
                        except KeyError as ex:
                            # Instruction is outside physical qubits for the component
                            # experiment.
                            # This could legitimately happen if the subcircuit was
                            # explicitly scheduled during transpilation which would
                            # insert delays on all auxillary device qubits.
                            # We skip delay instructions to allow for this.
                            if inst.name == "delay":
                                continue
                            raise QiskitError(
                                "Component experiment has been transpiled outside of the "
                                "allowed physical qubits for that component. Check the "
                                "experiment is valid on the backends coupling map."
                            ) from ex
                        mapped_cargs = [
                            circuit.clbits[clbits[sub_circ.find_bit(i).index]]
                            for i in cargs
                        ]
                        circuit._append(inst, mapped_qargs, mapped_cargs)

                    # Add subcircuit metadata
                    circuit.metadata["composite_index"].append(exp_idx)
                    circuit.metadata["composite_metadata"].append(
                        sub_circ.metadata)
                    circuit.metadata["composite_qubits"].append(qubits)
                    circuit.metadata["composite_clbits"].append(clbits)

                    # Add the calibrations
                    for gate, cals in sub_circ.calibrations.items():
                        for key, sched in cals.items():
                            circuit.add_calibration(gate,
                                                    qubits=key[0],
                                                    schedule=sched,
                                                    params=key[1])

            # Add joint circuit to returned list
            joint_circuits.append(circuit)

        return joint_circuits