Exemplo n.º 1
0
def detector_tomography_circuits_pymali(qubit_indices, probe_kets):
    """
    Analogical method_name of the circuits preparing method_name utilizing pymali general tensor calculator.
    """

    qubit_indices = sorted(
        qubit_indices
    )  # Sort to ensure, that results can easily be interpreted.
    tomography_circuits = []
    unitaries = [
        povmtools.get_unitary_change_ket_qubit(ket) for ket in probe_kets
    ]

    # create nice list with proper ordering of circuits. In first step, last qubit in list qubit_indices is iterated
    # while all the other are fixed. See function description for details.
    gtc = GeneralTensorCalculator.GeneralTensorCalculator(
        gtc_tensor_calculating_function)
    unitaries_lists_for_tensor_calculator = [
        unitaries.copy() for i in range(len(qubit_indices))
    ]
    list_of_unitaries_sets = gtc.calculate_tensor_to_increasing_list(
        unitaries_lists_for_tensor_calculator)
    qrs = max(qubit_indices) + 1

    # inner loop goes through all circuits in QDT experiments and prepares them
    for unitaries_set in list_of_unitaries_sets:

        qreg = QuantumRegister(qrs)
        creg = ClassicalRegister(len(qubit_indices))

        circuit = QuantumCircuit(qreg, creg)
        circuit.barrier()  # To prevent compiler from making changes.

        for j in range(len(unitaries_set)):

            current_angles = povmtools.get_su2_parametrizing_angles(
                unitaries_set[j])

            # TODO TR: I believe there may be more "special" cases.
            #  If so, then this should be placed in other method_name
            #  or in get_su2_ ... method_name.
            if current_angles[0] == 'id':
                circuit.i(qreg[qubit_indices[j]])
                continue
            if current_angles[0] == 'x':
                circuit.x(qreg[qubit_indices[j]])
                continue

            # implement unitary
            circuit.u3(current_angles[0], current_angles[1], current_angles[2],
                       qreg[qubit_indices[j]])

        # Add measurements
        for i in range(len(qubit_indices)):
            circuit.measure(qreg[qubit_indices[i]], creg[i])

        tomography_circuits.append(circuit)
    return tomography_circuits
Exemplo n.º 2
0
def detector_tomography_circuits_rigetti(qubit_indices,
                                         probe_kets,
                                         number_of_repetitions=1,
                                         shots=8192,
                                         qrs=None):
    """From list of probe kets and qubit data return quantum circuits which will be implemented to perform
    Quantum Detector Tomography (QDT).

    :param probe_kets: (list of numpy arrays) the list of ket representations of qubit pure quantum states which are to
    be used in QDT. For multi-qubit QDT, the combinations of tensor products of name_appendix will be taken.
    :param qubit_indices: (list of ints) labels of qubits for QDT
    :param number_of_repetitions: (int) parameter specifying how many copies of whole QDT experiment should be created
    (for larger statistics collection or comparision of results)

    :return: (list of QuantumCircuit objects) of length len(probe_states)**(number_of_qubits)
    """
    import pyquil as pyq

    qubit_indices = sorted(
        qubit_indices
    )  # Sort to ensure, that results can easily be interpreted.

    unitaries = [
        povmtools.get_unitary_change_ket_qubit(ket) for ket in probe_kets
    ]

    # create nice list with proper ordering of circuits. In first step, last qubit in list qubit_indices is iterated
    # while all the other are fixed. See function description for details.
    indices_for_circuits = get_list_of_lists_indices_qdt(
        qubit_indices, len(unitaries))
    if qrs is None:
        qrs = max(qubit_indices) + 1

    tomography_circuits = []
    # inner loop goes through all circuits in QDT experiments and prepares them
    for index_for_set in range(len(indices_for_circuits)):

        # index of set of qubits+unitaries for current step
        current_set = indices_for_circuits[index_for_set]

        # create quantum register
        # qreg = QuantumRegister(quantum_register_size)
        # creg = ClassicalRegister(len(qubit_indices))

        # create quantum circuit with nice names
        set_string = ''.join(['u' + str(st) for st in current_set[0]])
        qubits_string = ''.join(['q' + str(st) for st in qubit_indices])

        #
        # circuit = QuantumCircuit(qreg, creg,
        #                          name="QDT-" + qubits_string + "-id-" + set_string + '-no-' + str(number))
        program = pyq.Program()
        ro = program.declare('ro', memory_type='BIT', memory_size=qrs)

        # get barrier to prevent compiler from making changes
        # circuit.barrier()

        for qubit_unitary_pair_index in range(len(current_set)):
            # take qubit+unitary pair
            pair_now = current_set[qubit_unitary_pair_index]

            # take index of qubit and index of unitary
            q_now_index, u_now_index = pair_now[0], pair_now[1]

            # make sure that chosen quantum state is not one of the states in computational basis
            # TODO: this might not be necessary anymore, it's an old code, I had some problems long time ago with
            #  those guys because qiskit compiler went crazy if I defined identity or x gate using u3 unitary.

            if u_now_index == 0:
                program += pyq.gates.I(q_now_index)
            elif u_now_index == 1:
                program += pyq.gates.X(q_now_index)
            elif u_now_index == 2:
                program += pyq.gates.H(q_now_index)
            elif u_now_index == 3:
                program += pyq.gates.X(q_now_index)
                program += pyq.gates.H(q_now_index)
            elif u_now_index == 4:
                program += pyq.gates.H(q_now_index)
                program += pyq.gates.S(q_now_index)
            elif u_now_index == 5:
                program += pyq.gates.X(q_now_index)
                program += pyq.gates.H(q_now_index)
                program += pyq.gates.S(q_now_index)

        # Add measurements
        for i in range(len(qubit_indices)):
            program += pyq.gates.MEASURE(qubit_indices[i], ro[i])

        program.wrap_in_numshots_loop(shots)
        tomography_circuits.append(program)
    return tomography_circuits
