def bell(idx: int) -> np.ndarray: r""" Produce a Bell state. Returns one of the following four Bell states depending on the value of `idx`: .. math:: \begin{equation} \begin{aligned} \frac{1}{\sqrt{2}} \left( |00 \rangle + |11 \rangle \right) & \qquad & \frac{1}{\sqrt{2}} \left( |00 \rangle - |11 \rangle \right) \\ \frac{1}{\sqrt{2}} \left( |01 \rangle + |10 \rangle \right) & \qquad & \frac{1}{\sqrt{2}} \left( |01 \rangle - |10 \rangle \right) \end{aligned} \end{equation} References: [1] Wikipedia: Bell state https://en.wikipedia.org/wiki/Bell_state :param idx: A parameter in [0, 1, 2, 3] """ e_0, e_1 = ket(2, 0), ket(2, 1) if idx == 0: return 1 / np.sqrt(2) * (np.kron(e_0, e_0) + np.kron(e_1, e_1)) if idx == 1: return 1 / np.sqrt(2) * (np.kron(e_0, e_0) - np.kron(e_1, e_1)) if idx == 2: return 1 / np.sqrt(2) * (np.kron(e_0, e_1) + np.kron(e_1, e_0)) if idx == 3: return 1 / np.sqrt(2) * (np.kron(e_0, e_1) - np.kron(e_1, e_0)) raise ValueError("Invalid integer value for Bell state.")
def test_max_ent_2_0_0(self): """Generate maximally entangled state: `|00> + |11>`.""" e_0, e_1 = ket(2, 0), ket(2, 1) expected_res = 1 * (np.kron(e_0, e_0) + np.kron(e_1, e_1)) res = max_entangled(2, False, False) bool_mat = np.isclose(res, expected_res) self.assertEqual(np.all(bool_mat), True)
def test_max_ent_2(self): """Generate maximally entangled state: `1/sqrt(2) * (|00> + |11>)`.""" e_0, e_1 = ket(2, 0), ket(2, 1) expected_res = 1 / np.sqrt(2) * (np.kron(e_0, e_0) + np.kron(e_1, e_1)) res = max_entangled(2) bool_mat = np.isclose(res, expected_res) self.assertEqual(np.all(bool_mat), True)
def test_is_not_mub_dim_2(self): """Return False for non-MUB of dimension 2.""" e_0, e_1 = ket(2, 0), ket(2, 1) mub_1 = [e_0, e_1] mub_2 = [1 / np.sqrt(2) * (e_0 + e_1), e_1] mub_3 = [1 / np.sqrt(2) * (e_0 + 1j * e_1), e_0] mubs = [mub_1, mub_2, mub_3] self.assertEqual(is_mub(mubs), False)
def test_state_discrimination_three_state_vec(self): """State discrimination for two state vectors.""" e_0, e_1 = ket(2, 0), ket(2, 1) states = [e_0, e_1] probs = [1 / 2, 1 / 2] res = state_discrimination(states, probs) self.assertEqual(np.isclose(res, 1 / 2), True)
def test_is_pure_list(self): """Check that list of pure states returns True.""" e_0, e_1, e_2 = ket(3, 0), ket(3, 1), ket(3, 2) e0_dm = e_0 * e_0.conj().T e1_dm = e_1 * e_1.conj().T e2_dm = e_2 * e_2.conj().T self.assertEqual(is_pure([e0_dm, e1_dm, e2_dm]), True)
def test_bell_3(self): """Generates the Bell state: `1/sqrt(2) * (|01> - |10>)`.""" e_0, e_1 = ket(2, 0), ket(2, 1) expected_res = 1 / np.sqrt(2) * (np.kron(e_0, e_1) - np.kron(e_1, e_0)) res = bell(3) bool_mat = np.isclose(res, expected_res) self.assertEqual(np.all(bool_mat), True)
def test_schmidt_rank_singlet_state(self): """ Computing the Schmidt rank of the entangled singlet state should yield a value greater than 1. """ e_0, e_1 = ket(2, 0), ket(2, 1) rho = 1 / np.sqrt(2) * (np.kron(e_0, e_1) - np.kron(e_1, e_0)) rho = rho.conj().T * rho self.assertEqual(schmidt_rank(rho) > 1, 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_list([e_0, e_1, e_0]) bool_mat = np.isclose(res, expected_res) self.assertEqual(np.all(bool_mat), True)
def test_state_discrimination_two_states(self): """State discrimination for two state density matrices.""" e_0, e_1 = ket(2, 0), ket(2, 1) e_00 = e_0 * e_0.conj().T e_11 = e_1 * e_1.conj().T states = [e_00, e_11] probs = [1 / 2, 1 / 2] res = state_discrimination(states, probs) self.assertEqual(np.isclose(res, 1 / 2), 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_list([e_0, e_0, e_0]) + tensor_list([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_is_mub_dim_2(self): """Return True for MUB of dimension 2.""" e_0, e_1 = ket(2, 0), ket(2, 1) mub_1 = [e_0, e_1] mub_2 = [1 / np.sqrt(2) * (e_0 + e_1), 1 / np.sqrt(2) * (e_0 - e_1)] mub_3 = [ 1 / np.sqrt(2) * (e_0 + 1j * e_1), 1 / np.sqrt(2) * (e_0 - 1j * e_1) ] mubs = [mub_1, mub_2, mub_3] self.assertEqual(is_mub(mubs), True)
def test_concurrence(self): """The concurrence on maximally entangled Bell state.""" e_0, e_1 = ket(2, 0), ket(2, 1) e_00, e_11 = np.kron(e_0, e_0), np.kron(e_1, e_1) u_vec = 1 / np.sqrt(2) * (e_00 + e_11) rho = u_vec * u_vec.conj().T res = concurrence(rho) self.assertEqual(np.isclose(res, 1), True)
def test_schmidt_rank_separable_state(self): """ Computing the Schmidt rank of a separable state should yield a value equal to 1. """ e_0, e_1 = ket(2, 0), ket(2, 1) e_00 = np.kron(e_0, e_0) e_01 = np.kron(e_0, e_1) e_10 = np.kron(e_1, e_0) e_11 = np.kron(e_1, e_1) rho = 1 / 2 * (e_00 - e_01 - e_10 + e_11) rho = rho.conj().T * rho self.assertEqual(schmidt_rank(rho) == 1, True)
def test_trace_distance_same_state(self): r"""Test that: :math: `T(\rho, \sigma) = 0` iff `\rho = \sigma`.""" e_0, e_1 = ket(2, 0), ket(2, 1) e_00 = np.kron(e_0, e_0) e_11 = np.kron(e_1, e_1) u_vec = 1 / np.sqrt(2) * (e_00 + e_11) rho = u_vec * u_vec.conj().T sigma = rho res = trace_distance(rho, sigma) self.assertEqual(np.isclose(res, 0), True)
def test_helstrom_holevo_same_state(self): r"""Test Helstrom-Holevo distance on same state.""" e_0, e_1 = ket(2, 0), ket(2, 1) e_00 = np.kron(e_0, e_0) e_11 = np.kron(e_1, e_1) u_vec = 1 / np.sqrt(2) * (e_00 + e_11) rho = u_vec * u_vec.conj().T sigma = rho res = helstrom_holevo(rho, sigma) self.assertEqual(np.isclose(res, 1 / 2), True)
def test_trace_norm(self): """Test trace norm.""" e_0, e_1 = ket(2, 0), ket(2, 1) e_00 = np.kron(e_0, e_0) e_11 = np.kron(e_1, e_1) u_vec = 1 / np.sqrt(2) * (e_00 + e_11) rho = u_vec * u_vec.conj().T res = trace_norm(rho) _, singular_vals, _ = np.linalg.svd(rho) expected_res = float(np.sum(singular_vals)) self.assertEqual(np.isclose(res, expected_res), True)
def test_tensor_n_0(self): """Test tensor n=0 times.""" e_0 = ket(2, 0) expected_res = None res = tensor_n(e_0, 0) self.assertEqual(res, expected_res)
def test_ket_0(self): """Test for `|0>`.""" expected_res = np.array([[1], [0]]) res = ket(2, 0) bool_mat = np.isclose(res, expected_res) self.assertEqual(np.all(bool_mat), True)
def test_weak_coin_flipping(self): """ Test for maximally entangled state. Refer to the appendix of https://arxiv.org/abs/1703.03887 """ e_0, e_1 = ket(2, 0), ket(2, 1) e_m = (e_0 - e_1) / np.sqrt(2) rho = np.kron(e_1 * e_1.conj().T, e_0 * e_0.conj().T) + np.kron(e_m * e_m.conj().T, e_1 * e_1.conj().T) self.assertEqual( np.isclose(weak_coin_flipping(rho), np.cos(np.pi / 8)**2), True)
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_n(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_n(e_0, 1) 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_list([e_1, e_0, e_0]) + tensor_list([e_0, e_1, e_0]) + tensor_list([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_tensor_list_1(self): """Test tensor list with one item.""" e_0 = ket(2, 0) expected_res = e_0 res = tensor_list([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_list([e_1, e_0, e_0, e_0]) + 2 * tensor_list([e_0, e_1, e_0, e_0]) + 3 * tensor_list([e_0, e_0, e_1, e_0]) + 4 * tensor_list([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)
class TestHedgingValue(unittest.TestCase): """Unit test for hedging_value.""" e_0, e_1 = ket(2, 0), ket(2, 1) e_00, e_01 = kron(e_0, e_0), kron(e_0, e_1) e_10, e_11 = kron(e_1, e_0), kron(e_1, e_1) alpha = 1 / sqrt(2) theta = pi / 8 w_var = alpha * cos(theta) * e_00 + sqrt(1 - alpha**2) * sin(theta) * e_11 l_1 = -alpha * sin(theta) * e_00 + sqrt(1 - alpha**2) * cos(theta) * e_11 l_2 = alpha * sin(theta) * e_10 l_3 = sqrt(1 - alpha**2) * cos(theta) * e_01 q_1 = w_var * w_var.conj().T q_0 = l_1 * l_1.conj().T + l_2 * l_2.conj().T + l_3 * l_3.conj().T def test_max_prob_outcome_a_primal_1_dim(self): """ Maximal probability of outcome "a" when dim == 1. The primal problem of the hedging semidefinite program. """ q_0 = TestHedgingValue.q_0 hedging_value = HedgingValue(q_0, 1) self.assertEqual( isclose(hedging_value.max_prob_outcome_a_primal(), cos(pi / 8)**2), True) def test_max_prob_outcome_a_primal_2_dim(self): """ Test maximal probability of outcome "a" when dim == 2. The primal problem of the hedging semidefinite program. """ q_00 = kron(TestHedgingValue.q_0, TestHedgingValue.q_0) hedging_value = HedgingValue(q_00, 2) self.assertEqual( isclose(hedging_value.max_prob_outcome_a_primal(), cos(pi / 8)**4), True) def test_max_prob_outcome_a_dual_1_dim(self): """ Test maximal probability of outcome "a" when dim == 1. The dual problem of the hedging semidefinite program. """ q_0 = TestHedgingValue.q_0 hedging_value = HedgingValue(q_0, 1) self.assertEqual( isclose(hedging_value.max_prob_outcome_a_dual(), cos(pi / 8)**2), True) def test_max_prob_outcome_a_dual_2_dim(self): """ Test maximal probability of outcome "a" when dim == 2. The dual problem of the hedging semidefinite program. """ q_00 = kron(TestHedgingValue.q_0, TestHedgingValue.q_0) hedging_value = HedgingValue(q_00, 2) self.assertEqual( isclose(hedging_value.max_prob_outcome_a_dual(), cos(pi / 8)**4), True) def test_min_prob_outcome_a_primal_1_dim(self): """ Test minimal probability of outcome "a" when dim == 1. The primal problem of the hedging semidefinite program. """ q_1 = TestHedgingValue.q_1 hedging_value = HedgingValue(q_1, 1) self.assertEqual( isclose(hedging_value.min_prob_outcome_a_primal(), 0, atol=0.01), True) def test_min_prob_outcome_a_primal_2_dim(self): """ Test minimal probability of outcome "a" when dim == 2. The primal problem of the hedging semidefinite program. """ q_11 = kron(TestHedgingValue.q_1, TestHedgingValue.q_1) hedging_value = HedgingValue(q_11, 2) self.assertEqual( isclose(hedging_value.min_prob_outcome_a_primal(), 0, atol=0.01), True) def test_min_prob_outcome_a_dual_1_dim(self): """ Test minimal probability of outcome "a" when dim == 1. The dual problem of the hedging semidefinite program. """ q_1 = TestHedgingValue.q_1 hedging_value = HedgingValue(q_1, 1) self.assertEqual( isclose(hedging_value.min_prob_outcome_a_dual(), 0, atol=0.01), True) def test_min_prob_outcome_a_dual_2_dim(self): """ Test minimal probability of outcome "a" when dim == 2. The dual problem of the hedging semidefinite program. """ q_11 = kron(TestHedgingValue.q_1, TestHedgingValue.q_1) hedging_value = HedgingValue(q_11, 2) self.assertEqual( isclose(hedging_value.min_prob_outcome_a_dual(), 0, atol=0.01), True)
def test_invalid_dim(self): """Tests for invalid dimension inputs.""" with self.assertRaises(ValueError): ket(4, 4)
def domino(idx: int) -> np.ndarray: r""" Produce a domino state. The orthonormal product basis of domino states is given as .. math:: \begin{equation} \begin{aligned} |\phi_0\rangle = |1\rangle |1 \rangle \qquad |\phi_1\rangle = |0 \rangle \left(\frac{|0 \rangle + |1 \rangle}{\sqrt{2}} \right) & \qquad |\phi_2\rangle = |0\rangle \left(\frac{|0\rangle - |1\rangle}{\sqrt{2}}\right) \\ |\phi_3\rangle = |2\rangle \left(\frac{|0\rangle + |1\rangle}{\sqrt{2}}\right) \qquad |\phi_4\rangle = |2\rangle \left(\frac{|0\rangle - |1\rangle}{\sqrt{2}}\right) & \qquad |\phi_5\rangle = \left(\frac{|0\rangle + |1\rangle}{\sqrt{2}}\right) |0\rangle \\ |\phi_6\rangle = \left(\frac{|0\rangle - |1\rangle}{\sqrt{2}}\right) |0\rangle \qquad |\phi_7\rangle = \left(\frac{|0\rangle + |1\rangle}{\sqrt{2}}\right) |2\rangle & \qquad |\phi_8\rangle = \left(\frac{|0\rangle - |1\rangle}{\sqrt{2}}\right) |2\rangle \end{aligned} \end{equation} Returns one of the following nine domino states depending on the value of `idx`: References: [1] Bennett, Charles H., et al. Quantum nonlocality without entanglement. Phys. Rev. A, 59:1070–1091, Feb 1999. https://arxiv.org/abs/quant-ph/9804053 [2] Bennett, Charles H., et al. "Unextendible product bases and bound entanglement." Physical Review Letters 82.26 (1999): 5385. :param idx: A parameter in [0, 1, 2, 3, 4, 5, 6, 7, 8] """ e_0, e_1, e_2 = ket(3, 0), ket(3, 1), ket(3, 2) if idx == 0: return np.kron(e_1, e_1) if idx == 1: return np.kron(e_0, 1 / np.sqrt(2) * (e_0 + e_1)) if idx == 2: return np.kron(e_0, 1 / np.sqrt(2) * (e_0 - e_1)) if idx == 3: return np.kron(e_2, 1 / np.sqrt(2) * (e_1 + e_2)) if idx == 4: return np.kron(e_2, 1 / np.sqrt(2) * (e_1 - e_2)) if idx == 5: return np.kron(1 / np.sqrt(2) * (e_1 + e_2), e_0) if idx == 6: return np.kron(1 / np.sqrt(2) * (e_1 - e_2), e_0) if idx == 7: return np.kron(1 / np.sqrt(2) * (e_0 + e_1), e_2) if idx == 8: return np.kron(1 / np.sqrt(2) * (e_0 - e_1), e_2) raise ValueError("Invalid integer value for Domino state.")
def test_is_mixed(self): """Return True for mixed quantum state.""" e_0, e_1 = ket(2, 0), ket(2, 1) rho = 3 / 4 * e_0 * e_0.conj().T + 1 / 4 * e_1 * e_1.conj().T self.assertEqual(is_mixed(rho), True)