Пример #1
0
def entangling_power(U):
    """
    Calculate the entangling power of a two-qubit gate U, which
    is zero of nonentangling gates and 1 and 2/9 for maximally
    entangling gates.

    Parameters
    ----------
    U : qobj
        Qobj instance representing a two-qubit gate.

    Returns
    -------
    ep : float
        The entanglement power of U (real number between 0 and 1)

    References:

        Explorations in Quantum Computing, Colin P. Williams (Springer, 2011)
    """

    if not U.isoper:
        raise Exception("U must be an operator.")

    if U.dims != [[2, 2], [2, 2]]:
        raise Exception("U must be a two-qubit gate.")

    from qutip.qip.operations.gates import swap
    a = (tensor(U, U).dag() * swap(N=4, targets=[1, 3]) *
         tensor(U, U) * swap(N=4, targets=[1, 3]))
    b = (tensor(swap() * U, swap() * U).dag() * swap(N=4, targets=[1, 3]) *
         tensor(swap() * U, swap() * U) * swap(N=4, targets=[1, 3]))

    return 5.0/9 - 1.0/36 * (a.tr() + b.tr()).real
Пример #2
0
def qft_steps(N=1, swapping=True):
    """
    Quantum Fourier Transform operator on N qubits returning the individual
    steps as unitary matrices operating from left to right.

    Parameters
    ----------
    N: int
        Number of qubits.
    swap: boolean
        Flag indicating sequence of swap gates to be applied at the end or not.

    Returns
    -------
    U_step_list: list of qobj
        List of Hadamard and controlled rotation gates implementing QFT.

    """
    if N < 1:
        raise ValueError("Minimum value of N can be 1")

    U_step_list = []
    if N == 1:
        U_step_list.append(snot())
    else:
        for i in range(N):
            for j in range(i):
                U_step_list.append(
                    cphase(np.pi / (2**(i - j)), N, control=i, target=j))
            U_step_list.append(snot(N, i))
        if swapping:
            for i in range(N // 2):
                U_step_list.append(swap(N, [N - i - 1, i]))

    return U_step_list
Пример #3
0
def swap_map(x):
    W = swap()
    S = (1j * x * W).expm()
    S._type = None
    S.dims = [[[2], [2]], [[2], [2]]]
    S.superrep = 'super'
    return S
Пример #4
0
 def test_swap(self):
     states = [qutip.rand_ket(2) for _ in [None]*2]
     start = qutip.tensor(states)
     swapped = qutip.tensor(states[::-1])
     swap = gates.swap()
     assert _infidelity(swapped, swap*start) < 1e-12
     assert _infidelity(start, swap*swap*start) < 1e-12
Пример #5
0
    def testExpandGate2toNSwap(self):
        """
        gates: expand 2 to N (using swap)
        """

        a, b = np.random.rand(), np.random.rand()
        k1 = (a * basis(2, 0) + b * basis(2, 1)).unit()

        c, d = np.random.rand(), np.random.rand()
        k2 = (c * basis(2, 0) + d * basis(2, 1)).unit()

        N = 6
        kets = [rand_ket(2) for k in range(N)]

        for m in range(N):
            for n in set(range(N)) - {m}:

                psi_in = tensor([
                    k1 if k == m else k2 if k == n else kets[k]
                    for k in range(N)
                ])
                psi_out = tensor([
                    k2 if k == m else k1 if k == n else kets[k]
                    for k in range(N)
                ])

                targets = [m, n]
                G = swap(N, targets)

                psi_out = G * psi_in

                assert_((psi_out - G * psi_in).norm() < 1e-12)
Пример #6
0
    def testSwapGate(self):
        """
        gates: swap gate
        """
        a, b = np.random.rand(), np.random.rand()
        psi1 = (a * basis(2, 0) + b * basis(2, 1)).unit()

        c, d = np.random.rand(), np.random.rand()
        psi2 = (c * basis(2, 0) + d * basis(2, 1)).unit()

        psi_in = tensor(psi1, psi2)
        psi_out = tensor(psi2, psi1)

        psi_res = swap() * psi_in
        assert_((psi_out - psi_res).norm() < 1e-12)

        psi_res = swap() * swap() * psi_in
        assert_((psi_in - psi_res).norm() < 1e-12)
Пример #7
0
def test_EntanglingPower():
    "Entropy: Entangling power"
    assert_(abs(entangling_power(cnot()) - 2 / 9) < 1e-12)
    assert_(abs(entangling_power(iswap()) - 2 / 9) < 1e-12)
    assert_(abs(entangling_power(berkeley()) - 2 / 9) < 1e-12)
    assert_(abs(entangling_power(sqrtswap()) - 1 / 6) < 1e-12)
    alpha = 2 * np.pi * np.random.rand()
    assert_(
        abs(
            entangling_power(swapalpha(alpha)) -
            1 / 6 * np.sin(np.pi * alpha)**2) < 1e-12)
    assert_(abs(entangling_power(swap()) - 0) < 1e-12)
Пример #8
0
    def test_known_iscptp(self):
        """
        Superoperator: ishp, iscp, istp and iscptp known cases.
        """
        def case(qobj, shouldhp, shouldcp, shouldtp):
            hp = qobj.ishp
            cp = qobj.iscp
            tp = qobj.istp
            cptp = qobj.iscptp

            shouldcptp = shouldcp and shouldtp

            if (hp == shouldhp and cp == shouldcp and tp == shouldtp
                    and cptp == shouldcptp):
                return

            fails = []
            if hp != shouldhp:
                fails.append(("ishp", shouldhp, hp))
            if tp != shouldtp:
                fails.append(("istp", shouldtp, tp))
            if cp != shouldcp:
                fails.append(("iscp", shouldcp, cp))
            if cptp != shouldcptp:
                fails.append(("iscptp", shouldcptp, cptp))

            raise AssertionError("Expected {}.".format(" and ".join([
                "{} == {} (got {})".format(fail, expected, got)
                for fail, expected, got in fails
            ])))

        # Conjugation by a creation operator should
        # have be CP (and hence HP), but not TP.
        a = create(2).dag()
        S = sprepost(a, a.dag())
        case(S, True, True, False)

        # A single off-diagonal element should not be CP,
        # nor even HP.
        S = sprepost(a, a)
        case(S, False, False, False)

        # Check that unitaries are CPTP and HP.
        case(identity(2), True, True, True)
        case(sigmax(), True, True, True)

        # Check that unitaries on bipartite systems are CPTP and HP.
        case(tensor(sigmax(), identity(2)), True, True, True)

        # Check that a linear combination of bipartitie unitaries is CPTP and HP.
        S = (to_super(tensor(sigmax(), identity(2))) +
             to_super(tensor(identity(2), sigmay()))) / 2
        case(S, True, True, True)

        # The partial transpose map, whose Choi matrix is SWAP, is TP
        # and HP but not CP (one negative eigenvalue).
        W = Qobj(swap(), type='super', superrep='choi')
        case(W, True, False, True)

        # Subnormalized maps (representing erasure channels, for instance)
        # can be CP but not TP.
        subnorm_map = Qobj(identity(4) * 0.9, type='super', superrep='super')
        case(subnorm_map, True, True, False)

        # Check that things which aren't even operators aren't identified as
        # CPTP.
        case(basis(2), False, False, False)
Пример #9
0
msg = (qt.basis(2, 0) + qt.basis(2, 1)).unit()
state = qt.tensor(msg, TFD)

XYZ_msg = {"I": qt.tensor(qt.identity(2), IDrest),\
           "X": qt.tensor(qt.sigmax(), IDrest),\
           "Y": qt.tensor(qt.sigmay(), IDrest),\
           "Z": qt.tensor(qt.sigmaz(), IDrest)}

XYZ_L_ = dict([(op_name, qt.tensor(qt.identity(2), op))
               for op_name, op in XYZ_L.items()])
XYZ_R_ = dict([(op_name, qt.tensor(qt.identity(2), op))
               for op_name, op in XYZ_R.items()])

P = pauli_basis(2)
SWAP = swap(N=2, targets=[0, 1])
SWAPc = op_coeffs(SWAP, P)
INSERT = sum([
    coeff * XYZ_msg[op_name[0]] * XYZ_L_[op_name[1]]
    for op_name, coeff in SWAPc.items()
])

HL_ = qt.tensor(qt.identity(2), HL)
HR_ = qt.tensor(qt.identity(2), HR)
SIZE = qt.tensor(qt.identity(2), sum([cf_.dag() * cf_ for cf_ in cf[2:]]))


def wormhole(state, g, t=10):
    global HL, HR, SIZE
    return (-1j * HR_ * t).expm() * (1j * g * SIZE).expm() * (
        -1j * HL_ * t).expm() * INSERT * (1j * HL_ * t).expm() * state
Пример #10
0
class TestSuperopReps:
    """
    A test class for the QuTiP function for applying superoperators to
    subsystems.
    """
    def test_SuperChoiSuper(self, superoperator):
        """
        Superoperator: Converting superoperator to Choi matrix and back.
        """

        choi_matrix = to_choi(superoperator)
        test_supe = to_super(choi_matrix)

        # Assert both that the result is close to expected, and has the right
        # type.
        assert (test_supe - superoperator).norm() < tol
        assert choi_matrix.type == "super" and choi_matrix.superrep == "choi"
        assert test_supe.type == "super" and test_supe.superrep == "super"

    @pytest.mark.parametrize('dimension', [2, 4])
    def test_SuperChoiChiSuper(self, dimension):
        """
        Superoperator: Converting two-qubit superoperator through
        Choi and chi representations goes back to right superoperator.
        """
        superoperator = super_tensor(
            rand_super(dimension),
            rand_super(dimension),
        )

        choi_matrix = to_choi(superoperator)
        chi_matrix = to_chi(choi_matrix)
        test_supe = to_super(chi_matrix)

        # Assert both that the result is close to expected, and has the right
        # type.
        assert (test_supe - superoperator).norm() < tol
        assert choi_matrix.type == "super" and choi_matrix.superrep == "choi"
        assert chi_matrix.type == "super" and chi_matrix.superrep == "chi"
        assert test_supe.type == "super" and test_supe.superrep == "super"

    def test_ChoiKrausChoi(self, superoperator):
        """
        Superoperator: Convert superoperator to Choi matrix and back.
        """
        choi_matrix = to_choi(superoperator)
        kraus_ops = to_kraus(choi_matrix)
        test_choi = kraus_to_choi(kraus_ops)

        # Assert both that the result is close to expected, and has the right
        # type.
        assert (test_choi - choi_matrix).norm() < tol
        assert choi_matrix.type == "super" and choi_matrix.superrep == "choi"
        assert test_choi.type == "super" and test_choi.superrep == "choi"

    def test_NonSquareKrausSuperChoi(self):
        """
        Superoperator: Convert non-square Kraus operator to Super + Choi matrix
        and back.
        """
        zero = asarray([[1], [0]], dtype=complex)
        one = asarray([[0], [1]], dtype=complex)
        zero_log = kron(kron(zero, zero), zero)
        one_log = kron(kron(one, one), one)
        # non-square Kraus operator (isometry)
        kraus = Qobj(zero_log @ zero.T + one_log @ one.T)
        super = sprepost(kraus, kraus.dag())
        choi = to_choi(super)
        op1 = to_kraus(super)
        op2 = to_kraus(choi)
        op3 = to_super(choi)

        assert choi.type == "super" and choi.superrep == "choi"
        assert super.type == "super" and super.superrep == "super"
        assert (op1[0] - kraus).norm() < tol
        assert (op2[0] - kraus).norm() < tol
        assert (op3 - super).norm() < tol

    def test_NeglectSmallKraus(self):
        """
        Superoperator: Convert Kraus to Choi matrix and back. Neglect tiny
        Kraus operators.
        """
        zero = asarray([[1], [0]], dtype=complex)
        one = asarray([[0], [1]], dtype=complex)
        zero_log = kron(kron(zero, zero), zero)
        one_log = kron(kron(one, one), one)
        # non-square Kraus operator (isometry)
        kraus = Qobj(zero_log @ zero.T + one_log @ one.T)
        super = sprepost(kraus, kraus.dag())
        # 1 non-zero Kraus operator the rest are zero
        sixteen_kraus_ops = to_kraus(super, tol=0.0)
        # default is tol=1e-9
        one_kraus_op = to_kraus(super)
        assert len(sixteen_kraus_ops) == 16 and len(one_kraus_op) == 1
        assert (one_kraus_op[0] - kraus).norm() < tol

    def test_SuperPreservesSelf(self, superoperator):
        """
        Superoperator: to_super(q) returns q if q is already a
        supermatrix.
        """

        assert superoperator is to_super(superoperator)

    def test_ChoiPreservesSelf(self, superoperator):
        """
        Superoperator: to_choi(q) returns q if q is already Choi.
        """
        choi = to_choi(superoperator)
        assert choi is to_choi(choi)

    def test_random_iscptp(self, superoperator):
        """
        Superoperator: Randomly generated superoperators are
        correctly reported as CPTP and HP.
        """
        assert superoperator.iscptp
        assert superoperator.ishp

    # Conjugation by a creation operator
    a = create(2).dag()
    S = sprepost(a, a.dag())

    # A single off-diagonal element
    S_ = sprepost(a, a)

    # Check that a linear combination of bipartite unitaries is CPTP and HP.
    S_U = (to_super(tensor(sigmax(), identity(2))) +
           to_super(tensor(identity(2), sigmay()))) / 2

    # The partial transpose map, whose Choi matrix is SWAP
    ptr_swap = Qobj(swap(), type='super', superrep='choi')

    # Subnormalized maps (representing erasure channels, for instance)
    subnorm_map = Qobj(identity(4) * 0.9, type='super', superrep='super')

    @pytest.mark.parametrize(['qobj', 'shouldhp', 'shouldcp', 'shouldtp'], [
        pytest.param(S, True, True, False, id="conjugatio by create op"),
        pytest.param(S_, False, False, False, id="single off-diag"),
        pytest.param(identity(2), True, True, True, id="Identity"),
        pytest.param(sigmax(), True, True, True, id="Pauli X"),
        pytest.param(
            tensor(sigmax(), identity(2)),
            True,
            True,
            True,
            id="bipartite system",
        ),
        pytest.param(
            S_U,
            True,
            True,
            True,
            id="linear combination of bip. unitaries",
        ),
        pytest.param(ptr_swap, True, False, True, id="partial transpose map"),
        pytest.param(subnorm_map, True, True, False, id="subnorm map"),
        pytest.param(basis(2), False, False, False, id="not an operator"),
    ])
    def test_known_iscptp(self, qobj, shouldhp, shouldcp, shouldtp):
        """
        Superoperator: ishp, iscp, istp and iscptp known cases.
        """
        assert qobj.ishp == shouldhp
        assert qobj.iscp == shouldcp
        assert qobj.istp == shouldtp
        assert qobj.iscptp == (shouldcp and shouldtp)

    def test_choi_tr(self, dimension):
        """
        Superoperator: Trace returned by to_choi matches docstring.
        """
        assert abs(to_choi(identity(dimension)).tr() - dimension) <= tol

    def test_stinespring_cp(self, dimension):
        """
        Stinespring: A and B match for CP maps.
        """
        superop = rand_super_bcsz(dimension)
        A, B = to_stinespring(superop)

        assert norm(A - B) < tol

    @pytest.mark.repeat(3)
    def test_stinespring_agrees(self, dimension):
        """
        Stinespring: Partial Tr over pair agrees w/ supermatrix.
        """

        map = rand_super_bcsz(dimension)
        state = rand_dm_ginibre(dimension)

        S = to_super(map)
        A, B = to_stinespring(map)

        q1 = vector_to_operator(S * operator_to_vector(state))
        # FIXME: problem if Kraus index is implicitly
        #        ptraced!
        q2 = (A * state * B.dag()).ptrace((0, ))

        assert (q1 - q2).norm('tr') <= tol

    def test_stinespring_dims(self, dimension):
        """
        Stinespring: Check that dims of channels are preserved.
        """
        chan = super_tensor(to_super(sigmax()), to_super(qeye(dimension)))
        A, B = to_stinespring(chan)
        assert A.dims == [[2, dimension, 1], [2, dimension]]
        assert B.dims == [[2, dimension, 1], [2, dimension]]

    @pytest.mark.parametrize('dimension', [2, 4, 8])
    def test_chi_choi_roundtrip(self, dimension):

        superop = rand_super_bcsz(dimension)
        superop = to_chi(superop)
        rt_superop = to_chi(to_choi(superop))
        dif = norm(rt_superop - superop)

        assert dif == pytest.approx(0, abs=1e-7)
        assert rt_superop.type == superop.type
        assert rt_superop.dims == superop.dims

    chi_sigmax = [[0, 0, 0, 0], [0, 4, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
    chi_diag2 = [[4, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
    rotX_pi_4 = (-1j * sigmax() * pi / 4).expm()
    chi_rotX_pi_4 = [[2, 2j, 0, 0], [-2j, 2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

    @pytest.mark.parametrize(['superop', 'chi_expected'], [
        pytest.param(sigmax(), chi_sigmax),
        pytest.param(to_super(sigmax()), chi_sigmax),
        pytest.param(qeye(2), chi_diag2),
        pytest.param(rotX_pi_4, chi_rotX_pi_4)
    ])
    def test_chi_known(self, superop, chi_expected):
        """
        Superoperator: Chi-matrix for known cases is correct.
        """
        chi_actual = to_chi(superop)
        chiq = Qobj(
            chi_expected,
            dims=[[[2], [2]], [[2], [2]]],
            superrep='chi',
        )
        assert (chi_actual - chiq).norm() < tol