Example #1
0
def test_permutation_matrix_inconsistent_tuple_sizes():

    initial_order = (0, 1, 2)
    final_order = (0, 2, 1)
    dimension_subsystems = (2, 2)

    with assert_raises(RuntimeError):
        nlg.permutation_matrix(initial_order, final_order,
                               dimension_subsystems)
Example #2
0
    def linear_constraint_Bob(self):

        # Permutation matrix (T1...Tn1)(T1...Tn2)(SS) -> (Tn2...T1)(T1...Tn1)(SS)
        order = np.arange(self.n1 + self.n2 + 2)

        maskA = order[:self.n1]
        maskB = np.flip(order[self.n1:self.n1 + self.n2])
        maskS = order[self.n1 + self.n2:]
        mask = np.concatenate((maskB, maskA, maskS))

        P = cp.Constant(nlg.permutation_matrix(order, mask,
                                               self.subs_TTSS_ext))

        # Create dimension tuple for the partial tracing
        sub_dim = (self.dimT,
                   self.dimT**(self.n1 + self.n2 - 1) * self.dimS**2)

        for q2 in range(self.dimQ2):
            for index_else in self.indices_but_A2Q2:
                indices_a1q1A2q2_ext = [
                    np.append(index_else, np.array([a2, q2]))
                    for a2 in range(self.dimA2)
                ]
                indices_a1q1A2Q2_ext = [
                    np.append(index_else, index_A2Q2)
                    for index_A2Q2 in self.indices_A2Q2
                ]

                lhs_variable = sum([
                    self.rho_variable[self.StI(index)]
                    for index in indices_a1q1A2q2_ext
                ])
                lhs = P @ lhs_variable @ P.T

                rhs_variable = sum([
                    self.rho_variable[self.StI(index)]
                    for index in indices_a1q1A2Q2_ext
                ])
                rhs_permuted = P @ rhs_variable @ P.T
                rhs_partial = nlg.partial_trace(rhs_permuted, sub_dim)
                rhs = self.probQ2[q2] * cp.kron(self.rhoT, rhs_partial)

                self.constraints.append(lhs - rhs == 0)
Example #3
0
    def _permutation_constraint(self, order_Alice, order_Bob):

        # Order for the quantum systems
        init_order_QS = np.arange(self.n1 + self.n2 + 2)
        order_SS = np.arange(self.n1 + self.n2, self.n1 + self.n2 + 2)
        fin_order_qs = np.concatenate(
            (order_Alice, order_Bob + self.n1, order_SS))

        # The permutation matrix swapping the quantum subsystems
        P = nlg.permutation_matrix(init_order_QS, fin_order_qs,
                                   self.subs_TTSS_ext)

        # The permutation function for the classical indices
        perm = lambda index: self._permute_index(index, order_Alice, order_Bob)

        for index in self.indices_A1Q1A2Q2_ext:
            lhs = self.rho_variable[self.StI(index)]

            rhs_variable = self.rho_variable[self.StI(perm(index))]
            rhs = P @ rhs_variable @ P.T

            self.constraints.append(lhs - rhs == 0)
Example #4
0
def test_permutation_matrix_three_subsystems():

    initial_order = (0, 1, 2)
    final_order = (0, 2, 1)
    dimension_subsystems = (2, 2, 3)

    expected_matrix = np.array(
        [[1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
         [0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
         [0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
         [0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],
         [0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
         [0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],
         [0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],
         [0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
         [0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],
         [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],
         [0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
         [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1.]])

    obtained_matrix = nlg.permutation_matrix(initial_order, final_order,
                                             dimension_subsystems)

    np.testing.assert_allclose(expected_matrix, obtained_matrix)
Example #5
0
    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 = []