コード例 #1
0
def stacked_QAE_fidelity(QAE, L, k):
    # QAE : QAE to use
    # L : list of test states
    # k : stacking maximum
    
    backend = Aer.get_backend('statevector_simulator')
    
    QAE_circ, out_qubits = QAE.subroutine_2()
    circ_0 = QuantumCircuit(QAE.W)
    circ_0.append(L[0][0], range(QAE.M[0])) 
    
    for i in range(k):
        circ_0.append(QAE_circ, range(QAE.W))
        circ_0.reset(list(set(range(QAE.W)) - set(out_qubits)))
    
    fid = []
    for pair in L:
        circ_0.data[0] = (pair[0], circ_0.data[0][1], circ_0.data[0][2])
        state_0 = partial_trace(execute(circ_0, backend).result().get_statevector(), list(set(range(QAE.W)) - set(out_qubits)))
        state_1 = execute(pair[1], backend).result().get_statevector()
        fid.append(state_fidelity(state_0, state_1))
        
    return fid
コード例 #2
0
def stacked_QAE_fidelity_range(QAE, L, k, filename = None):
    # QAE : QAE to use
    # L : list of test states
    # k : stacking maximum
    # filename : whether to save figure and figure name
    
    backend = Aer.get_backend('statevector_simulator')
    
    QAE_circ, out_qubits = QAE.subroutine_2()
    circ_0 = QuantumCircuit(QAE.W)
    circ_0.append(L[0][0], range(QAE.M[0]))    
    
    all_fid_mean = []
    all_fid_std = []
    for i in range(k):
        circ_0.append(QAE_circ, range(QAE.W))
        circ_0.reset(list(set(range(QAE.W)) - set(out_qubits)))
        
        fid = []
        for pair in L:
            circ_0.data[0] = (pair[0], circ_0.data[0][1], circ_0.data[0][2])
            state_0 = partial_trace(execute(circ_0, backend).result().get_statevector(), list(set(range(QAE.W)) - set(out_qubits)))
            state_1 = execute(pair[1], backend).result().get_statevector()
            fid.append(state_fidelity(state_0, state_1))
            
        all_fid_mean.append(np.mean(fid))
        all_fid_std.append(np.std(fid))
    
    # Plot
    plt.errorbar(range(1,k+1), all_fid_mean, all_fid_std, marker = 'D', ms = 4, color = '#0000CC', capsize = 5)
    plt.grid(lw = 0.5, ls = 'dotted')
    plt.xlabel('Number of QAEs stacked')
    plt.ylabel('Fidelity with GHZ')
    
    if filename != None:
        plt.savefig(filename + '.pdf', bbox_inches = 'tight')
