Esempio n. 1
0
def expression2CG(io_config, expression):
    """
	Inputs:

			io_config - input/output configuration

			expression - matrix representing the coefficients s_ab|xy of the Bell expression.
			 			 Eg: for io_config = [[2,2],[2,2]],

						 	|	s00|00  s01|00  s00|01  s01|01	|
			expression =	|	s10|00  s11|00  s10|01  s11|01	|
							|	s00|10  s01|10  s00|11  s01|11	|
							|	s10|10  s11|10  s10|11  s11|11	|

	Returns:
			CG-reduction of the expression matrix.
	"""

    #Adding one to each output results in all the operators being defined
    A = ncp.generate_measurements([int(a + 1) for a in io_config[0]], 'A')
    B = ncp.generate_measurements([int(b + 1) for b in io_config[1]], 'B')

    op_mat = np.outer(np.array(ncp.flatten(A)), np.array(ncp.flatten(B)))

    #Obtain the overall expression
    expr = np.sum(expression * op_mat)

    #Removing the terms we don't want
    for i in range(len(A)):
        expr = expr.subs(A[i][-1], 1 - np.sum(A[i][:-1]))
    for j in range(len(B)):
        expr = expr.subs(B[j][-1], 1 - np.sum(B[j][:-1]))

    # Now we get our full expression
    expr = expr.expand()

    # Removing the additional operator
    for i in range(len(A)):
        A[i] = A[i][:-1]
    for i in range(len(B)):
        B[i] = B[i][:-1]

    A = np.array([1] + ncp.flatten(A))
    B = np.array([1] + ncp.flatten(B))

    # Construct the operator cg-matrix and then find relevant coefficients
    op_mat = np.outer(A, B)
    coefs = expr.as_coefficients_dict()
    for i in range(len(A)):
        for j in range(len(B)):
            if op_mat[i][j] in coefs:
                op_mat[i][j] = coefs[op_mat[i, j]]
            else:
                op_mat[i][j] = 0

    return op_mat
Esempio n. 2
0
 def test_ground_state(self):
     length, n, h, U, t = 2, 0.8, 3.8, -6, 1
     fu = generate_operators('fu', length)
     fd = generate_operators('fd', length)
     _b = flatten([fu, fd])
     monomials = [[ci for ci in _b]]
     monomials[-1].extend([Dagger(ci) for ci in _b])
     monomials.append([cj*ci for ci in _b for cj in _b])
     monomials.append([Dagger(cj)*ci for ci in _b for cj in _b])
     monomials[-1].extend([cj*Dagger(ci)
                           for ci in _b for cj in _b])
     monomials.append([Dagger(cj)*Dagger(ci)
                       for ci in _b for cj in _b])
     hamiltonian = 0
     for j in range(length):
         hamiltonian += U * (Dagger(fu[j])*Dagger(fd[j]) * fd[j]*fu[j])
         hamiltonian += -h/2*(Dagger(fu[j])*fu[j] - Dagger(fd[j])*fd[j])
         for k in get_neighbors(j, len(fu), width=1):
             hamiltonian += -t*Dagger(fu[j])*fu[k]-t*Dagger(fu[k])*fu[j]
             hamiltonian += -t*Dagger(fd[j])*fd[k]-t*Dagger(fd[k])*fd[j]
     momentequalities = [n-sum(Dagger(br)*br for br in _b)]
     sdpRelaxation = SdpRelaxation(_b, verbose=0)
     sdpRelaxation.get_relaxation(-1,
                                  objective=hamiltonian,
                                  momentequalities=momentequalities,
                                  substitutions=fermionic_constraints(_b),
                                  extramonomials=monomials)
     sdpRelaxation.solve()
     s = 0.5*(sum((Dagger(u)*u) for u in fu) -
              sum((Dagger(d)*d) for d in fd))
     magnetization = sdpRelaxation[s]
     self.assertTrue(abs(magnetization-0.021325317328560453) < 10e-5)
