Пример #1
0
def test_ghz_2_3():
    """Produces the 3-qubit GHZ state: `1/sqrt(2) * (|000> + |111>)`."""
    e_0, e_1 = basis(2, 0), basis(2, 1)
    expected_res = 1 / np.sqrt(2) * (tensor(e_0, e_0, e_0) +
                                     tensor(e_1, e_1, e_1))

    res = ghz(2, 3).toarray()

    bool_mat = np.isclose(res, expected_res)
    np.testing.assert_equal(np.all(bool_mat), True)
Пример #2
0
def test_w_state_3():
    """The 3-qubit W-state."""
    e_0, e_1 = basis(2, 0), basis(2, 1)
    expected_res = (1 / np.sqrt(3) *
                    (tensor(e_1, e_0, e_0) + tensor(e_0, e_1, e_0) +
                     tensor(e_0, e_0, e_1)))

    res = w_state(3)

    bool_mat = np.isclose(res, expected_res, atol=0.2)
    np.testing.assert_equal(np.all(bool_mat), True)
Пример #3
0
def test_w_state_generalized():
    """Generalized 4-qubit W-state."""
    e_0, e_1 = basis(2, 0), basis(2, 1)
    expected_res = (
        1 / np.sqrt(30) *
        (tensor(e_1, e_0, e_0, e_0) + 2 * tensor(e_0, e_1, e_0, e_0) +
         3 * tensor(e_0, e_0, e_1, e_0) + 4 * tensor(e_0, e_0, e_0, e_1)))

    coeffs = np.array([1, 2, 3, 4]) / np.sqrt(30)
    res = w_state(4, coeffs)

    bool_mat = np.isclose(res, expected_res, atol=0.2)
    np.testing.assert_equal(np.all(bool_mat), True)
Пример #4
0
    def __init__(self,
                 prob_mat: np.ndarray,
                 pred_mat: np.ndarray,
                 reps: int = 1) -> None:
        """
        Construct extended nonlocal game object.

        :param prob_mat: A matrix whose (x, y)-entry gives the probability
                        that the referee will give Alice the value `x` and Bob
                        the value `y`.
        :param pred_mat:
        :param reps: Number of parallel repetitions to perform.
        """
        if reps == 1:
            self.prob_mat = prob_mat
            self.pred_mat = pred_mat
            self.reps = reps

        else:
            (
                dim_x,
                dim_y,
                num_alice_out,
                num_bob_out,
                num_alice_in,
                num_bob_in,
            ) = pred_mat.shape
            self.prob_mat = tensor(prob_mat, reps)

            pred_mat2 = np.zeros((
                dim_x**reps,
                dim_y**reps,
                num_alice_out**reps,
                num_bob_out**reps,
                num_alice_in**reps,
                num_bob_in**reps,
            ))
            i_ind = np.zeros(reps, dtype=int)
            j_ind = np.zeros(reps, dtype=int)
            for i in range(num_alice_in**reps):
                for j in range(num_bob_in**reps):
                    to_tensor = np.empty(
                        [reps, dim_x, dim_y, num_alice_out, num_bob_out])
                    for k in range(reps - 1, -1, -1):
                        to_tensor[k] = pred_mat[:, :, :, :, i_ind[k], j_ind[k]]
                    pred_mat2[:, :, :, :, i, j] = tensor(to_tensor)
                    j_ind = update_odometer(j_ind, num_bob_in * np.ones(reps))
                i_ind = update_odometer(i_ind, num_alice_in * np.ones(reps))
            self.pred_mat = pred_mat2
            self.reps = reps
Пример #5
0
def test_tensor_single_arg():
    """Performing tensor product on one item should return item back."""
    input_arr = np.array([[1, 2], [3, 4]])
    res = tensor(input_arr)

    bool_mat = np.isclose(res, input_arr)
    np.testing.assert_equal(np.all(bool_mat), True)
