Exemplo n.º 1
0
def su_structure_constants(d):
    '''
    Generates the structure constants corresponding to the su(d)
    basis elements. They are defined as follows:

        f_{i,j,k}=(1/(1j*d^2))*Tr[S_k*[S_i,S_j]]

        g_{i,j,k}=(1/d^2)*Tr[S_k*{S_i,S_j}]
    
    '''

    f = {}
    g = {}

    S = su_generators(d)

    for i in range(1, d**2):
        for j in range(1, d**2):
            for k in range(1, d**2):

                f[(i, j,
                   k)] = (1 /
                          (1j * d**2)) * Tr(S[k] @ (S[i] @ S[j] - S[j] @ S[i]))

                g[(i, j,
                   k)] = (1 / d**2) * Tr(S[k] @ (S[i] @ S[j] + S[j] @ S[i]))

    return f, g
Exemplo n.º 2
0
def nQubit_Pauli_coeff(X, n, return_dict=False):
    '''
    Generates the coefficients of the matrix X in the n-qubit Pauli basis.
    The coefficients c_{alpha} are such that

    X=(1/2^n)\sum_{alpha} c_alpha \sigma_alpha

    The coefficients are returned in lexicographical ordering.
    '''

    indices = list(itertools.product(*[range(0, 4)] * n))

    if return_dict:
        C = {}
    else:
        C = []

    for index in indices:
        sigma_i = generate_nQubit_Pauli(index)
        if return_dict:
            C[index] = Tr(dag(sigma_i) @ X)
        else:
            C.append(Tr(dag(sigma_i) @ X))

    return C
Exemplo n.º 3
0
def entropy(rho):

    '''
    Returns the quantum (von Neumann) entropy of the state rho.
    '''

    return -np.real(Tr(rho@logm(rho)))/np.log(2)
Exemplo n.º 4
0
def relative_entropy(rho, sigma):
    '''
    Computes the standard (von Neumann) quantum relative entropy of rho
    and sigma, provided that supp(rho) is contained in supp(sigma).
    '''

    return np.real(Tr(rho @ (logm(rho) - logm(sigma)))) / np.log(2)
Exemplo n.º 5
0
def partial_trace(X,sys,dim):

    '''
    sys is a list of systems over which to take the partial trace (i.e., the
    systems to discard).

    Example: If rho_AB is a bipartite state with dimA the dimension of system A 
    and dimB the dimension of system B, then

    partial_trace(rho_AB,[2],[dimA,dimB]) gives the density matrix on

    system A, i.e., rho_A:=partial_trace[rho_AB].

    Similarly, partial_trace(rho_AB,[1],[dimA,dimB]) discards the first subsystem,
    returning the density matrix of system B.

    If rho_ABC is a tripartite state, then, e.g.,

    partial_trace(rho_ABC,[1,3],[dimA,dimB,dimC])

    discards the first and third subsystems, so that we obtain the density
    matrix for system B.

    '''

    if isinstance(X,cvxpy.Variable):
        X=cvxpy_to_numpy(X)
        X_out=partial_trace(X,sys,dim)
        return numpy_to_cvxpy(X_out)


    if not sys:  # If sys is empty, just return the original operator
        return X
    elif len(sys)==len(dim):  # If tracing over all systems
        return Tr(X)
    else:

        if X.shape[1]==1:
            X=X@dag(X)

        num_sys=len(dim)
        total_sys=range(1,num_sys+1)

        dims_sys=[dim[s-1] for s in sys] # Dimensions of the system to be traced over
        dims_keep=[dim[s-1] for s in list(set(total_sys)-set(sys))]
        dim_sys=np.product(dims_sys)
        dim_keep=np.product(dims_keep)

        perm=sys+list(set(total_sys)-set(sys))
        X=syspermute(X,perm,dim)

        X=np.array(X)
        dim=[dim_sys]+dims_keep
        X_reshape=np.reshape(X,dim+dim)
        X_reshape=np.sum(np.diagonal(X_reshape,axis1=0,axis2=len(dim)),axis=-1)
        X=np.reshape(X_reshape,(dim_keep,dim_keep))

        return X