Esempio n. 3
0
    def test_apply_substitutions(self):

        def apply_correct_substitutions(monomial, substitutions):
            if isinstance(monomial, int) or isinstance(monomial, float):
                return monomial
            original_monomial = monomial
            changed = True
            while changed:
                for lhs, rhs in substitutions.items():
                    monomial = monomial.subs(lhs, rhs)
                if original_monomial == monomial:
                    changed = False
                original_monomial = monomial
            return monomial

        length, h, U, t = 2, 3.8, -6, 1
        fu = generate_operators('fu', length)
        fd = generate_operators('fd', length)
        _b = flatten([fu, fd])
        hamiltonian = 0
        for j in range(length):
            hamiltonian += U * (Dagger(fu[j])*Dagger(fd[j]) * fd[j]*fu[j])
            hamiltonian += -h/2*(Dagger(fu[j])*fu[j] - Dagger(fd[j])*fd[j])
            for k in get_neighbors(j, len(fu), width=1):
                hamiltonian += -t*Dagger(fu[j])*fu[k]-t*Dagger(fu[k])*fu[j]
                hamiltonian += -t*Dagger(fd[j])*fd[k]-t*Dagger(fd[k])*fd[j]
        substitutions = fermionic_constraints(_b)
        monomials = expand(hamiltonian).as_coeff_mul()[1][0].as_coeff_add()[1]
        substituted_hamiltonian = sum([apply_substitutions(monomial,
                                                           substitutions)
                                       for monomial in monomials])
        correct_hamiltonian = sum([apply_correct_substitutions(monomial,
                                                               substitutions)
                                   for monomial in monomials])
        self.assertTrue(substituted_hamiltonian == expand(correct_hamiltonian))
Esempio n. 4
0
 def test_ground_state(self):
     length, n, h, U, t = 2, 0.8, 3.8, -6, 1
     fu = generate_operators('fu', length)
     fd = generate_operators('fd', length)
     _b = flatten([fu, fd])
     monomials = [[ci for ci in _b]]
     monomials[-1].extend([Dagger(ci) for ci in _b])
     monomials.append([cj * ci for ci in _b for cj in _b])
     monomials.append([Dagger(cj) * ci for ci in _b for cj in _b])
     monomials[-1].extend([cj * Dagger(ci) for ci in _b for cj in _b])
     monomials.append([Dagger(cj) * Dagger(ci) for ci in _b for cj in _b])
     hamiltonian = 0
     for j in range(length):
         hamiltonian += U * (Dagger(fu[j]) * Dagger(fd[j]) * fd[j] * fu[j])
         hamiltonian += -h / 2 * (Dagger(fu[j]) * fu[j] -
                                  Dagger(fd[j]) * fd[j])
         for k in get_neighbors(j, len(fu), width=1):
             hamiltonian += -t * Dagger(fu[j]) * fu[k] - t * Dagger(
                 fu[k]) * fu[j]
             hamiltonian += -t * Dagger(fd[j]) * fd[k] - t * Dagger(
                 fd[k]) * fd[j]
     momentequalities = [n - sum(Dagger(br) * br for br in _b)]
     sdpRelaxation = SdpRelaxation(_b, verbose=0)
     sdpRelaxation.get_relaxation(-1,
                                  objective=hamiltonian,
                                  momentequalities=momentequalities,
                                  substitutions=fermionic_constraints(_b),
                                  extramonomials=monomials)
     sdpRelaxation.solve()
     s = 0.5 * (sum((Dagger(u) * u) for u in fu) - sum(
         (Dagger(d) * d) for d in fd))
     magnetization = sdpRelaxation[s]
     self.assertTrue(abs(magnetization - 0.021325317328560453) < 10e-5)
Esempio n. 5
0
 def test_violation(self):
     I = [[0, -1, 0], [-1, 1, 1], [0, 1, -1]]
     P = Probability([2, 2], [2, 2])
     objective = define_objective_with_I(I, P)
     sdpRelaxation = MoroderHierarchy([flatten(P.parties[0]), flatten(P.parties[1])], verbose=0, normalized=False)
     sdpRelaxation.get_relaxation(1, objective=objective, substitutions=P.substitutions)
     Problem = convert_to_picos(sdpRelaxation, duplicate_moment_matrix=True)
     X = Problem.get_variable("X")
     Y = Problem.get_variable("Y")
     Z = Problem.add_variable("Z", (sdpRelaxation.block_struct[0], sdpRelaxation.block_struct[0]))
     Problem.add_constraint(Y.partial_transpose() >> 0)
     Problem.add_constraint(Z.partial_transpose() >> 0)
     Problem.add_constraint(X - Y + Z == 0)
     Problem.add_constraint(Z[0, 0] == 1)
     solution = Problem.solve(verbose=0)
     self.assertTrue(abs(solution["obj"] - 0.139) < 10e-3)