コード例 #3
0
    def collisional_model(self,
                          channel='phase_damping',
                          target_qubit=2,
                          collision_number=5,
                          theta=np.pi / 4,
                          initial_statevector=np.array([1, 1] / np.sqrt(2)),
                          print_results=True,
                          **kwargs):  # collisional model function
        def collision(channel,
                      **kwargs):  # introduces one collision into the circuit
            if channel == 'phase_damping':
                phase_damping(**kwargs)

        def phase_damping(qc, q, a, k,
                          theta):  # sets up phase damping collision
            qc.h(a[k - 1])
            qc.cx(a[k - 1], q[-1])
            qc.rz(theta, q[-1])
            qc.cx(a[k - 1], q[-1])

        # obtains unitary function for the phase damping operator
        def phase_damping_operator(n, theta):
            if n:  # unitary function when measuring entangled state
                _qc = QuantumCircuit(n)
                _qc.h(-1)
                _qc.cx(-1, -2)
                _qc.rz(theta, -2)
                _qc.cx(-1, -2)
            else:  # unitary function when measuring teleported state
                _qc = QuantumCircuit(2)
                _qc.h(1)
                _qc.cx(1, 0)
                _qc.rz(theta, 0)
                _qc.cx(1, 0)

            job = execute(_qc, Aer.get_backend('unitary_simulator'))
            result = job.result()

            return result.get_unitary()

        def evolve_theoretical_rho(
            rho, U, traced_out_qubit
        ):  # evolution function of state after every collision
            evolving_rho = np.kron(np.array([[1, 0], [0, 0]]), rho)
            evolved_rho = np.matmul(np.matmul(U, evolving_rho), U.conj().T)

            return partial_trace(evolved_rho, [traced_out_qubit]).data

        def apply_protocol(qc, state):  # apply teleportation protocol
            qc.barrier()  # barrier to separate components

            qc.cx(0, 1)
            qc.h(0)
            if state == 'GHZ':  # protocol for secret sharing
                qc.h(2)
                qc.cz(2, 3)
                qc.cx(1, 3)
                qc.cz(0, 3)
            elif state == 'Bell':  # protocol for standard teleportation
                qc.cx(1, 2)
                qc.cz(0, 2)

        def revert(qc,
                   d):  # Function to revert back before protocol was applied
            for _ in range(d):
                qc.data.pop(-1)

        print('Collisional model for protocol {} on {}:'.format(
            self.protocol, self.device))
        print('Channel: {}, number of collisions: {}\n'.format(
            channel, collision_number))

        if self.protocol == 'GHZ_teleport':  # Settings for secret sharing protocol
            state = 'GHZ'
            n = 3
            d = 6
            theoretical_rho_S = self.general_GHZ_matrix(
                n)  # Create theoretical GHZ state
        elif self.protocol == 'Bell_teleport':  # Settings for standard teleportation protocol
            state = 'Bell'
            n = 2
            d = 4
            theoretical_rho_S = self.general_GHZ_matrix(
                n)  # Create theoretical Bell state

        # Create quantum circuit
        q = QuantumRegister(n + 1, 'q')
        qc = QuantumCircuit(q)

        # Initialise random qubit state to be teleported
        qc.initialize(initial_statevector, q[0])
        theoretical_rho_T = np.outer(initial_statevector,
                                     np.conj(initial_statevector))

        self.general_GHZ(qc, q, n, 1)  # Create general GHZ state in circuit

        # Generate ancilla states
        if collision_number > 0:
            a = QuantumRegister(collision_number, 'a')
            qc.add_register(a)

        if channel == 'phase_damping':  # Create phase damping operators
            U_S = phase_damping_operator(n + 1, theta)
            U_T = phase_damping_operator(None, theta)

        # create lists used to store data for simulation
        theoretical_rho_S_list = []
        rho_S_list = []
        theoretical_rho_T_list = []
        rho_T_list = []
        numerical_tangle_list = []
        concurrence_list = []
        fidelity_S_list = []
        fidelity_T_list = []
        rho_S_list_sim = []
        rho_T_list_sim = []
        numerical_tangle_list_sim = []
        concurrence_list_sim = []
        fidelity_S_list_sim = []
        fidelity_T_list_sim = []
        job_ids_list = []

        # Start simulation and collision process
        for k in range(collision_number + 1):
            if k > 0:  # Apply collision to circuit
                collision(channel, qc=qc, q=q, a=a, k=k, theta=theta)
                theoretical_rho_S = evolve_theoretical_rho(
                    theoretical_rho_S, U_S, n)
                theoretical_rho_T = evolve_theoretical_rho(
                    theoretical_rho_T, U_T, 1)

            if self.protocol == 'GHZ_teleport':  # State tomography for GHZ state
                rho_S, S_id = self.tomography(qc, self.backend, True,
                                              [q[1], q[2], q[3]])
            elif self.protocol == 'Bell_teleport':  # State tomography for Bell state
                rho_S, S_id = self.tomography(qc, self.backend, True,
                                              [q[1], q[2]])

            apply_protocol(qc,
                           state)  # applies teleportation protocol in circuit

            # State tomography for teleported state
            rho_T, T_id = self.tomography(qc, self.backend, True,
                                          [q[target_qubit]])

            revert(qc, d)  # Revert back before protocol was applied

            # Append results to respective lists, calculated concurrence/three-tangle and fidelity
            rho_S_list.append(rho_S)
            theoretical_rho_S_list.append(theoretical_rho_S)
            rho_T_list.append(rho_T)
            theoretical_rho_T_list.append(theoretical_rho_T)
            job_ids_list.append([S_id, T_id])
            if self.protocol == 'GHZ_teleport':
                NT = self.three_tangle(rho_S, **kwargs)
                numerical_tangle_list.append(NT)
            if self.protocol == 'Bell_teleport':
                C = self.concurrence(rho_S)
                concurrence_list.append(C)
            F_S = state_fidelity(theoretical_rho_S_list[0], rho_S)
            fidelity_S_list.append(F_S)
            F_T = state_fidelity(theoretical_rho_T_list[0], rho_T)
            fidelity_T_list.append(F_T)

            # simulate artificial quantum computer
            if self.qasm_sim:
                if self.protocol == 'GHZ_teleport':  # State tomography for GHZ state
                    rho_S_sim, _ = self.tomography(
                        qc, Aer.get_backend('qasm_simulator'), False,
                        [q[1], q[2], q[3]])
                elif self.protocol == 'Bell_teleport':  # State tomography for Bell state
                    rho_S_sim, _ = self.tomography(
                        qc, Aer.get_backend('qasm_simulator'), False,
                        [q[1], q[2]])

                apply_protocol(
                    qc, state)  # applies teleportation protocol in circuit

                rho_T_sim, _ = self.tomography(
                    qc, Aer.get_backend('qasm_simulator'), False,
                    [q[target_qubit]])

                revert(qc, d)  # Revert back before protocol was applied

                # Append results to respective lists, calculated concurrence/three-tangle and fidelity
                rho_S_list_sim.append(rho_S_sim)
                rho_T_list_sim.append(rho_T_sim)
                if self.protocol == 'GHZ_teleport':
                    NT_sim = self.three_tangle(rho_S_sim, **kwargs)
                    numerical_tangle_list_sim.append(NT_sim)
                if self.protocol == 'Bell_teleport':
                    C_sim = self.concurrence(rho_S_sim)
                    concurrence_list_sim.append(C_sim)
                F_S_sim = state_fidelity(theoretical_rho_S_list[0], rho_S_sim)
                fidelity_S_list_sim.append(F_S_sim)
                F_T_sim = state_fidelity(theoretical_rho_T_list[0], rho_T_sim)
                fidelity_T_list_sim.append(F_T_sim)

            # Print results and other quantities
            if print_results:
                print("Collision Number:", k)
                print("Original {} Density Matrix:".format(state))
                print(theoretical_rho_S_list[0])
                print("Theoretical {} Density Matrix:".format(state))
                print(theoretical_rho_S)
                print("Measured {} Density Matrix:".format(state))
                print(rho_S)
                print("Original Teleported Density Matrix:")
                print(theoretical_rho_T_list[0])
                print("Theoretical Teleported Density Matrix:")
                print(theoretical_rho_T)
                print("Measured Teleported Density Matrix:")
                print(rho_T)
                print("Trace:", np.real(np.trace(rho_S)))
                if self.protocol == 'GHZ_teleport':
                    print("Numerical Three-Tangle:", NT)
                if self.protocol == 'Bell_teleport':
                    print("Concurrence:", C)
                print("{} State Fidelity:".format(state), F_S)
                print("Teleported state Fidelity:", F_T)
                print("{} state Eigenvalues:".format(state),
                      np.sort(np.real(np.linalg.eigvals(rho_S)))[::-1])
                print("Teleported state Eigenvalues:",
                      np.sort(np.real(np.linalg.eigvals(rho_T)))[::-1])
                print('\n')

        if self.save_results:  # save results
            self.save_data(self.directory,
                           collision_number=collision_number,
                           theoretical_rho_S_list=theoretical_rho_S_list,
                           rho_S_list=rho_S_list,
                           theoretical_rho_T_list=theoretical_rho_T_list,
                           rho_T_list=rho_T_list,
                           numerical_tangle_list=numerical_tangle_list,
                           concurrence_list=concurrence_list,
                           fidelity_S_list=fidelity_S_list,
                           fidelity_T_list=fidelity_T_list,
                           rho_S_list_sim=rho_S_list_sim,
                           rho_T_list_sim=rho_T_list_sim,
                           numerical_tangle_list_sim=numerical_tangle_list_sim,
                           concurrence_list_sim=concurrence_list_sim,
                           fidelity_S_list_sim=fidelity_S_list_sim,
                           fidelity_T_list_sim=fidelity_T_list_sim,
                           theta=theta,
                           initial_statevector=initial_statevector,
                           job_ids_list=job_ids_list,
                           **kwargs)
