Beispiel #1
0
def mutual_information(rhoAB, dimA, dimB):
    '''
    Computes the mutual information of the bipartite state rhoAB, defined as

    I(A;B)_rho=D(rhoAB||rhoA\otimes rhoB)
    '''

    rhoA = partial_trace(rhoAB, [2], [dimA, dimB])
    rhoB = partial_trace(rhoAB, [1], [dimA, dimB])

    return relative_entropy(rhoAB, tensor(rhoA, rhoB))
def coherent_inf_state(rho_AB,dimA,dimB,s=1):

    '''
    Calculates the coherent information of the state rho_AB.

    If s=2, then calculates the reverse coherent information.
    '''

    if s==1: # Calculate I_c(A>B)=H(B)-H(AB)
        rho_B=partial_trace(rho_AB,[1],[dimA,dimB])
        return entropy(rho_B)-entropy(rho_AB)
    else: # Calculate I_c(B>A)=H(A)- H(AB) (AKA reverse coherent information)
        rho_A=partial_trace(rho_AB,[2],[dimA,dimB])
        return entropy(rho_A)-entropy(rho_AB)
Beispiel #3
0
def Petz_Renyi_mut_inf_state(rhoAB, dimA, dimB, alpha, opt=True):
    '''
    Computes the Petz-Renyi mutual information of the bipartite state
    rhoAB for 0<=alpha<=1.

    TO DO: Figure out how to do the computation with optimization over sigmaB.
    '''

    rhoA = partial_trace(rhoAB, [2], [dimA, dimB])
    rhoB = partial_trace(rhoAB, [1], [dimA, dimB])

    if opt == False:
        return Petz_Renyi_rel_ent(rhoAB, tensor(rhoA, rhoB), alpha)
    else:
        return None
Beispiel #4
0
def check_kext(rhoAB, dimA, dimB, k, display=False):
    '''
    Checks if the bipartite state rhoAB is k-extendible.
    '''

    all_sys = list(range(1, k + 2))
    dim = [dimA] + [dimB] * k

    t = cvx.Variable()
    R = cvx.Variable((dimA * dimB**k, dimA * dimB**k), hermitian=True)

    obj = cvx.Maximize(t)

    c = [R - t * eye(dimA * dimB**k) >> 0]

    for j in range(2, k + 2):

        sys = list(np.setdiff1d(all_sys, [1, j]))

        R_ABj = partial_trace(R, sys, dim)

        c.append(R_ABj == rhoAB)

    prob = cvx.Problem(obj, constraints=c)

    prob.solve(verbose=display)

    return prob.value, R.value
def entanglement_distillation(rho1,
                              rho2,
                              outcome=1,
                              twirl_after=False,
                              normalize=False):
    '''
    Applies a particular entanglement distillation channel to the two two-qubit states
    rho1 and rho2. [PRL 76, 722 (1996)]

    The channel is probabilistic. If the variable outcome=1, then the function returns
    the two-qubit state conditioned on the success of the distillation protocol.
    '''

    CNOT = CNOT_ij(1, 2, 2)
    proj0 = ket(2, 0) @ dag(ket(2, 0))
    proj1 = ket(2, 1) @ dag(ket(2, 1))

    P0 = tensor(eye(2), proj0, eye(2), proj0)
    P1 = tensor(eye(2), proj1, eye(2), proj1)
    P2 = eye(16) - P0 - P1
    C = tensor(CNOT, CNOT)
    K0 = P0 * C
    K1 = P1 * C
    K2 = P2 * C

    rho_in = syspermute(tensor(rho1, rho2), [1, 3, 2, 4],
                        [2, 2, 2, 2])  # rho_in==rho_{A1A2B1B2}

    if outcome == 1:
        # rho_out is unnormalized. The trace of rho_out is equal to the success probability.
        rho_out = partial_trace(K0 @ rho_in @ dag(K0) + K1 @ rho_in @ dag(K1),
                                [2, 4], [2, 2, 2, 2])
        if twirl_after:
            rho_out = isotropic_twirl_state(rho_out, 2)
        if normalize:
            rho_out = rho_out / Tr(rho_out)

    elif outcome == 0:
        # rho_out is unnormalized. The trace of rho_out is equal to the failure probability.
        rho_out = partial_trace(K2 @ rho_in @ dag(K2), [2, 4], [2, 2, 2, 2])
        if normalize:
            rho_out = rho_out / Tr(rho_out)

    return rho_out