Esempio n. 6
0
    def test_apply_substitutions(self):

        def apply_correct_substitutions(monomial, substitutions):
            if isinstance(monomial, int) or isinstance(monomial, float):
                return monomial
            original_monomial = monomial
            changed = True
            while changed:
                for lhs, rhs in substitutions.items():
                    monomial = monomial.subs(lhs, rhs)
                if original_monomial == monomial:
                    changed = False
                original_monomial = monomial
            return monomial

        length, h, U, t = 2, 3.8, -6, 1
        fu = generate_operators('fu', length)
        fd = generate_operators('fd', length)
        _b = flatten([fu, fd])
        hamiltonian = 0
        for j in range(length):
            hamiltonian += U * (Dagger(fu[j])*Dagger(fd[j]) * fd[j]*fu[j])
            hamiltonian += -h/2*(Dagger(fu[j])*fu[j] - Dagger(fd[j])*fd[j])
            for k in get_neighbors(j, len(fu), width=1):
                hamiltonian += -t*Dagger(fu[j])*fu[k]-t*Dagger(fu[k])*fu[j]
                hamiltonian += -t*Dagger(fd[j])*fd[k]-t*Dagger(fd[k])*fd[j]
        substitutions = fermionic_constraints(_b)
        monomials = expand(hamiltonian).as_coeff_mul()[1][0].as_coeff_add()[1]
        substituted_hamiltonian = sum([apply_substitutions(monomial,
                                                           substitutions)
                                       for monomial in monomials])
        correct_hamiltonian = sum([apply_correct_substitutions(monomial,
                                                               substitutions)
                                   for monomial in monomials])
        self.assertTrue(substituted_hamiltonian == expand(correct_hamiltonian))
Esempio n. 7
0
 def __init__(self, lattice_length, lattice_width, solver, outputDir,
              periodic=0, window_length=0, removeequalities=False, parallel=True):
     SecondQuantizedModel.__init__(self, lattice_length, lattice_width,
                                   solver, outputDir, periodic,
                                   window_length, removeequalities, parallel=parallel)
     self._fu = generate_variables(
         'fu', lattice_length * lattice_width, commutative=False)
     self._fd = generate_variables(
         'fd', lattice_length * lattice_width, commutative=False)
     self._b = flatten([self._fu, self._fd])
     self.mu, self.t, self.h, self.U = 0, 0, 0, 0
Esempio n. 8
0
 def test_violation(self):
     I = [[0,   -1,    0],
          [-1,    1,    1],
          [0,    1,   -1]]
     P = Probability([2, 2], [2, 2])
     objective = define_objective_with_I(I, P)
     sdpRelaxation = MoroderHierarchy([flatten(P.parties[0]),
                                       flatten(P.parties[1])],
                                      verbose=0, normalized=False)
     sdpRelaxation.get_relaxation(1, objective=objective,
                                  substitutions=P.substitutions)
     Problem = sdpRelaxation.convert_to_picos(duplicate_moment_matrix=True)
     X = Problem.get_variable('X')
     Y = Problem.get_variable('Y')
     Z = Problem.add_variable('Z', (sdpRelaxation.block_struct[0],
                              sdpRelaxation.block_struct[0]))
     Problem.add_constraint(Y.partial_transpose() >> 0)
     Problem.add_constraint(Z.partial_transpose() >> 0)
     Problem.add_constraint(X - Y + Z == 0)
     Problem.add_constraint(Z[0, 0] == 1)
     solution = Problem.solve(verbose=0)
     self.assertTrue(abs(solution["obj"] - 0.1236) < 10e-3)