Пример #6
0
def test_tensor_n_0():
    """Test tensor n=0 times."""
    e_0 = basis(2, 0)
    expected_res = None

    res = tensor(e_0, 0)
    np.testing.assert_equal(res, expected_res)
Пример #7
0
def test_tensor_n_2():
    """Test tensor n=2 times."""
    e_0 = basis(2, 0)
    expected_res = np.kron(e_0, e_0)

    res = tensor(e_0, 2)
    bool_mat = np.isclose(res, expected_res)
    np.testing.assert_equal(np.all(bool_mat), True)
Пример #8
0
def test_tensor_n_1():
    """Test tensor n=1 times."""
    e_0 = basis(2, 0)
    expected_res = e_0

    res = tensor(e_0, 1)
    bool_mat = np.isclose(res, expected_res)
    np.testing.assert_equal(np.all(bool_mat), True)
Пример #9
0
def test_tensor():
    """Test standard tensor on vectors."""
    e_0 = basis(2, 0)
    expected_res = np.kron(e_0, e_0)

    res = tensor(e_0, e_0)

    bool_mat = np.isclose(res, expected_res)
    np.testing.assert_equal(np.all(bool_mat), True)
Пример #10
0
def test_tensor_array_of_numpy_arrays_three():
    """Performing tensor product on three numpy array of numpy arrays."""
    input_arr = np.array([np.identity(2), np.identity(2), np.identity(2)])
    res = tensor(input_arr)

    expected_res = np.identity(8)

    bool_mat = np.isclose(res, expected_res)
    np.testing.assert_equal(np.all(bool_mat), True)
Пример #11
0
def test_tensor_list_3():
    """Test tensor list with three items."""
    e_0, e_1 = basis(2, 0), basis(2, 1)
    expected_res = np.kron(np.kron(e_0, e_1), e_0)

    res = tensor([e_0, e_1, e_0])

    bool_mat = np.isclose(res, expected_res)
    np.testing.assert_equal(np.all(bool_mat), True)
Пример #12
0
def test_tensor_list_1():
    """Test tensor list with one item."""
    e_0 = basis(2, 0)
    expected_res = e_0

    res = tensor([e_0])

    bool_mat = np.isclose(res, expected_res)
    np.testing.assert_equal(np.all(bool_mat), True)
Пример #13
0
def test_tensor_multiple_args():
    """Performing tensor product on multiple matrices."""
    input_arr_1 = np.identity(2)
    input_arr_2 = np.identity(2)
    input_arr_3 = np.identity(2)
    input_arr_4 = np.identity(2)
    res = tensor(input_arr_1, input_arr_2, input_arr_3, input_arr_4)

    bool_mat = np.isclose(res, np.identity(16))
    np.testing.assert_equal(np.all(bool_mat), True)
Пример #14
0
def test_tensor_array_of_numpy_arrays_two():
    """Performing tensor product on two numpy array of numpy arrays."""
    input_arr = np.array(
        [np.array([[1, 2], [3, 4]]),
         np.array([[5, 6], [7, 8]])])
    res = tensor(input_arr)

    expected_res = np.array([[5, 6, 10, 12], [7, 8, 14, 16], [15, 18, 20, 24],
                             [21, 24, 28, 32]])

    bool_mat = np.isclose(res, expected_res)
    np.testing.assert_equal(np.all(bool_mat), True)
