def primal_problem(q_a: np.ndarray, pperm: np.ndarray, num_reps: int) -> float: """ Primal problem for counterfeit attack. As the primal problem takes longer to solve than the dual problem (as the variables are of larger dimension), the primal problem is only here for reference. :return: The optimal value of performing a counterfeit attack. """ num_spaces = 3 sys = list(range(1, num_spaces * num_reps)) sys = [elem for elem in sys if elem % num_spaces != 0] # The dimension of each subsystem is assumed to be of dimension 2. dim = 2 * np.ones((1, num_spaces * num_reps)).astype(int).flatten() dim = dim.tolist() x_var = cvxpy.Variable((8**num_reps, 8**num_reps), hermitian=True) if num_reps == 1: objective = cvxpy.Maximize( cvxpy.trace(cvxpy.real(q_a.conj().T @ x_var))) else: objective = cvxpy.Maximize( cvxpy.trace( cvxpy.real(pperm @ q_a.conj().T @ pperm.conj().T @ x_var))) constraints = [ partial_trace(x_var, sys, dim) == np.identity(2**num_reps), x_var >> 0, ] problem = cvxpy.Problem(objective, constraints) return problem.solve()
def StateRobustnessVerifier(OO, data, label, e): dim, n = data.shape[1], data.shape[0] non_robust_num = 0 e = 1. - np.sqrt(1. - e) print('=' * 35 + '\nStarting state robustness verifier\n' + '-' * 35) for i in range(n): rho = data[i, :, :] # For convenience, only find real entries state sigma = cp.Variable((dim, dim), PSD=True) X = cp.Variable((dim, dim), complex=True) Y = cp.bmat([[rho, X], [X.H, sigma]]) cons = [sigma >> 0., cp.trace(sigma) == 1., Y >> 0.] if label[i] == 0: cons += [cp.real(cp.trace((OO / dim) @ sigma)) >= (0.5 / dim)] else: cons += [cp.real(cp.trace((OO / dim) @ sigma)) <= (0.5 / dim)] obj = cp.Minimize(1 - cp.real(cp.trace(X))) prob = cp.Problem(obj, cons) prob.solve(solver=cp.SCS) delta = 1 - (1. - prob.value) / np.trace(sigma.value) if delta < e: non_robust_num += 1 print('{:d}/{:d} states checked: {:d} unrobust state'.format( i + 1, n, non_robust_num), end='\r') print('{:d}/{:d} states checked: {:d} unrobust state'.format( i + 1, n, non_robust_num)) print('=' * 35) return non_robust_num
def compute_min_norm_solution(x, y, norm_type): """Compute the min-norm solution using a convex-program solver.""" w = cp.Variable((x.shape[0], 1)) if norm_type == 'linf': # compute minimal L_infinity solution constraints = [cp.multiply(y, (w.T @ x)) >= 1] prob = cp.Problem(cp.Minimize(cp.norm_inf(w)), constraints) elif norm_type == 'l2': # compute minimal L_2 solution constraints = [cp.multiply(y, (w.T @ x)) >= 1] prob = cp.Problem(cp.Minimize(cp.norm2(w)), constraints) elif norm_type == 'l1': # compute minimal L_1 solution constraints = [cp.multiply(y, (w.T @ x)) >= 1] prob = cp.Problem(cp.Minimize(cp.norm1(w)), constraints) elif norm_type[0] == 'l': # compute minimal Lp solution p = float(norm_type[1:]) constraints = [cp.multiply(y, (w.T @ x)) >= 1] prob = cp.Problem(cp.Minimize(cp.pnorm(w, p)), constraints) elif norm_type == 'dft1': w = cp.Variable((x.shape[0], 1), complex=True) # compute minimal Fourier L1 norm (||F(w)||_1) solution dft = np.matrix(scipy.linalg.dft(x.shape[0], scale='sqrtn')) constraints = [cp.multiply(y, (cp.real(w).T @ x)) >= 1] prob = cp.Problem(cp.Minimize(cp.norm1(dft @ w)), constraints) prob.solve() logging.info('Min %s-norm solution found (norm=%.4f)', norm_type, float(norm_f(w.value, norm_type))) return cp.real(w).value
def get_primal_problem(self): # matrix sizes for AB and A'B n_basis = len(self._basis_info_list) # number of bases postselected mat_size_AB = self.dim_A * self.dim_B mat_size_ApBp = n_basis * mat_size_AB * self._n_value_A X11 = cvx.Variable((mat_size_ApBp, mat_size_ApBp), complex=True) X12 = cvx.Variable((mat_size_ApBp, mat_size_ApBp), complex=True) X22 = cvx.Variable((mat_size_ApBp, mat_size_ApBp), complex=True) rho_AB = cvx.Variable((mat_size_AB, mat_size_AB), hermitian=True) sigma_ApBp = cvx.Variable((mat_size_ApBp, mat_size_ApBp), hermitian=True) X = cvx.bmat([[X11, X12], [X12.H, X22]]) obj = cvx.Maximize(cvx.trace(cvx.real(X12))) K_AB = self._basis_info_list.unpack('kraus_op') rho_ApBp_ = [k * rho_AB * np.conj(k.T) for k in K_AB] rho_ApBp = block_diagonal_stack(rho_ApBp_) const_X11 = (X11 << rho_ApBp) key_map_povm_ = [ np.kron(np.eye(n_basis * mat_size_AB), povm) for povm in self._key_map_povm ] cq_sigma_ApBp = np.sum(povm * sigma_ApBp * povm for povm in key_map_povm_) const_X22 = (X22 << cq_sigma_ApBp) const_sigma_AB = (cvx.real(cvx.trace(sigma_ApBp)) <= 1) const_X_pos = (X >> 0) const_rho_AB = const_rho_AB_ub = const_rho_AB_lb = [] if self.Gamma_exact is not None: const_rho_AB = [(cvx.trace(rho_AB * G) == g) for g, G in zip(self.gamma, self.Gamma_exact)] if self.Gamma_inexact is not None: const_rho_AB_ub = [ (cvx.real(cvx.trace(rho_AB * G)) <= g_ub) for g_ub, G in zip(self.gamma_ub, self.Gamma_inexact) ] const_rho_AB_lb = [ (cvx.real(cvx.trace(rho_AB * G)) >= g_lb) for g_lb, G in zip(self.gamma_lb, self.Gamma_inexact) ] const_rho_normalized = (cvx.trace(rho_AB) == 1) const_sigma_pos = (sigma_ApBp >> 0) const_rho_pos = (rho_AB >> 0) constraints = [const_X11, const_X22, const_sigma_AB, const_X_pos, const_sigma_pos, const_rho_pos, const_rho_normalized] \ + const_rho_AB + const_rho_AB_ub + const_rho_AB_lb problem = cvx.Problem(obj, constraints) return problem
def test_affine_atoms_canon(self): """Test canonicalization for affine atoms. """ # Scalar. x = Variable() expr = cvx.imag(x + 1j * x) prob = Problem(Minimize(expr), [x >= 0]) result = prob.solve() self.assertAlmostEqual(result, 0) self.assertAlmostEqual(x.value, 0) x = Variable(imag=True) expr = 1j * x prob = Problem(Minimize(expr), [cvx.imag(x) <= 1]) result = prob.solve() self.assertAlmostEqual(result, -1) self.assertAlmostEqual(x.value, 1j) x = Variable(2) expr = x / 1j prob = Problem(Minimize(expr[0] * 1j + expr[1] * 1j), [cvx.real(x + 1j) >= 1]) result = prob.solve() self.assertAlmostEqual(result, -np.inf) prob = Problem(Minimize(expr[0] * 1j + expr[1] * 1j), [cvx.real(x + 1j) <= 1]) result = prob.solve() self.assertAlmostEqual(result, -2) self.assertItemsAlmostEqual(x.value, [1, 1]) prob = Problem( Minimize(expr[0] * 1j + expr[1] * 1j), [cvx.real(x + 1j) >= 1, cvx.conj(x) <= 0]) result = prob.solve() self.assertAlmostEqual(result, np.inf) x = Variable((2, 2)) y = Variable((3, 2), complex=True) expr = cvx.vstack([x, y]) prob = Problem(Minimize(cvx.sum(cvx.imag(cvx.conj(expr)))), [x == 0, cvx.real(y) == 0, cvx.imag(y) <= 1]) result = prob.solve() self.assertAlmostEqual(result, -6) self.assertItemsAlmostEqual(y.value, 1j * np.ones((3, 2))) self.assertItemsAlmostEqual(x.value, np.zeros((2, 2))) x = Variable((2, 2)) y = Variable((3, 2), complex=True) expr = cvx.vstack([x, y]) prob = Problem(Minimize(cvx.sum(cvx.imag(expr.H))), [x == 0, cvx.real(y) == 0, cvx.imag(y) <= 1]) result = prob.solve() self.assertAlmostEqual(result, -6) self.assertItemsAlmostEqual(y.value, 1j * np.ones((3, 2))) self.assertItemsAlmostEqual(x.value, np.zeros((2, 2)))
def linearize(expr): """Returns the tangent approximation to the expression. Gives an elementwise lower (upper) bound for convex (concave) expressions. No guarantees for non-DCP expressions. Args: expr: An expression. Returns: An affine expression. """ if expr.is_affine(): return expr else: if expr.value is None: raise ValueError( "Cannot linearize non-affine expression with missing variable values." ) tangent = np.real(expr.value) #+ np.imag(expr.value) grad_map = expr.grad for var in expr.variables(): if grad_map[var] is None: return None complex_flag = False if var.is_complex() or np.any(np.iscomplex(grad_map[var])): complex_flag = True if var.ndim > 1: temp = cvx.reshape(cvx.vec(var - var.value), (var.shape[0] * var.shape[1], 1)) if complex_flag: flattened = np.transpose(np.real(grad_map[var])) @ cvx.real(temp) + \ np.transpose(np.imag(grad_map[var])) @ cvx.imag(temp) else: flattened = np.transpose(np.real(grad_map[var])) @ temp tangent = tangent + cvx.reshape(flattened, expr.shape) elif var.size > 1: if complex_flag: tangent = tangent + np.transpose(np.real(grad_map[var])) @ (cvx.real(var) - np.real(var.value)) \ + np.transpose(np.imag(grad_map[var])) @ (cvx.imag(var) - np.imag(var.value)) else: tangent = tangent + np.transpose(np.real( grad_map[var])) @ (var - var.value) else: if complex_flag: tangent = tangent + np.real(grad_map[var]) * (cvx.real(var) - np.real(var.value)) \ + np.imag(grad_map[var]) * (cvx.imag(var) - np.imag(var.value)) else: tangent = tangent + np.real( grad_map[var]) * (var - var.value) return tangent
def test_real(self): """Test real. """ A = np.ones((2, 2)) expr = Constant(A) + 1j*Constant(A) expr = cvx.real(expr) assert expr.is_real() assert not expr.is_complex() assert not expr.is_imag() self.assertItemsAlmostEqual(expr.value, A) x = Variable(complex=True) expr = cvx.imag(x) + cvx.real(x) assert expr.is_real()
def test_missing_imag(self): """Test problems where imaginary is missing. """ Z = Variable((2, 2), hermitian=True) constraints = [cvx.trace(cvx.real(Z)) == 1] obj = cvx.Minimize(0) prob = cvx.Problem(obj, constraints) prob.solve() Z = Variable((2, 2), imag=True) obj = cvx.Minimize(cvx.trace(cvx.real(Z))) prob = cvx.Problem(obj, constraints) result = prob.solve() self.assertAlmostEqual(result, 0)
def pure_witness_ansatz(rho): constraints, F, Lam = utils._UNF_witness(9, 9, hermitian=False) target = F - cp.real(cp.trace(rho @ Lam)) pr = cp.Problem(cp.Minimize(target), constraints) pr.solve(solver=cp.MOSEK) eig_vals, eig_vecs = np.linalg.eig(Lam.value) return eig_vecs[:, 0]
def cvxpy_density_matrix_routine(D_matrix,E_matrix): numstate = len(D_matrix) #print(numstate) D_matrix_np = np.array(D_matrix) D_matrix_np = 0.5*(D_matrix_np + np.conjugate(np.transpose(D_matrix_np))) E_matrix_np = np.array(E_matrix) E_matrix_np = 0.5*(E_matrix_np + np.conjugate(np.transpose(E_matrix_np))) #Realification of E #E_real = np.real(E_matrix_np) #E_imag = np.imag(E_matrix_np) #E_realified = np.bmat([[E_real,-E_imag],[E_imag,E_real]]) #Realification of D #D_real = np.real(D_matrix_np) #D_imag = np.imag(D_matrix_np) #D_realified = np.bmat([[D_real,-D_imag],[D_imag,D_real]]) beta = cp.Variable((numstate,numstate),hermitian=True) #print(np.shape(beta)) # Define and solve the CVXPY problem. constraints = [beta >> 0] #constraints += [beta == beta.H] constraints += [cp.trace(E_matrix_np @ beta) == 1] prob = cp.Problem(cp.Minimize(cp.real(cp.trace(D_matrix_np @ beta))),constraints) prob.solve(solver=cp.MOSEK,verbose=False) #Return result. #Returns an np array of the density matrix and the min eigenvalue #Needs to unrealify denmat = beta.value #denmat_real = denmat[0:numstate,0:numstate] #denmat_imag = denmat[numstate:numstate*2,0:numstate] #denmat = denmat_real+1j*denmat_imag minval = np.trace(denmat@D_matrix_np) return denmat,minval
def convexify_constr(constr): """ :param constr: a constraint of a problem :return: for a dcp constraint, return itself; for a non-dcp constraint, return a convexified constraint and domain constraints; return None if non-sub/super-diff """ if not constr.is_dcp(): dom = [] # left hand concave if constr.args[0].curvature == 'CONCAVE': left = linearize(constr.args[0]) if left is None: return None else: for con in constr.args[0].domain: dom.append(con) else: left = constr.args[0] # right hand convex if constr.args[1].curvature == 'CONVEX': right = linearize(constr.args[1]) if right is None: return None else: for con in constr.args[1].domain: dom.append(con) else: right = constr.args[1] return cvx.real(left - right) <= 0, dom else: return constr
def test_symmetric(self) -> None: """Test symmetric variables. """ with self.assertRaises(Exception) as cm: v = Variable((4, 3), symmetric=True) self.assertEqual( str(cm.exception), "Invalid dimensions (4, 3). Must be a square matrix.") v = Variable((2, 2), symmetric=True) assert v.is_symmetric() v = Variable((2, 2), PSD=True) assert v.is_symmetric() v = Variable((2, 2), NSD=True) assert v.is_symmetric() v = Variable((2, 2), diag=True) assert v.is_symmetric() assert self.a.is_symmetric() assert not self.A.is_symmetric() v = Variable((2, 2), symmetric=True) expr = v + v assert expr.is_symmetric() expr = -v assert expr.is_symmetric() expr = v.T assert expr.is_symmetric() expr = cp.real(v) assert expr.is_symmetric() expr = cp.imag(v) assert expr.is_symmetric() expr = cp.conj(v) assert expr.is_symmetric() expr = cp.promote(Variable(), (2, 2)) assert expr.is_symmetric()
def test_complex_matrices(self): """Test complex matrices. """ # Complex-valued matrix K = np.array(np.random.rand(2, 2) + 1j * np.random.rand(2, 2)) # example matrix n1 = la.svdvals(K).sum() # trace norm of K # Dual Problem X = cp.Variable((2, 2), complex=True) Y = cp.Variable((2, 2), complex=True) # X, Y >= 0 so trace is real objective = cp.Minimize( cp.real(0.5 * cp.trace(X) + 0.5 * cp.trace(Y)) ) constraints = [ cp.bmat([[X, -K.conj().T], [-K, Y]]) >> 0, X >> 0, Y >> 0, ] problem = cp.Problem(objective, constraints) sol_scs = problem.solve(solver='SCS') self.assertEqual(constraints[0].dual_value.shape, (4, 4)) self.assertEqual(constraints[1].dual_value.shape, (2, 2)) self.assertEqual(constraints[2].dual_value.shape, (2, 2)) self.assertAlmostEqual(sol_scs, n1)
def test_hermitian(self): """Test Hermitian variables. """ with self.assertRaises(Exception) as cm: v = Variable((4, 3), hermitian=True) self.assertEqual( str(cm.exception), "Invalid dimensions (4, 3). Must be a square matrix.") v = Variable((2, 2), hermitian=True) assert v.is_hermitian() # v = Variable((2,2), PSD=True) # assert v.is_symmetric() # v = Variable((2,2), NSD=True) # assert v.is_symmetric() v = Variable((2, 2), diag=True) assert v.is_hermitian() v = Variable((2, 2), hermitian=True) expr = v + v assert expr.is_hermitian() expr = -v assert expr.is_hermitian() expr = v.T assert expr.is_hermitian() expr = cp.real(v) assert expr.is_hermitian() expr = cp.imag(v) assert expr.is_hermitian() expr = cp.conj(v) assert expr.is_hermitian() expr = cp.promote(Variable(), (2, 2)) assert expr.is_hermitian()
def solve(self, solver='OLE'): ''' Method to solve the model Args: solver:'OLE' Ordinary Least Squares method 'Huber': Uses Huber smoother to down estimate the outliers. ''' W = cp.Variable((self.N, 1), complex=True) if solver.upper() == 'OLE': # Ordinary least squares _objective = cp.Minimize(cp.sum_squares(self.ALPHA @ W + self.A)) elif solver.upper( ) == 'HUBER': # TODO test Huber solver for robust optimization _real = cp.real(self.ALPHA @ W + self.A) _imag = cp.imag(self.ALPHA @ W + self.A) _objective = cp.Minimize( cp.sum_squares(cp.huber(cp.hstack([_real, _imag]), M=0))) elif solver.upper() == 'WLS': # TODO test weighted least squares _objective = cp.Minimize( cp.sum_squares(cp.diag(self.C) @ (self.ALPHA @ W + self.A))) else: raise tools.CustomError('Unrecognized Solver name') prob = cp.Problem(_objective) prob.solve() self.W = W.value return W.value
def optimize_alice(dim: int, prob_mat: np.ndarray, pred_mat: np.ndarray, bob_povms) -> Tuple[Dict, float]: """Fix Bob's measurements and optimize over Alice's measurements.""" # Get number of inputs and outputs. num_inputs_alice, num_inputs_bob = prob_mat.shape num_outputs_alice, num_outputs_bob = pred_mat.shape[0], pred_mat.shape[1] # The cvxpy package does not support optimizing over 4-dimensional objects. # To overcome this, we use a dictionary to index between the questions and # answers, while the cvxpy variables held at this positions are # `dim`-by-`dim` cvxpy variables. alice_povms = defaultdict(cvxpy.Variable) for x_ques in range(num_inputs_alice): for a_ans in range(num_outputs_bob): alice_povms[x_ques, a_ans] = cvxpy.Variable((dim, dim), PSD=True) tau = cvxpy.Variable((dim, dim), PSD=True) # ..math # \sum_{(x,y) \in \Sigma} \pi(x, y) V(a,b|x,y) \ip{B_b^y}{A_a^x} win = 0 is_real = True for x_ques in range(num_inputs_alice): for y_ques in range(num_inputs_bob): for a_ans in range(num_outputs_alice): for b_ans in range(num_outputs_bob): if isinstance(bob_povms[y_ques, b_ans], np.ndarray): win += (prob_mat[x_ques, y_ques] * pred_mat[a_ans, b_ans, x_ques, y_ques] * cvxpy.trace(bob_povms[y_ques, b_ans].conj().T @ alice_povms[x_ques, a_ans])) if isinstance(bob_povms[y_ques, b_ans], cvxpy.expressions.variable.Variable): is_real = False win += ( prob_mat[x_ques, y_ques] * pred_mat[a_ans, b_ans, x_ques, y_ques] * cvxpy.trace(bob_povms[y_ques, b_ans].value.conj().T @ alice_povms[x_ques, a_ans])) if is_real: objective = cvxpy.Maximize(cvxpy.real(win)) else: objective = cvxpy.Maximize(win) constraints = [] # Sum over "a" for all "x" for Alice's measurements. for x_ques in range(num_inputs_alice): alice_sum_a = 0 for a_ans in range(num_outputs_alice): alice_sum_a += alice_povms[x_ques, a_ans] constraints.append(alice_sum_a == tau) constraints.append(cvxpy.trace(tau) == 1) problem = cvxpy.Problem(objective, constraints) lower_bound = problem.solve() return alice_povms, lower_bound
def sdpRho(self): ''' Build and solve optimisation for rho With parameters, we could build it only once. ''' constraints = [] n = self.dimension**self.nbJoueurs rho = cp.Variable((n, n), hermitian=True) constraints += [rho >> 0] constraints += [cp.trace(rho) == 1] socialWelfaire = cp.Constant(0) winrate = cp.Constant(0) for question in self.game.questions(): for answer in self.game.validAnswerIt(question): proba = self.probaRho(answer, question, rho) socialWelfaire += self.game.questionDistribution * self.game.answerPayoutWin( answer) * proba winrate += self.game.questionDistribution * proba sdp = cp.Problem(cp.Maximize(cp.real(socialWelfaire)), constraints) sdp.solve(solver=cp.MOSEK, verbose=False) return rho
def test_cplx_mats(self): """Test complex matrices. """ if cvx.SUPER_SCS in cvx.installed_solvers(): # Complex-valued matrix K = np.matrix(np.random.rand(2, 2) + 1j * np.random.rand(2, 2)) # example matrix n1 = la.svdvals(K).sum() # trace norm of K # Dual Problem X = cvx.Variable((2, 2), complex=True) Y = cvx.Variable((2, 2), complex=True) Z = cvx.Variable((2, 2)) # X, Y >= 0 so trace is real objective = cvx.Minimize( cvx.real(0.5 * cvx.trace(X) + 0.5 * cvx.trace(Y))) constraints = [ cvx.bmat([[X, -K.H], [-K, Y]]) >> 0, X >> 0, Y >> 0, ] problem = cvx.Problem(objective, constraints) sol_scs = problem.solve(solver='SUPER_SCS') self.assertEqual(constraints[0].dual_value.shape, (4, 4)) self.assertEqual(constraints[1].dual_value.shape, (2, 2)) self.assertEqual(constraints[2].dual_value.shape, (2, 2)) self.assertAlmostEqual(sol_scs, n1) else: pass
def test_pnorm(self): """Test complex with pnorm. """ x = Variable((1, 2), complex=True) prob = Problem(cvx.Maximize(cvx.sum(cvx.imag(x) + cvx.real(x))), [cvx.norm1(x) <= 2]) result = prob.solve() self.assertAlmostEqual(result, 2*np.sqrt(2)) val = np.ones(2)*np.sqrt(2)/2 # self.assertItemsAlmostEqual(x.value, val + 1j*val) x = Variable((2, 2), complex=True) prob = Problem(cvx.Maximize(cvx.sum(cvx.imag(x) + cvx.real(x))), [cvx.pnorm(x, p=2) <= np.sqrt(8)]) result = prob.solve() self.assertAlmostEqual(result, 8) val = np.ones((2, 2)) self.assertItemsAlmostEqual(x.value, val + 1j*val)
def test_diag(self) -> None: """Test diag of mat, and of vector. """ X = cvx.Variable((2, 2), complex=True) obj = cvx.Maximize(cvx.trace(cvx.real(X))) cons = [cvx.diag(X) == 1] prob = cvx.Problem(obj, cons) result = prob.solve(solver="SCS") self.assertAlmostEqual(result, 2) x = cvx.Variable(2, complex=True) X = cvx.diag(x) obj = cvx.Maximize(cvx.trace(cvx.real(X))) cons = [cvx.diag(X) == 1] prob = cvx.Problem(obj, cons) result = prob.solve(solver="SCS") self.assertAlmostEqual(result, 2)
def test_bool(self) -> None: # The purpose of this test is to make sure # that we don't try to recover dual variables # unless they're actually present. # # Added as part of fixing GitHub issue 1133. bool_var = cp.Variable(boolean=True) complex_var = cp.Variable(complex=True) constraints = [ cp.real(complex_var) <= bool_var, ] obj = cp.Maximize(cp.real(complex_var)) prob = cp.Problem(obj, constraints) prob.solve(solver='ECOS_BB') self.assertAlmostEqual(prob.value, 1, places=4)
def cvxpy_density_matrix_feasibility_sdp_routine_old(D_matrix,E_matrix,R_matrices,F_matrices,gammas,sdp_tolerance_bound): numstate = len(D_matrix) D_matrix_np = np.array(D_matrix) #D_matrix_np = 0.5*(D_matrix_np + np.conjugate(np.transpose(D_matrix_np))) E_matrix_np = np.array(E_matrix) #E_matrix_np = 0.5*(E_matrix_np + np.conjugate(np.transpose(E_matrix_np))) R_matrices_np = [] F_matrices_np = [] for r in R_matrices: R_matrices_np.append(np.array(r)) for f in F_matrices: F_matrices_np.append(np.array(f)) beta = cp.Variable((numstate,numstate),complex=True) constraints = [beta >> 0] #constraints += [cp.trace(E_matrix_np @ beta) == 1] constraints += [beta.H == beta] a = -1j*(D_matrix_np@beta@E_matrix_np-E_matrix_np@beta@D_matrix_np) #finalconstraints = [] for i in range(len(gammas)): a = a + gammas[i]*(R_matrices_np[i]@[email protected](np.conjugate(R_matrices_np[i]))-0.5*F_matrices_np[i]@beta@E_matrix_np-0.5*E_matrix_np@beta@F_matrices_np[i]) #a = -1j*(D_matrix_np@beta@E_matrix_np-E_matrix_np@beta@D_matrix_np)+gammas[0]*(R_matrices_np[0]@[email protected](np.conjugate(R_matrices_np[0]))-0.5*F_matrices_np[0]@beta@E_matrix_np-0.5*E_matrix_np@beta@F_matrices_np[0]) #constraints += [cp.trace(E_matrix_np @ beta) == 1] constraints += [a == 0] #constraints += [cp.trace(a@(a.H))<=sdp_tolerance_bound] #constraints += [cp.trace(a@(a.H))>=-sdp_tolerance_bound] if sdp_tolerance_bound == 0: print('Feasibility SDP is set up with hard constraint == 1') #constraints += [a == 0] constraints += [cp.trace(E_matrix_np @ beta) == 1] else: print('Feasibility SDP is set up with interval constraint <'+str(sdp_tolerance_bound)+ ' & >-'+str(sdp_tolerance_bound)) #constraints += [cp.abs(cp.trace(a@(a.H)))<=sdp_tolerance_bound] #constraints += [cp.abs(cp.trace(a@(a.H)))>=-sdp_tolerance_bound] constraints += [cp.real(cp.trace(E_matrix_np @ beta)) <= 1+sdp_tolerance_bound] constraints += [cp.real(cp.trace(E_matrix_np @ beta)) >= 1-sdp_tolerance_bound] prob = cp.Problem(cp.Minimize(0),constraints) prob.solve(solver=cp.MOSEK,verbose=False) denmat = beta.value #print(denmat) if type(denmat) == type(None): return None,None else: minval = np.trace(denmat@D_matrix_np) return denmat,minval
def test_promote(self): """Test promotion of complex variables. """ v = Variable(complex=True) obj = cvx.Maximize(cvx.real(cvx.sum(v * np.ones((2, 2))))) con = [cvx.norm(v) <= 1] prob = cvx.Problem(obj, con) result = prob.solve() self.assertAlmostEqual(result, 4.0)
def test_abs(self): """Test with absolute value. """ x = Variable(2, complex=True) prob = Problem(cvx.Maximize(cvx.sum(cvx.imag(x) + cvx.real(x))), [cvx.abs(x) <= 2]) result = prob.solve() self.assertAlmostEqual(result, 4*np.sqrt(2)) val = np.ones(2)*np.sqrt(2) self.assertItemsAlmostEqual(x.value, val + 1j*val)
def diamond_norm(chan0: Channel, chan1: Channel) -> float: """Return the diamond norm between two completely positive trace-preserving (CPTP) superoperators. Note: Requires "cvxpy" package (and dependencies) to be fully installed. The calculation uses the simplified semidefinite program of Watrous [arXiv:0901.4709](http://arxiv.org/abs/0901.4709) [J. Watrous, [Theory of Computing 5, 11, pp. 217-238 (2009)](http://theoryofcomputing.org/articles/v005a011/)] """ # Kudos: Based on MatLab code written by Marcus P. da Silva # (https://github.com/BBN-Q/matlab-diamond-norm/) import cvxpy as cvx if set(chan0.qubits) != set(chan1.qubits): raise ValueError("Channels must operate on same qubits") if chan0.qubits != chan1.qubits: chan1 = chan1.permute(chan0.qubits) N = chan0.qubit_nb dim = 2**N choi0 = chan0.choi() choi1 = chan1.choi() delta_choi = choi0 - choi1 # Density matrix must be Hermitian, positive semidefinite, trace 1 rho = cvx.Variable([dim, dim], complex=True) constraints = [rho == rho.H] constraints += [rho >> 0] constraints += [cvx.trace(rho) == 1] # W must be Hermitian, positive semidefinite W = cvx.Variable([dim**2, dim**2], complex=True) constraints += [W == W.H] constraints += [W >> 0] constraints += [(W - cvx.kron(np.eye(dim), rho)) << 0] J = cvx.Parameter([dim**2, dim**2], complex=True) objective = cvx.Maximize(cvx.real(cvx.trace(J.H * W))) prob = cvx.Problem(objective, constraints) J.value = delta_choi prob.solve() dnorm = prob.value * 2 # Diamond norm is between 0 and 2. Correct for floating point errors dnorm = min(2, dnorm) dnorm = max(0, dnorm) return dnorm
def write_problem(self, complex_field=False): if complex_field: problem = cp.Problem(cp.Maximize(cp.real(self.object_function)), self.constraints) else: problem = cp.Problem(cp.Maximize(self.object_function), self.constraints) return problem
def get_primal_problem(self): mat_size = np.prod(self.dims) # matrix sizes X11 = cvx.Variable((mat_size, mat_size), complex=True) X12 = cvx.Variable((mat_size, mat_size), complex=True) X22 = cvx.Variable((mat_size, mat_size), complex=True) rho_AB = cvx.Variable((mat_size, mat_size), hermitian=True) sigma_AB = cvx.Variable((mat_size, mat_size), hermitian=True) X = cvx.bmat([[X11, X12], [X12.H, X22]]) obj = cvx.Maximize(cvx.trace(cvx.real(X12))) const_X11 = (X11 << rho_AB) cq_sigma_AB = np.sum(povm * sigma_AB * povm for povm in self._key_map_povm) const_X22 = (X22 << cq_sigma_AB) const_sigma_AB = (cvx.real(cvx.trace(sigma_AB)) <= 1) const_X_pos = (X >> 0) const_rho_AB = const_rho_AB_ub = const_rho_AB_lb = [] if self.Gamma_exact is not None: const_rho_AB = [(cvx.trace(rho_AB * G) == g) for g, G in zip(self.gamma, self.Gamma_exact)] if self.Gamma_inexact is not None: const_rho_AB_ub = [ (cvx.real(cvx.trace(rho_AB * G)) <= g_ub) for g_ub, G in zip(self.gamma_ub, self.Gamma_inexact) ] const_rho_AB_lb = [ (cvx.real(cvx.trace(rho_AB * G)) >= g_lb) for g_lb, G in zip(self.gamma_lb, self.Gamma_inexact) ] const_rho_normalized = (cvx.trace(rho_AB) == 1) const_sigma_pos = (sigma_AB >> 0) const_rho_pos = (rho_AB >> 0) constraints = [const_X11, const_X22, const_sigma_AB, const_X_pos, const_sigma_pos, const_rho_pos, const_rho_normalized] \ + const_rho_AB + const_rho_AB_ub + const_rho_AB_lb problem = cvx.Problem(obj, constraints) return problem
def diamond_norm(J, dimA, dimB, display=False): ''' Computes the diamond norm of a superoperator with Choi representation J. dimA is the dimension of the input space of the channel, and dimB is the dimension of the output space. The form of the SDP used comes from Theorem 3.1 of: 'Simpler semidefinite programs for completely bounded norms', Chicago Journal of Theoretical Computer Science 2013, by John Watrous ''' ''' The Choi representation J in the above paper is defined using a different convention: J=(N\otimes I)(|Phi^+><Phi^+|). In other words, the channel N acts on the first half of the maximally- entangled state, while the convention used throughout this code stack is J=(I\otimes N)(|Phi^+><Phi^+|). We thus use syspermute to convert to the form used in the aforementioned paper. ''' J = syspermute(J, [2, 1], [dimA, dimB]) X = cvx.Variable((dimA * dimB, dimA * dimB), hermitian=False) rho0 = cvx.Variable((dimA, dimA), PSD=True) rho1 = cvx.Variable((dimA, dimA), PSD=True) M = cvx.bmat([[cvx.kron(eye(dimB), rho0), X], [X.H, cvx.kron(eye(dimB), rho1)]]) c = [] c += [M >> 0, cvx.trace(rho0) == 1, cvx.trace(rho1) == 1] obj = cvx.Maximize((1 / 2) * cvx.real(cvx.trace(dag(J) @ X)) + (1 / 2) * cvx.real(cvx.trace(J @ X.H))) prob = cvx.Problem(obj, constraints=c) prob.solve(verbose=display, eps=1e-7) return prob.value
def diamond_norm_distance(choi0: np.ndarray, choi1: np.ndarray) -> float: """ Return the diamond norm distance between two completely positive trace-preserving (CPTP) superoperators, represented as Choi matrices. The calculation uses the simplified semidefinite program of Watrous in [CBN]_ .. note:: This calculation becomes very slow for 4 or more qubits. .. [CBN] Semidefinite programs for completely bounded norms. J. Watrous. Theory of Computing 5, 11, pp. 217-238 (2009). http://theoryofcomputing.org/articles/v005a011 http://arxiv.org/abs/0901.4709 :param choi0: A 4**N by 4**N matrix (where N is the number of qubits) :param choi1: A 4**N by 4**N matrix (where N is the number of qubits) """ # Kudos: Based on MatLab code written by Marcus P. da Silva # (https://github.com/BBN-Q/matlab-diamond-norm/) import cvxpy as cvx assert choi0.shape == choi1.shape assert choi0.shape[0] == choi1.shape[1] dim_squared = choi0.shape[0] dim = int(np.sqrt(dim_squared)) delta_choi = choi0 - choi1 delta_choi = (delta_choi.conj().T + delta_choi) / 2 # Enforce Hermiticity # Density matrix must be Hermitian, positive semidefinite, trace 1 rho = cvx.Variable([dim, dim], complex=True) constraints = [rho == rho.H] constraints += [rho >> 0] constraints += [cvx.trace(rho) == 1] # W must be Hermitian, positive semidefinite W = cvx.Variable([dim_squared, dim_squared], complex=True) constraints += [W == W.H] constraints += [W >> 0] constraints += [(W - cvx.kron(np.eye(dim), rho)) << 0] J = cvx.Parameter([dim_squared, dim_squared], complex=True) objective = cvx.Maximize(cvx.real(cvx.trace(J.H * W))) prob = cvx.Problem(objective, constraints) J.value = delta_choi prob.solve() dnorm = prob.value * 2 return dnorm
def test_params(self): """Test with parameters. """ p = cvx.Parameter(imag=True, value=1j) x = Variable(2, complex=True) prob = Problem(cvx.Maximize(cvx.sum(cvx.imag(x) + cvx.real(x))), [cvx.abs(p*x) <= 2]) result = prob.solve() self.assertAlmostEqual(result, 4*np.sqrt(2)) val = np.ones(2)*np.sqrt(2) self.assertItemsAlmostEqual(x.value, val + 1j*val)