Esempio n. 9
0
def optimiseQubitGP(device, starting_angles, eta=1.0, vis=1.0, tol=1e-6):
    """
	Iteratively optimise the angle choices by trying to minimise the extracted dual functional
	"""
    a_in, b_in = device.num_inputs
    bounds = [[0, pi / 2]] + [[-pi, pi] for k in range(a_in + b_in)]
    old_ang, new_ang = starting_angles[:], starting_angles[:]
    cg_shift = device._cgshift

    old_gp = 2.0
    new_gp = 1.0

    # Start iteratively optimising
    while new_gp < old_gp - tol:
        old_ang = new_ang[:]
        old_gp = new_gp

        # Get the current dual solution
        av_curr, lv_curr, _, _, status = device.dualSolution(
            angles2Score(device, old_ang, eta, vis))

        # If this is not a bad solve then proceed with an optimisation.
        if status == 'optimal':
            # function to optimise
            def f0(x):
                ang = [x[0], x[1:a_in + 1], x[1 + a_in:]]
                scr = angles2Score(device, ang, eta, vis)
                return av_curr + np.dot(lv_curr, scr - cg_shift)

            # Find minimising angles
            res = minimize(f0, ncp.flatten(old_ang), bounds=bounds)

            # record results
            new_gp = res.fun
            new_ang = [
                res.x[0], res.x[1:a_in + 1].tolist(),
                res.x[a_in + 1:].tolist()
            ]
        else:
            break

    return old_gp, old_ang
Esempio n. 10
0
    def _relax(self):
        """
		Creates the sdp relaxation object from ncpol2sdpa.
		"""
        if self.solver == None:
            self.solver = self.DEFAULT_SOLVER_PATH
        self._eq_cons = []  # equality constraints
        self._proj_cons = {}  # projective constraints
        self._A_ops = []  # Alice's operators
        self._B_ops = []  # Bob's operators
        self._obj = 0  # Objective function
        self._obj_const = ''  # Extra objective normalisation constant
        self._sdp = None  # SDP object

        # Creating the operator constraints
        nrm = ''
        # Need as many decompositions as there are generating outcomes
        for k in range(np.prod(self.generation_output_size)):
            self._A_ops += [
                ncp.generate_measurements(self.io_config[0],
                                          'A' + str(k) + '_')
            ]
            self._B_ops += [
                ncp.generate_measurements(self.io_config[1],
                                          'B' + str(k) + '_')
            ]
            self._proj_cons.update(
                ncp.projective_measurement_constraints(self._A_ops[k],
                                                       self._B_ops[k]))

            #Also building a normalisation string for next step
            nrm += '+' + str(k) + '[0,0]'

        # Adding the constraints
        # Normalisation constraint
        self._eq_cons.append(nrm + '-1')

        self._base_constraint_expressions = []
        # Create the game expressions
        for game in self.games:
            tmp_expr = 0
            for k in range(np.prod(self.generation_output_size)):
                tmp_expr += -ncp.define_objective_with_I(
                    game._cgmatrix, self._A_ops[k], self._B_ops[k])

            self._base_constraint_expressions.append(tmp_expr)

        # Specify the scores for these expressions including any shifts
        for i, game in enumerate(self.games):
            #We must account for overshifting in the score coming from the decomposition
            self._eq_cons.append(self._base_constraint_expressions[i] -
                                 game.score - game._cgshift *
                                 (np.prod(self.generation_output_size) - 1))

        self._obj, self._obj_const = guessingProbabilityObjectiveFunction(
            self.io_config, self.generation_inputs, self._A_ops, self._B_ops)

        # Initialising SDP
        ops = [
            ncp.flatten([self._A_ops[0], self._B_ops[0]]),
            ncp.flatten([self._A_ops[1], self._B_ops[1]]),
            ncp.flatten([self._A_ops[2], self._B_ops[2]]),
            ncp.flatten([self._A_ops[3], self._B_ops[3]])
        ]

        self._sdp = ncp.SdpRelaxation(ops,
                                      verbose=self.verbose,
                                      normalized=False)
        self._sdp.get_relaxation(level=self._relaxation_level,
                                 momentequalities=self._eq_cons,
                                 objective=self._obj,
                                 substitutions=self._proj_cons,
                                 extraobjexpr=self._obj_const)