Пример #15
0
def test_ghz_4_7():
    r"""
    The following generates the following GHZ state in `(C^4)^{\otimes 7}`.

    `1/sqrt(30) * (|0000000> + 2|1111111> + 3|2222222> + 4|3333333>)`.
    """
    e0_4 = np.array([[1], [0], [0], [0]])
    e1_4 = np.array([[0], [1], [0], [0]])
    e2_4 = np.array([[0], [0], [1], [0]])
    e3_4 = np.array([[0], [0], [0], [1]])

    expected_res = (1 / np.sqrt(30) *
                    (tensor(e0_4, e0_4, e0_4, e0_4, e0_4, e0_4, e0_4) +
                     2 * tensor(e1_4, e1_4, e1_4, e1_4, e1_4, e1_4, e1_4) +
                     3 * tensor(e2_4, e2_4, e2_4, e2_4, e2_4, e2_4, e2_4) +
                     4 * tensor(e3_4, e3_4, e3_4, e3_4, e3_4, e3_4, e3_4)))

    res = ghz(4, 7, np.array([1, 2, 3, 4]) / np.sqrt(30)).toarray()

    bool_mat = np.isclose(res, expected_res)
    np.testing.assert_equal(np.all(bool_mat), True)
Пример #16
0
def test_tensor_empty_args():
    r"""Test tensor with no arguments."""
    with np.testing.assert_raises(ValueError):
        tensor()
Пример #17
0
def brauer(dim: int, p_val: int) -> np.ndarray:
    r"""
    Produce all Brauer states [WikBrauer]_.

    Produce a matrix whose columns are all of the (unnormalized) "Brauer" states: states that are
    the :code:`p_val`-fold tensor product of the standard maximally-entangled pure state on
    :code:`dim` local dimensions. There are many such states, since there are many different ways to
    group the :code:`2 * p_val` parties into :code:`p_val` pairs (with each pair corresponding to
    one maximally-entangled state).

    The exact number of such states is:

    ```python
    np.factorial(2 * p_val) / (np.factorial(p_val) * 2**p_val)
    ```

    which is the number of columns of the returned matrix.

    This function has been adapted from QETLAB.

    Examples
    ==========

    Generate a matrix whose columns are all Brauer states on 4 qubits.

    >>> from toqito.states import brauer
    >>> brauer(2, 2)
    [[1. 1. 1.]
     [0. 0. 0.]
     [0. 0. 0.]
     [1. 0. 0.]
     [0. 0. 0.]
     [0. 1. 0.]
     [0. 0. 1.]
     [0. 0. 0.]
     [0. 0. 0.]
     [0. 0. 1.]
     [0. 1. 0.]
     [0. 0. 0.]
     [1. 0. 0.]
     [0. 0. 0.]
     [0. 0. 0.]
     [1. 1. 1.]]

    References
    ==========
    .. [WikBrauer] Wikipedia: Brauer algebra
        https://en.wikipedia.org/wiki/Brauer_algebra

    :param dim: Dimension of each local subsystem
    :param p_val: Half of the number of parties (i.e., the state that this function computes will
                  live in :math:`(\mathbb{C}^D)^{\otimes 2 P})`
    :return: Matrix whose columns are all of the unnormalized Brauer states.
    """
    # The Brauer states are computed from perfect matchings of the complete graph. So compute all
    # perfect matchings first.
    phi = tensor(max_entangled(dim, False, False), p_val)
    matchings = perfect_matchings(2 * p_val)
    num_matchings = matchings.shape[0]
    state = np.zeros((dim**(2 * p_val), num_matchings))

    # Turn these perfect matchings into the corresponding states.
    for i in range(num_matchings):
        state[:,
              i] = permute_systems(phi, matchings[i, :],
                                   dim * np.ones((1, 2 * p_val), dtype=int)[0])
    return state
Пример #18
0
def test_tensor_list_0():
    """Test tensor empty list."""
    expected_res = None

    res = tensor([])
    np.testing.assert_equal(res, expected_res)