コード例 #4
0
ファイル: measures.py プロジェクト: su-yiting/qiskit-terra
def process_fidelity(channel, target=None, require_cp=True, require_tp=True):
    r"""Return the process fidelity of a noisy quantum channel.


    The process fidelity :math:`F_{\text{pro}}(\mathcal{E}, \methcal{F})`
    between two quantum channels :math:`\mathcal{E}, \mathcal{F}` is given by

    .. math:
        F_{\text{pro}}(\mathcal{E}, \mathcal{F})
            = F(\rho_{\mathcal{E}}, \rho_{\mathcal{F}})

    where :math:`F` is the :func:`~qiskit.quantum_info.state_fidelity`,
    :math:`\rho_{\mathcal{E}} = \Lambda_{\mathcal{E}} / d` is the
    normalized :class:`~qiskit.quantum_info.Choi` matrix for the channel
    :math:`\mathcal{E}`, and :math:`d` is the input dimension of
    :math:`\mathcal{E}`.

    When the target channel is unitary this is equivalent to

    .. math::
        F_{\text{pro}}(\mathcal{E}, U)
            = \frac{Tr[S_U^\dagger S_{\mathcal{E}}]}{d^2}

    where :math:`S_{\mathcal{E}}, S_{U}` are the
    :class:`~qiskit.quantum_info.SuperOp` matrices for the *input* quantum
    channel :math:`\mathcal{E}` and *target* unitary :math:`U` respectively,
    and :math:`d` is the input dimension of the channel.

    Args:
        channel (Operator or QuantumChannel): input quantum channel.
        target (Operator or QuantumChannel or None): target quantum channel.
            If `None` target is the identity operator [Default: None].
        require_cp (bool): check if input and target channels are
                           completely-positive and if non-CP log warning
                           containing negative eigenvalues of Choi-matrix
                           [Default: True].
        require_tp (bool): check if input and target channels are
                           trace-preserving and if non-TP log warning
                           containing negative eigenvalues of partial
                           Choi-matrix :math:`Tr_{\mbox{out}}[\mathcal{E}] - I`
                           [Default: True].

    Returns:
        float: The process fidelity :math:`F_{\text{pro}}`.

    Raises:
        QiskitError: if the channel and target do not have the same dimensions.
    """
    # Format inputs
    channel = _input_formatter(channel, SuperOp, 'process_fidelity', 'channel')
    target = _input_formatter(target, Operator, 'process_fidelity', 'target')

    if target:
        # Validate dimensions
        if channel.dim != target.dim:
            raise QiskitError(
                'Input quantum channel and target unitary must have the same '
                'dimensions ({} != {}).'.format(channel.dim, target.dim))

    # Validate complete-positivity and trace-preserving
    for label, chan in [('Input', channel), ('Target', target)]:
        if chan is not None and require_cp:
            cp_cond = _cp_condition(chan)
            neg = cp_cond < -1 * chan.atol
            if np.any(neg):
                logger.warning(
                    '%s channel is not CP. Choi-matrix has negative eigenvalues: %s',
                    label, cp_cond[neg])
        if chan is not None and require_tp:
            tp_cond = _tp_condition(chan)
            non_zero = np.logical_not(
                np.isclose(tp_cond, 0, atol=chan.atol, rtol=chan.rtol))
            if np.any(non_zero):
                logger.warning(
                    '%s channel is not TP. Tr_2[Choi] - I has non-zero eigenvalues: %s',
                    label, tp_cond[non_zero])

    if isinstance(target, Operator):
        # Compute fidelity with unitary target by applying the inverse
        # to channel and computing fidelity with the identity
        channel = channel @ target.adjoint()
        target = None

    input_dim, _ = channel.dim
    if target is None:
        # Compute process fidelity with identity channel
        if isinstance(channel, Operator):
            # |Tr[U]/dim| ** 2
            fid = np.abs(np.trace(channel.data) / input_dim)**2
        else:
            # Tr[S] / (dim ** 2)
            fid = np.trace(SuperOp(channel).data) / (input_dim**2)
        return float(np.real(fid))

    # For comparing two non-unitary channels we compute the state fidelity of
    # the normalized Choi-matrices. This is equivalent to the previous definition
    # when the target is a unitary channel.
    state1 = DensityMatrix(Choi(channel).data / input_dim)
    state2 = DensityMatrix(Choi(target).data / input_dim)
    return state_fidelity(state1, state2, validate=False)
