def minimalCommutatorDistance(c1, c2, sdp=None, relaxation_level = 2): # No sdp passed, create one if sdp is None: D = ncp.generate_operators('D', 1)[0] X = ncp.generate_operators('X', 1)[0] # The sdp will ignore the +1 term, we have to add it on at the end obj = Dagger(commutator(D,X) - 1)*(commutator(D,X) - 1) inequality_cons = [c1**2 - Dagger(X)*X >= 0, c2**2 - Dagger(D)*D >= 0] sdp = ncp.SdpRelaxation([D,X], normalized = True) sdp.get_relaxation(level = relaxation_level, objective = obj, inequalities = inequality_cons) else: # sdp object passed. Use process_constraints instead D = sdp.monomial_sets[0][1] X = sdp.monomial_sets[0][2] inequality_cons = [c1**2 - Dagger(X)*X >= 0, c2**2 - Dagger(D)*D >= 0] sdp.process_constraints(inequalities = inequality_cons) # Now solve sdp.solve(solver = SOLVER_NAME, solverparameters = SOLVER_EXE) if sdp.status == 'optimal': return sqrt(sdp.primal + 1), sdp else: return None, sdp
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)
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))
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)
def isFeasible(c1, c2, eps, sdp = None, relaxation_level = 2): # No sdp passed, create one if sdp is None: D = ncp.generate_operators('D', 1)[0] X = ncp.generate_operators('X', 1)[0] obj = 1.0 inequality_cons = [c1**2 - Dagger(X)*X >= 0, c2**2 - Dagger(D)*D >= 0, eps**2 - Dagger(commutator(D,X))*commutator(D,X) + Dagger(commutator(D,X)) + commutator(D,X) - 1 >= 0] sdp = ncp.SdpRelaxation([D,X], normalized = True) sdp.get_relaxation(level = relaxation_level, objective = obj, inequalities = inequality_cons) else: # sdp object passed. Use process_constraints instead D = sdp.monomial_sets[0][1] X = sdp.monomial_sets[0][2] inequality_cons = [c1**2 - Dagger(X)*X >= 0, c2**2 - Dagger(D)*D >= 0, eps**2 - Dagger(commutator(D,X))*commutator(D,X) + Dagger(commutator(D,X)) + commutator(D,X) - 1 >= 0] sdp.process_constraints(inequalities = inequality_cons) # Now solve sdp.solve(solver = SOLVER_NAME, solverparameters = SOLVER_EXE) if sdp.status == 'optimal': return True, sdp else: return False, sdp
def test_maximum_violation(self): def expectation_values(measurement, outcomes): exp_values = [] for k in range(len(measurement)): exp_value = 0 for j in range(len(measurement[k])): exp_value += outcomes[k][j] * measurement[k][j] exp_values.append(exp_value) return exp_values E = generate_operators('E', 8, hermitian=True) M, outcomes = [], [] for i in range(4): M.append([E[2 * i], E[2 * i + 1]]) outcomes.append([1, -1]) A = [M[0], M[1]] B = [M[2], M[3]] substitutions = projective_measurement_constraints(A, B) C = expectation_values(M, outcomes) chsh = -(C[0] * C[2] + C[0] * C[3] + C[1] * C[2] - C[1] * C[3]) sdpRelaxation = SdpRelaxation(E, verbose=0) sdpRelaxation.get_relaxation(1, objective=chsh, substitutions=substitutions) sdpRelaxation.solve() self.assertTrue(abs(sdpRelaxation.primal + 2*np.sqrt(2)) < 10e-5)
def test_maximum_violation(self): def expectation_values(measurement, outcomes): exp_values = [] for k in range(len(measurement)): exp_value = 0 for j in range(len(measurement[k])): exp_value += outcomes[k][j] * measurement[k][j] exp_values.append(exp_value) return exp_values E = generate_operators('E', 8, hermitian=True) M, outcomes = [], [] for i in range(4): M.append([E[2 * i], E[2 * i + 1]]) outcomes.append([1, -1]) A = [M[0], M[1]] B = [M[2], M[3]] substitutions = projective_measurement_constraints(A, B) C = expectation_values(M, outcomes) chsh = -(C[0] * C[2] + C[0] * C[3] + C[1] * C[2] - C[1] * C[3]) sdpRelaxation = SdpRelaxation(E, verbose=0) sdpRelaxation.get_relaxation(1, objective=chsh, substitutions=substitutions) sdpRelaxation.solve() self.assertTrue(abs(sdpRelaxation.primal + 2 * np.sqrt(2)) < 10e-5)
def setUp(self): X = generate_operators('x', 2, hermitian=True) self.sdpRelaxation = SdpRelaxation(X) self.sdpRelaxation.get_relaxation(2, objective=X[0] * X[1] + X[1] * X[0], inequalities=[-X[1]**2 + X[1] + 0.5], substitutions={X[0]**2: X[0]})
def test_ground_state_energy(self): N = 3 a = generate_operators('a', N) substitutions = bosonic_constraints(a) hamiltonian = sum(Dagger(a[i]) * a[i] for i in range(N)) sdpRelaxation = SdpRelaxation(a, verbose=0) sdpRelaxation.get_relaxation(1, objective=hamiltonian, substitutions=substitutions) sdpRelaxation.solve() self.assertTrue(abs(sdpRelaxation.primal) < 10e-5)
def test_fast_substitute(self): f = generate_operators('f', 2) substitutions = {} substitutions[Dagger(f[0])*f[0]] = -f[0]*Dagger(f[0]) monomial = Dagger(f[0])*f[0] lhs = Dagger(f[0])*f[0] rhs = -f[0]*Dagger(f[0]) self.assertTrue(fast_substitute(monomial, lhs, rhs) == monomial.subs(lhs, rhs)) monomial = Dagger(f[0])*f[0]**2 self.assertTrue(fast_substitute(monomial, lhs, rhs) == monomial.subs(lhs, rhs)) monomial = Dagger(f[0])**2*f[0] self.assertTrue(fast_substitute(monomial, lhs, rhs) == monomial.subs(lhs, rhs)) monomial = Dagger(f[0])**2*f[0] lhs = Dagger(f[0])**2 rhs = -f[0]*Dagger(f[0]) self.assertTrue(fast_substitute(monomial, lhs, rhs) == monomial.subs(lhs, rhs)) g = generate_operators('g', 2) monomial = 2*g[0]**3*g[1]*Dagger(f[0])**2*f[0] self.assertTrue(fast_substitute(monomial, lhs, rhs) == monomial.subs(lhs, rhs)) monomial = S.One self.assertTrue(fast_substitute(monomial, lhs, rhs) == monomial.subs(lhs, rhs)) monomial = 5 self.assertTrue(fast_substitute(monomial, lhs, rhs) == monomial) monomial = 2*g[0]**3*g[1]*Dagger(f[0])**2*f[0] + f[1] self.assertTrue(fast_substitute(monomial, lhs, rhs) == monomial.subs(lhs, rhs)) monomial = f[1]*Dagger(f[0])**2*f[0] lhs = f[1] rhs = 1.0 + f[0] self.assertTrue(fast_substitute(monomial, lhs, rhs) == expand(monomial.subs(lhs, rhs))) monomial = f[1]**2*Dagger(f[0])**2*f[0] result = fast_substitute(fast_substitute(monomial, lhs, rhs), lhs, rhs) self.assertTrue(result == expand(monomial.subs(lhs, rhs)))
def test_fast_substitute(self): f = generate_operators('f', 2) substitutions = {} substitutions[Dagger(f[0]) * f[0]] = -f[0] * Dagger(f[0]) monomial = Dagger(f[0]) * f[0] lhs = Dagger(f[0]) * f[0] rhs = -f[0] * Dagger(f[0]) self.assertTrue( fast_substitute(monomial, lhs, rhs) == monomial.subs(lhs, rhs)) monomial = Dagger(f[0]) * f[0]**2 self.assertTrue( fast_substitute(monomial, lhs, rhs) == monomial.subs(lhs, rhs)) monomial = Dagger(f[0])**2 * f[0] self.assertTrue( fast_substitute(monomial, lhs, rhs) == monomial.subs(lhs, rhs)) monomial = Dagger(f[0])**2 * f[0] lhs = Dagger(f[0])**2 rhs = -f[0] * Dagger(f[0]) self.assertTrue( fast_substitute(monomial, lhs, rhs) == monomial.subs(lhs, rhs)) g = generate_operators('g', 2) monomial = 2 * g[0]**3 * g[1] * Dagger(f[0])**2 * f[0] self.assertTrue( fast_substitute(monomial, lhs, rhs) == monomial.subs(lhs, rhs)) monomial = S.One self.assertTrue( fast_substitute(monomial, lhs, rhs) == monomial.subs(lhs, rhs)) monomial = 5 self.assertTrue(fast_substitute(monomial, lhs, rhs) == monomial) monomial = 2 * g[0]**3 * g[1] * Dagger(f[0])**2 * f[0] + f[1] self.assertTrue( fast_substitute(monomial, lhs, rhs) == monomial.subs(lhs, rhs)) monomial = f[1] * Dagger(f[0])**2 * f[0] lhs = f[1] rhs = 1.0 + f[0] self.assertTrue( fast_substitute(monomial, lhs, rhs) == expand( monomial.subs(lhs, rhs))) monomial = f[1]**2 * Dagger(f[0])**2 * f[0] result = fast_substitute(fast_substitute(monomial, lhs, rhs), lhs, rhs) self.assertTrue(result == expand(monomial.subs(lhs, rhs)))
def setUp(self): X = generate_operators('x', 2, hermitian=True) self.sdpRelaxation = SdpRelaxation(X) self.sdpRelaxation.get_relaxation(2, objective=X[0]*X[1] + X[1]*X[0], inequalities=[-X[1]**2 + X[1] + 0.5], substitutions={X[0]**2: X[0]})
LEVEL = 2 # Defining the measurement scheme we add additional operators to the inputs # X=0 as the package ncpol2sdpa will automatically remove a # projector for efficiency purposes. However, we need all projectors # for the randomness certification inputs to ensure certain Cauchy-Schwarz # relations are enforced. # We also don't need to specify Bobs third input as we can lower bound H(A|E) # using only the measurements on inputs {0,1} A_config = [3, 2] B_config = [2, 2] # Measurement operators A = [Ai for Ai in ncp.generate_measurements(A_config, 'A')] B = [Bj for Bj in ncp.generate_measurements(B_config, 'B')] V1 = ncp.generate_operators('V1', 2, hermitian=False) V2 = ncp.generate_operators('V2', 2, hermitian=False) substitutions = {} moment_ineqs = [] moment_eqs = [] operator_eqs = [] operator_ineqs = [] # Projectors sum to identity # We can speed up the computation (for potentially worse rates) by imposing these # as moment equalities. moment_eqs += [A[0][0] + A[0][1] - 1] # Adding the constraints for the measurement operators substitutions.update(ncp.projective_measurement_constraints(A, B))
# Global level of NPA relaxation LEVEL = 2 # Maximum CHSH score WMAX = 0.5 + sqrt(2) / 4 # Defining the measurement scheme we add additional operators to the inputs # (X,Y) = (0,0) as the package ncpol2sdpa will automatically remove a # projector for efficiency purposes. However, we need all projectors # for the randomness certification inputs to ensure certain Cauchy-Schwarz # relations are enforced. A_config = [3, 2] B_config = [3, 2] # Measurement operators A = [Ax for Ax in ncp.generate_measurements(A_config, 'A')] B = [By for By in ncp.generate_measurements(B_config, 'B')] V = ncp.generate_operators('V', 4, hermitian=False) # Collecting all monomials of form AB for later AB = [] for Ax, By in product(A, B): AB += [a * b for a, b in product(Ax, By)] substitutions = {} moment_ineqs = [] moment_eqs = [] operator_eqs = [] operator_ineqs = [] localizing_monos = [ ] # op_eqs are processed last so need to add three Nones to end # Projectors sum to identity