Пример #19
0
def pauli(ind: Union[int, str, List[int], List[str]],
          is_sparse: bool = False) -> Union[np.ndarray, sparse.csr_matrix]:
    r"""
    Produce a Pauli operator [WikPauli]_.

    Provides the 2-by-2 Pauli matrix indicated by the value of `ind`. The
    variable `ind = 1` gives the Pauli-X operator, `ind = 2` gives the Pauli-Y
    operator, `ind =3` gives the Pauli-Z operator, and `ind = 0`gives the
    identity operator. Alternatively, `ind` can be set to "I", "X", "Y", or "Z"
    (case insensitive) to indicate the Pauli identity, X, Y, or Z operator.

    The 2-by-2 Pauli matrices are defined as the following matrices:

    .. math::

        \begin{equation}
            \begin{aligned}
                X = \begin{pmatrix}
                        0 & 1 \\
                        1 & 0
                    \end{pmatrix}, \quad
                Y = \begin{pmatrix}
                        0 & -i \\
                        i & 0
                    \end{pmatrix}, \quad
                Z = \begin{pmatrix}
                        1 & 0 \\
                        0 & -1
                    \end{pmatrix}, \quad
                I = \begin{pmatrix}
                        1 & 0 \\
                        0 & 1
                    \end{pmatrix}.
                \end{aligned}
            \end{equation}

    Examples
    ==========

    Example for identity Pauli matrix.

    >>> from toqito.matrices import pauli
    >>> pauli("I")
    [[1., 0.],
     [0., 1.]])

    Example for Pauli-X matrix.

    >>> from toqito.matrices import pauli
    >>> pauli("X")
    [[0, 1],
     [1, 0]])

    Example for Pauli-Y matrix.

    >>> from toqito.matrices import pauli
    >>> pauli("Y")
    [[ 0.+0.j, -0.-1.j],
     [ 0.+1.j,  0.+0.j]])

    Example for Pauli-Z matrix.

    >>> from toqito.matrices import pauli
    >>> pauli("Z")
    [[ 1,  0],
     [ 0, -1]])

    References
    ==========
    .. [WikPauli] Wikipedia: Pauli matrices
        https://en.wikipedia.org/wiki/Pauli_matrices

    :param ind: The index to indicate which Pauli operator to generate.
    :param is_sparse: Returns a sparse matrix if set to True and a non-sparse
                      matrix if set to False.
    """
    if isinstance(ind, (int, str)):
        if ind in ("x", "X", 1):
            pauli_mat = np.array([[0, 1], [1, 0]])
        elif ind in ("y", "Y", 2):
            pauli_mat = np.array([[0, -1j], [1j, 0]])
        elif ind in ("z", "Z", 3):
            pauli_mat = np.array([[1, 0], [0, -1]])
        else:
            pauli_mat = np.identity(2)

        if is_sparse:
            pauli_mat = sparse.csr_matrix(pauli_mat)

        return pauli_mat

    num_qubits = len(ind)
    pauli_mats = []
    for i in range(num_qubits - 1, -1, -1):
        pauli_mats.append(pauli(ind[i], is_sparse))
    return tensor(pauli_mats)