Esempio n. 11
0
# We include some extra monomials in the relaxation to boost rates
extra_monos = []
for v in V1 + V2:
    for Ax in A:
        for a in Ax:
            for By in B:
                for b in By:
                    extra_monos += [a * b * v]
                    extra_monos += [a * b * Dagger(v)]

# Objective function
obj = A[0][0] * (V1[0] + Dagger(V1[0])) / 2.0 + A[0][1] * (V1[1] +
                                                           Dagger(V1[1])) / 2.0

ops = ncp.flatten([A, B, V1, V2])
sdp = ncp.SdpRelaxation(ops, verbose=1, normalized=True, parallel=0)
sdp.get_relaxation(level=LEVEL,
                   equalities=operator_equalities,
                   inequalities=operator_inequalities,
                   momentequalities=moment_equalities,
                   momentinequalities=moment_inequalities,
                   objective=-obj,
                   substitutions=substitutions,
                   extramonomials=extra_monos)

sdp.solve('mosek')
print(
    f"For detection efficiency {test_eta} the system {test_sys} achieves a DI-QKD rate of {rate(sdp,test_sys,test_eta)}"
)
            substitutions.update({v * b: b * v})
            substitutions.update({Dagger(v) * b: b * Dagger(v)})

# We can also impose the relations coming from the dilation theorem
for i in range(len(V)):
    substitutions.update({V[i] * Dagger(V[i]): 1})
    for j in range(len(V)):
        if i != j:
            substitutions.update({V[i] * Dagger(V[j]): 0})

# V* V <= 1
operator_ineqs += [1 - (Dagger(V[0])*V[0] + Dagger(V[1])*V[1] + \
       Dagger(V[2])*V[2] + Dagger(V[3])*V[3])]
# We build a localizing set of monomials for the constraint V* V <= 1
# This set includes the monomials AB
localizing_set = ncp.nc_utils.get_all_monomials(ncp.flatten([A, B, V]),
                                                extramonomials=None,
                                                substitutions=substitutions,
                                                degree=1)
localizing_set += AB
# We add this set to the localizing_monomials
localizing_monos += [localizing_set]
# We must also specify localizing mmonomials for the other constraints of the
# problem but by specifying None ncpol2sdpa uses a default set
localizing_monos += [None, None, None]

moment_equalities = moment_eqs[:]
moment_inequalities = moment_ineqs[:] + score_con[:]
operator_equalities = operator_eqs[:]
operator_inequalities = operator_ineqs[:]
Esempio n. 13
0
This example calculates the maximum quantum violation of the CHSH inequality in
the probability picture with a mixed-level relaxation of 1+AB.

Created on Mon Dec  1 14:19:08 2014

