def test_ghz_4_7(self): 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) self.assertEqual(np.all(bool_mat), True)
def test_ghz_2_3(self): """Produces the 3-qubit GHZ state: `1/sqrt(2) * (|000> + |111>)`.""" e_0, e_1 = ket(2, 0), ket(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) self.assertEqual(np.all(bool_mat), True)
def test_w_state_3(self): """The 3-qubit W-state.""" e_0, e_1 = ket(2, 0), ket(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) self.assertEqual(np.all(bool_mat), True)
def test_counterfeit_attack_wiesner_money(self): """Probability of counterfeit attack on Wiesner's quantum money.""" e_0, e_1 = ket(2, 0), ket(2, 1) e_p = (e_0 + e_1) / np.sqrt(2) e_m = (e_0 - e_1) / np.sqrt(2) e_000 = tensor(e_0, e_0, e_0) e_111 = tensor(e_1, e_1, e_1) e_ppp = tensor(e_p, e_p, e_p) e_mmm = tensor(e_m, e_m, e_m) q_a = (1 / 4 * (e_000 * e_000.conj().T + e_111 * e_111.conj().T + e_ppp * e_ppp.conj().T + e_mmm * e_mmm.conj().T)) res = counterfeit_attack(q_a) self.assertEqual(np.isclose(res, 3 / 4), True)
def test_tensor_n_0(self): """Test tensor n=0 times.""" e_0 = ket(2, 0) expected_res = None res = tensor(e_0, 0) self.assertEqual(res, expected_res)
def test_tensor_n_3(self): """Test tensor n=3 times.""" e_0 = ket(2, 0) expected_res = np.kron(np.kron(e_0, e_0), e_0) res = tensor(e_0, 3) bool_mat = np.isclose(res, expected_res) self.assertEqual(np.all(bool_mat), True)
def test_tensor_n_1(self): """Test tensor n=1 times.""" e_0 = ket(2, 0) expected_res = e_0 res = tensor(e_0, 1) bool_mat = np.isclose(res, expected_res) self.assertEqual(np.all(bool_mat), True)
def test_tensor_list_3(self): """Test tensor list with three items.""" e_0, e_1 = ket(2, 0), ket(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) self.assertEqual(np.all(bool_mat), True)
def test_tensor_list_1(self): """Test tensor list with one item.""" e_0 = ket(2, 0) expected_res = e_0 res = tensor([e_0]) bool_mat = np.isclose(res, expected_res) self.assertEqual(np.all(bool_mat), True)
def test_tensor(self): """Test standard tensor on vectors.""" e_0 = ket(2, 0) expected_res = np.kron(e_0, e_0) res = tensor(e_0, e_0) bool_mat = np.isclose(res, expected_res) self.assertEqual(np.all(bool_mat), True)
def test_generalized_w_state(self): """Generalized 4-qubit W-state.""" e_0, e_1 = ket(2, 0), ket(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) self.assertEqual(np.all(bool_mat), True)
def counterfeit_attack(q_a: np.ndarray, num_reps: int = 1) -> float: 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:: Q = \frac{1}{4} \left( |000\rangle + \langle 000| + |111\rangle \langle 111| + |+++\rangle + \langle +++| + |---\rangle \langle ---| \right) We can see that the optimal value we obtain in solving the SDP is 3/4. >>> from toqito.states.operations.tensor import tensor >>> from toqito.core.ket import ket >>> import numpy as np >>> e_0, e_1 = ket(2, 0), ket(2, 1) >>> e_p = (e_0 + e_1) / np.sqrt(2) >>> e_m = (e_0 - e_1) / np.sqrt(2) >>> >>> e_000 = tensor(e_0, e_0, e_0) >>> e_111 = tensor(e_1, e_1, e_1) >>> e_ppp = tensor(e_p, e_p, e_p) >>> e_mmm = tensor(e_m, e_m, e_m) >>> >>> q_a = 1 / 4 * (e_000 * e_000.conj().T + e_111 * e_111.conj().T + \ >>> e_ppp * e_ppp.conj().T + e_mmm * e_mmm.conj().T) >>> print(counterfeit_attack(q_a)) 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 :param q_a: The fixed SDP variable. :param num_reps: The number of parallel repetitions. :return: The optimal probability with of counterfeiting quantum money. """ # 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) return dual_problem(q_a, pperm, num_reps)
def test_tensor_list_0(self): """Test tensor empty list.""" expected_res = None res = tensor([]) self.assertEqual(res, expected_res)
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 [WIKPAU]_. 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.linear_algebra.matrices.pauli import pauli >>> pauli("I") array([[1., 0.], [0., 1.]]) Example for Pauli-X matrix. >>> from toqito.linear_algebra.matrices.pauli import pauli >>> pauli("X") array([[0, 1], [1, 0]]) Example for Pauli-Y matrix. >>> from toqito.linear_algebra.matrices.pauli import pauli >>> pauli("Y") array([[ 0.+0.j, -0.-1.j], [ 0.+1.j, 0.+0.j]]) Example for Pauli-Z matrix. >>> from toqito.linear_algebra.matrices.pauli import pauli >>> pauli("Z") array([[ 1, 0], [ 0, -1]]) References ========== .. [WIKPAU] 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)