Beispiel #6
0
def apply_ent_swap_GHZ_chain_channel(rho, n):
    '''
    Applies the channel that takes n+1 copies of a maximally entangled state and outputs
    a (n+2)-party GHZ state. The input state rho is of the form

        rho_{A R11 R12 R21 R22 ... Rn1 Rn2 B}

    A CNOT is applies to each pair Rj1 Rj2. Then, the qubits Rj2 are measured in the
    standard basis. Conditioned on these outcomes, a correction operation is applied
    at B.

    Currently only works for qubits. For n=1, we get the same thing as apply_ent_swap_GHZ_channel().
    '''
    def K(j, x):

        # j is between 1 and n, denoting the pair of R systems. x is either 0 or 1.
        # For each j, the qubit indices are 2*j and 2*j+1 for the pair Rj1 and Rj2

        Mx = tensor(eye(2), eye(2**(2 * j - 2)), eye(2),
                    ket(2, x) @ dag(ket(2, x)), eye(2**(2 * (n - j))), eye(2))

        C = CNOT_ij(2 * j, 2 * j + 1, 2 * n + 2)

        X = 1j * Rx_i(2 * j + 2, np.pi, 2 * n + 2)

        return Mx @ C @ matrix_power(X, x)

    indices = list(itertools.product(*[range(2)] * n))

    rho_out = np.array(
        np.zeros((2**(2 * n + 2), 2**(2 * n + 2)), dtype=complex))

    for index in indices:
        index = list(index)

        L = K(1, index[0])
        for j in range(2, n + 1):
            L = K(j, index[j - 1]) @ L

        rho_out = rho_out + L @ rho @ dag(L)

    rho_out = partial_trace(rho_out, [2 * j + 1 for j in range(1, n + 1)],
                            [2] * (2 * n + 2))

    return rho_out
Beispiel #7
0
def depolarizing_channel_n_uses(p,n,rho,m):


    '''
    Generates the output state corresponding to the depolarizing channel
    applied to each one of n systems in the joint state rho. p is the 
    depolarizing probability as defined in the function "depolarizing_channel"
    above.

    If rho contains m>n systems, then the first m-n systems are left alone.
    '''

    dims=2*np.ones(m).astype(int)

    rho_out=np.zeros((2**m,2**m))

    for k in range(n+1):
        indices=list(itertools.combinations(range(1,n+1),k))

        #print k,indices

        for index in indices:
            index=list(index)

            index=np.array(index)+(m-n)
            index=list(index.astype(int))

            index_diff=np.setdiff1d(range(1,m+1),index)

            perm_arrange=np.append(index,index_diff).astype(int)
            perm_rearrange=np.zeros(m)

            for i in range(m):
                perm_rearrange[i]=np.argwhere(perm_arrange==i+1)[0][0]+1

            perm_rearrange=perm_rearrange.astype(int)

            mix=matrix_power(eye(2**k)/2,k)

            rho_part=partial_trace(rho,index,dims)

            rho_out=rho_out+(4*p/3.)**k*(1-(4*p/3.))**(n-k)*syspermute(tensor(mix,rho_part),perm_rearrange,dims)

    return rho_out
Beispiel #8
0
def channel_discrimination(J0,
                           J1,
                           dimA,
                           dimB,
                           p,
                           succ=False,
                           sdp=False,
                           dual=False,
                           display=False):
    '''
    Calculates the optimal error probability for quantum channel discrimination, with prior
    probability p for the channel with Choi representation J1.

    J0 and J1 are the Choi representations of the two channels. dimA and dimB are the input
    and output dimensions, respectively, of the channels.

    If succ=True, then this function returns the optimal success probability instead.
    If sdp=True, then this function calculates the optimal value (error or success 
    probability) using an SDP.
    '''

    if sdp:

        if not dual:

            # Need the following syspermute because the cvxpy kron function
            # requires a constant in the first argument
            J0 = syspermute(J0, [2, 1], [dimA, dimB])
            J1 = syspermute(J1, [2, 1], [dimA, dimB])

            Q0 = cvx.Variable((dimA * dimB, dimA * dimB), hermitian=True)
            Q1 = cvx.Variable((dimA * dimB, dimA * dimB), hermitian=True)
            rho = cvx.Variable((dimA, dimA), hermitian=True)

            c = [
                Q0 >> 0, Q1 >> 0, rho >> 0,
                cvx.real(cvx.trace(rho)) == 1,
                Q0 + Q1 == cvx.kron(eye(dimB), rho)
            ]

            obj = cvx.Minimize(
                cvx.real(p * cvx.trace(Q1 @ J0) +
                         (1 - p) * cvx.trace(Q0 @ J1)))
            prob = cvx.Problem(obj, constraints=c)

            prob.solve(verbose=display, eps=1e-7)

            p_err = prob.value

            if succ:
                return 1 - p_err
            else:
                return p_err

        elif dual:

            mu = cvx.Variable()
            W = cvx.Variable((dimA * dimB, dimA * dimB), hermitian=True)

            WA = numpy_to_cvxpy(
                partial_trace(cvxpy_to_numpy(W), [2], [dimA, dimB]))

            c = [W << p * J0, W << (1 - p) * J1, mu * eye(dimA) << WA]

            obj = cvx.Maximize(mu)
            prob = cvx.Problem(obj, constraints=c)

            prob.solve(verbose=display, eps=1e-7)

            p_err = prob.value

            if succ:
                return 1 - p_err
            else:
                return p_err

    else:
        p_err = (1 / 2) * (1 - diamond_norm(
            p * J0 - (1 - p) * J1, dimA, dimB, display=display))
        if succ:
            return 1 - p_err
        else:
            return p_err