@author: Peter Wittek
"""
from ncpol2sdpa import generate_measurements, \
                       projective_measurement_constraints, flatten, \
                       SdpRelaxation, define_objective_with_I, solve_sdp

level = 1
A_configuration = [2, 2]
B_configuration = [2, 2]
I = [[ 0,   -1,    0 ],
     [-1,    1,    1 ],
     [ 0,    1,   -1 ]]
A = generate_measurements(A_configuration, 'A')
B = generate_measurements(B_configuration, 'B')
monomial_substitutions = projective_measurement_constraints(
    A, B)
objective = define_objective_with_I(I, A, B)

AB = [Ai*Bj for Ai in flatten(A) for Bj in flatten(B)]

sdpRelaxation = SdpRelaxation(flatten([A, B]))
sdpRelaxation.get_relaxation(level, objective=objective,
                             substitutions=monomial_substitutions,
                             extramonomials=AB)
print(solve_sdp(sdpRelaxation))
Esempio n. 14
0
def get_factorization_constraints(parties,
                                  moments,
                                  substitutions,
                                  level,
                                  all_parties=False,
                                  return_column_names=False):
    '''Creates all the constraints in moments related to n-locality, namely
    the factorizations <P_i P_j...> = <P_i><P_j>..., where P_i, P_j, ... are
    collections of operators of spacelike-separated parties i, j...

    :param parties: list of measurements for each of the parties spacelike
                    separated. The structure is [party1, party2...], where
                    party_i are the measurements of party i, arranged in
                    the structure [meas1, meas2...], where meas_i is a
                    list containing the symbols of the operators of
                    measurement i.
    :type parties: list of lists of lists of sympy.core.Symbol
    :param moments: known moments obtained with get_moment_constraints.
    :type moments: dict
    :param substitutions: Measurement constraints (commuting, projective...)
                          for the operators involved. Required by
                          get_all_monomials.
    :type substitutions: dict
    :param level: level of the moment matrix
    :type level: int
    :param all_parties: Optional flag for specifying whether the columns for all
                        parties should be created instead of a minimal set.
    :type all_parties: bool
    :param return_column_names: Optional flag to return the moments to which
                                the extra columns correspond
    :type return_column_names: bool

    :returns momentsbilocal: dict with <P_i P_j...> = <P_i><P_j>... constraints.
    :returns extracolumns: list of sympy.core.Symbol that correspond to the
                           extra monomials created.
    :returns columnsnames: list of original monomials corresponding to the
                           names of the extra monomials created.
    '''
    # Factorizations will at most be of size 1|2*level-1
    parties_moments = [
        get_all_monomials(flatten(party), None, substitutions,
                          2 * level - 1)[1:] for party in parties
    ]
    # Strictly speaking, we need to build extra columns of all except one party
    # to sucessfully implement all factorization constraints.
    if not all_parties:
        parties_moments = parties_moments[:-1]

    # Generate commuting symbols for all the additional columns
    parties_columns = [
        generate_variables(
            str(party_moments[0])[0].split('_')[0].lower() + '_',
            len(party_moments)) for party_moments in parties_moments
    ]
    # Substitute symbols whose values are known
    parties_columns = [[
        moments.get(parties_moments[i][parties_columns[i].index(element)],
                    element) for element in party
    ] for i, party in enumerate(parties_columns)]
    # Obtain actual additional columns
    extracolumns = [
        extra for extra in flatten(parties_columns)
        if isinstance(extra, Symbol)
    ]
    columnsnames = [
        symbol for i, symbol in enumerate(flatten(parties_moments))
        if flatten(parties_columns)[i] in extracolumns
    ]

    # Add identities for later computations
    partiesplus1 = [
        party_moments + [S.One] for party_moments in parties_moments
    ]
    extramomentsplus1 = [extracols + [1] for extracols in parties_columns]

    momentsbilocal = {}
    for monomial in get_all_monomials(flatten(parties), None, substitutions,
                                      2 * level)[1:]:
        monomial = monomial.as_ordered_factors()
        party_monomials = [[
            element for element in monomial if element in flatten(party)
        ] for party in parties]
        factors = [prod(party) for party in party_monomials]
        if len(monomial) <= level:
            for z in flatten([extracolumns, 1]):
                key = prod([factor for factor in [z] + factors if factor != 1])
                if all_parties:
                    item = prod([z] + [
                        extramomentsplus1[i][partiesplus1[i].index(factors[i])]
                        for i in range(len(factors))
                    ])
                else:
                    item = prod([z] + [
                        extramomentsplus1[i][partiesplus1[i].index(factors[i])]
                        for i in range(len(factors) - 1)
                    ] + [moments.get(factors[-1], factors[-1])])
                if key != item:
                    momentsbilocal[key] = item
        else:
            if prod([
                    len(party_monomial) < 2 * level
                    for party_monomial in party_monomials
            ]):
                key = prod([factor for factor in factors if factor != 1])
                if all_parties:
                    item = prod([
                        extramomentsplus1[i][partiesplus1[i].index(factors[i])]
                        for i in range(len(factors))
                    ])
                else:
                    item = prod([
                        extramomentsplus1[i][partiesplus1[i].index(factors[i])]
                        for i in range(len(factors) - 1)
                    ] + [moments.get(factors[-1], factors[-1])])
                if key != item:
                    momentsbilocal[key] = item
    if return_column_names:
        return momentsbilocal, extracolumns, columnsnames
    return momentsbilocal, extracolumns