Exemplo n.º 3
0
def detector_tomography_circuits(qubit_indices,
                                 probe_kets,
                                 number_of_repetitions=1,
                                 qrs=None):
    """From list of probe kets and qubit data return quantum circuits which will be implemented to perform
    Quantum Detector Tomography (QDT).

    :param probe_kets: (list of numpy arrays) the list of ket representations of qubit pure quantum states which are to
    be used in QDT. For multi-qubit QDT, the combinations of tensor products of name_appendix will be taken.
    :param qubit_indices: (list of ints) labels of qubits for QDT
    :param number_of_repetitions: (int) parameter specifying how many copies of whole QDT experiment should be created
    (for larger statistics collection or comparision of results)

    :return: (list of QuantumCircuit objects) of length len(probe_states)**(number_of_qubits)
    """

    qubit_indices = sorted(
        qubit_indices
    )  # Sort to ensure, that results can easily be interpreted.
    tomography_circuits = []
    unitaries = [
        povmtools.get_unitary_change_ket_qubit(ket) for ket in probe_kets
    ]

    # create nice list with proper ordering of circuits. In first step, last qubit in list qubit_indices is iterated
    # while all the other are fixed. See function description for details.
    indices_for_circuits = get_list_of_lists_indices_qdt(
        qubit_indices, len(unitaries))
    if qrs is None:
        qrs = max(qubit_indices) + 1

    # outer loop is for copies of QDT experiment
    for number in range(number_of_repetitions):

        # inner loop goes through all circuits in QDT experiments and prepares them
        for index_for_set in range(len(indices_for_circuits)):

            # index of set of qubits+unitaries for current step
            current_set = indices_for_circuits[index_for_set]

            # create quantum register
            qreg = QuantumRegister(qrs)
            creg = ClassicalRegister(len(qubit_indices))

            # create quantum circuit with nice names
            set_string = ''.join(['u' + str(st) for st in current_set[0]])
            qubits_string = ''.join(['q' + str(st) for st in qubit_indices])

            circuit = QuantumCircuit(qreg,
                                     creg,
                                     name="QDT-" + qubits_string + "-id-" +
                                     set_string + '-no-' + str(number))

            # get barrier to prevent compiler from making changes
            circuit.barrier()

            for qubit_unitary_pair_index in range(len(current_set)):
                # take qubit+unitary pair
                pair_now = current_set[qubit_unitary_pair_index]

                # take index of qubit and index of unitary
                q_now_index, u_now_index = pair_now[0], pair_now[1]

                # make sure that chosen quantum state is not one of the states in computational basis
                # TODO: this might not be necessary anymore, it's an old code, I had some problems long time ago with
                #  those guys because qiskit compiler went crazy if I defined identity or x gate using u3 unitary.
                if povmtools.check_if_projector_is_in_computational_basis(
                        povmtools.get_density_matrix(probe_kets[u_now_index])):
                    if povmtools.get_density_matrix(
                            probe_kets[u_now_index])[0][0] == 1:
                        circuit.i(qreg[q_now_index])
                    elif povmtools.get_density_matrix(
                            probe_kets[u_now_index])[1][1] == 1:
                        circuit.x(qreg[q_now_index])
                    else:
                        raise ValueError('error')
                else:
                    # get angles for single-qubit state change unitary
                    current_angles = povmtools.get_su2_parametrizing_angles(
                        unitaries[u_now_index])

                    # implement unitary
                    circuit.u3(current_angles[0], current_angles[1],
                               current_angles[2], qreg[q_now_index])

            # Add measurements
            for i in range(len(qubit_indices)):
                circuit.measure(qreg[qubit_indices[i]], creg[i])

            tomography_circuits.append(circuit)
    return tomography_circuits