Exemplo n.º 6
0
def ent_fidelity(sigma, d):
    '''
    Finds the fidelity between the state sigma and the Bell state.
    d is the dimension.
    '''

    Bell = MaxEnt_state(d, density_matrix=True)

    return np.real(Tr(Bell @ sigma))
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
Exemplo n.º 8
0
    def objfunc(x):

        Re = np.array(x[0:dim**3])
        Im = np.array(x[dim**3:])

        psi = np.array([Re + 1j * Im]).T
        psi = psi / norm(psi)

        p = []
        S = []

        for j in range(dim**2):
            R = tensor(dag(ket(dim**2, j)), eye(dim)) @ (
                psi @ dag(psi)) @ tensor(ket(dim**2, j), eye(dim))
            p.append(Tr(R))
            rho = R / Tr(R)
            rho_out = apply_channel(K, rho)
            S.append(rho_out)

        return -np.real(Holevo_inf_ensemble(p, S))
Exemplo n.º 9
0
def ent_fidelity_channel(K, d):
    '''
    Finds the entanglement fidelity of the channel given by the set K of 
    Kraus operators. d is the dimension of the input space.
    '''

    Bell = MaxEnt_state(d)

    K_choi = (1. / d) * Choi_representation(K, d)

    return np.real(Tr((Bell) @ K_choi))
Exemplo n.º 10
0
def Petz_Renyi_rel_ent(rho, sigma, alpha):
    '''
    Computes the Petz-Renyi relative entropy of rho and sigma for 0<=alpha<=1.
    '''

    rho_a = fractional_matrix_power(rho, alpha)
    sigma_a = fractional_matrix_power(sigma, 1 - alpha)

    Q = np.real(Tr(rho_a @ sigma_a))

    return (1. / (alpha - 1)) * np.log2(Q)
Exemplo n.º 11
0
def relative_entropy_var(rho, sigma):
    '''
    Returns the relative entropy variance of rho and sigma, defined as

    V(rho||sigma)=Tr[rho*(log2(rho)-log2(sigma))^2]-D(rho||sigma)^2.
    '''

    return np.real(
        Tr(rho @ matrix_power(
            (logm(rho)) / np.log(2) -
            (logm(sigma)) / np.log(2), 2))) - relative_entropy(rho, sigma)**2
Exemplo n.º 12
0
def sandwiched_Renyi_rel_ent(rho,sigma,alpha):

    '''
    Computes the sandwiched Renyi relative entropy for either 0<=alpha<=1,
    or for alpha>=1 provided that supp(rho) is contained in supp(sigma).
    '''

    sigma_a=np.matrix(fractional_matrix_power(sigma,(1.-alpha)/(2*alpha)))

    Q=np.real(Tr(fractional_matrix_power(sigma_a@rho@sigma_a,alpha)))

    return (1./(alpha-1))*np.log2(Q)
Exemplo n.º 13
0
def isotropic_twirl_state(X,d):

    '''
    Applies the twirling channel

        X -> ∫ (U ⊗ conj(U))*X*(U ⊗ conj(U)).H dU

    to the input operator X acting on two d-dimensional systems.

    For d=2, this is equivalent to

        X -> (1/24)*sum_i (c_i ⊗ conj(c_i))*X*(c_i ⊗ conj(c_i)).H

    where the unitaries c_i form the one-qubit Clifford group (because the Clifford
    unitaries constitute a unitary 2-design).

    This channel takes any state rho and converts it to an isotropic state with
    the same fidelity to the maximally entangled state as rho.
    '''

    G=MaxEnt_state(d,normalized=False,density_matrix=True)

    return (Tr(X)/(d**2-1)-Tr(G@X)/(d*(d**2-1)))*eye(d**2)+(Tr(G@X)/(d**2-1)-Tr(X)/(d*(d**2-1)))@G
Exemplo n.º 14
0
def unitary_distance(U, V):
    '''
    Checks whether two unitaries U and V are the same (taking into account global phase) by using the distance measure:
    
    1-(1/d)*|Tr[UV^†]|,
    
    where d is the dimension of the space on which the unitaries act.
    
    U and V are the same if and only if this is equal to zero; otherwise, it is greater than zero.
    '''

    d = U.shape[0]

    return 1 - (1 / d) * np.abs(Tr(U @ dag(V)))
Exemplo n.º 15
0
def trace_distance_pure_states(psi, phi):
    '''
    Computes the squared trace distance between two pure states psi and phi,
    i.e.,

    || |psi><psi|-|phi><phi| ||_1^2

    '''

    if psi.shape[1] == 1:
        psi = psi @ dag(psi)
    if phi.shape[1] == 1:
        phi = phi @ dag(phi)

    return 1 - Tr(psi * phi)