コード例 #5
0
    def collisional_model(self,
                          backend='qasm_simulator',
                          live=False,
                          noise_model=None,
                          channel='amplitude_damping',
                          shots=1024,
                          measured_qubits=(),
                          max_collisions=5,
                          theta=np.pi / 2,
                          concurrence=False,
                          tangle=False,
                          witness=False,
                          tangle_witness=True,
                          markov=True,
                          print_results=True,
                          save_results=False,
                          directory=None,
                          full=True,
                          initial_statevector=np.array([0.5, 0.5])):

        self.channel = channel
        self.markov = markov

        if self.state == 'h':
            self.qc.h(0)

        elif self.state == 'GHZ_teleport':
            initial_state = initial_statevector
            initial_state /= np.linalg.norm(initial_state)
            self.qc.initialize(initial_state, [0])
            self.theoretical_rho = np.outer(initial_state, initial_state)
            self.GHZ([1, 2, 3])

        elif self.state == 'D':
            self.D()
            if full:
                self.theoretical_rho = self.full_theoretical_D(self.n, self.k)
            else:
                self.theoretical_rho = self.theoretical_D(self.n, self.k)

        elif self.state == 'W':
            self.W()
            if full:
                self.theoretical_rho = self.full_theoretical_D(self.n, self.k)
            else:
                self.theoretical_rho = self.theoretical_D(self.n, self.k)

        elif self.state == 'GHZ':
            self.GHZ(range(self.n))
            if full:
                self.theoretical_rho = self.full_theoretical_GHZ(self.n)
            else:
                self.theoretical_rho = self.theoretical_GHZ(self.n)

        self.histogram_data = []
        self.directory = directory

        if backend == 'qasm_simulator':
            self.backend = Aer.get_backend('qasm_simulator')
            self.coupling_map = None
            if noise_model:
                self.noise_model = noise_model
                self.basis_gates = self.noise_model.basis_gates
            else:
                self.noise_model = None
                self.basis_gates = None
        else:
            provider = IBMQ.get_provider(group='open')
            self.device = provider.get_backend(backend)
            self.properties = self.device.properties()
            self.coupling_map = self.device.configuration().coupling_map
            self.noise_model = noise.device.basic_device_noise_model(
                self.properties)
            self.basis_gates = self.noise_model.basis_gates

            if save_results:
                visual.plot_error_map(self.device).savefig(
                    '{}/error_map.png'.format(self.directory))

            if live:
                check = input(
                    "Are you sure you want to run the circuit live? [y/n]: ")
                if check == 'y' or check == 'yes':
                    self.backend = self.device
                else:
                    self.backend = Aer.get_backend('qasm_simulator')
            else:
                self.backend = Aer.get_backend('qasm_simulator')

        self.unitary_backend = Aer.get_backend('unitary_simulator')

        self.shots = shots

        if self.state == 'GHZ_teleport':
            self.a = 3
            self.b = 3
        elif measured_qubits == ():
            self.a = 0
            self.b = self.n - 1
        else:
            self.a = measured_qubits[0]
            self.b = measured_qubits[1]

        self.max_collisions = max_collisions
        self.theta = theta

        if self.max_collisions > 0:
            if self.channel == 'phase_damping_one_qubit':
                self.ancilla = QuantumRegister(1, 'a')
                self.qc.add_register(self.ancilla)
            elif not markov:
                self.ancilla = QuantumRegister(3, 'a')
                self.qc.add_register(self.ancilla)
                self.qc.h(self.ancilla[2])
                self.qc.cx(self.ancilla[2], self.ancilla[1])
                self.qc.cx(self.ancilla[1], self.ancilla[0])
            else:
                self.ancilla = QuantumRegister(self.max_collisions, 'a')
                self.qc.add_register(self.ancilla)

        if self.channel == 'amplitude_damping':
            self.U = self.amplitude_damping_operator(full)
        elif self.channel == 'phase_damping' or 'phase_damping_one_qubit':
            self.U = self.phase_damping_operator(full)
        elif self.channel == 'heisenberg':
            print('Not yet programmed')
            quit()
            self.U = self.heisenberg_operator()

        if tangle_witness:
            self.tangle_witness_GHZ = 3 / 4 * np.kron(np.kron(
                I, I), I) - self.full_theoretical_GHZ(3)
            self.tangle_witness_tri = 1 / 2 * np.kron(np.kron(
                I, I), I) - self.full_theoretical_GHZ(3)

        counts_list = []
        rho_list = []
        theoretical_rho_list = []
        concurrence_list = []
        theoretical_concurrence_list = []
        tangle_ub_list = []
        tangle_lb_list = []
        theoretical_tangle_list = []
        fidelity_list = []
        witness_list = []
        tangle_witness_GHZ_list = []
        tangle_witness_tri_list = []
        trace_squared_list = []
        for k in range(self.max_collisions + 1):
            if k > 0:
                self.collision(k)
                if witness:
                    counts = self.measure(witness)
                else:
                    rho = self.tomography(full)
                    self.evolve_theoretical_rho(full)
            else:
                if witness:
                    counts = 1 / 2
                else:
                    rho = self.tomography(full)

            if save_results:
                visual.plot_state_city(rho).savefig(
                    '{}/state_city_{}.png'.format(self.directory, k))
                visual.plot_state_paulivec(rho).savefig(
                    '{}/paulivec_{}.png'.format(self.directory, k))

            if witness:
                counts_list.append(counts)
            else:
                rho_list.append(rho)
                theoretical_rho_list.append(self.theoretical_rho)
                if not full and self.state != 'GHZ_teleport':
                    C = self.concurrence(rho)
                    concurrence_list.append(C)
                    TC = self.concurrence(self.theoretical_rho)
                    theoretical_concurrence_list.append(TC)
                if tangle:
                    T_ub = self.tangle_ub(rho)
                    tangle_ub_list.append(T_ub)
                    #T_lb = self.tangle_lb(rho)
                    #tangle_lb_list.append(T_lb)
                    if self.state == 'GHZ':
                        TT = np.exp(np.log(np.cos(self.theta)) * k)
                        theoretical_tangle_list.append(TT)
                F = state_fidelity(theoretical_rho_list[0], rho)
                fidelity_list.append(F)
                if witness:
                    W = np.real(
                        np.trace(
                            np.matmul(self.full_theoretical_GHZ(self.n), rho)))
                    witness_list.append(W)
                if tangle_witness and full:
                    TWGHZ = np.real(
                        np.trace(np.matmul(self.tangle_witness_GHZ, rho)))
                    tangle_witness_GHZ_list.append(TWGHZ)
                    TWtri = np.real(
                        np.trace(np.matmul(self.tangle_witness_tri, rho)))
                    tangle_witness_tri_list.append(TWtri)
                Tr2 = np.real(np.trace(np.matmul(rho, rho)))
                trace_squared_list.append(Tr2)

                if print_results:
                    print("Collision Number:", k)
                    print("Original Density Matrix:")
                    print(theoretical_rho_list[0])
                    print("Theoretical Density Matrix:")
                    print(self.theoretical_rho)
                    print("Measured Density Matrix:")
                    print(rho)
                    print("Trace:", np.real(np.trace(rho)))
                    print("Trace Squared:", Tr2)
                    if concurrence:
                        print("Concurrence:", C)
                        print("Theoretical Concurrence:", TC)
                    if tangle:
                        print("Tangle Upper Bound:", T_ub)
                        #print("Tangle Lower Bound:", T_lb)
                        print("Theoretical Tangle:", TT)
                    print("Fidelity:", F)
                    if witness:
                        print("Witness:", W)
                    if tangle_witness and full:
                        print("GHZ Tangle Witness:", TWGHZ)
                        print("Tripartite Tangle Witness:", TWtri)
                    print("Eigenvalues:",
                          np.sort(np.real(np.linalg.eigvals(rho)))[::-1])
                    print(
                        "\n-----------------------------------------------------------------------------------\n"
                    )

        if print_results:
            if save_results:
                visual.circuit_drawer(
                    self.qc,
                    filename='{}/constructed_circuit.png'.format(
                        self.directory),
                    output='mpl')
            else:
                print(self.qc)
            print("Constructed Circuit Depth: ", self.qc.depth())
            try:
                transpiled_qc = transpile(self.qc,
                                          self.device,
                                          optimization_level=3)
                if save_results:
                    visual.circuit_drawer(
                        transpiled_qc,
                        filename='{}/transpiled_circuit.png'.format(
                            self.directory),
                        output='mpl')
                print("Transpiled Circuit Depth: ", self.qc.depth())
            except:
                pass
            print()

        if save_results:
            visual.plot_histogram(
                self.histogram_data, title=self.state).savefig(
                    '{}/histogram.png'.format(self.directory))

        return counts_list, theoretical_rho_list, rho_list, theoretical_concurrence_list, concurrence_list, \
               theoretical_tangle_list, tangle_ub_list, tangle_lb_list, fidelity_list, witness_list, \
               tangle_witness_GHZ_list, tangle_witness_tri_list, trace_squared_list