Пример #20
0
def optimal_clone(
    states: List[np.ndarray],
    probs: List[float],
    num_reps: int = 1,
    strategy: bool = False,
) -> Union[float, np.ndarray]:
    r"""
    Compute probability of counterfeiting quantum money [MVW12]_.

    The primal problem for the :math:`n`-fold parallel repetition is given as follows:

    .. math::
        \begin{equation}
            \begin{aligned}
                \text{maximize:} \quad &
                \langle W_{\pi} \left(Q^{\otimes n} \right) W_{\pi}^*, X \rangle \\
                \text{subject to:} \quad & \text{Tr}_{\mathcal{Y}^{\otimes n}
                                           \otimes \mathcal{Z}^{\otimes n}}(X)
                                           = \mathbb{I}_{\mathcal{X}^{\otimes
                                           n}},\\
                                           & X \in \text{Pos}(
                                           \mathcal{Y}^{\otimes n}
                                           \otimes \mathcal{Z}^{\otimes n}
                                           \otimes \mathcal{X}^{\otimes n})
            \end{aligned}
        \end{equation}

    The dual problem for the :math:`n`-fold parallel repetition is given as follows:

    .. math::
        \begin{equation}
            \begin{aligned}
                \text{minimize:} \quad & \text{Tr}(Y) \\
                \text{subject to:} \quad & \mathbb{I}_{\mathcal{Y}^{\otimes n}
                \otimes \mathcal{Z}^{\otimes n}} \otimes Y \geq W_{\pi}
                \left( Q^{\otimes n} \right) W_{\pi}^*, \\
                & Y \in \text{Herm} \left(\mathcal{X}^{\otimes n} \right)
            \end{aligned}
        \end{equation}

    Examples
    ==========

    Wiesner's original quantum money scheme [Wies83]_ was shown in [MVW12]_ to have an optimal
    probability of 3/4 for succeeding a counterfeiting attack.

    Specifically, in the single-qubit case, Wiesner's quantum money scheme corresponds to the
    following ensemble:

    .. math::
        \left\{
            \left( \frac{1}{4}, |0\rangle \right),
            \left( \frac{1}{4}, |1\rangle \right),
            \left( \frac{1}{4}, |+\rangle \right),
            \left( \frac{1}{4}, |-\rangle \right)
        \right\},

    which yields the operator

    .. math::
        \begin{equation}
            Q = \frac{1}{4} \left(|000 \rangle \langle 000| + |111 \rangle \langle 111| +
                                  |+++ \rangle + \langle +++| + |--- \rangle \langle ---| \right)
        \end{equation}

    We can see that the optimal value we obtain in solving the SDP is 3/4.

    >>> from toqito.state_opt import optimal_clone
    >>> from toqito.states import basis
    >>> import numpy as np
    >>> e_0, e_1 = basis(2, 0), basis(2, 1)
    >>> e_p = (e_0 + e_1) / np.sqrt(2)
    >>> e_m = (e_0 - e_1) / np.sqrt(2)
    >>>
    >>> states = [e_0, e_1, e_p, e_m]
    >>> probs = [1 / 4, 1 / 4, 1 / 4, 1 / 4]
    >>> wiesner = optimal_clone(states, probs)
    0.749999999967631

    References
    ==========
    .. [MVW12] Abel Molina, Thomas Vidick, and John Watrous.
        "Optimal counterfeiting attacks and generalizations for Wiesner’s
        quantum money."
        Conference on Quantum Computation, Communication, and Cryptography.
        Springer, Berlin, Heidelberg, 2012.
        https://arxiv.org/abs/1202.4010

    .. [Wies83] Stephen Wiesner
        "Conjugate coding."
        ACM Sigact News 15.1 (1983): 78-88.
        https://dl.acm.org/doi/pdf/10.1145/1008908.1008920

    :return: The optimal probability with of counterfeiting quantum money.
    """
    dim = len(states[0])**3

    # Construct the following operator:
    #                                ___               ___
    # Q = ∑_{k=1}^N p_k |ψ_k ⊗ ψ_k ⊗ ψ_k> <ψ_k ⊗ ψ_k ⊗ ψ_k|
    q_a = np.zeros((dim, dim))
    for k, state in enumerate(states):
        q_a += (probs[k] * tensor(state, state, state.conj()) *
                tensor(state, state, state.conj()).conj().T)

    # The system is over:
    # Y_1 ⊗ Z_1 ⊗ X_1, ... , Y_n ⊗ Z_n ⊗ X_n.
    num_spaces = 3

    # In the event of more than a single repetition, one needs to apply a
    # permutation operator to the variables in the SDP to properly align
    # the spaces.
    if num_reps == 1:
        pperm = np.array([1])
    else:
        # The permutation vector `perm` contains elements of the
        # sequence from: https://oeis.org/A023123
        q_a = tensor(q_a, num_reps)
        perm = []
        for i in range(1, num_spaces + 1):
            perm.append(i)
            var = i
            for j in range(1, num_reps):
                perm.append(var + num_spaces * j)
        pperm = permutation_operator(2, perm)

    if strategy:
        return primal_problem(q_a, pperm, num_reps)
    return dual_problem(q_a, pperm, num_reps)