def test_partial_transpose_BC(): cvx_sigma_BC = cp.Variable(shape=sigma_BC.shape) cvx_sigma_BC.value = sigma_BC obtained_sigma_BC_TB = nlg.partial_transpose(cvx_sigma_BC, [2, 2], (1, 0)) obtained_sigma_BC_TC = nlg.partial_transpose(cvx_sigma_BC, [2, 2], (0, 1)) np.testing.assert_allclose(obtained_sigma_BC_TB.value, sigma_BC_TB) np.testing.assert_allclose(obtained_sigma_BC_TC.value, sigma_BC_TB)
def test_partial_transpose_ABC_as_2_subsystems_AB_C(): cvx_sigma_ABC = cp.Variable(shape=sigma_ABC.shape) cvx_sigma_ABC.value = sigma_ABC obtained_sigma_ABC_TAB = nlg.partial_transpose(cvx_sigma_ABC, [4, 2], (1, 0)) obtained_sigma_ABC_TC = nlg.partial_transpose(cvx_sigma_ABC, [4, 2], (0, 1)) np.testing.assert_allclose(obtained_sigma_ABC_TAB.value, sigma_ABC_TB) np.testing.assert_allclose(obtained_sigma_ABC_TC.value, sigma_ABC_TB)
def PPT_constraints(self): # Create tuple of choices (0=no-PT and 1=PT), one for each subsystem (SS subsystem counts as one) PT_choice = (2, ) * (self.n1 + self.n2 + 1) # Create all possible combinations of PT and no-PT allowed by the cuts PT_list = np.array([ np.concatenate((item[:-1], np.full(2, item[-1]))) for item in nlg.indices_list(PT_choice) ]) # Remove trivial cases (all 0's and all 1's) num_subs = self.n1 + self.n2 + 2 bool_trivial = np.sum(PT_list, axis=1) % num_subs != 0 PT_list = PT_list[bool_trivial] # Remove double cases and add PPT constraints used_PT_list = [] for PT in PT_list: opposite_PT = (PT + 1) % 2 is_PT_in = np.any([ np.all(item == PT) or np.all(item == opposite_PT) for item in used_PT_list ]) if not is_PT_in: used_PT_list.append( PT ) # We use this to decide whether to add new constraints or not for i in map(self.StI, self.indices_A1Q1A2Q2_ext): PPT_constr = nlg.partial_transpose( self.rho_variable[i], self.subs_TTSS_ext, PT) >> 0 self.constraints.append(PPT_constr)
def __init__(self, level, answers, questions, dim_assistance, rule_function, distributions): # Level of the SDP relaxation self.n1, self.n2 = level # Dimension of questions and answers for the game self.dimA1, self.dimA2 = answers self.dimQ1, self.dimQ2 = questions # Dimension of the assisting quantum system self.dimT = dim_assistance self.dimS = dim_assistance # Copy due to swap-trick # Rules of the game self.rule = rule_function # Probability distribution of questions asked by referee self.probQ1, self.probQ2 = distributions # Useful variables for the methods of the class self.subs_A1Q1 = (self.dimA1, self.dimQ1) self.indices_A1Q1 = nlg.indices_list(self.subs_A1Q1) self.subs_A2Q2 = (self.dimA2, self.dimQ2) self.indices_A2Q2 = nlg.indices_list(self.subs_A2Q2) self.subs_A1Q1A2Q2 = self.subs_A1Q1 + self.subs_A2Q2 self.indices_A1Q1A2Q2 = nlg.indices_list(self.subs_A1Q1A2Q2) self.subs_A1Q1A2Q2_ext = self.subs_A1Q1 * self.n1 + self.subs_A2Q2 * self.n2 self.indices_A1Q1A2Q2_ext = nlg.indices_list(self.subs_A1Q1A2Q2_ext) self.subs_but_A1Q1A2Q2 = self.subs_A1Q1 * ( self.n1 - 1) + self.subs_A2Q2 * (self.n2 - 1) self.indices_but_A1Q1A2Q2 = nlg.indices_list(self.subs_but_A1Q1A2Q2) self.subs_but_A1Q1 = self.subs_A1Q1 * (self.n1 - 1) + self.subs_A2Q2 * self.n2 self.indices_but_A1Q1 = nlg.indices_list(self.subs_but_A1Q1) self.subs_but_A2Q2 = self.subs_A1Q1 * self.n1 + self.subs_A2Q2 * ( self.n2 - 1) self.indices_but_A2Q2 = nlg.indices_list(self.subs_but_A2Q2) self.subs_TTSS = (self.dimT, self.dimT, self.dimS, self.dimS) self.subs_TTSS_ext = (self.dimT, ) * (self.n1 + self.n2) + (self.dimS, self.dimS) self.dim_TTSS_ext = fc.reduce(mul, self.subs_TTSS_ext, 1) # Maximally-entangled states between TT|SS self.F_TTSS = cp.Constant( nlg.permutation_matrix((0, 1, 2, 3), (2, 3, 0, 1), self.subs_TTSS)) self.Phi_TTSS = nlg.partial_transpose(self.F_TTSS, self.subs_TTSS, (0, 0, 1, 1)) # Maximally-mixed state on T self.rhoT = np.identity(self.dimT) / self.dimT # Function mapping a sequence of indices to integers self.StI = lambda seq: nlg.seqtoint(seq, self.subs_A1Q1A2Q2_ext) # List of SDP variable self.rho_variable = [] # Objective function of the problem self.object_function = 0 # The list of constraints self.constraints = []