Exemplo n.º 16
0
def Werner_twirl_state(X, d):
    '''
    Applies the twirling channel

        X -> ∫ (U ⊗ U)*rho*(U ⊗ U).H dU

    to the input operator X acting on two d-dimensional systems.

    For d=2, this is equivalent to

        X -> (1/24)*sum_i (c_i ⊗ c_i)*X*(c_i ⊗ c_i).H

    where the unitaries c_i form the one-qubit Clifford group (because the Clifford
    unitaries constitute a unitary 2-design).

    This channel takes any state rho and converts it to a Werner state with
    the same fidelity to the singlet state as rho.
    '''

    F = SWAP([1, 2], [d, d])

    return (Tr(X) / (d**2 - 1) - Tr(F @ X) /
            (d * (d**2 - 1))) * eye(d**2) + (Tr(F @ X) / (d**2 - 1) - Tr(X) /
                                             (d * (d**2 - 1))) @ F
Exemplo n.º 17
0
def cov_matrix_fermi(X, n, rep='JW'):
    '''
    Generates the covariance matrix associated with the operator X. The underlying
    calculations are done using the specified representation, although the matrix
    itself is independent of the representation used for the calculation.
    '''

    G = np.zeros((2 * n, 2 * n), dtype=complex)

    _, c = jordan_wigner(n)

    for j in range(1, 2 * n + 1):
        for k in range(1, 2 * n + 1):
            G[j - 1, k - 1] = (1j / 2) * Tr(X @ (c[j] @ c[k] - c[k] @ c[j]))

    return G
Exemplo n.º 18
0
def nQubit_mean_vector(X, n):
    '''
    Using the n-qubit quadrature operators, we define the n-qubit "mean vector" as
    follows:

        r_i=Tr[X*S_i]
    '''

    S = nQubit_quadratures(n)

    r = np.array(np.zeros((2 * n, 1)), dtype=np.complex128)

    for i in range(2 * n):
        r[i, 0] = Tr(X @ S[i + 1])

    return r
Exemplo n.º 19
0
def nQubit_cov_matrix(X, n):
    '''
    Using the n-qubit quadrature operators, we define the n-qubit "covariance matrix"
    as follows:

    V_{i,j}=Tr[X*S_i*S_j]
    '''

    S = nQubit_quadratures(n)

    V = np.array(np.zeros((2 * n, 2 * n)), dtype=np.complex128)

    for i in range(2 * n):
        for j in range(2 * n):
            V[i, j] = Tr(X @ S[i + 1] @ S[j + 1])

    return V
Exemplo n.º 20
0
def nQudit_Weyl_coeff(X, d, n):
    '''
    Generates the coefficients of the operator X acting on n qudit
    systems.
    '''

    C = {}

    S = list(itertools.product(*[range(0, d)] * n))

    for s in S:
        s = list(s)
        for t in S:
            t = list(t)
            G = generate_nQudit_X(d, s) @ generate_nQudit_Z(d, t)
            C[(str(s), str(t))] = np.around(Tr(dag(X) @ G), 10)

    return C
Exemplo n.º 21
0
def RandomDensityMatrix(dim, *args):
    '''
    Generates a random density matrix.
    
    Optional argument is for the rank r of the state.
    
    Optional argument comp is for whether the state should have
    complex entries
    '''

    args = np.array(args)

    if args.size == 0:
        r = dim
    else:
        r = args[0]

    gin = np.random.randn(dim, r) + 1j * np.random.randn(dim, r)
    rho = gin @ dag(gin)

    return rho / Tr(rho)
Exemplo n.º 22
0
def avg_fidelity_qubit(K):
    '''
    K is the set of Kraus operators for the (qubit to qubit) channel whose
    average fidelity is to be found.
    '''

    ket0 = ket(2, 0)
    ket1 = ket(2, 1)
    ket_plus = (1. / np.sqrt(2)) * (ket0 + ket1)
    ket_minus = (1. / np.sqrt(2)) * (ket0 - ket1)
    ket_plusi = (1. / np.sqrt(2)) * (ket0 + 1j * ket1)
    ket_minusi = (1. / np.sqrt(2)) * (ket0 - 1j * ket1)

    states = [ket0, ket1, ket_plus, ket_minus, ket_plusi, ket_minusi]

    F = 0

    for state in states:

        F += np.real(
            Tr((state @ dag(state)) * apply_channel(K, state @ dag(state))))

    return (1. / 6.) * F