コード例 #6
0
ファイル: measures.py プロジェクト: wbclark/qiskit-terra
def process_fidelity(channel, target=None, require_cp=True, require_tp=False):
    r"""Return the process fidelity of a noisy quantum channel.


    The process fidelity :math:`F_{\text{pro}}(\mathcal{E}, \methcal{F})`
    between two quantum channels :math:`\mathcal{E}, \mathcal{F}` is given by

    .. math:
        F_{\text{pro}}(\mathcal{E}, \mathcal{F})
            = F(\rho_{\mathcal{E}}, \rho_{\mathcal{F}})

    where :math:`F` is the :func:`~qiskit.quantum_info.state_fidelity`,
    :math:`\rho_{\mathcal{E}} = \Lambda_{\mathcal{E}} / d` is the
    normalized :class:`~qiskit.quantum_info.Choi` matrix for the channel
    :math:`\mathcal{E}`, and :math:`d` is the input dimension of
    :math:`\mathcal{E}`.

    When the target channel is unitary this is equivalent to

    .. math::
        F_{\text{pro}}(\mathcal{E}, U)
            = \frac{Tr[S_U^\dagger S_{\mathcal{E}}]}{d^2}

    where :math:`S_{\mathcal{E}}, S_{U}` are the
    :class:`~qiskit.quantum_info.SuperOp` matrices for the *input* quantum
    channel :math:`\mathcal{E}` and *target* unitary :math:`U` respectively,
    and :math:`d` is the input dimension of the channel.

    Args:
        channel (Operator or QuantumChannel): input quantum channel.
        target (Operator or QuantumChannel or None): target quantum channel.
            If `None` target is the identity operator [Default: None].
        require_cp (bool): require channel to be completely-positive
            [Default: True].
        require_tp (bool): require channel to be trace-preserving
            [Default: False].

    Returns:
        float: The process fidelity :math:`F_{\text{pro}}`.

    Raises:
        QiskitError: if the channel and target do not have the same dimensions.
        QiskitError: if the channel and target are not completely-positive
                     (with ``require_cp=True``) or not trace-preserving
                     (with ``require_tp=True``).
    """
    # Format inputs
    channel = _input_formatter(channel, SuperOp, 'process_fidelity', 'channel')
    target = _input_formatter(target, Operator, 'process_fidelity', 'target')

    if target:
        # Validate dimensions
        if channel.dim != target.dim:
            raise QiskitError(
                'Input quantum channel and target unitary must have the same '
                'dimensions ({} != {}).'.format(channel.dim, target.dim))

    # Validate complete-positivity and trace-preserving
    for label, chan in [('Input', channel), ('Target', target)]:
        if isinstance(chan, Operator) and (require_cp or require_tp):
            is_unitary = chan.is_unitary()
            # Validate as unitary
            if require_cp and not is_unitary:
                raise QiskitError(
                    '{} channel is not completely-positive'.format(label))
            if require_tp and not is_unitary:
                raise QiskitError(
                    '{} channel is not trace-preserving'.format(label))
        elif chan is not None:
            # Validate as QuantumChannel
            if require_cp and not chan.is_cp():
                raise QiskitError(
                    '{} channel is not completely-positive'.format(label))
            if require_tp and not chan.is_tp():
                raise QiskitError(
                    '{} channel is not trace-preserving'.format(label))

    if isinstance(target, Operator):
        # Compute fidelity with unitary target by applying the inverse
        # to channel and computing fidelity with the identity
        channel = channel @ target.adjoint()
        target = None

    input_dim, _ = channel.dim
    if target is None:
        # Compute process fidelity with identity channel
        if isinstance(channel, Operator):
            # |Tr[U]/dim| ** 2
            fid = np.abs(np.trace(channel.data) / input_dim)**2
        else:
            # Tr[S] / (dim ** 2)
            fid = np.trace(SuperOp(channel).data) / (input_dim**2)
        return float(np.real(fid))

    # For comparing two non-unitary channels we compute the state fidelity of
    # the normalized Choi-matrices. This is equivalent to the previous definition
    # when the target is a unitary channel.
    state1 = DensityMatrix(Choi(channel).data / input_dim)
    state2 = DensityMatrix(Choi(target).data / input_dim)
    return state_fidelity(state1, state2, validate=False)