def solve_full(self, bi, lmbd, show_progress=True): solvers.options['show_progress'] = show_progress # load problem data self.bi = bi self.lmbd = lmbd self.c[1 + self.Nm:1 + self.Nm + self.Nb] = lmbd self.h[1:1 + self.Nm] = -bi t1 = time() self.sol = solvers.conelp( self.c, self.G, self.h, self.dims, self.A, self.b) t2 = time() t3 = time() if self.sol['status'] in ('optimal'): S = self.sol['s'][1 + self.Nm:] self.sA[:] = S[self.I11] + 1j*S[self.I21] lapack.heevr( self.sA, self.sW, jobz='V', range='I', uplo='L', vl=0.0, vu=0.0, il=self.Nb, iu=self.Nb, Z=self.sZ) self.beta_hat[:] = math.sqrt(self.sW[0])*self.sZ[:, 0] else: raise RuntimeError('numerical problems') t4 = time() self.solver_time = t2 - t1 self.eig_time = t4 - t3
def solve(opts): c = matrix([-6., -4., -5.]) G = matrix([[ 16., 7., 24., -8., 8., -1., 0., -1., 0., 0., 7., -5., 1., -5., 1., -7., 1., -7., -4. ], [ -14., 2., 7., -13., -18., 3., 0., 0., -1., 0., 3., 13., -6., 13., 12., -10., -6., -10., -28. ], [ 5., 0., -15., 12., -6., 17., 0., 0., 0., -1., 9., 6., -6., 6., -7., -7., -6., -7., -11. ]]) h = matrix([ -3., 5., 12., -2., -14., -13., 10., 0., 0., 0., 68., -30., -19., -30., 99., 23., -19., 23., 10. ]) A = matrix(0.0, (0, c.size[0])) b = matrix(0.0, (0, 1)) dims = {'l': 2, 'q': [4, 4], 's': [3]} #localcones.options.update(opts) #sol = localcones.conelp(c, G, h, dims, kktsolver='qr') solvers.options.update(opts) sol = solvers.conelp(c, G, h, dims) print("\nStatus: " + sol['status']) if sol['status'] == 'optimal': print "x=\n", helpers.strSpe(sol['x'], "%.5f") print "s=\n", helpers.strSpe(sol['s'], "%.5f") print "z=\n", helpers.strSpe(sol['z'], "%.5f") rungotest(sol)
def solve_full(self, bi, lmbd, show_progress=True): solvers.options['show_progress'] = show_progress # load problem data self.bi = bi self.lmbd = lmbd self.c[1 + self.Nm:1 + self.Nm + self.Nb] = lmbd self.h[1:1 + self.Nm] = -bi t1 = time() self.sol = solvers.conelp(self.c, self.G, self.h, self.dims, self.A, self.b) t2 = time() t3 = time() if self.sol['status'] in ('optimal'): S = self.sol['s'][1 + self.Nm:] self.sA[:] = S[self.I11] + 1j * S[self.I21] lapack.heevr(self.sA, self.sW, jobz='V', range='I', uplo='L', vl=0.0, vu=0.0, il=self.Nb, iu=self.Nb, Z=self.sZ) self.beta_hat[:] = math.sqrt(self.sW[0]) * self.sZ[:, 0] else: raise RuntimeError('numerical problems') t4 = time() self.solver_time = t2 - t1 self.eig_time = t4 - t3
def call_solver(p,quiet): """ Calls solver. :param p: Convex cvxpy_program. Assumed to be expanded. :param quiet: Boolean. """ # Set printing format for cvxopt sparse matrices opt.spmatrix_str = opt.printing.spmatrix_str_triplet # Expand objects defined via partial minimization constr_list = cvxpy_list(pm_expand(p.constraints)) # Get variables variables = constr_list.variables variables.sort() # Count variables n = len(variables) # Create variable-index map var_to_index = {} for i in range(0,n,1): var_to_index[variables[i]] = i # Construct objective vector c = construct_c(p.objective,var_to_index,n,p.action) # Construct Ax == b A,b = construct_Ab(constr_list._get_eq(),var_to_index,n) # Construct Gx <= h G,h,dim_l,dim_q,dim_s = construct_Gh(constr_list._get_ineq_in(), var_to_index,n) # Construct F F = construct_F(constr_list._get_ineq_in(),var_to_index,n) # Call cvxopt solvers.options['maxiters'] = p.options['maxiters'] solvers.options['abstol'] = p.options['abstol'] solvers.options['reltol'] = p.options['reltol'] solvers.options['feastol'] = p.options['feastol'] solvers.options['show_progress'] = not quiet dims = {'l':dim_l, 'q':dim_q, 's':dim_s} if F is None: r = solvers.conelp(c,G,h,dims,A,b) else: r = solvers.cpl(c,F,G,h,dims,A,b) # Store numerical values if r['status'] != PRIMAL_INFEASIBLE: for v in variables: v.value = r['x'][var_to_index[v]] # Return result return r
def call_solver(p, quiet): """ Calls solver. :param p: Convex cvxpy_program. Assumed to be expanded. :param quiet: Boolean. """ # Set printing format for cvxopt sparse matrices opt.spmatrix_str = opt.printing.spmatrix_str_triplet # Expand objects defined via partial minimization constr_list = cvxpy_list(pm_expand(p.constraints)) # Get variables variables = constr_list.variables variables.sort() # Count variables n = len(variables) # Create variable-index map var_to_index = {} for i in range(0, n, 1): var_to_index[variables[i]] = i # Construct objective vector c = construct_c(p.objective, var_to_index, n, p.action) # Construct Ax == b A, b = construct_Ab(constr_list._get_eq(), var_to_index, n) # Construct Gx <= h G, h, dim_l, dim_q, dim_s = construct_Gh(constr_list._get_ineq_in(), var_to_index, n) # Construct F F = construct_F(constr_list._get_ineq_in(), var_to_index, n) # Call cvxopt solvers.options['maxiters'] = p.options['maxiters'] solvers.options['abstol'] = p.options['abstol'] solvers.options['reltol'] = p.options['reltol'] solvers.options['feastol'] = p.options['feastol'] solvers.options['show_progress'] = not quiet dims = {'l': dim_l, 'q': dim_q, 's': dim_s} if F is None: r = solvers.conelp(c, G, h, dims, A, b) else: r = solvers.cpl(c, F, G, h, dims, A, b) # Store numerical values if r['status'] != PRIMAL_INFEASIBLE: for v in variables: v.value = r['x'][var_to_index[v]] # Return result return r
def test_conelp(self): from cvxopt import matrix, msk, solvers c = matrix([-6., -4., -5.]) G = matrix([[ 16., 7., 24., -8., 8., -1., 0., -1., 0., 0., 7., -5., 1., -5., 1., -7., 1., -7., -4.], [-14., 2., 7., -13., -18., 3., 0., 0., -1., 0., 3., 13., -6., 13., 12., -10., -6., -10., -28.], [ 5., 0., -15., 12., -6., 17., 0., 0., 0., -1., 9., 6., -6., 6., -7., -7., -6., -7., -11.]]) h = matrix( [ -3., 5., 12., -2., -14., -13., 10., 0., 0., 0., 68., -30., -19., -30., 99., 23., -19., 23., 10.] ) dims = {'l': 2, 'q': [4, 4], 's': [3]} self.assertAlmostEqualLists(list(solvers.conelp(c, G, h, dims)['x']),list(msk.conelp(c, G, h, dims)[1]))
def run(self, lam=10.0, mu=0.0, eps=0.0, s0_val=0.001): G_tmp, h_tmp = get_G_h(self.var_No) h_eps = matrix(0.0, (self.G_No, 1)) G_x = [] G_i = [] G_j = [] for G_name in self.SFG: G = self.SFG.node[G_name] if G['type'] == 'G': g_cnt = G['cnt'] h_eps[g_cnt] = G['intensity'] + eps for I_name in self.SFG[G_name]: i_cnt = self.SFG.node[I_name]['cnt'] G_x.append(1.0) G_i.append(g_cnt) G_j.append(i_cnt) G_x.append(-1.0) G_i.append(g_cnt) G_j.append(self.GI_No + self.M_No + g_cnt) G_tmp2 = spmatrix(G_x, G_i, G_j, size=(self.G_No, self.var_No)) G = sparse([G_tmp, G_tmp2]) h = matrix([h_tmp, h_eps]) A_tmp, b = get_A_b(self.SFG, self.M_No, self.I_No, self.GI_No) A_eps = spmatrix([], [], [], (self.I_No, self.G_No)) A = sparse([[A_tmp], [A_eps]]) x0 = get_initvals(self.var_No) x0['s'] = matrix(s0_val, size=h.size) c = matrix([ matrix(-1.0, size=(self.GI_No, 1)), matrix(mu, size=(self.M_No, 1)), matrix((1.0 + lam), size=(self.G_No, 1)) ]) self.sol = solvers.conelp(c=c, G=G, h=h, A=A, b=b, primalstart=x0) Xopt = self.sol['x'] alphas = [] # reporting results for N_name in self.SFG: N = self.SFG.node[N_name] if N['type'] == 'M': N['estimate'] = Xopt[self.GI_No + N['cnt']] alphas.append(N.copy()) if N['type'] == 'G': for I_name in self.SFG[N_name]: NI = self.SFG.edge[N_name][I_name] NI['estimate'] = Xopt[NI['cnt']] g_cnt = self.GI_No + self.M_No + N['cnt'] N['relaxation'] = Xopt[g_cnt] # fit error: evaluation of the cost function at the minimizer error = self.get_mean_square_error() return alphas, error, self.sol['status']
def find_naive_one_time_best_team(Q, A, B, G, H): # Tracer()() Q = matrix(Q) best_team = conelp(Q, G, H, A=A, b=B) team = [int(round(s)) for s in best_team['x']] players_np = np.array(players) scores_np = np.array(scores) team_players = players_np[np.nonzero(team)].tolist() team_player_scores = scores_np[np.nonzero(team)].tolist() print team_player_scores print team_players
def find_naive_one_time_best_team(Q,A,B,G,H): # Tracer()() Q = matrix(Q) best_team = conelp(Q,G,H,A=A,b=B) team = [int(round(s)) for s in best_team['x']] players_np = np.array(players) scores_np = np.array(scores) team_players = players_np[np.nonzero(team)].tolist() team_player_scores = scores_np[np.nonzero(team)].tolist() print team_player_scores print team_players
def balanced_cut(A, delta=1.0, cut='min', solver="conelp_custom"): """ Solves semidefinite relaxation of the following balance-constrained min/max cut problem """ N = A.shape[0] prob = balanced_cut_conelp(A, N, delta, cut) if solver == "mosek": sol = msk.conelp(*prob) Z = matrix(sol[2][1:], (N, N), tc='d') elif solver == "conelp": sol = solvers.conelp(*prob) Z = matrix(sol['z'][1:], (N, N), tc='d') elif solver == "conelp_custom": sol = solvers.conelp(*prob, kktsolver=custom_kkt, options={'refinement': 3}) Z = matrix(sol['z'][1:], (N, N), tc='d') else: raise ValueError("Unknown solver") return Z
def Optimise(self, obj, n, order=None): c, G, h, A, b, dims = self.ConstructSDP(obj, n, order, self.ineqcons, self.eqcons) solvers.options['show_progress'] = False sol = solvers.conelp(c, G, h, dims, A, b) solution = {'status': None, 'obj': None, 'iterations': None, 'x': None} xopt = np.array(sol['x'][:n]) solution['iterations'] = sol['iterations'] if sol['status'] == 'optimal': solution['status'] = sol['status'] solution['x'] = np.array(xopt) solution['obj'] = sol['primal objective'] + obj[0][0, 0] return solution
def solve(self): if len(self.aux.G) == 0: raise ArithmeticError('No constraints') A = solvers.conelp(c=matrix(self.__c), G=matrix(numpy.array(self.aux.G)), h=matrix(numpy.array(self.aux.h)), dims=self.aux.dims) if A["status"] == "optimal": return numpy.array(A['x']).transpose()[0], A else: raise ArithmeticError("Solution not optimal: " + A["status"])
def l1(P, q): m, n = P.size c = matrix(n*[0.0] + m*[1.0]) h = matrix([q, -q]) def Fi(x, y, alpha = 1.0, beta = 0.0, trans = 'N'): if trans == 'N': u = P*x[:n] y[:m] = alpha * ( u - x[n:]) + beta*y[:m] y[m:] = alpha * (-u - x[n:]) + beta*y[m:] else: y[:n] = alpha * P.T * (x[:m] - x[m:]) + beta*y[:n] y[n:] = -alpha * (x[:m] + x[m:]) + beta*y[n:] def Fkkt(W): d1, d2 = W['d'][:m], W['d'][m:] D = 4*(d1**2 + d2**2)**-1 A = P.T * spdiag(D) * P lapack.potrf(A) def f(x, y, z): x[:n] += P.T * ( mul( div(d2**2 - d1**2, d1**2 + d2**2), x[n:]) + mul( .5*D, z[:m]-z[m:] ) ) lapack.potrs(A, x) u = P*x[:n] x[n:] = div( x[n:] - div(z[:m], d1**2) - div(z[m:], d2**2) + mul(d1**-2 - d2**-2, u), d1**-2 + d2**-2 ) z[:m] = div(u-x[n:]-z[:m], d1) z[m:] = div(-u-x[n:]-z[m:], d2) return f uls = +q lapack.gels(+P, uls) rls = P*uls[:n] - q x0 = matrix( [uls[:n], 1.1*abs(rls)] ) s0 = +h Fi(x0, s0, alpha=-1, beta=1) if max(abs(rls)) > 1e-10: w = .9/max(abs(rls)) * rls else: w = matrix(0.0, (m,1)) z0 = matrix([.5*(1+w), .5*(1-w)]) dims = {'l': 2*m, 'q': [], 's': []} sol = solvers.conelp(c, Fi, h, dims, kktsolver = Fkkt, primalstart={'x': x0, 's': s0}, dualstart={'z': z0}) return sol['x'][:n]
def optimise(self,obj,n,order=None,ineqcons=[],eqcons=[]): c,G,h,A,b,dims = self.constructsdp(obj,n,ineqcons,eqcons,order) sol = solvers.conelp(c, G, h, dims, A, b) solution = {'status': None, 'objective': None, 'iterations': None, 'xopt': None} solution['status'] = sol['status'] solution['iterations'] = sol['iterations'] if solution['status'] is 'optimal': solution['objective'] = sol['primal objective'] + obj[0][0,0] solution['xopt'] = np.array(sol['x'][:n]) return solution else: return solution
def check_point(self, p, A1, B_s, u_s): dims = { 'l': self.size_tb() + 2*self.size_x(), # Pure inequality constraints # No com cone 'q': [4]*len(self.contacts)*len(self.gravity_envelope), 's': [] # No sd cones } size_cones = self.size_x()*4 // 3 #Min x ~ who cares, we just want to know if there is a solution c = matrix(np.ones((self.size_x(), 1))) A1_diag = block_diag(*([A1]*len(self.gravity_envelope))) A2 = np.vstack([self.computeA2(self.gravity+e) for e in self.gravity_envelope]) T = np.vstack([self.computeT(self.gravity+e, height=self.height) for e in self.gravity_envelope]) - A2.dot(p) A = matrix(A1_diag) g_s = [] h_s = [] if self.L_s: g_s.append(np.vstack(self.L_s)) h_s.append(np.vstack(self.tb_s)) g_force = np.vstack([np.eye(self.size_x()), -np.eye(self.size_x())]) g_s.append(g_force) h_s.append(self.force_lim*self.mass*9.81*np.ones((2*self.size_x(), 1))) #B = diag{[u_i b_i.T].T} blocks = [-np.vstack([u.T, B]) for u, B in zip(u_s, B_s)]*len(self.gravity_envelope) block = block_diag(*blocks) g_s.append(block) h_cones = np.zeros((size_cones, 1)) h_s.append(h_cones) g = np.vstack(g_s) h = np.vstack(h_s) sol = solvers.conelp(c, G=matrix(g), h=matrix(h), A=A, b=matrix(T), dims=dims) return sol
def QP(self, expert, features, epsilon=None): if epsilon is None: epsilon = self.M.epsilon assert expert.shape[-1] == np.array(features).shape[-1] c = matrix(np.eye(len(expert) + 1)[-1] * -1) G_i = [] h_i = [] for k in range(len(expert)): G_i.append([0]) G_i.append([-1]) h_i.append(0) for j in range(len(features)): for k in range(len(expert)): G_i[k].append(-expert[k] + features[j][k]) G_i[len(expert)].append(1) h_i.append(0) for k in range(len(expert)): G_i[k] = G_i[k] + [0.0] * (k + 1) + [ -1.0 ] + [0.0] * (len(expert) + 1 - k - 1) G_i[len(expert)] = G_i[len(expert)] + [0.0] * (1 + len(expert)) + [0.0] h_i = h_i + [1] + (1 + len(expert)) * [0.0] G = matrix(G_i) h = matrix(h_i) dims = {'l': 1 + len(features), 'q': [len(expert) + 1, 1], 's': []} start = time.time() sol = solvers.conelp(c, G, h, dims) end = time.time() print("QP operation time = " + str(end - start)) solution = np.array(sol['x']) if solution is not None: solution = solution.reshape([len(expert) + 1]).tolist() w = solution[0:-1] t = solution[-1] else: w = None t = None return w, t
def l2_bound_layer1(self, weight, bias, x): """ Given input weights and biases will compute if each neuron can be on or off We do this using cvxopt conelp, but it's a messy formulation the G matrix looks like [ -I | I | 0row | -I]^T and the h matrix looks like [-lo_bounds, u_bounds, radius, -x] """ G_list = [ -1 * np.eye(self.dimension), np.eye(self.dimension), np.zeros((1, self.dimension)), -1 * np.eye(self.dimension) ] G = matrix(np.vstack(G_list).astype(np.float)) h_list = [ -1 * self.box_low, self.box_high, np.array([self.l2_radius]), -x ] h = matrix(np.hstack(h_list).astype(np.float)) dims = {'l': self.dimension * 2, 'q': [self.dimension + 1], 's': [0]} m = weight.shape[0] # Do lowers first new_lows, new_highs = [], [] for scale, working_list in [(1, new_lows), (-1, new_highs)]: for i in range(m): if (i % 10) == 0: print(scale, i) c = matrix(weight[i].astype(np.float) * scale) import time start = time.time() solve_out = solvers.conelp(c, G, h, dims, solver='mosek') print(i, time.time() - start) working_list.append(scale * solve_out['primal objective'] + bias[i]) return new_lows, new_highs
def s_SDP(self, Sigma): p = Sigma.shape[0] c = -np.ones(p) c = matrix(c) G = np.zeros((2 * p + p**2, p)) G[:p, :] = np.eye(p) G[p:2 * p, :] = -np.eye(p) for i in range(p): G[2 * p + p * i, i] = 1 G = matrix(G) h = np.ones(2 * p + p**2) h[p:2 * p] *= 0 h[2 * p:] *= 2 * (Sigma).reshape(-1) h = matrix(h) dims = {'l': 2 * p, 'q': [], 's': [p]} solvers.options['show_progress'] = False sol = conelp(c, G, h, dims) s = np.array(sol['x']).reshape(-1) return s
def test_conelp(self): from cvxopt import matrix, msk, solvers c = matrix([-6., -4., -5.]) G = matrix([[ 16., 7., 24., -8., 8., -1., 0., -1., 0., 0., 7., -5., 1., -5., 1., -7., 1., -7., -4. ], [ -14., 2., 7., -13., -18., 3., 0., 0., -1., 0., 3., 13., -6., 13., 12., -10., -6., -10., -28. ], [ 5., 0., -15., 12., -6., 17., 0., 0., 0., -1., 9., 6., -6., 6., -7., -7., -6., -7., -11. ]]) h = matrix([ -3., 5., 12., -2., -14., -13., 10., 0., 0., 0., 68., -30., -19., -30., 99., 23., -19., 23., 10. ]) dims = {'l': 2, 'q': [4, 4], 's': [3]} self.assertAlmostEqualLists(list(solvers.conelp(c, G, h, dims)['x']), list(msk.conelp(c, G, h, dims)[1]))
def block_socp(self, a, A1, A2, t, B_s, u_s): dims = { 'l': 0, # No pure inequality constraints 'q': [4]*len(self.contacts), # Size of the 2nd order cones : x,y,z+1 's': [] # No sd cones } #Max a^T z ~ min -a^T z c = matrix(np.vstack([np.zeros((self.size_x(), 1)), -a])) A = matrix(np.hstack([A1, A2])) #B = diag{[u_i b_i.T].T} blocks = [-np.vstack([u.T, B]) for u, B in zip(u_s, B_s)] block = block_diag(*blocks) g = np.hstack([block, np.zeros((self.size_x()*4 // 3, self.size_z()))]) h = np.zeros((self.size_x()*4 // 3, 1)) sol = solvers.conelp(c, G=matrix(g), h=matrix(h), A=A, b=matrix(t), dims=dims) return sol
def _intersection_point(T, radii, alpha, values): lines = list() for i in range(0, len(T)): lines.append([(1 - values[i]) * T[i][alpha[i] - 1][k] + values[i] * T[i][alpha[i]][k] for k in range(0, T[i].dimensions)]) c = matrix([0.] * T[0].dimensions) G = [] for i in range(0, T[0].dimensions): m = len(T) * ([0.] + i * [0.] + [-1] + (T[0].dimensions - i - 1) * [0.]) G.append(m) G = matrix(G) h = [] for i in range(0, len(T)): h += [radii[i]] + [-lines[i][j] for j in range(0, T[i].dimensions)] h = matrix(h) dims = {'l': 0, 'q': [1 + T[0].dimensions] * len(T), 's': [0]} sol = solvers.conelp(c, G, h, dims) return sol['status'] == 'optimal', np.array( [s for s in sol['x']]) if sol['x'] is not None else None
def solve(opts): c = matrix([-6., -4., -5.]) G = matrix([[ 16., 7., 24., -8., 8., -1., 0., -1., 0., 0., 7., -5., 1., -5., 1., -7., 1., -7., -4.], [-14., 2., 7., -13., -18., 3., 0., 0., -1., 0., 3., 13., -6., 13., 12., -10., -6., -10., -28.], [ 5., 0., -15., 12., -6., 17., 0., 0., 0., -1., 9., 6., -6., 6., -7., -7., -6., -7., -11.]]) h = matrix([-3., 5., 12., -2., -14., -13., 10., 0., 0., 0., 68., -30., -19., -30., 99., 23., -19., 23., 10.] ) A = matrix(0.0, (0, c.size[0])) b = matrix(0.0, (0, 1)) dims = {'l': 2, 'q': [4, 4], 's': [3]} solvers.options.update(opts) sol = solvers.conelp(c, G, h, dims, kktsolver='ldl') print("\nStatus: " + sol['status']) if sol['status'] == 'optimal': print "x=\n", helpers.str2(sol['x']) print "s=\n", helpers.str2(sol['s']) print "z=\n", helpers.str2(sol['z']) helpers.run_go_test("../testconelp", {'x': sol['x'], 's': sol['s'], 'z': sol['z']})
def solve_convex(p,mode): """ Description ----------- Solves the convex program p. It assumes p is the convex part of an expanded and transformed program. Arguments --------- p: convex cvxpy_program. mode: 'rel' (relaxation) or 'scp' (sequential convex programming). """ # Select options if(mode == 'scp'): options = p.options['SCP_SOL'] else: options = p.options['REL_SOL'] quiet = p.options['quiet'] # Printing format for cvxopt sparse matrices opt.spmatrix_str = opt.printing.spmatrix_str_triplet # Partial minimization expansion constr_list = pm_expand(p.constr) # Get variables variables = constr_list.get_vars() # Count variables n = len(variables) # Create a map (var - pos) if(options['show steps'] and not quiet): print '\nCreating variable - index map' var_to_index = {} for i in range(0,n,1): if(options['show steps'] and not quiet): print variables[i],'<-->',i var_to_index[variables[i]] = i # Construct objective vector c = construct_c(p.obj,var_to_index,n,p.action) if(options['show steps'] and not quiet): print '\nConstructing c vector' print 'c = ' print c # Construct Ax == b A,b = construct_Ab(constr_list._get_eq(),var_to_index,n,options) if(options['show steps'] and not quiet): print '\nConstructing Ax == b' print 'A =' print A print 'b =' print b # Construct Gx <= h G,h,dim_l,dim_q,dim_s = construct_Gh(constr_list._get_ineq_in(), var_to_index,n) if(options['show steps'] and not quiet): print '\nConstructing Gx <= h' print 'G =' print G print 'h =' print h # Construct F F = construct_F(constr_list._get_ineq_in(),var_to_index,n) if(options['show steps'] and not quiet): print '\nConstructing F' # Call cvxopt solvers.options['show_progress'] = options['solver progress'] and not quiet solvers.options['maxiters'] = options['maxiters'] solvers.options['abstol'] = options['abstol'] solvers.options['reltol'] = options['reltol'] solvers.options['feastol'] = options['feastol'] dims = {'l':dim_l, 'q':dim_q, 's':dim_s} if(F is None): if(options['show steps'] and not quiet): print '\nCalling cvxopt conelp solver' r = solvers.conelp(c,G,h,dims,A,b) else: if(options['show steps'] and not quiet): print '\nCalling cvxopt cpl solver' r = solvers.cpl(c,F,G,h,dims,A,b) # Store numerical values if(r['status'] != 'primal infeasible'): if(options['show steps'] and not quiet): print '\nStoring numerical values:' for v in variables: value = r['x'][var_to_index[v]] v.data = value if(options['show steps']and not quiet): print v,' <- ', v.data # Return result return r
def ubsdp(c, A, B, pstart = None, dstart = None): """ minimize c'*x + tr(X) s.t. sum_{i=1}^n xi * Ai - X <= B X >= 0 maximize -tr(B * Z0) s.t. tr(Ai * Z0) + ci = 0, i = 1, ..., n -Z0 - Z1 + I = 0 Z0 >= 0, Z1 >= 0. c is an n-vector. A is an m^2 x n-matrix. B is an m x m-matrix. """ msq, n = A.size m = int(math.sqrt(msq)) mpckd = int(m * (m+1) / 2) dims = {'l': 0, 'q': [], 's': [m, m]} # The primal variable is stored as a tuple (x, X). cc = (c, matrix(0.0, (m, m))) cc[1][::m+1] = 1.0 def xnewcopy(u): return (+u[0], +u[1]) def xdot(u, v): return blas.dot(u[0], v[0]) + misc.sdot2(u[1], v[1]) def xscal(alpha, u): blas.scal(alpha, u[0]) blas.scal(alpha, u[1]) def xaxpy(u, v, alpha = 1.0): blas.axpy(u[0], v[0], alpha) blas.axpy(u[1], v[1], alpha) def G(u, v, alpha = 1.0, beta = 0.0, trans = 'N'): """ If trans is 'N': v[:msq] := alpha * (A*u[0] - u[1][:]) + beta * v[:msq] v[msq:] := -alpha * u[1][:] + beta * v[msq:]. If trans is 'T': v[0] := alpha * A' * u[:msq] + beta * v[0] v[1][:] := alpha * (-u[:msq] - u[msq:]) + beta * v[1][:]. """ if trans == 'N': blas.gemv(A, u[0], v, alpha = alpha, beta = beta) blas.axpy(u[1], v, alpha = -alpha) blas.scal(beta, v, offset = msq) blas.axpy(u[1], v, alpha = -alpha, offsety = msq) else: misc.sgemv(A, u, v[0], dims = {'l': 0, 'q': [], 's': [m]}, alpha = alpha, beta = beta, trans = 'T') blas.scal(beta, v[1]) blas.axpy(u, v[1], alpha = -alpha, n = msq) blas.axpy(u, v[1], alpha = -alpha, n = msq, offsetx = msq) h = matrix(0.0, (2*msq, 1)) blas.copy(B, h) L = matrix(0.0, (m, m)) U = matrix(0.0, (m, m)) Us = matrix(0.0, (m, m)) Uti = matrix(0.0, (m, m)) s = matrix(0.0, (m, 1)) Asc = matrix(0.0, (msq, n)) S = matrix(0.0, (m, m)) tmp = matrix(0.0, (m, m)) x1 = matrix(0.0, (m**2, 1)) H = matrix(0.0, (n, n)) def F(W): """ Generate a solver for A'(uz0) = bx[0] -uz0 - uz1 = bx[1] A(ux[0]) - ux[1] - r0*r0' * uz0 * r0*r0' = bz0 - ux[1] - r1*r1' * uz1 * r1*r1' = bz1. uz0, uz1, bz0, bz1 are symmetric m x m-matrices. ux[0], bx[0] are n-vectors. ux[1], bx[1] are symmetric m x m-matrices. We first calculate a congruence that diagonalizes r0*r0' and r1*r1': U' * r0 * r0' * U = I, U' * r1 * r1' * U = S. We then make a change of variables usx[0] = ux[0], usx[1] = U' * ux[1] * U usz0 = U^-1 * uz0 * U^-T usz1 = U^-1 * uz1 * U^-T and define As() = U' * A() * U' bsx[1] = U^-1 * bx[1] * U^-T bsz0 = U' * bz0 * U bsz1 = U' * bz1 * U. This gives As'(usz0) = bx[0] -usz0 - usz1 = bsx[1] As(usx[0]) - usx[1] - usz0 = bsz0 -usx[1] - S * usz1 * S = bsz1. 1. Eliminate usz0, usz1 using equations 3 and 4, usz0 = As(usx[0]) - usx[1] - bsz0 usz1 = -S^-1 * (usx[1] + bsz1) * S^-1. This gives two equations in usx[0] an usx[1]. As'(As(usx[0]) - usx[1]) = bx[0] + As'(bsz0) -As(usx[0]) + usx[1] + S^-1 * usx[1] * S^-1 = bsx[1] - bsz0 - S^-1 * bsz1 * S^-1. 2. Eliminate usx[1] using equation 2: usx[1] + S * usx[1] * S = S * ( As(usx[0]) + bsx[1] - bsz0 ) * S - bsz1 i.e., with Gamma[i,j] = 1.0 + S[i,i] * S[j,j], usx[1] = ( S * As(usx[0]) * S ) ./ Gamma + ( S * ( bsx[1] - bsz0 ) * S - bsz1 ) ./ Gamma. This gives an equation in usx[0]. As'( As(usx[0]) ./ Gamma ) = bx0 + As'(bsz0) + As'( (S * ( bsx[1] - bsz0 ) * S - bsz1) ./ Gamma ) = bx0 + As'( ( bsz0 - bsz1 + S * bsx[1] * S ) ./ Gamma ). """ # Calculate U s.t. # # U' * r0*r0' * U = I, U' * r1*r1' * U = diag(s). # Cholesky factorization r0 * r0' = L * L' blas.syrk(W['r'][0], L) lapack.potrf(L) # SVD L^-1 * r1 = U * diag(s) * V' blas.copy(W['r'][1], U) blas.trsm(L, U) lapack.gesvd(U, s, jobu = 'O') # s := s**2 s[:] = s**2 # Uti := U blas.copy(U, Uti) # U := L^-T * U blas.trsm(L, U, transA = 'T') # Uti := L * Uti = U^-T blas.trmm(L, Uti) # Us := U * diag(s)^-1 blas.copy(U, Us) for i in range(m): blas.tbsv(s, Us, n = m, k = 0, ldA = 1, incx = m, offsetx = i) # S is m x m with lower triangular entries s[i] * s[j] # sqrtG is m x m with lower triangular entries sqrt(1.0 + s[i]*s[j]) # Upper triangular entries are undefined but nonzero. blas.scal(0.0, S) blas.syrk(s, S) Gamma = 1.0 + S sqrtG = sqrt(Gamma) # Asc[i] = (U' * Ai * * U ) ./ sqrtG, for i = 1, ..., n # = Asi ./ sqrt(Gamma) blas.copy(A, Asc) misc.scale(Asc, # only 'r' part of the dictionary is used {'dnl': matrix(0.0, (0, 1)), 'dnli': matrix(0.0, (0, 1)), 'd': matrix(0.0, (0, 1)), 'di': matrix(0.0, (0, 1)), 'v': [], 'beta': [], 'r': [ U ], 'rti': [ U ]}) for i in range(n): blas.tbsv(sqrtG, Asc, n = msq, k = 0, ldA = 1, offsetx = i*msq) # Convert columns of Asc to packed storage misc.pack2(Asc, {'l': 0, 'q': [], 's': [ m ]}) # Cholesky factorization of Asc' * Asc. H = matrix(0.0, (n, n)) blas.syrk(Asc, H, trans = 'T', k = mpckd) lapack.potrf(H) def solve(x, y, z): """ 1. Solve for usx[0]: Asc'(Asc(usx[0])) = bx0 + Asc'( ( bsz0 - bsz1 + S * bsx[1] * S ) ./ sqrtG) = bx0 + Asc'( ( bsz0 + S * ( bsx[1] - bssz1) S ) ./ sqrtG) where bsx[1] = U^-1 * bx[1] * U^-T, bsz0 = U' * bz0 * U, bsz1 = U' * bz1 * U, bssz1 = S^-1 * bsz1 * S^-1 2. Solve for usx[1]: usx[1] + S * usx[1] * S = S * ( As(usx[0]) + bsx[1] - bsz0 ) * S - bsz1 usx[1] = ( S * (As(usx[0]) + bsx[1] - bsz0) * S - bsz1) ./ Gamma = -bsz0 + (S * As(usx[0]) * S) ./ Gamma + (bsz0 - bsz1 + S * bsx[1] * S ) . / Gamma = -bsz0 + (S * As(usx[0]) * S) ./ Gamma + (bsz0 + S * ( bsx[1] - bssz1 ) * S ) . / Gamma Unscale ux[1] = Uti * usx[1] * Uti' 3. Compute usz0, usz1 r0' * uz0 * r0 = r0^-1 * ( A(ux[0]) - ux[1] - bz0 ) * r0^-T r1' * uz1 * r1 = r1^-1 * ( -ux[1] - bz1 ) * r1^-T """ # z0 := U' * z0 * U # = bsz0 __cngrnc(U, z, trans = 'T') # z1 := Us' * bz1 * Us # = S^-1 * U' * bz1 * U * S^-1 # = S^-1 * bsz1 * S^-1 __cngrnc(Us, z, trans = 'T', offsetx = msq) # x[1] := Uti' * x[1] * Uti # = bsx[1] __cngrnc(Uti, x[1], trans = 'T') # x[1] := x[1] - z[msq:] # = bsx[1] - S^-1 * bsz1 * S^-1 blas.axpy(z, x[1], alpha = -1.0, offsetx = msq) # x1 = (S * x[1] * S + z[:msq] ) ./ sqrtG # = (S * ( bsx[1] - S^-1 * bsz1 * S^-1) * S + bsz0 ) ./ sqrtG # = (S * bsx[1] * S - bsz1 + bsz0 ) ./ sqrtG # in packed storage blas.copy(x[1], x1) blas.tbmv(S, x1, n = msq, k = 0, ldA = 1) blas.axpy(z, x1, n = msq) blas.tbsv(sqrtG, x1, n = msq, k = 0, ldA = 1) misc.pack2(x1, {'l': 0, 'q': [], 's': [m]}) # x[0] := x[0] + Asc'*x1 # = bx0 + Asc'( ( bsz0 - bsz1 + S * bsx[1] * S ) ./ sqrtG) # = bx0 + As'( ( bz0 - bz1 + S * bx[1] * S ) ./ Gamma ) blas.gemv(Asc, x1, x[0], m = mpckd, trans = 'T', beta = 1.0) # x[0] := H^-1 * x[0] # = ux[0] lapack.potrs(H, x[0]) # x1 = Asc(x[0]) .* sqrtG (unpacked) # = As(x[0]) blas.gemv(Asc, x[0], tmp, m = mpckd) misc.unpack(tmp, x1, {'l': 0, 'q': [], 's': [m]}) blas.tbmv(sqrtG, x1, n = msq, k = 0, ldA = 1) # usx[1] = (x1 + (x[1] - z[:msq])) ./ sqrtG**2 # = (As(ux[0]) + bsx[1] - bsz0 - S^-1 * bsz1 * S^-1) # ./ Gamma # x[1] := x[1] - z[:msq] # = bsx[1] - bsz0 - S^-1 * bsz1 * S^-1 blas.axpy(z, x[1], -1.0, n = msq) # x[1] := x[1] + x1 # = As(ux) + bsx[1] - bsz0 - S^-1 * bsz1 * S^-1 blas.axpy(x1, x[1]) # x[1] := x[1] / Gammma # = (As(ux) + bsx[1] - bsz0 + S^-1 * bsz1 * S^-1 ) / Gamma # = S^-1 * usx[1] * S^-1 blas.tbsv(Gamma, x[1], n = msq, k = 0, ldA = 1) # z[msq:] := r1' * U * (-z[msq:] - x[1]) * U * r1 # := -r1' * U * S^-1 * (bsz1 + ux[1]) * S^-1 * U * r1 # := -r1' * uz1 * r1 blas.axpy(x[1], z, n = msq, offsety = msq) blas.scal(-1.0, z, offset = msq) __cngrnc(U, z, offsetx = msq) __cngrnc(W['r'][1], z, trans = 'T', offsetx = msq) # x[1] := S * x[1] * S # = usx1 blas.tbmv(S, x[1], n = msq, k = 0, ldA = 1) # z[:msq] = r0' * U' * ( x1 - x[1] - z[:msq] ) * U * r0 # = r0' * U' * ( As(ux) - usx1 - bsz0 ) * U * r0 # = r0' * U' * usz0 * U * r0 # = r0' * uz0 * r0 blas.axpy(x1, z, -1.0, n = msq) blas.scal(-1.0, z, n = msq) blas.axpy(x[1], z, -1.0, n = msq) __cngrnc(U, z) __cngrnc(W['r'][0], z, trans = 'T') # x[1] := Uti * x[1] * Uti' # = ux[1] __cngrnc(Uti, x[1]) return solve solvers.options['show_progress'] = 0 sol = solvers.conelp(cc, G, h, dims = {'l': 0, 's': [m, m], 'q': []}, kktsolver = F, xnewcopy = xnewcopy, xdot = xdot, xaxpy = xaxpy, xscal = xscal, primalstart = pstart, dualstart = dstart) return matrix(sol['x'][1], (n,n))
c = matrix([-2., 1., 5.]) G = [ matrix( [[12., 13., 12.], [6., -3., -12.], [-5., -5., 6.]] ) ] G += [ matrix( [[3., 3., -1., 1.], [-6., -6., -9., 19.], [10., -2., -2., -3.]] ) ] h = [ matrix( [-12., -3., -2.] ), matrix( [27., 0., 3., -42.] ) ] sol = solvers.socp(c, Gq = G, hq = h) sol['status'] c = matrix([-2., 1., 5.]) G = matrix( [[12., 13., 12., 3., 3., -1., 1.], [6., -3., -12., -6., -6., -9., 19.], [-5., -5., 6., 10., -2., -2., -3.]]) h = matrix( [-12., -3., -2., 27., 0., 3., -42.] ) dims = {'l': 0, 'q': [3,4], 's': []} sol2 = solvers.conelp(c, G, h, dims) ## least sqaures problem, as a QP A = matrix([ [ .3, -.4, -.2, -.4, 1.3 ], [ .6, 1.2, -1.7, .3, -.3 ], [-.3, .0, .6, -1.2, -2.0 ] ]) b = matrix([ 1.5, .0, -1.2, -.7, .0]) m, n = A.size I = matrix(0.0, (n,n)) I[::n+1] = 1.0 G = matrix([-I, matrix(0.0, (1,n)), I]) h = matrix(n*[0.0] + [1.0] + n*[0.0]) dimsQP = {'l': n, 'q': [n+1], 's': []}
def _updateTrustRegionSOCP(x, fx, oldFx, oldDeltaX, p, radius, g, oldGrad, H, func, grad, z, G, h, y, A, b): if A is not None: bTemp = b - A.dot(x) else: bTemp = None GTemp = numpy.append(numpy.zeros((1,p)), numpy.eye(p), axis=0) hTemp = numpy.zeros(p+1) hTemp[0] += radius if G is not None: GTemp = numpy.append(G, GTemp, axis=0) hTemp = numpy.append(h - G.dot(x), hTemp) dims1 = {'l': G.shape[0], 'q': [p+1,p+1], 's': []} else: dims1 = {'l': 0, 'q': [p+1,p+1], 's': []} # now we have finished the setup process, we reformulate # the problem as a SOCP m,n = GTemp.shape c = matrix([1.0] + [0.0]*n) hTemp1 = matrix([0.0]+(-g.flatten()).tolist()) GTemp1 = matrix(numpy.array(scipy.sparse.bmat([ [[-1.0],None], [None,H] ]).todense())) GTemp1 = matrix(numpy.append(numpy.append(numpy.array([0]*m).reshape(m,1),numpy.array(GTemp),axis=1), numpy.array(GTemp1), axis=0)) hTemp1 = matrix(numpy.append(hTemp,hTemp1)) if A is not None: out = solvers.conelp(c, GTemp1, hTemp1, dims1, matrix(A), matrix(bTemp)) else: out = solvers.conelp(c, GTemp1, hTemp1, dims1) # exact the descent diretion and do a line search deltaX = numpy.array(out['x'][1::]) M = _diffM(g.flatten(), H) newFx = func(x + deltaX) predRatio = (fx - newFx) / M(deltaX) if predRatio>=0.75: radius = min(2.0*radius, maxRadius) elif predRatio<=0.25: radius *= 0.25 if predRatio>=0.25: oldGrad = g.copy() x += deltaX oldFx = fx fx = newFx update = True else: update = False if G is not None: # only want the information for the inequalities # and not the two cones - trust region, objective functionn z[:] = numpy.array(out['z'])[G.shape[0]] if A is not None: y[:] = numpy.array(out['y']) # print numpy.append(numpy.array(out['s']),numpy.array(s),axis=1) return x, update, radius, deltaX, z, y, fx, oldFx, oldGrad, out['iterations']
def l1blas (P, q): """ Returns the solution u of the ell-1 approximation problem (primal) minimize ||P*u - q||_1 (dual) maximize q'*w subject to P'*w = 0 ||w||_infty <= 1. """ m, n = P.size # Solve equivalent LP # # minimize [0; 1]' * [u; v] # subject to [P, -I; -P, -I] * [u; v] <= [q; -q] # # maximize -[q; -q]' * z # subject to [P', -P']*z = 0 # [-I, -I]*z + 1 = 0 # z >= 0 c = matrix(n*[0.0] + m*[1.0]) h = matrix([q, -q]) u = matrix(0.0, (m,1)) Ps = matrix(0.0, (m,n)) A = matrix(0.0, (n,n)) def Fi(x, y, alpha = 1.0, beta = 0.0, trans = 'N'): if trans == 'N': # y := alpha * [P, -I; -P, -I] * x + beta*y blas.gemv(P, x, u) y[:m] = alpha * ( u - x[n:]) + beta*y[:m] y[m:] = alpha * (-u - x[n:]) + beta*y[m:] else: # y := alpha * [P', -P'; -I, -I] * x + beta*y blas.copy(x[:m] - x[m:], u) blas.gemv(P, u, y, alpha = alpha, beta = beta, trans = 'T') y[n:] = -alpha * (x[:m] + x[m:]) + beta*y[n:] def Fkkt(W): # Returns a function f(x, y, z) that solves # # [ 0 0 P' -P' ] [ x[:n] ] [ bx[:n] ] # [ 0 0 -I -I ] [ x[n:] ] [ bx[n:] ] # [ P -I -D1^{-1} 0 ] [ z[:m] ] = [ bz[:m] ] # [-P -I 0 -D2^{-1} ] [ z[m:] ] [ bz[m:] ] # # where D1 = diag(di[:m])^2, D2 = diag(di[m:])^2 and di = W['di']. # # On entry bx, bz are stored in x, z. # On exit x, z contain the solution, with z scaled (di .* z is # returned instead of z). # Factor A = 4*P'*D*P where D = d1.*d2 ./(d1+d2) and # d1 = d[:m].^2, d2 = d[m:].^2. di = W['di'] d1, d2 = di[:m]**2, di[m:]**2 D = div( mul(d1,d2), d1+d2 ) Ds = spdiag(2 * sqrt(D)) base.gemm(Ds, P, Ps) blas.syrk(Ps, A, trans = 'T') lapack.potrf(A) def f(x, y, z): # Solve for x[:n]: # # A*x[:n] = bx[:n] + P' * ( ((D1-D2)*(D1+D2)^{-1})*bx[n:] # + (2*D1*D2*(D1+D2)^{-1}) * (bz[:m] - bz[m:]) ). blas.copy(( mul( div(d1-d2, d1+d2), x[n:]) + mul( 2*D, z[:m]-z[m:] ) ), u) blas.gemv(P, u, x, beta = 1.0, trans = 'T') lapack.potrs(A, x) # x[n:] := (D1+D2)^{-1} * (bx[n:] - D1*bz[:m] - D2*bz[m:] # + (D1-D2)*P*x[:n]) base.gemv(P, x, u) x[n:] = div( x[n:] - mul(d1, z[:m]) - mul(d2, z[m:]) + mul(d1-d2, u), d1+d2 ) # z[:m] := d1[:m] .* ( P*x[:n] - x[n:] - bz[:m]) # z[m:] := d2[m:] .* (-P*x[:n] - x[n:] - bz[m:]) z[:m] = mul(di[:m], u-x[n:]-z[:m]) z[m:] = mul(di[m:], -u-x[n:]-z[m:]) return f # Initial primal and dual points from least-squares solution. # uls minimizes ||P*u-q||_2; rls is the LS residual. uls = +q lapack.gels(+P, uls) rls = P*uls[:n] - q # x0 = [ uls; 1.1*abs(rls) ]; s0 = [q;-q] - [P,-I; -P,-I] * x0 x0 = matrix( [uls[:n], 1.1*abs(rls)] ) s0 = +h Fi(x0, s0, alpha=-1, beta=1) # z0 = [ (1+w)/2; (1-w)/2 ] where w = (.9/||rls||_inf) * rls # if rls is nonzero and w = 0 otherwise. if max(abs(rls)) > 1e-10: w = .9/max(abs(rls)) * rls else: w = matrix(0.0, (m,1)) z0 = matrix([.5*(1+w), .5*(1-w)]) dims = {'l': 2*m, 'q': [], 's': []} sol = solvers.conelp(c, Fi, h, dims, kktsolver = Fkkt, primalstart={'x': x0, 's': s0}, dualstart={'z': z0}) return sol['x'][:n]
def solve(opts): c = matrix([-6.0, -4.0, -5.0]) G = matrix( [ [16.0, 7.0, 24.0, -8.0, 8.0, -1.0, 0.0, -1.0, 0.0, 0.0, 7.0, -5.0, 1.0, -5.0, 1.0, -7.0, 1.0, -7.0, -4.0], [ -14.0, 2.0, 7.0, -13.0, -18.0, 3.0, 0.0, 0.0, -1.0, 0.0, 3.0, 13.0, -6.0, 13.0, 12.0, -10.0, -6.0, -10.0, -28.0, ], [ 5.0, 0.0, -15.0, 12.0, -6.0, 17.0, 0.0, 0.0, 0.0, -1.0, 9.0, 6.0, -6.0, 6.0, -7.0, -7.0, -6.0, -7.0, -11.0, ], ] ) h = matrix( [ -3.0, 5.0, 12.0, -2.0, -14.0, -13.0, 10.0, 0.0, 0.0, 0.0, 68.0, -30.0, -19.0, -30.0, 99.0, 23.0, -19.0, 23.0, 10.0, ] ) A = matrix(0.0, (0, c.size[0])) b = matrix(0.0, (0, 1)) dims = {"l": 2, "q": [4, 4], "s": [3]} # localcones.options.update(opts) # sol = localcones.conelp(c, G, h, dims, kktsolver='qr') solvers.options.update(opts) sol = solvers.conelp(c, G, h, dims) print ("\nStatus: " + sol["status"]) if sol["status"] == "optimal": print "x=\n", helpers.strSpe(sol["x"], "%.5f") print "s=\n", helpers.strSpe(sol["s"], "%.5f") print "z=\n", helpers.strSpe(sol["z"], "%.5f") rungotest(sol)
def l1(P, q): """ Returns the solution u of the ell-1 approximation problem (primal) minimize ||P*u - q||_1 (dual) maximize q'*w subject to P'*w = 0 ||w||_infty <= 1. """ m, n = P.size # Solve equivalent LP # # minimize [0; 1]' * [u; v] # subject to [P, -I; -P, -I] * [u; v] <= [q; -q] # # maximize -[q; -q]' * z # subject to [P', -P']*z = 0 # [-I, -I]*z + 1 = 0 # z >= 0 c = matrix(n * [0.0] + m * [1.0]) h = matrix([q, -q]) def Fi(x, y, alpha=1.0, beta=0.0, trans='N'): if trans == 'N': # y := alpha * [P, -I; -P, -I] * x + beta*y u = P * x[:n] y[:m] = alpha * (u - x[n:]) + beta * y[:m] y[m:] = alpha * (-u - x[n:]) + beta * y[m:] else: # y := alpha * [P', -P'; -I, -I] * x + beta*y y[:n] = alpha * P.T * (x[:m] - x[m:]) + beta * y[:n] y[n:] = -alpha * (x[:m] + x[m:]) + beta * y[n:] def Fkkt(W): # Returns a function f(x, y, z) that solves # # [ 0 0 P' -P' ] [ x[:n] ] [ bx[:n] ] # [ 0 0 -I -I ] [ x[n:] ] [ bx[n:] ] # [ P -I -W1^2 0 ] [ z[:m] ] = [ bz[:m] ] # [-P -I 0 -W2 ] [ z[m:] ] [ bz[m:] ] # # On entry bx, bz are stored in x, z. # On exit x, z contain the solution, with z scaled (W['di'] .* z is # returned instead of z). d1, d2 = W['d'][:m], W['d'][m:] D = 4 * (d1**2 + d2**2)**-1 A = P.T * spdiag(D) * P lapack.potrf(A) def f(x, y, z): x[:n] += P.T * (mul(div(d2**2 - d1**2, d1**2 + d2**2), x[n:]) + mul(.5 * D, z[:m] - z[m:])) lapack.potrs(A, x) u = P * x[:n] x[n:] = div( x[n:] - div(z[:m], d1**2) - div(z[m:], d2**2) + mul(d1**-2 - d2**-2, u), d1**-2 + d2**-2) z[:m] = div(u - x[n:] - z[:m], d1) z[m:] = div(-u - x[n:] - z[m:], d2) return f # Initial primal and dual points from least-squares solution. # uls minimizes ||P*u-q||_2; rls is the LS residual. uls = +q lapack.gels(+P, uls) rls = P * uls[:n] - q # x0 = [ uls; 1.1*abs(rls) ]; s0 = [q;-q] - [P,-I; -P,-I] * x0 x0 = matrix([uls[:n], 1.1 * abs(rls)]) s0 = +h Fi(x0, s0, alpha=-1, beta=1) # z0 = [ (1+w)/2; (1-w)/2 ] where w = (.9/||rls||_inf) * rls # if rls is nonzero and w = 0 otherwise. if max(abs(rls)) > 1e-10: w = .9 / max(abs(rls)) * rls else: w = matrix(0.0, (m, 1)) z0 = matrix([.5 * (1 + w), .5 * (1 - w)]) dims = {'l': 2 * m, 'q': [], 's': []} sol = solvers.conelp(c, Fi, h, dims, kktsolver=Fkkt, primalstart={ 'x': x0, 's': s0 }, dualstart={'z': z0}) return sol['x'][:n]
def mcsdp(w): """ Returns solution x, z to (primal) minimize sum(x) subject to w + diag(x) >= 0 (dual) maximize -tr(w*z) subject to diag(z) = 1 z >= 0. """ n = w.size[0] def Fs(x, y, alpha = 1.0, beta = 0.0, trans = 'N'): """ y := alpha*(-diag(x)) + beta*y. """ if trans=='N': # x is a vector; y is a matrix. blas.scal(beta, y) blas.axpy(x, y, alpha = -alpha, incy = n+1) else: # x is a matrix; y is a vector. blas.scal(beta, y) blas.axpy(x, y, alpha = -alpha, incx = n+1) def cngrnc(r, x, alpha = 1.0): """ Congruence transformation x := alpha * r'*x*r. r and x are square matrices. """ # Scale diagonal of x by 1/2. x[::n+1] *= 0.5 # a := tril(x)*r a = +r tx = matrix(x, (n,n)) blas.trmm(tx, a, side='L') # x := alpha*(a*r' + r*a') blas.syr2k(r, a, tx, trans = 'T', alpha = alpha) x[:] = tx[:] def Fkkt(W): rti = W['rti'][0] # t = rti*rti' as a nonsymmetric matrix. t = matrix(0.0, (n,n)) blas.gemm(rti, rti, t, transB = 'T') # Cholesky factorization of tsq = t.*t. tsq = t**2 lapack.potrf(tsq) def f(x, y, z): """ Solve -diag(z) = bx -diag(x) - inv(rti*rti') * z * inv(rti*rti') = bs On entry, x and z contain bx and bs. On exit, they contain the solution, with z scaled (inv(rti)'*z*inv(rti) is returned instead of z). We first solve ((rti*rti') .* (rti*rti')) * x = bx - diag(t*bs*t) and take z = -rti' * (diag(x) + bs) * rti. """ # tbst := t * zs * t = t * bs * t tbst = matrix(z, (n,n)) cngrnc(t, tbst) # x := x - diag(tbst) = bx - diag(rti*rti' * bs * rti*rti') x -= tbst[::n+1] # x := (t.*t)^{-1} * x = (t.*t)^{-1} * (bx - diag(t*bs*t)) lapack.potrs(tsq, x) # z := z + diag(x) = bs + diag(x) z[::n+1] += x # z := -rti' * z * rti = -rti' * (diag(x) + bs) * rti cngrnc(rti, z, alpha = -1.0) return f c = matrix(1.0, (n,1)) # Initial feasible x: x = 1.0 - min(lambda(w)). lmbda = matrix(0.0, (n,1)) lapack.syevx(+w, lmbda, range='I', il=1, iu=1) x0 = matrix(-lmbda[0]+1.0, (n,1)) s0 = +w s0[::n+1] += x0 # Initial feasible z is identity. z0 = matrix(0.0, (n,n)) z0[::n+1] = 1.0 dims = {'l': 0, 'q': [], 's': [n]} sol = solvers.conelp(c, Fs, w[:], dims, kktsolver = Fkkt, primalstart = {'x': x0, 's': s0[:]}, dualstart = {'z': z0[:]}) return sol['x'], matrix(sol['z'], (n,n))
def solve_convex(p, mode): """ Description ----------- Solves the convex program p. It assumes p is the convex part of an expanded and transformed program. Arguments --------- p: convex cvxpy_program. mode: 'rel' (relaxation) or 'scp' (sequential convex programming). """ # Select options if (mode == 'scp'): options = p.options['SCP_SOL'] else: options = p.options['REL_SOL'] quiet = p.options['quiet'] # Printing format for cvxopt sparse matrices opt.spmatrix_str = opt.printing.spmatrix_str_triplet # Partial minimization expansion constr_list = pm_expand(p.constr) # Get variables variables = constr_list.get_vars() # Count variables n = len(variables) # Create a map (var - pos) if (options['show steps'] and not quiet): print '\nCreating variable - index map' var_to_index = {} for i in range(0, n, 1): if (options['show steps'] and not quiet): print variables[i], '<-->', i var_to_index[variables[i]] = i # Construct objective vector c = construct_c(p.obj, var_to_index, n, p.action) if (options['show steps'] and not quiet): print '\nConstructing c vector' print 'c = ' print c # Construct Ax == b A, b = construct_Ab(constr_list._get_eq(), var_to_index, n, options) if (options['show steps'] and not quiet): print '\nConstructing Ax == b' print 'A =' print A print 'b =' print b # Construct Gx <= h G, h, dim_l, dim_q, dim_s = construct_Gh(constr_list._get_ineq_in(), var_to_index, n) if (options['show steps'] and not quiet): print '\nConstructing Gx <= h' print 'G =' print G print 'h =' print h # Construct F F = construct_F(constr_list._get_ineq_in(), var_to_index, n) if (options['show steps'] and not quiet): print '\nConstructing F' # Call cvxopt solvers.options['show_progress'] = options['solver progress'] and not quiet solvers.options['maxiters'] = options['maxiters'] solvers.options['abstol'] = options['abstol'] solvers.options['reltol'] = options['reltol'] solvers.options['feastol'] = options['feastol'] dims = {'l': dim_l, 'q': dim_q, 's': dim_s} if (F is None): if (options['show steps'] and not quiet): print '\nCalling cvxopt conelp solver' r = solvers.conelp(c, G, h, dims, A, b) else: if (options['show steps'] and not quiet): print '\nCalling cvxopt cpl solver' r = solvers.cpl(c, F, G, h, dims, A, b) # Store numerical values if (r['status'] != 'primal infeasible'): if (options['show steps'] and not quiet): print '\nStoring numerical values:' for v in variables: value = r['x'][var_to_index[v]] v.data = value if (options['show steps'] and not quiet): print v, ' <- ', v.data # Return result return r
A = sp_rand(n,n,0.015) + spmatrix(1.0,range(n),range(n)) I = cp.tril(A)[:].I N = len(I)/50 # each data matrix has 1/50 of total nonzeros in pattern Ig = []; Jg = [] for j in range(m): Ig += sorted(random.sample(I,N)) Jg += N*[j] G = spmatrix(normal(len(Ig),1),Ig,Jg,(n**2,m)) h = G*normal(m,1) + spmatrix(1.0,range(n),range(n))[:] c = normal(m,1) dims = {'l':0, 'q':[], 's': [n]}; # solve SDP with CVXOPT print("Solving SDP with CVXOPT..") prob = (c, G, matrix(h), dims) sol = solvers.conelp(*prob) Z1 = matrix(sol['z'], (n,n)) # convert SDP and solve prob2, blocks_to_sparse, symbs = cp.convert_conelp(*prob) print("Solving converted SDP (no merging)..") sol2 = solvers.conelp(*prob2) # convert block-diagonal solution to spmatrix blki,I,J,bn = blocks_to_sparse[0] Z2 = spmatrix(sol2['z'][blki],I,J) # compute completion symb = cp.symbolic(Z2, p=cp.maxcardsearch) Z2c = cp.psdcompletion(cp.cspmatrix(symb)+Z2, reordered=False)
def MOQP(self, expert, features, K, epsilon = None): if epsilon is None: epsilon = self.M.epsilon cexs = features['cexs'] cands = features['cands'] safes = features['safes'] if True: #G_i_j=[[], [], [], []] G_i_j_k = [] for e in range(len(expert) + 2): G_i_j_k.append([]) h_i_j_k = [] c = matrix(- ((K) * np.eye(len(expert) + 2)[-2] + (1 - K) * np.eye(len(expert) + 2)[-1])) for m in range(len(cands)): for e in range(len(expert)): G_i_j_k[e].append(K * (- expert[e] + cands[m][e])) G_i_j_k[len(expert)].append(1) G_i_j_k[len(expert) + 1].append(0) h_i_j_k.append(0) #G_i_j[0].append(- (expert[0] - cands[m][0])) #G_i_j[1].append(- (expert[1] - cands[m][1])) #G_i_j[2].append(- (expert[2] - cands[m][2])) #G_i_j[3].append(- (expert[3] - cands[m][3])) for j in range(len(cexs)): for k in range(len(safes)): for e in range(len(expert)): G_i_j_k[e].append((1.0 - K) * (- safes[k][e] + cexs[j][e])) G_i_j_k[len(expert)].append(0) G_i_j_k[len(expert) + 1].append(1) h_i_j_k.append(0) #G_i_j[0].append(cands[k][0] - mu_Bs[j][0] - (cands[l][0] - mu_Bs[n][0])) #G_i_j[1].append(cands[k][1] - mu_Bs[j][1] - (cands[l][1] - mu_Bs[n][1])) #G_i_j[2].append(cands[k][2] - mu_Bs[j][2] - (cands[l][2] - mu_Bs[n][2])) #G_i_j[3].append(cands[k][3] - mu_Bs[j][3] - (cands[l][3] - mu_Bs[n][3])) #h_i_j.append(0) for e in range(len(expert)): G_i_j_k[e] = G_i_j_k[e] + [0.0] * (e + 1) + [-1.0] + [0.0] * (len(expert) + 2 - e - 1) G_i_j_k[len(expert)] = G_i_j_k[len(expert)] + [0.0] * (len(expert) + 3) G_i_j_k[len(expert) + 1] = G_i_j_k[len(expert) + 1] + [0.0] * (len(expert) + 3) h_i_j_k = h_i_j_k + [10] + (2 + len(expert)) * [0.0] #G_i_j[0]= G_i_j[0] + [0., -1., 0., 0., 0.] #G_i_j[1]= G_i_j[1] + [0., 0., -1., 0., 0.] #G_i_j[2]= G_i_j[2] + [0., 0., 0., -1., 0.] #G_i_j[3]= G_i_j[3] + [0., 0., 0., 0., -1.] #h_i_j = h_i_j + [1., 0., 0., 0., 0.] G = matrix(G_i_j_k) h = matrix(h_i_j_k) #G = matrix(G_i_j) # h = matrix([-1 * penalty, 1., 0., 0., 0.]) #h = matrix(h_i_j) dims = {'l': len(cands) + len(cexs) * len(safes), 'q': [2 + len(expert), 1], 's': []} sol = solvers.conelp(c, G, h, dims) sol['status'] solution = np.array(sol['x']) if solution is not None: solution=solution.reshape(len(expert) + 2) t=(1 - K) * solution[-1] + K * solution[-2] w=solution[:-2] else: solution = None t = None w = None return w, t
def solve_linmap(self, bi, lmbd, linmap, show_progress=True): solvers.options['show_progress'] = show_progress # save all problem data self.bi, self.lmbd = bi, lmbd # count alive in map Nm2 = int(sum(linmap)) self.Nm2 = Nm2 self.linmap = linmap n_x1 = self.Nb*(self.Nb + 1)//2 n_x2 = self.Nb*(self.Nb - 1)//2 n_x = 1 + Nm2 + n_x1 + n_x2 c = matrix(0.0, (1 + Nm2 + n_x1 + n_x2, 1)) c[0] = 1.0 c[1 + Nm2:1 + Nm2 + self.Nb] = lmbd G = matrix(0.0, (1 + Nm2 + (2*self.Nb)**2, n_x)) G[:1 + Nm2, :1 + Nm2] = -eye(1 + Nm2) G[1 + Nm2:, 1 + Nm2:] = self.G[1 + self.Nm:, 1 + self.Nm:] h = matrix(0.0, (1 + Nm2 + (2*self.Nb)**2, 1)) A = matrix(0.0, (Nm2, n_x)) lbi = matrix(0.0, (Nm2, 1)) A[:, 1:1 + Nm2] = eye(Nm2) pos = 0 for i in range(self.Nm): if linmap[i] != 0.0: A[pos, 1 + Nm2:] = self.A[i, 1 + self.Nm:] lbi[pos] = bi[i] h[1 + pos] = -bi[i] pos += 1 assert(pos == Nm2) b = matrix(0.0, (Nm2, 1)) dims = {'l': 0, 'q': [1 + Nm2], 's': [2*self.Nb]} t1 = time() self.sol = solvers.conelp(c, G, h, dims, A, b) t2 = time() self.lc = c self.lG = G self.lh = h self.ldims = dims self.lA = A self.lb = b self.lNm = Nm2 self.lbi = lbi t3 = time() if self.sol['status'] in ('optimal', 'unknown'): S = self.sol['s'][1 + Nm2:] self.sA[:] = S[self.I11] + 1j*S[self.I21] lapack.heevr( self.sA, self.sW, jobz='V', range='I', uplo='L', vl=0.0, vu=0.0, il=self.Nb, iu=self.Nb, Z=self.sZ) self.beta_hat[:] = math.sqrt(self.sW[0])*self.sZ[:, 0] else: raise RuntimeError('numerical problems') t4 = time() self.solver_time = t2 - t1 self.eig_time = t4 - t3
def solve_linmap(self, bi, lmbd, linmap, show_progress=True): solvers.options['show_progress'] = show_progress # save all problem data self.bi, self.lmbd = bi, lmbd # count alive in map Nm2 = int(sum(linmap)) self.Nm2 = Nm2 self.linmap = linmap n_x1 = self.Nb * (self.Nb + 1) // 2 n_x2 = self.Nb * (self.Nb - 1) // 2 n_x = 1 + Nm2 + n_x1 + n_x2 c = matrix(0.0, (1 + Nm2 + n_x1 + n_x2, 1)) c[0] = 1.0 c[1 + Nm2:1 + Nm2 + self.Nb] = lmbd G = matrix(0.0, (1 + Nm2 + (2 * self.Nb)**2, n_x)) G[:1 + Nm2, :1 + Nm2] = -eye(1 + Nm2) G[1 + Nm2:, 1 + Nm2:] = self.G[1 + self.Nm:, 1 + self.Nm:] h = matrix(0.0, (1 + Nm2 + (2 * self.Nb)**2, 1)) A = matrix(0.0, (Nm2, n_x)) lbi = matrix(0.0, (Nm2, 1)) A[:, 1:1 + Nm2] = eye(Nm2) pos = 0 for i in range(self.Nm): if linmap[i] != 0.0: A[pos, 1 + Nm2:] = self.A[i, 1 + self.Nm:] lbi[pos] = bi[i] h[1 + pos] = -bi[i] pos += 1 assert (pos == Nm2) b = matrix(0.0, (Nm2, 1)) dims = {'l': 0, 'q': [1 + Nm2], 's': [2 * self.Nb]} t1 = time() self.sol = solvers.conelp(c, G, h, dims, A, b) t2 = time() self.lc = c self.lG = G self.lh = h self.ldims = dims self.lA = A self.lb = b self.lNm = Nm2 self.lbi = lbi t3 = time() if self.sol['status'] in ('optimal', 'unknown'): S = self.sol['s'][1 + Nm2:] self.sA[:] = S[self.I11] + 1j * S[self.I21] lapack.heevr(self.sA, self.sW, jobz='V', range='I', uplo='L', vl=0.0, vu=0.0, il=self.Nb, iu=self.Nb, Z=self.sZ) self.beta_hat[:] = math.sqrt(self.sW[0]) * self.sZ[:, 0] else: raise RuntimeError('numerical problems') t4 = time() self.solver_time = t2 - t1 self.eig_time = t4 - t3
def SDP(): return solvers.conelp(c, G, h, dims)
figure(2) clf() spy(matrix(Cun)) title('Sparsity of C') figure(3) clf() spy(matrix(Aun[:, 10], Cun.size)) title('Sparsity of A_10') print "(Close figure plots to continue)\n" show() #Solve unconverted problem using CVXOPT print "Solve unconverted problem using CVXOPT" solvers.options['show_progress'] = True usol = solvers.conelp(-matrix(bun), Aun, matrix(Cun[:]), dims=dims_un) print "Primal objective: %f" % -usol['primal objective'] print '(Press any key to continue)\n' raw_input() #Converted problem print "Converted problem" Acon, bcon, Ccon, Lcon, dims_con = convert(Aun, bun, Cun, Spun, dims_un, Atype=matrix) #Plot sparsity pattern for converted pattern. print "Plot sparsity pattern for converted pattern."
def nrmapp(A, B, C = None, d = None, G = None, h = None): """ Solves the regularized nuclear norm approximation problem minimize || A(x) + B ||_* + 1/2 x'*C*x + d'*x subject to G*x <= h and its dual maximize -h'*z + tr(B'*Z) - 1/2 v'*C*v subject to d + G'*z + A'(Z) = C*v z >= 0 || Z || <= 1. A(x) is a linear mapping that maps n-vectors x to (p x q)-matrices A(x). ||.||_* is the nuclear norm (sum of singular values). A'(Z) is the adjoint mapping of A(x). ||.|| is the maximum singular value norm. INPUT A real dense or sparse matrix of size (p*q, n). Its columns are the coefficients A_i of the mapping A: reals^n --> reals^pxq, A(x) = sum_i=1^n x_i * A_i, stored in column-major order, as p*q-vectors. B real dense or sparse matrix of size (p, q), with p >= q. C real symmetric positive semidefinite dense or sparse matrix of order n. Only the lower triangular part of C is accessed. The default value is a zero matrix. d real dense matrix of size (n, 1). The default value is a zero vector. G real dense or sparse matrix of size (m, n), with m >= 0. The default value is a matrix of size (0, n). h real dense matrix of size (m, 1). The default value is a matrix of size (0, 1). OUTPUT status 'optimal', 'primal infeasible', or 'unknown'. x 'd' matrix of size (n, 1) if status is 'optimal'; None otherwise. z 'd' matrix of size (m, 1) if status is 'optimal' or 'primal infeasible'; None otherwise. Z 'd' matrix of size (p, q) if status is 'optimal' or 'primal infeasible'; None otherwise. If status is 'optimal', then x, z, Z are approximate solutions of the optimality conditions C * x + G' * z + A'(Z) + d = 0 G * x <= h z >= 0, || Z || < = 1 z' * (h - G*x) = 0 tr (Z' * (A(x) + B)) = || A(x) + B ||_*. The last (complementary slackness) condition can be replaced by the following. If the singular value decomposition of A(x) + B is A(x) + B = [ U1 U2 ] * diag(s, 0) * [ V1 V2 ]', with s > 0, then Z = U1 * V1' + U2 * W * V2', || W || <= 1. If status is 'primal infeasible', then Z = 0 and z is a certificate of infeasibility for the inequalities G * x <= h, i.e., a vector that satisfies h' * z = 1, G' * z = 0, z >= 0. """ if type(B) not in (matrix, spmatrix) or B.typecode is not 'd': raise TypeError, "B must be a real dense or sparse matrix" p, q = B.size if p < q: raise ValueError, "row dimension of B must be greater than or "\ "equal to column dimension" if type(A) not in (matrix, spmatrix) or A.typecode is not 'd' or \ A.size[0] != p*q: raise TypeError, "A must be a real dense or sparse matrix with "\ "p*q rows if B has size (p, q)" n = A.size[1] if G is None: G = spmatrix([], [], [], (0, n)) if h is None: h = matrix(0.0, (0, 1)) if type(h) is not matrix or h.typecode is not 'd' or h.size[1] != 1: raise TypeError, "h must be a real dense matrix with one column" m = h.size[0] if type(G) not in (matrix, spmatrix) or G.typecode is not 'd' or \ G.size != (m, n): raise TypeError, "G must be a real dense matrix or sparse matrix "\ "of size (m, n) if h has length m and A has n columns" if C is None: C = spmatrix(0.0, [], [], (n,n)) if d is None: d = matrix(0.0, (n, 1)) if type(C) not in (matrix, spmatrix) or C.typecode is not 'd' or \ C.size != (n,n): raise TypeError, "C must be real dense or sparse matrix of size "\ "(n, n) if A has n columns" if type(d) is not matrix or d.typecode is not 'd' or d.size != (n,1): raise TypeError, "d must be a real matrix of size (n, 1) if A has "\ "n columns" # The problem is solved as a cone program # # minimize (1/2) * x'*C*x + d'*x + (1/2) * (tr X1 + tr X2) # subject to G*x <= h # [ X1 (A(x) + B)' ] # [ A(x) + B X2 ] >= 0. # # The primal variable is stored as a list [ x, X1, X2 ]. def xnewcopy(u): return [ matrix(u[0]), matrix(u[1]), matrix(u[2]) ] def xdot(u,v): return blas.dot(u[0], v[0]) + misc.sdot2(u[1], v[1]) + \ misc.sdot2(u[2], v[2]) def xscal(alpha, u): blas.scal(alpha, u[0]) blas.scal(alpha, u[1]) blas.scal(alpha, u[2]) def xaxpy(u, v, alpha = 1.0): blas.axpy(u[0], v[0], alpha) blas.axpy(u[1], v[1], alpha) blas.axpy(u[2], v[2], alpha) def Pf(u, v, alpha = 1.0, beta = 0.0): base.symv(C, u[0], v[0], alpha = alpha, beta = beta) blas.scal(beta, v[1]) blas.scal(beta, v[2]) c = [ d, matrix(0.0, (q,q)), matrix(0.0, (p,p)) ] c[1][::q+1] = 0.5 c[2][::p+1] = 0.5 # If V is a p+q x p+q matrix # # [ V11 V12 ] # V = [ ] # [ V21 V22 ] # # with V11 q x q, V21 p x q, V12 q x p, and V22 p x p, then I11, I21, # I22 are the index sets defined by # # V[I11] = V11[:], V[I21] = V21[:], V[I22] = V22[:]. # I11 = matrix([ i + j*(p+q) for j in xrange(q) for i in xrange(q) ]) I21 = matrix([ q + i + j*(p+q) for j in xrange(q) for i in xrange(p) ]) I22 = matrix([ (p+q)*q + q + i + j*(p+q) for j in xrange(p) for i in xrange(p) ]) dims = {'l': m, 'q': [], 's': [p+q]} hh = matrix(0.0, (m + (p+q)**2, 1)) hh[:m] = h hh[m + I21] = B[:] def Gf(u, v, alpha = 1.0, beta = 0.0, trans = 'N'): if trans == 'N': # v[:m] := alpha * G * u[0] + beta * v[:m] base.gemv(G, u[0], v, alpha = alpha, beta = beta) # v[m:] := alpha * [-u[1], -A(u[0])'; -A(u[0]), -u[2]] # + beta * v[m:] blas.scal(beta, v, offset = m) v[m + I11] -= alpha * u[1][:] v[m + I21] -= alpha * A * u[0] v[m + I22] -= alpha * u[2][:] else: # v[0] := alpha * ( G.T * u[:m] - 2.0 * A.T * u[m + I21] ) # + beta v[1] base.gemv(G, u, v[0], trans = 'T', alpha = alpha, beta = beta) base.gemv(A, u[m + I21], v[0], trans = 'T', alpha = -2.0*alpha, beta = 1.0) # v[1] := -alpha * u[m + I11] + beta * v[1] blas.scal(beta, v[1]) blas.axpy(u[m + I11], v[1], alpha = -alpha) # v[2] := -alpha * u[m + I22] + beta * v[2] blas.scal(beta, v[2]) blas.axpy(u[m + I22], v[2], alpha = -alpha) def Af(u, v, alpha = 1.0, beta = 0.0, trans = 'N'): if trans == 'N': pass else: blas.scal(beta, v[0]) blas.scal(beta, v[1]) blas.scal(beta, v[2]) L1 = matrix(0.0, (q, q)) L2 = matrix(0.0, (p, p)) T21 = matrix(0.0, (p, q)) s = matrix(0.0, (q, 1)) SS = matrix(0.0, (q, q)) V1 = matrix(0.0, (q, q)) V2 = matrix(0.0, (p, p)) As = matrix(0.0, (p*q, n)) As2 = matrix(0.0, (p*q, n)) tmp = matrix(0.0, (p, q)) a = matrix(0.0, (p+q, p+q)) H = matrix(0.0, (n,n)) Gs = matrix(0.0, (m, n)) Q1 = matrix(0.0, (q, p+q)) Q2 = matrix(0.0, (p, p+q)) tau1 = matrix(0.0, (q,1)) tau2 = matrix(0.0, (p,1)) bz11 = matrix(0.0, (q,q)) bz22 = matrix(0.0, (p,p)) bz21 = matrix(0.0, (p,q)) # Suppose V = [V1; V2] is p x q with V1 q x q. If v = V[:] then # v[Itriu] are the strict upper triangular entries of V1 stored # columnwise. Itriu = [ i + j*p for j in xrange(1,q) for i in xrange(j) ] # v[Itril] are the strict lower triangular entries of V1 stored rowwise. Itril = [ j + i*p for j in xrange(1,q) for i in xrange(j) ] # v[Idiag] are the diagonal entries of V1. Idiag = [ i*(p+1) for i in xrange(q) ] # v[Itriu2] are the upper triangular entries of V1, with the diagonal # entries stored first, followed by the strict upper triangular entries # stored columnwise. Itriu2 = Idiag + Itriu # If V is a q x q matrix and v = V[:], then v[Itril2] are the strict # lower triangular entries of V stored columnwise and v[Itril3] are # the strict lower triangular entries stored rowwise. Itril2 = [ i + j*q for j in xrange(q) for i in xrange(j+1,q) ] Itril3 = [ i + j*q for i in xrange(q) for j in xrange(i) ] P = spmatrix(0.0, Itriu, Itril, (p*q, p*q)) D = spmatrix(1.0, range(p*q), range(p*q)) DV = matrix(1.0, (p*q, 1)) def F(W): """ Create a solver for the linear equations C * ux + G' * uzl - 2*A'(uzs21) = bx -uzs11 = bX1 -uzs22 = bX2 G * ux - Dl^2 * uzl = bzl [ -uX1 -A(ux)' ] [ uzs11 uzs21' ] [ ] - r*r' * [ ] * r*r' = bzs [ -A(ux) -uX2 ] [ uzs21 uzs22 ] where Dl = diag(W['l']), r = W['r'][0]. On entry, x = (bx, bX1, bX2) and z = [ bzl; bzs[:] ]. On exit, x = (ux, uX1, uX2) and z = [ Dl*uzl; (r'*uzs*r)[:] ]. 1. Compute matrices V1, V2 such that (with T = r*r') [ V1 0 ] [ T11 T21' ] [ V1' 0 ] [ I S' ] [ ] [ ] [ ] = [ ] [ 0 V2' ] [ T21 T22 ] [ 0 V2 ] [ S I ] and S = [ diag(s); 0 ], s a positive q-vector. 2. Factor the mapping X -> X + S * X' * S: X + S * X' * S = L( L'( X )). 3. Compute scaled mappings: a matrix As with as its columns the coefficients of the scaled mapping L^-1( V2' * A() * V1' ) and the matrix Gs = Dl^-1 * G. 4. Cholesky factorization of H = C + Gs'*Gs + 2*As'*As. """ # 1. Compute V1, V2, s. r = W['r'][0] # LQ factorization R[:q, :] = L1 * Q1. lapack.lacpy(r, Q1, m = q) lapack.gelqf(Q1, tau1) lapack.lacpy(Q1, L1, n = q, uplo = 'L') lapack.orglq(Q1, tau1) # LQ factorization R[q:, :] = L2 * Q2. lapack.lacpy(r, Q2, m = p, offsetA = q) lapack.gelqf(Q2, tau2) lapack.lacpy(Q2, L2, n = p, uplo = 'L') lapack.orglq(Q2, tau2) # V2, V1, s are computed from an SVD: if # # Q2 * Q1' = U * diag(s) * V', # # then V1 = V' * L1^-1 and V2 = L2^-T * U. # T21 = Q2 * Q1.T blas.gemm(Q2, Q1, T21, transB = 'T') # SVD T21 = U * diag(s) * V'. Store U in V2 and V' in V1. lapack.gesvd(T21, s, jobu = 'A', jobvt = 'A', U = V2, Vt = V1) # # Q2 := Q2 * Q1' without extracting Q1; store T21 in Q2 # this will requires lapack.ormlq or lapack.unmlq # V2 = L2^-T * U blas.trsm(L2, V2, transA = 'T') # V1 = V' * L1^-1 blas.trsm(L1, V1, side = 'R') # 2. Factorization X + S * X' * S = L( L'( X )). # # The factor L is stored as a diagonal matrix D and a sparse lower # triangular matrix P, such that # # L(X)[:] = D**-1 * (I + P) * X[:] # L^-1(X)[:] = D * (I - P) * X[:]. # SS is q x q with SS[i,j] = si*sj. blas.scal(0.0, SS) blas.syr(s, SS) # For a p x q matrix X, P*X[:] is Y[:] where # # Yij = si * sj * Xji if i < j # = 0 otherwise. # P.V = SS[Itril2] # For a p x q matrix X, D*X[:] is Y[:] where # # Yij = Xij / sqrt( 1 - si^2 * sj^2 ) if i < j # = Xii / sqrt( 1 + si^2 ) if i = j # = Xij otherwise. # DV[Idiag] = sqrt(1.0 + SS[::q+1]) DV[Itriu] = sqrt(1.0 - SS[Itril3]**2) D.V = DV**-1 # 3. Scaled linear mappings # Ask := V2' * Ask * V1' blas.scal(0.0, As) base.axpy(A, As) for i in xrange(n): # tmp := V2' * As[i, :] blas.gemm(V2, As, tmp, transA = 'T', m = p, n = q, k = p, ldB = p, offsetB = i*p*q) # As[:,i] := tmp * V1' blas.gemm(tmp, V1, As, transB = 'T', m = p, n = q, k = q, ldC = p, offsetC = i*p*q) # As := D * (I - P) * As # = L^-1 * As. blas.copy(As, As2) base.gemm(P, As, As2, alpha = -1.0, beta = 1.0) base.gemm(D, As2, As) # Gs := Dl^-1 * G blas.scal(0.0, Gs) base.axpy(G, Gs) for k in xrange(n): blas.tbmv(W['di'], Gs, n = m, k = 0, ldA = 1, offsetx = k*m) # 4. Cholesky factorization of H = C + Gs' * Gs + 2 * As' * As. blas.syrk(As, H, trans = 'T', alpha = 2.0) blas.syrk(Gs, H, trans = 'T', beta = 1.0) base.axpy(C, H) lapack.potrf(H) def f(x, y, z): """ Solve C * ux + G' * uzl - 2*A'(uzs21) = bx -uzs11 = bX1 -uzs22 = bX2 G * ux - D^2 * uzl = bzl [ -uX1 -A(ux)' ] [ uzs11 uzs21' ] [ ] - T * [ ] * T = bzs. [ -A(ux) -uX2 ] [ uzs21 uzs22 ] On entry, x = (bx, bX1, bX2) and z = [ bzl; bzs[:] ]. On exit, x = (ux, uX1, uX2) and z = [ D*uzl; (r'*uzs*r)[:] ]. Define X = uzs21, Z = T * uzs * T: C * ux + G' * uzl - 2*A'(X) = bx [ 0 X' ] [ bX1 0 ] T * [ ] * T - Z = T * [ ] * T [ X 0 ] [ 0 bX2 ] G * ux - D^2 * uzl = bzl [ -uX1 -A(ux)' ] [ Z11 Z21' ] [ ] - [ ] = bzs [ -A(ux) -uX2 ] [ Z21 Z22 ] Return x = (ux, uX1, uX2), z = [ D*uzl; (rti'*Z*rti)[:] ]. We use the congruence transformation [ V1 0 ] [ T11 T21' ] [ V1' 0 ] [ I S' ] [ ] [ ] [ ] = [ ] [ 0 V2' ] [ T21 T22 ] [ 0 V2 ] [ S I ] and the factorization X + S * X' * S = L( L'(X) ) to write this as C * ux + G' * uzl - 2*A'(X) = bx L'(V2^-1 * X * V1^-1) - L^-1(V2' * Z21 * V1') = bX G * ux - D^2 * uzl = bzl [ -uX1 -A(ux)' ] [ Z11 Z21' ] [ ] - [ ] = bzs, [ -A(ux) -uX2 ] [ Z21 Z22 ] or C * ux + Gs' * uuzl - 2*As'(XX) = bx XX - ZZ21 = bX Gs * ux - uuzl = D^-1 * bzl -As(ux) - ZZ21 = bbzs_21 -uX1 - Z11 = bzs_11 -uX2 - Z22 = bzs_22 if we introduce scaled variables uuzl = D * uzl XX = L'(V2^-1 * X * V1^-1) = L'(V2^-1 * uzs21 * V1^-1) ZZ21 = L^-1(V2' * Z21 * V1') and define bbzs_21 = L^-1(V2' * bzs_21 * V1') [ bX1 0 ] bX = L^-1( V2' * (T * [ ] * T)_21 * V1'). [ 0 bX2 ] Eliminating Z21 gives C * ux + Gs' * uuzl - 2*As'(XX) = bx Gs * ux - uuzl = D^-1 * bzl -As(ux) - XX = bbzs_21 - bX -uX1 - Z11 = bzs_11 -uX2 - Z22 = bzs_22 and eliminating uuzl and XX gives H * ux = bx + Gs' * D^-1 * bzl + 2*As'(bX - bbzs_21) Gs * ux - uuzl = D^-1 * bzl -As(ux) - XX = bbzs_21 - bX -uX1 - Z11 = bzs_11 -uX2 - Z22 = bzs_22. In summary, we can use the following algorithm: 1. bXX := bX - bbzs21 [ bX1 0 ] = L^-1( V2' * ((T * [ ] * T)_21 - bzs_21) * V1') [ 0 bX2 ] 2. Solve H * ux = bx + Gs' * D^-1 * bzl + 2*As'(bXX). 3. From ux, compute uuzl = Gs*ux - D^-1 * bzl and X = V2 * L^-T(-As(ux) + bXX) * V1. 4. Return ux, uuzl, rti' * Z * rti = r' * [ -bX1, X'; X, -bX2 ] * r and uX1 = -Z11 - bzs_11, uX2 = -Z22 - bzs_22. """ # Save bzs_11, bzs_22, bzs_21. lapack.lacpy(z, bz11, uplo = 'L', m = q, n = q, ldA = p+q, offsetA = m) lapack.lacpy(z, bz21, m = p, n = q, ldA = p+q, offsetA = m+q) lapack.lacpy(z, bz22, uplo = 'L', m = p, n = p, ldA = p+q, offsetA = m + (p+q+1)*q) # zl := D^-1 * zl # = D^-1 * bzl blas.tbmv(W['di'], z, n = m, k = 0, ldA = 1) # zs := r' * [ bX1, 0; 0, bX2 ] * r. # zs := [ bX1, 0; 0, bX2 ] blas.scal(0.0, z, offset = m) lapack.lacpy(x[1], z, uplo = 'L', m = q, n = q, ldB = p+q, offsetB = m) lapack.lacpy(x[2], z, uplo = 'L', m = p, n = p, ldB = p+q, offsetB = m + (p+q+1)*q) # scale diagonal of zs by 1/2 blas.scal(0.5, z, inc = p+q+1, offset = m) # a := tril(zs)*r blas.copy(r, a) blas.trmm(z, a, side = 'L', m = p+q, n = p+q, ldA = p+q, ldB = p+q, offsetA = m) # zs := a'*r + r'*a blas.syr2k(r, a, z, trans = 'T', n = p+q, k = p+q, ldB = p+q, ldC = p+q, offsetC = m) # bz21 := L^-1( V2' * ((r * zs * r')_21 - bz21) * V1') # # [ bX1 0 ] # = L^-1( V2' * ((T * [ ] * T)_21 - bz21) * V1'). # [ 0 bX2 ] # a = [ r21 r22 ] * z # = [ r21 r22 ] * r' * [ bX1, 0; 0, bX2 ] * r # = [ T21 T22 ] * [ bX1, 0; 0, bX2 ] * r blas.symm(z, r, a, side = 'R', m = p, n = p+q, ldA = p+q, ldC = p+q, offsetB = q) # bz21 := -bz21 + a * [ r11, r12 ]' # = -bz21 + (T * [ bX1, 0; 0, bX2 ] * T)_21 blas.gemm(a, r, bz21, transB = 'T', m = p, n = q, k = p+q, beta = -1.0, ldA = p+q, ldC = p) # bz21 := V2' * bz21 * V1' # = V2' * (-bz21 + (T*[bX1, 0; 0, bX2]*T)_21) * V1' blas.gemm(V2, bz21, tmp, transA = 'T', m = p, n = q, k = p, ldB = p) blas.gemm(tmp, V1, bz21, transB = 'T', m = p, n = q, k = q, ldC = p) # bz21[:] := D * (I-P) * bz21[:] # = L^-1 * bz21[:] # = bXX[:] blas.copy(bz21, tmp) base.gemv(P, bz21, tmp, alpha = -1.0, beta = 1.0) base.gemv(D, tmp, bz21) # Solve H * ux = bx + Gs' * D^-1 * bzl + 2*As'(bXX). # x[0] := x[0] + Gs'*zl + 2*As'(bz21) # = bx + G' * D^-1 * bzl + 2 * As'(bXX) blas.gemv(Gs, z, x[0], trans = 'T', alpha = 1.0, beta = 1.0) blas.gemv(As, bz21, x[0], trans = 'T', alpha = 2.0, beta = 1.0) # x[0] := H \ x[0] # = ux lapack.potrs(H, x[0]) # uuzl = Gs*ux - D^-1 * bzl blas.gemv(Gs, x[0], z, alpha = 1.0, beta = -1.0) # bz21 := V2 * L^-T(-As(ux) + bz21) * V1 # = X blas.gemv(As, x[0], bz21, alpha = -1.0, beta = 1.0) blas.tbsv(DV, bz21, n = p*q, k = 0, ldA = 1) blas.copy(bz21, tmp) base.gemv(P, tmp, bz21, alpha = -1.0, beta = 1.0, trans = 'T') blas.gemm(V2, bz21, tmp) blas.gemm(tmp, V1, bz21) # zs := -zs + r' * [ 0, X'; X, 0 ] * r # = r' * [ -bX1, X'; X, -bX2 ] * r. # a := bz21 * [ r11, r12 ] # = X * [ r11, r12 ] blas.gemm(bz21, r, a, m = p, n = p+q, k = q, ldA = p, ldC = p+q) # z := -z + [ r21, r22 ]' * a + a' * [ r21, r22 ] # = rti' * uzs * rti blas.syr2k(r, a, z, trans = 'T', beta = -1.0, n = p+q, k = p, offsetA = q, offsetC = m, ldB = p+q, ldC = p+q) # uX1 = -Z11 - bzs_11 # = -(r*zs*r')_11 - bzs_11 # uX2 = -Z22 - bzs_22 # = -(r*zs*r')_22 - bzs_22 blas.copy(bz11, x[1]) blas.copy(bz22, x[2]) # scale diagonal of zs by 1/2 blas.scal(0.5, z, inc = p+q+1, offset = m) # a := r*tril(zs) blas.copy(r, a) blas.trmm(z, a, side = 'R', m = p+q, n = p+q, ldA = p+q, ldB = p+q, offsetA = m) # x[1] := -x[1] - a[:q,:] * r[:q, :]' - r[:q,:] * a[:q,:]' # = -bzs_11 - (r*zs*r')_11 blas.syr2k(a, r, x[1], n = q, alpha = -1.0, beta = -1.0) # x[2] := -x[2] - a[q:,:] * r[q:, :]' - r[q:,:] * a[q:,:]' # = -bzs_22 - (r*zs*r')_22 blas.syr2k(a, r, x[2], n = p, alpha = -1.0, beta = -1.0, offsetA = q, offsetB = q) # scale diagonal of zs by 1/2 blas.scal(2.0, z, inc = p+q+1, offset = m) return f if C: sol = solvers.coneqp(Pf, c, Gf, hh, dims, Af, kktsolver = F, xnewcopy = xnewcopy, xdot = xdot, xaxpy = xaxpy, xscal = xscal) else: sol = solvers.conelp(c, Gf, hh, dims, Af, kktsolver = F, xnewcopy = xnewcopy, xdot = xdot, xaxpy = xaxpy, xscal = xscal) if sol['status'] is 'optimal': x = sol['x'][0] z = sol['z'][:m] Z = sol['z'][m:] Z.size = (p + q, p + q) Z = -2.0 * Z[-p:, :q] elif sol['status'] is 'primal infeasible': x = None z = sol['z'][:m] Z = sol['z'][m:] Z.size = (p + q, p + q) Z = -2.0 * Z[-p:, :q] else: x, z, Z = None, None, None return {'status': sol['status'], 'x': x, 'z': z, 'Z': Z }
def A_optimize_fast(sij, N=1., nsofar=None, delta=None, only_include_measurements=None, maxiters=100, feastol=1e-6): ''' Find the A-optimal of the difference network that minimizes the trace of the covariance matrix. This corresponds to minimizing the average error. In an iterative optimization of the difference network, the optimal allocation is updated with the estimate of s_{ij}, and we need to allocate the next iteration of sampling based on what has already been sampled for each pair. This implementation uses a customized KKT solver. The time complexity is O(K^5), memory complexity is O(K^4). Args: sij: KxK symmetric matrix, where the measurement variance of the difference between i and j is proportional to s[i][j]^2 = s[j][i]^2, and the measurement variance of i is proportional to s[i][i]^2. nadd: float, Nadd gives the additional number of samples to be collected in the next iteration. nsofar: KxK symmetric matrix, where nsofar[i,j] is the number of samples that has already been collected for (i,j) pair. delta: a length K vector. delta[i] is the measurement uncertainty on the quantity x[i] from an independent experiment; if no independent experiment provides a value for x[i], delta[i] is set to numpy.infty. only_include_measurements: set of pairs, if not None, indicate which pairs should be considered in the optimal network. Any pair (i,j) not in the set will be excluded in the allocation (i.e. dn[i,j] = 0). The pair (i,j) in the set must be ordered so that i<=j. Return: KxK symmetric matrix of float, the (i,j) element of which gives the number of samples to be allocated to the measurement of (i,j) difference in the next iteration. ''' si2 = cvxopt.div(1., sij**2) K = si2.size[0] if delta is not None: di2 = np.array([ 1. / delta[i]**2 if delta[i] is not None else 0. for i in xrange(K) ]) else: di2 = None if only_include_measurements is not None: for i in xrange(K): for j in xrange(i, K): if not (i, j) in only_include_measurements: # Set the s[i,j] to infinity, thus excluding the pair. si2[i, j] = si2[j, i] = 0. Gm, hv, Am = Aopt_GhA(si2, nsofar, di2=di2, G_as_function=True) dims = dict(l=K * (K + 1) / 2, q=[], s=[K + 1] * K) cv = matrix(np.concatenate([np.zeros(K * (K + 1) / 2), np.ones(K)]), (K * (K + 1) / 2 + K, 1)) bv = matrix(float(N), (1, 1)) def default_kkt_solver(W): return misc.kkt_ldl(Gm, dims, Am)(W) sol = solvers.conelp(cv, Gm, hv, dims, Am, bv, options=dict(maxiters=maxiters, feastol=feastol), kktsolver=lambda W: Aopt_KKT_solver(si2, W)) return conelp_solution_to_nij(sol['x'], K)
c = matrix([1.0] + [0.0]*n) hTemp1 = matrix([0.0]+(-g).tolist()) GTemp1 = matrix(numpy.array(scipy.sparse.bmat([ [[-1.0],None], [None,H] ]).todense())) GTemp1 = matrix(numpy.append(numpy.append(numpy.array([0]*m).reshape(m,1),numpy.array(GTemp),axis=1), numpy.array(GTemp1), axis=0)) hTemp1 = matrix(numpy.append(hTemp,hTemp1)) dims1 = {'l': G.shape[0], 'q': [n+1,n+1], 's': []} solSOCP = solvers.conelp(c, GTemp1, hTemp1, dims1) print solSOCP['x'][1::] ## testing the change in objective function print F(matrix(theta))[0] print F(matrix(theta) + solSOCP['x'][1::])[0] print F(matrix(theta) + sol1['x'])[0] blas.nrm2(solSOCP['x'][1::]) blas.nrm2(sol1['x']) blas.nrm2(qpOut['x']) blas.nrm2(hTemp1[-n::] - matrix(GTemp)[-n::,:] * solSOCP['x'][1::] )
# The small linear cone program of section 8.1 (Linear cone programs). from cvxopt import matrix, solvers c = matrix([-6., -4., -5.]) G = matrix([[ 16., 7., 24., -8., 8., -1., 0., -1., 0., 0., 7., -5., 1., -5., 1., -7., 1., -7., -4.], [-14., 2., 7., -13., -18., 3., 0., 0., -1., 0., 3., 13., -6., 13., 12., -10., -6., -10., -28.], [ 5., 0., -15., 12., -6., 17., 0., 0., 0., -1., 9., 6., -6., 6., -7., -7., -6., -7., -11.]]) h = matrix( [ -3., 5., 12., -2., -14., -13., 10., 0., 0., 0., 68., -30., -19., -30., 99., 23., -19., 23., 10.] ) dims = {'l': 2, 'q': [4, 4], 's': [3]} sol = solvers.conelp(c, G, h, dims) print("\nStatus: " + sol['status']) print("\nx = \n") print(sol['x']) print("\nz = \n") print(sol['z'])
def ubsdp(c, A, B, pstart=None, dstart=None): """ minimize c'*x + tr(X) s.t. sum_{i=1}^n xi * Ai - X <= B X >= 0 maximize -tr(B * Z0) s.t. tr(Ai * Z0) + ci = 0, i = 1, ..., n -Z0 - Z1 + I = 0 Z0 >= 0, Z1 >= 0. c is an n-vector. A is an m^2 x n-matrix. B is an m x m-matrix. """ msq, n = A.size m = int(math.sqrt(msq)) mpckd = int(m * (m + 1) / 2) dims = {'l': 0, 'q': [], 's': [m, m]} # The primal variable is stored as a tuple (x, X). cc = (c, matrix(0.0, (m, m))) cc[1][::m + 1] = 1.0 def xnewcopy(u): return (+u[0], +u[1]) def xdot(u, v): return blas.dot(u[0], v[0]) + misc.sdot2(u[1], v[1]) def xscal(alpha, u): blas.scal(alpha, u[0]) blas.scal(alpha, u[1]) def xaxpy(u, v, alpha=1.0): blas.axpy(u[0], v[0], alpha) blas.axpy(u[1], v[1], alpha) def G(u, v, alpha=1.0, beta=0.0, trans='N'): """ If trans is 'N': v[:msq] := alpha * (A*u[0] - u[1][:]) + beta * v[:msq] v[msq:] := -alpha * u[1][:] + beta * v[msq:]. If trans is 'T': v[0] := alpha * A' * u[:msq] + beta * v[0] v[1][:] := alpha * (-u[:msq] - u[msq:]) + beta * v[1][:]. """ if trans == 'N': blas.gemv(A, u[0], v, alpha=alpha, beta=beta) blas.axpy(u[1], v, alpha=-alpha) blas.scal(beta, v, offset=msq) blas.axpy(u[1], v, alpha=-alpha, offsety=msq) else: misc.sgemv(A, u, v[0], dims={ 'l': 0, 'q': [], 's': [m] }, alpha=alpha, beta=beta, trans='T') blas.scal(beta, v[1]) blas.axpy(u, v[1], alpha=-alpha, n=msq) blas.axpy(u, v[1], alpha=-alpha, n=msq, offsetx=msq) h = matrix(0.0, (2 * msq, 1)) blas.copy(B, h) L = matrix(0.0, (m, m)) U = matrix(0.0, (m, m)) Us = matrix(0.0, (m, m)) Uti = matrix(0.0, (m, m)) s = matrix(0.0, (m, 1)) Asc = matrix(0.0, (msq, n)) S = matrix(0.0, (m, m)) tmp = matrix(0.0, (m, m)) x1 = matrix(0.0, (m**2, 1)) H = matrix(0.0, (n, n)) def F(W): """ Generate a solver for A'(uz0) = bx[0] -uz0 - uz1 = bx[1] A(ux[0]) - ux[1] - r0*r0' * uz0 * r0*r0' = bz0 - ux[1] - r1*r1' * uz1 * r1*r1' = bz1. uz0, uz1, bz0, bz1 are symmetric m x m-matrices. ux[0], bx[0] are n-vectors. ux[1], bx[1] are symmetric m x m-matrices. We first calculate a congruence that diagonalizes r0*r0' and r1*r1': U' * r0 * r0' * U = I, U' * r1 * r1' * U = S. We then make a change of variables usx[0] = ux[0], usx[1] = U' * ux[1] * U usz0 = U^-1 * uz0 * U^-T usz1 = U^-1 * uz1 * U^-T and define As() = U' * A() * U' bsx[1] = U^-1 * bx[1] * U^-T bsz0 = U' * bz0 * U bsz1 = U' * bz1 * U. This gives As'(usz0) = bx[0] -usz0 - usz1 = bsx[1] As(usx[0]) - usx[1] - usz0 = bsz0 -usx[1] - S * usz1 * S = bsz1. 1. Eliminate usz0, usz1 using equations 3 and 4, usz0 = As(usx[0]) - usx[1] - bsz0 usz1 = -S^-1 * (usx[1] + bsz1) * S^-1. This gives two equations in usx[0] an usx[1]. As'(As(usx[0]) - usx[1]) = bx[0] + As'(bsz0) -As(usx[0]) + usx[1] + S^-1 * usx[1] * S^-1 = bsx[1] - bsz0 - S^-1 * bsz1 * S^-1. 2. Eliminate usx[1] using equation 2: usx[1] + S * usx[1] * S = S * ( As(usx[0]) + bsx[1] - bsz0 ) * S - bsz1 i.e., with Gamma[i,j] = 1.0 + S[i,i] * S[j,j], usx[1] = ( S * As(usx[0]) * S ) ./ Gamma + ( S * ( bsx[1] - bsz0 ) * S - bsz1 ) ./ Gamma. This gives an equation in usx[0]. As'( As(usx[0]) ./ Gamma ) = bx0 + As'(bsz0) + As'( (S * ( bsx[1] - bsz0 ) * S - bsz1) ./ Gamma ) = bx0 + As'( ( bsz0 - bsz1 + S * bsx[1] * S ) ./ Gamma ). """ # Calculate U s.t. # # U' * r0*r0' * U = I, U' * r1*r1' * U = diag(s). # Cholesky factorization r0 * r0' = L * L' blas.syrk(W['r'][0], L) lapack.potrf(L) # SVD L^-1 * r1 = U * diag(s) * V' blas.copy(W['r'][1], U) blas.trsm(L, U) lapack.gesvd(U, s, jobu='O') # s := s**2 s[:] = s**2 # Uti := U blas.copy(U, Uti) # U := L^-T * U blas.trsm(L, U, transA='T') # Uti := L * Uti = U^-T blas.trmm(L, Uti) # Us := U * diag(s)^-1 blas.copy(U, Us) for i in range(m): blas.tbsv(s, Us, n=m, k=0, ldA=1, incx=m, offsetx=i) # S is m x m with lower triangular entries s[i] * s[j] # sqrtG is m x m with lower triangular entries sqrt(1.0 + s[i]*s[j]) # Upper triangular entries are undefined but nonzero. blas.scal(0.0, S) blas.syrk(s, S) Gamma = 1.0 + S sqrtG = sqrt(Gamma) # Asc[i] = (U' * Ai * * U ) ./ sqrtG, for i = 1, ..., n # = Asi ./ sqrt(Gamma) blas.copy(A, Asc) misc.scale( Asc, # only 'r' part of the dictionary is used { 'dnl': matrix(0.0, (0, 1)), 'dnli': matrix(0.0, (0, 1)), 'd': matrix(0.0, (0, 1)), 'di': matrix(0.0, (0, 1)), 'v': [], 'beta': [], 'r': [U], 'rti': [U] }) for i in range(n): blas.tbsv(sqrtG, Asc, n=msq, k=0, ldA=1, offsetx=i * msq) # Convert columns of Asc to packed storage misc.pack2(Asc, {'l': 0, 'q': [], 's': [m]}) # Cholesky factorization of Asc' * Asc. H = matrix(0.0, (n, n)) blas.syrk(Asc, H, trans='T', k=mpckd) lapack.potrf(H) def solve(x, y, z): """ 1. Solve for usx[0]: Asc'(Asc(usx[0])) = bx0 + Asc'( ( bsz0 - bsz1 + S * bsx[1] * S ) ./ sqrtG) = bx0 + Asc'( ( bsz0 + S * ( bsx[1] - bssz1) S ) ./ sqrtG) where bsx[1] = U^-1 * bx[1] * U^-T, bsz0 = U' * bz0 * U, bsz1 = U' * bz1 * U, bssz1 = S^-1 * bsz1 * S^-1 2. Solve for usx[1]: usx[1] + S * usx[1] * S = S * ( As(usx[0]) + bsx[1] - bsz0 ) * S - bsz1 usx[1] = ( S * (As(usx[0]) + bsx[1] - bsz0) * S - bsz1) ./ Gamma = -bsz0 + (S * As(usx[0]) * S) ./ Gamma + (bsz0 - bsz1 + S * bsx[1] * S ) . / Gamma = -bsz0 + (S * As(usx[0]) * S) ./ Gamma + (bsz0 + S * ( bsx[1] - bssz1 ) * S ) . / Gamma Unscale ux[1] = Uti * usx[1] * Uti' 3. Compute usz0, usz1 r0' * uz0 * r0 = r0^-1 * ( A(ux[0]) - ux[1] - bz0 ) * r0^-T r1' * uz1 * r1 = r1^-1 * ( -ux[1] - bz1 ) * r1^-T """ # z0 := U' * z0 * U # = bsz0 __cngrnc(U, z, trans='T') # z1 := Us' * bz1 * Us # = S^-1 * U' * bz1 * U * S^-1 # = S^-1 * bsz1 * S^-1 __cngrnc(Us, z, trans='T', offsetx=msq) # x[1] := Uti' * x[1] * Uti # = bsx[1] __cngrnc(Uti, x[1], trans='T') # x[1] := x[1] - z[msq:] # = bsx[1] - S^-1 * bsz1 * S^-1 blas.axpy(z, x[1], alpha=-1.0, offsetx=msq) # x1 = (S * x[1] * S + z[:msq] ) ./ sqrtG # = (S * ( bsx[1] - S^-1 * bsz1 * S^-1) * S + bsz0 ) ./ sqrtG # = (S * bsx[1] * S - bsz1 + bsz0 ) ./ sqrtG # in packed storage blas.copy(x[1], x1) blas.tbmv(S, x1, n=msq, k=0, ldA=1) blas.axpy(z, x1, n=msq) blas.tbsv(sqrtG, x1, n=msq, k=0, ldA=1) misc.pack2(x1, {'l': 0, 'q': [], 's': [m]}) # x[0] := x[0] + Asc'*x1 # = bx0 + Asc'( ( bsz0 - bsz1 + S * bsx[1] * S ) ./ sqrtG) # = bx0 + As'( ( bz0 - bz1 + S * bx[1] * S ) ./ Gamma ) blas.gemv(Asc, x1, x[0], m=mpckd, trans='T', beta=1.0) # x[0] := H^-1 * x[0] # = ux[0] lapack.potrs(H, x[0]) # x1 = Asc(x[0]) .* sqrtG (unpacked) # = As(x[0]) blas.gemv(Asc, x[0], tmp, m=mpckd) misc.unpack(tmp, x1, {'l': 0, 'q': [], 's': [m]}) blas.tbmv(sqrtG, x1, n=msq, k=0, ldA=1) # usx[1] = (x1 + (x[1] - z[:msq])) ./ sqrtG**2 # = (As(ux[0]) + bsx[1] - bsz0 - S^-1 * bsz1 * S^-1) # ./ Gamma # x[1] := x[1] - z[:msq] # = bsx[1] - bsz0 - S^-1 * bsz1 * S^-1 blas.axpy(z, x[1], -1.0, n=msq) # x[1] := x[1] + x1 # = As(ux) + bsx[1] - bsz0 - S^-1 * bsz1 * S^-1 blas.axpy(x1, x[1]) # x[1] := x[1] / Gammma # = (As(ux) + bsx[1] - bsz0 + S^-1 * bsz1 * S^-1 ) / Gamma # = S^-1 * usx[1] * S^-1 blas.tbsv(Gamma, x[1], n=msq, k=0, ldA=1) # z[msq:] := r1' * U * (-z[msq:] - x[1]) * U * r1 # := -r1' * U * S^-1 * (bsz1 + ux[1]) * S^-1 * U * r1 # := -r1' * uz1 * r1 blas.axpy(x[1], z, n=msq, offsety=msq) blas.scal(-1.0, z, offset=msq) __cngrnc(U, z, offsetx=msq) __cngrnc(W['r'][1], z, trans='T', offsetx=msq) # x[1] := S * x[1] * S # = usx1 blas.tbmv(S, x[1], n=msq, k=0, ldA=1) # z[:msq] = r0' * U' * ( x1 - x[1] - z[:msq] ) * U * r0 # = r0' * U' * ( As(ux) - usx1 - bsz0 ) * U * r0 # = r0' * U' * usz0 * U * r0 # = r0' * uz0 * r0 blas.axpy(x1, z, -1.0, n=msq) blas.scal(-1.0, z, n=msq) blas.axpy(x[1], z, -1.0, n=msq) __cngrnc(U, z) __cngrnc(W['r'][0], z, trans='T') # x[1] := Uti * x[1] * Uti' # = ux[1] __cngrnc(Uti, x[1]) return solve sol = solvers.conelp(cc, G, h, dims={ 'l': 0, 's': [m, m], 'q': [] }, kktsolver=F, xnewcopy=xnewcopy, xdot=xdot, xaxpy=xaxpy, xscal=xscal, primalstart=pstart, dualstart=dstart) return matrix(sol['x'][1], (n, n))
def nrmapp(A, B, C=None, d=None, G=None, h=None): """ Solves the regularized nuclear norm approximation problem minimize || A(x) + B ||_* + 1/2 x'*C*x + d'*x subject to G*x <= h and its dual maximize -h'*z + tr(B'*Z) - 1/2 v'*C*v subject to d + G'*z + A'(Z) = C*v z >= 0 || Z || <= 1. A(x) is a linear mapping that maps n-vectors x to (p x q)-matrices A(x). ||.||_* is the nuclear norm (sum of singular values). A'(Z) is the adjoint mapping of A(x). ||.|| is the maximum singular value norm. INPUT A real dense or sparse matrix of size (p*q, n). Its columns are the coefficients A_i of the mapping A: reals^n --> reals^pxq, A(x) = sum_i=1^n x_i * A_i, stored in column-major order, as p*q-vectors. B real dense or sparse matrix of size (p, q), with p >= q. C real symmetric positive semidefinite dense or sparse matrix of order n. Only the lower triangular part of C is accessed. The default value is a zero matrix. d real dense matrix of size (n, 1). The default value is a zero vector. G real dense or sparse matrix of size (m, n), with m >= 0. The default value is a matrix of size (0, n). h real dense matrix of size (m, 1). The default value is a matrix of size (0, 1). OUTPUT status 'optimal', 'primal infeasible', or 'unknown'. x 'd' matrix of size (n, 1) if status is 'optimal'; None otherwise. z 'd' matrix of size (m, 1) if status is 'optimal' or 'primal infeasible'; None otherwise. Z 'd' matrix of size (p, q) if status is 'optimal' or 'primal infeasible'; None otherwise. If status is 'optimal', then x, z, Z are approximate solutions of the optimality conditions C * x + G' * z + A'(Z) + d = 0 G * x <= h z >= 0, || Z || < = 1 z' * (h - G*x) = 0 tr (Z' * (A(x) + B)) = || A(x) + B ||_*. The last (complementary slackness) condition can be replaced by the following. If the singular value decomposition of A(x) + B is A(x) + B = [ U1 U2 ] * diag(s, 0) * [ V1 V2 ]', with s > 0, then Z = U1 * V1' + U2 * W * V2', || W || <= 1. If status is 'primal infeasible', then Z = 0 and z is a certificate of infeasibility for the inequalities G * x <= h, i.e., a vector that satisfies h' * z = 1, G' * z = 0, z >= 0. """ if type(B) not in (matrix, spmatrix) or B.typecode is not 'd': raise TypeError, "B must be a real dense or sparse matrix" p, q = B.size if p < q: raise ValueError, "row dimension of B must be greater than or "\ "equal to column dimension" if type(A) not in (matrix, spmatrix) or A.typecode is not 'd' or \ A.size[0] != p*q: raise TypeError, "A must be a real dense or sparse matrix with "\ "p*q rows if B has size (p, q)" n = A.size[1] if G is None: G = spmatrix([], [], [], (0, n)) if h is None: h = matrix(0.0, (0, 1)) if type(h) is not matrix or h.typecode is not 'd' or h.size[1] != 1: raise TypeError, "h must be a real dense matrix with one column" m = h.size[0] if type(G) not in (matrix, spmatrix) or G.typecode is not 'd' or \ G.size != (m, n): raise TypeError, "G must be a real dense matrix or sparse matrix "\ "of size (m, n) if h has length m and A has n columns" if C is None: C = spmatrix(0.0, [], [], (n, n)) if d is None: d = matrix(0.0, (n, 1)) if type(C) not in (matrix, spmatrix) or C.typecode is not 'd' or \ C.size != (n,n): raise TypeError, "C must be real dense or sparse matrix of size "\ "(n, n) if A has n columns" if type(d) is not matrix or d.typecode is not 'd' or d.size != (n, 1): raise TypeError, "d must be a real matrix of size (n, 1) if A has "\ "n columns" # The problem is solved as a cone program # # minimize (1/2) * x'*C*x + d'*x + (1/2) * (tr X1 + tr X2) # subject to G*x <= h # [ X1 (A(x) + B)' ] # [ A(x) + B X2 ] >= 0. # # The primal variable is stored as a list [ x, X1, X2 ]. def xnewcopy(u): return [matrix(u[0]), matrix(u[1]), matrix(u[2])] def xdot(u, v): return blas.dot(u[0], v[0]) + misc.sdot2(u[1], v[1]) + \ misc.sdot2(u[2], v[2]) def xscal(alpha, u): blas.scal(alpha, u[0]) blas.scal(alpha, u[1]) blas.scal(alpha, u[2]) def xaxpy(u, v, alpha=1.0): blas.axpy(u[0], v[0], alpha) blas.axpy(u[1], v[1], alpha) blas.axpy(u[2], v[2], alpha) def Pf(u, v, alpha=1.0, beta=0.0): base.symv(C, u[0], v[0], alpha=alpha, beta=beta) blas.scal(beta, v[1]) blas.scal(beta, v[2]) c = [d, matrix(0.0, (q, q)), matrix(0.0, (p, p))] c[1][::q + 1] = 0.5 c[2][::p + 1] = 0.5 # If V is a p+q x p+q matrix # # [ V11 V12 ] # V = [ ] # [ V21 V22 ] # # with V11 q x q, V21 p x q, V12 q x p, and V22 p x p, then I11, I21, # I22 are the index sets defined by # # V[I11] = V11[:], V[I21] = V21[:], V[I22] = V22[:]. # I11 = matrix([i + j * (p + q) for j in xrange(q) for i in xrange(q)]) I21 = matrix([q + i + j * (p + q) for j in xrange(q) for i in xrange(p)]) I22 = matrix([(p + q) * q + q + i + j * (p + q) for j in xrange(p) for i in xrange(p)]) dims = {'l': m, 'q': [], 's': [p + q]} hh = matrix(0.0, (m + (p + q)**2, 1)) hh[:m] = h hh[m + I21] = B[:] def Gf(u, v, alpha=1.0, beta=0.0, trans='N'): if trans == 'N': # v[:m] := alpha * G * u[0] + beta * v[:m] base.gemv(G, u[0], v, alpha=alpha, beta=beta) # v[m:] := alpha * [-u[1], -A(u[0])'; -A(u[0]), -u[2]] # + beta * v[m:] blas.scal(beta, v, offset=m) v[m + I11] -= alpha * u[1][:] v[m + I21] -= alpha * A * u[0] v[m + I22] -= alpha * u[2][:] else: # v[0] := alpha * ( G.T * u[:m] - 2.0 * A.T * u[m + I21] ) # + beta v[1] base.gemv(G, u, v[0], trans='T', alpha=alpha, beta=beta) base.gemv(A, u[m + I21], v[0], trans='T', alpha=-2.0 * alpha, beta=1.0) # v[1] := -alpha * u[m + I11] + beta * v[1] blas.scal(beta, v[1]) blas.axpy(u[m + I11], v[1], alpha=-alpha) # v[2] := -alpha * u[m + I22] + beta * v[2] blas.scal(beta, v[2]) blas.axpy(u[m + I22], v[2], alpha=-alpha) def Af(u, v, alpha=1.0, beta=0.0, trans='N'): if trans == 'N': pass else: blas.scal(beta, v[0]) blas.scal(beta, v[1]) blas.scal(beta, v[2]) L1 = matrix(0.0, (q, q)) L2 = matrix(0.0, (p, p)) T21 = matrix(0.0, (p, q)) s = matrix(0.0, (q, 1)) SS = matrix(0.0, (q, q)) V1 = matrix(0.0, (q, q)) V2 = matrix(0.0, (p, p)) As = matrix(0.0, (p * q, n)) As2 = matrix(0.0, (p * q, n)) tmp = matrix(0.0, (p, q)) a = matrix(0.0, (p + q, p + q)) H = matrix(0.0, (n, n)) Gs = matrix(0.0, (m, n)) Q1 = matrix(0.0, (q, p + q)) Q2 = matrix(0.0, (p, p + q)) tau1 = matrix(0.0, (q, 1)) tau2 = matrix(0.0, (p, 1)) bz11 = matrix(0.0, (q, q)) bz22 = matrix(0.0, (p, p)) bz21 = matrix(0.0, (p, q)) # Suppose V = [V1; V2] is p x q with V1 q x q. If v = V[:] then # v[Itriu] are the strict upper triangular entries of V1 stored # columnwise. Itriu = [i + j * p for j in xrange(1, q) for i in xrange(j)] # v[Itril] are the strict lower triangular entries of V1 stored rowwise. Itril = [j + i * p for j in xrange(1, q) for i in xrange(j)] # v[Idiag] are the diagonal entries of V1. Idiag = [i * (p + 1) for i in xrange(q)] # v[Itriu2] are the upper triangular entries of V1, with the diagonal # entries stored first, followed by the strict upper triangular entries # stored columnwise. Itriu2 = Idiag + Itriu # If V is a q x q matrix and v = V[:], then v[Itril2] are the strict # lower triangular entries of V stored columnwise and v[Itril3] are # the strict lower triangular entries stored rowwise. Itril2 = [i + j * q for j in xrange(q) for i in xrange(j + 1, q)] Itril3 = [i + j * q for i in xrange(q) for j in xrange(i)] P = spmatrix(0.0, Itriu, Itril, (p * q, p * q)) D = spmatrix(1.0, range(p * q), range(p * q)) DV = matrix(1.0, (p * q, 1)) def F(W): """ Create a solver for the linear equations C * ux + G' * uzl - 2*A'(uzs21) = bx -uzs11 = bX1 -uzs22 = bX2 G * ux - Dl^2 * uzl = bzl [ -uX1 -A(ux)' ] [ uzs11 uzs21' ] [ ] - r*r' * [ ] * r*r' = bzs [ -A(ux) -uX2 ] [ uzs21 uzs22 ] where Dl = diag(W['l']), r = W['r'][0]. On entry, x = (bx, bX1, bX2) and z = [ bzl; bzs[:] ]. On exit, x = (ux, uX1, uX2) and z = [ Dl*uzl; (r'*uzs*r)[:] ]. 1. Compute matrices V1, V2 such that (with T = r*r') [ V1 0 ] [ T11 T21' ] [ V1' 0 ] [ I S' ] [ ] [ ] [ ] = [ ] [ 0 V2' ] [ T21 T22 ] [ 0 V2 ] [ S I ] and S = [ diag(s); 0 ], s a positive q-vector. 2. Factor the mapping X -> X + S * X' * S: X + S * X' * S = L( L'( X )). 3. Compute scaled mappings: a matrix As with as its columns the coefficients of the scaled mapping L^-1( V2' * A() * V1' ) and the matrix Gs = Dl^-1 * G. 4. Cholesky factorization of H = C + Gs'*Gs + 2*As'*As. """ # 1. Compute V1, V2, s. r = W['r'][0] # LQ factorization R[:q, :] = L1 * Q1. lapack.lacpy(r, Q1, m=q) lapack.gelqf(Q1, tau1) lapack.lacpy(Q1, L1, n=q, uplo='L') lapack.orglq(Q1, tau1) # LQ factorization R[q:, :] = L2 * Q2. lapack.lacpy(r, Q2, m=p, offsetA=q) lapack.gelqf(Q2, tau2) lapack.lacpy(Q2, L2, n=p, uplo='L') lapack.orglq(Q2, tau2) # V2, V1, s are computed from an SVD: if # # Q2 * Q1' = U * diag(s) * V', # # then V1 = V' * L1^-1 and V2 = L2^-T * U. # T21 = Q2 * Q1.T blas.gemm(Q2, Q1, T21, transB='T') # SVD T21 = U * diag(s) * V'. Store U in V2 and V' in V1. lapack.gesvd(T21, s, jobu='A', jobvt='A', U=V2, Vt=V1) # # Q2 := Q2 * Q1' without extracting Q1; store T21 in Q2 # this will requires lapack.ormlq or lapack.unmlq # V2 = L2^-T * U blas.trsm(L2, V2, transA='T') # V1 = V' * L1^-1 blas.trsm(L1, V1, side='R') # 2. Factorization X + S * X' * S = L( L'( X )). # # The factor L is stored as a diagonal matrix D and a sparse lower # triangular matrix P, such that # # L(X)[:] = D**-1 * (I + P) * X[:] # L^-1(X)[:] = D * (I - P) * X[:]. # SS is q x q with SS[i,j] = si*sj. blas.scal(0.0, SS) blas.syr(s, SS) # For a p x q matrix X, P*X[:] is Y[:] where # # Yij = si * sj * Xji if i < j # = 0 otherwise. # P.V = SS[Itril2] # For a p x q matrix X, D*X[:] is Y[:] where # # Yij = Xij / sqrt( 1 - si^2 * sj^2 ) if i < j # = Xii / sqrt( 1 + si^2 ) if i = j # = Xij otherwise. # DV[Idiag] = sqrt(1.0 + SS[::q + 1]) DV[Itriu] = sqrt(1.0 - SS[Itril3]**2) D.V = DV**-1 # 3. Scaled linear mappings # Ask := V2' * Ask * V1' blas.scal(0.0, As) base.axpy(A, As) for i in xrange(n): # tmp := V2' * As[i, :] blas.gemm(V2, As, tmp, transA='T', m=p, n=q, k=p, ldB=p, offsetB=i * p * q) # As[:,i] := tmp * V1' blas.gemm(tmp, V1, As, transB='T', m=p, n=q, k=q, ldC=p, offsetC=i * p * q) # As := D * (I - P) * As # = L^-1 * As. blas.copy(As, As2) base.gemm(P, As, As2, alpha=-1.0, beta=1.0) base.gemm(D, As2, As) # Gs := Dl^-1 * G blas.scal(0.0, Gs) base.axpy(G, Gs) for k in xrange(n): blas.tbmv(W['di'], Gs, n=m, k=0, ldA=1, offsetx=k * m) # 4. Cholesky factorization of H = C + Gs' * Gs + 2 * As' * As. blas.syrk(As, H, trans='T', alpha=2.0) blas.syrk(Gs, H, trans='T', beta=1.0) base.axpy(C, H) lapack.potrf(H) def f(x, y, z): """ Solve C * ux + G' * uzl - 2*A'(uzs21) = bx -uzs11 = bX1 -uzs22 = bX2 G * ux - D^2 * uzl = bzl [ -uX1 -A(ux)' ] [ uzs11 uzs21' ] [ ] - T * [ ] * T = bzs. [ -A(ux) -uX2 ] [ uzs21 uzs22 ] On entry, x = (bx, bX1, bX2) and z = [ bzl; bzs[:] ]. On exit, x = (ux, uX1, uX2) and z = [ D*uzl; (r'*uzs*r)[:] ]. Define X = uzs21, Z = T * uzs * T: C * ux + G' * uzl - 2*A'(X) = bx [ 0 X' ] [ bX1 0 ] T * [ ] * T - Z = T * [ ] * T [ X 0 ] [ 0 bX2 ] G * ux - D^2 * uzl = bzl [ -uX1 -A(ux)' ] [ Z11 Z21' ] [ ] - [ ] = bzs [ -A(ux) -uX2 ] [ Z21 Z22 ] Return x = (ux, uX1, uX2), z = [ D*uzl; (rti'*Z*rti)[:] ]. We use the congruence transformation [ V1 0 ] [ T11 T21' ] [ V1' 0 ] [ I S' ] [ ] [ ] [ ] = [ ] [ 0 V2' ] [ T21 T22 ] [ 0 V2 ] [ S I ] and the factorization X + S * X' * S = L( L'(X) ) to write this as C * ux + G' * uzl - 2*A'(X) = bx L'(V2^-1 * X * V1^-1) - L^-1(V2' * Z21 * V1') = bX G * ux - D^2 * uzl = bzl [ -uX1 -A(ux)' ] [ Z11 Z21' ] [ ] - [ ] = bzs, [ -A(ux) -uX2 ] [ Z21 Z22 ] or C * ux + Gs' * uuzl - 2*As'(XX) = bx XX - ZZ21 = bX Gs * ux - uuzl = D^-1 * bzl -As(ux) - ZZ21 = bbzs_21 -uX1 - Z11 = bzs_11 -uX2 - Z22 = bzs_22 if we introduce scaled variables uuzl = D * uzl XX = L'(V2^-1 * X * V1^-1) = L'(V2^-1 * uzs21 * V1^-1) ZZ21 = L^-1(V2' * Z21 * V1') and define bbzs_21 = L^-1(V2' * bzs_21 * V1') [ bX1 0 ] bX = L^-1( V2' * (T * [ ] * T)_21 * V1'). [ 0 bX2 ] Eliminating Z21 gives C * ux + Gs' * uuzl - 2*As'(XX) = bx Gs * ux - uuzl = D^-1 * bzl -As(ux) - XX = bbzs_21 - bX -uX1 - Z11 = bzs_11 -uX2 - Z22 = bzs_22 and eliminating uuzl and XX gives H * ux = bx + Gs' * D^-1 * bzl + 2*As'(bX - bbzs_21) Gs * ux - uuzl = D^-1 * bzl -As(ux) - XX = bbzs_21 - bX -uX1 - Z11 = bzs_11 -uX2 - Z22 = bzs_22. In summary, we can use the following algorithm: 1. bXX := bX - bbzs21 [ bX1 0 ] = L^-1( V2' * ((T * [ ] * T)_21 - bzs_21) * V1') [ 0 bX2 ] 2. Solve H * ux = bx + Gs' * D^-1 * bzl + 2*As'(bXX). 3. From ux, compute uuzl = Gs*ux - D^-1 * bzl and X = V2 * L^-T(-As(ux) + bXX) * V1. 4. Return ux, uuzl, rti' * Z * rti = r' * [ -bX1, X'; X, -bX2 ] * r and uX1 = -Z11 - bzs_11, uX2 = -Z22 - bzs_22. """ # Save bzs_11, bzs_22, bzs_21. lapack.lacpy(z, bz11, uplo='L', m=q, n=q, ldA=p + q, offsetA=m) lapack.lacpy(z, bz21, m=p, n=q, ldA=p + q, offsetA=m + q) lapack.lacpy(z, bz22, uplo='L', m=p, n=p, ldA=p + q, offsetA=m + (p + q + 1) * q) # zl := D^-1 * zl # = D^-1 * bzl blas.tbmv(W['di'], z, n=m, k=0, ldA=1) # zs := r' * [ bX1, 0; 0, bX2 ] * r. # zs := [ bX1, 0; 0, bX2 ] blas.scal(0.0, z, offset=m) lapack.lacpy(x[1], z, uplo='L', m=q, n=q, ldB=p + q, offsetB=m) lapack.lacpy(x[2], z, uplo='L', m=p, n=p, ldB=p + q, offsetB=m + (p + q + 1) * q) # scale diagonal of zs by 1/2 blas.scal(0.5, z, inc=p + q + 1, offset=m) # a := tril(zs)*r blas.copy(r, a) blas.trmm(z, a, side='L', m=p + q, n=p + q, ldA=p + q, ldB=p + q, offsetA=m) # zs := a'*r + r'*a blas.syr2k(r, a, z, trans='T', n=p + q, k=p + q, ldB=p + q, ldC=p + q, offsetC=m) # bz21 := L^-1( V2' * ((r * zs * r')_21 - bz21) * V1') # # [ bX1 0 ] # = L^-1( V2' * ((T * [ ] * T)_21 - bz21) * V1'). # [ 0 bX2 ] # a = [ r21 r22 ] * z # = [ r21 r22 ] * r' * [ bX1, 0; 0, bX2 ] * r # = [ T21 T22 ] * [ bX1, 0; 0, bX2 ] * r blas.symm(z, r, a, side='R', m=p, n=p + q, ldA=p + q, ldC=p + q, offsetB=q) # bz21 := -bz21 + a * [ r11, r12 ]' # = -bz21 + (T * [ bX1, 0; 0, bX2 ] * T)_21 blas.gemm(a, r, bz21, transB='T', m=p, n=q, k=p + q, beta=-1.0, ldA=p + q, ldC=p) # bz21 := V2' * bz21 * V1' # = V2' * (-bz21 + (T*[bX1, 0; 0, bX2]*T)_21) * V1' blas.gemm(V2, bz21, tmp, transA='T', m=p, n=q, k=p, ldB=p) blas.gemm(tmp, V1, bz21, transB='T', m=p, n=q, k=q, ldC=p) # bz21[:] := D * (I-P) * bz21[:] # = L^-1 * bz21[:] # = bXX[:] blas.copy(bz21, tmp) base.gemv(P, bz21, tmp, alpha=-1.0, beta=1.0) base.gemv(D, tmp, bz21) # Solve H * ux = bx + Gs' * D^-1 * bzl + 2*As'(bXX). # x[0] := x[0] + Gs'*zl + 2*As'(bz21) # = bx + G' * D^-1 * bzl + 2 * As'(bXX) blas.gemv(Gs, z, x[0], trans='T', alpha=1.0, beta=1.0) blas.gemv(As, bz21, x[0], trans='T', alpha=2.0, beta=1.0) # x[0] := H \ x[0] # = ux lapack.potrs(H, x[0]) # uuzl = Gs*ux - D^-1 * bzl blas.gemv(Gs, x[0], z, alpha=1.0, beta=-1.0) # bz21 := V2 * L^-T(-As(ux) + bz21) * V1 # = X blas.gemv(As, x[0], bz21, alpha=-1.0, beta=1.0) blas.tbsv(DV, bz21, n=p * q, k=0, ldA=1) blas.copy(bz21, tmp) base.gemv(P, tmp, bz21, alpha=-1.0, beta=1.0, trans='T') blas.gemm(V2, bz21, tmp) blas.gemm(tmp, V1, bz21) # zs := -zs + r' * [ 0, X'; X, 0 ] * r # = r' * [ -bX1, X'; X, -bX2 ] * r. # a := bz21 * [ r11, r12 ] # = X * [ r11, r12 ] blas.gemm(bz21, r, a, m=p, n=p + q, k=q, ldA=p, ldC=p + q) # z := -z + [ r21, r22 ]' * a + a' * [ r21, r22 ] # = rti' * uzs * rti blas.syr2k(r, a, z, trans='T', beta=-1.0, n=p + q, k=p, offsetA=q, offsetC=m, ldB=p + q, ldC=p + q) # uX1 = -Z11 - bzs_11 # = -(r*zs*r')_11 - bzs_11 # uX2 = -Z22 - bzs_22 # = -(r*zs*r')_22 - bzs_22 blas.copy(bz11, x[1]) blas.copy(bz22, x[2]) # scale diagonal of zs by 1/2 blas.scal(0.5, z, inc=p + q + 1, offset=m) # a := r*tril(zs) blas.copy(r, a) blas.trmm(z, a, side='R', m=p + q, n=p + q, ldA=p + q, ldB=p + q, offsetA=m) # x[1] := -x[1] - a[:q,:] * r[:q, :]' - r[:q,:] * a[:q,:]' # = -bzs_11 - (r*zs*r')_11 blas.syr2k(a, r, x[1], n=q, alpha=-1.0, beta=-1.0) # x[2] := -x[2] - a[q:,:] * r[q:, :]' - r[q:,:] * a[q:,:]' # = -bzs_22 - (r*zs*r')_22 blas.syr2k(a, r, x[2], n=p, alpha=-1.0, beta=-1.0, offsetA=q, offsetB=q) # scale diagonal of zs by 1/2 blas.scal(2.0, z, inc=p + q + 1, offset=m) return f if C: sol = solvers.coneqp(Pf, c, Gf, hh, dims, Af, kktsolver=F, xnewcopy=xnewcopy, xdot=xdot, xaxpy=xaxpy, xscal=xscal) else: sol = solvers.conelp(c, Gf, hh, dims, Af, kktsolver=F, xnewcopy=xnewcopy, xdot=xdot, xaxpy=xaxpy, xscal=xscal) if sol['status'] is 'optimal': x = sol['x'][0] z = sol['z'][:m] Z = sol['z'][m:] Z.size = (p + q, p + q) Z = -2.0 * Z[-p:, :q] elif sol['status'] is 'primal infeasible': x = None z = sol['z'][:m] Z = sol['z'][m:] Z.size = (p + q, p + q) Z = -2.0 * Z[-p:, :q] else: x, z, Z = None, None, None return {'status': sol['status'], 'x': x, 'z': z, 'Z': Z}
def l1(P, q): """ Returns the solution u of the ell-1 approximation problem (primal) minimize ||P*u - q||_1 (dual) maximize q'*w subject to P'*w = 0 ||w||_infty <= 1. """ m, n = P.size # Solve equivalent LP # # minimize [0; 1]' * [u; v] # subject to [P, -I; -P, -I] * [u; v] <= [q; -q] # # maximize -[q; -q]' * z # subject to [P', -P']*z = 0 # [-I, -I]*z + 1 = 0 # z >= 0 c = matrix(n*[0.0] + m*[1.0]) h = matrix([q, -q]) def Fi(x, y, alpha = 1.0, beta = 0.0, trans = 'N'): if trans == 'N': # y := alpha * [P, -I; -P, -I] * x + beta*y u = P*x[:n] y[:m] = alpha * ( u - x[n:]) + beta*y[:m] y[m:] = alpha * (-u - x[n:]) + beta*y[m:] else: # y := alpha * [P', -P'; -I, -I] * x + beta*y y[:n] = alpha * P.T * (x[:m] - x[m:]) + beta*y[:n] y[n:] = -alpha * (x[:m] + x[m:]) + beta*y[n:] def Fkkt(W): # Returns a function f(x, y, z) that solves # # [ 0 0 P' -P' ] [ x[:n] ] [ bx[:n] ] # [ 0 0 -I -I ] [ x[n:] ] [ bx[n:] ] # [ P -I -W1^2 0 ] [ z[:m] ] = [ bz[:m] ] # [-P -I 0 -W2 ] [ z[m:] ] [ bz[m:] ] # # On entry bx, bz are stored in x, z. # On exit x, z contain the solution, with z scaled (W['di'] .* z is # returned instead of z). d1, d2 = W['d'][:m], W['d'][m:] D = 4*(d1**2 + d2**2)**-1 A = P.T * spdiag(D) * P lapack.potrf(A) def f(x, y, z): x[:n] += P.T * ( mul( div(d2**2 - d1**2, d1**2 + d2**2), x[n:]) + mul( .5*D, z[:m]-z[m:] ) ) lapack.potrs(A, x) u = P*x[:n] x[n:] = div( x[n:] - div(z[:m], d1**2) - div(z[m:], d2**2) + mul(d1**-2 - d2**-2, u), d1**-2 + d2**-2 ) z[:m] = div(u-x[n:]-z[:m], d1) z[m:] = div(-u-x[n:]-z[m:], d2) return f # Initial primal and dual points from least-squares solution. # uls minimizes ||P*u-q||_2; rls is the LS residual. uls = +q lapack.gels(+P, uls) rls = P*uls[:n] - q # x0 = [ uls; 1.1*abs(rls) ]; s0 = [q;-q] - [P,-I; -P,-I] * x0 x0 = matrix( [uls[:n], 1.1*abs(rls)] ) s0 = +h Fi(x0, s0, alpha=-1, beta=1) # z0 = [ (1+w)/2; (1-w)/2 ] where w = (.9/||rls||_inf) * rls # if rls is nonzero and w = 0 otherwise. if max(abs(rls)) > 1e-10: w = .9/max(abs(rls)) * rls else: w = matrix(0.0, (m,1)) z0 = matrix([.5*(1+w), .5*(1-w)]) dims = {'l': 2*m, 'q': [], 's': []} sol = solvers.conelp(c, Fi, h, dims, kktsolver = Fkkt, primalstart={'x': x0, 's': s0}, dualstart={'z': z0}) return sol['x'][:n]
def block_socp(self, a, A1, A2, t, B_s, u_s): dims = { 'l': self.size_tb() + 2*self.size_x() + sum([cc.size for cc in self.cube_constraints]), # Pure inequality constraints # Com cone is now 3d, Size of the cones: x,y,z+1 'q': [dc.size for dc in self.dist_constraints]+[4]*len(self.contacts)*len(self.gravity_envelope)+[self.size_z()+1]*self.size_s()+[fc.size for fc in self.force_constraints], 's': [] # No sd cones } size_cones = self.size_x()*4 // 3 #Optimization vector [ f1 ... fn CoM s1 ... sn] #Max a^T z ~ min -a^T z #Final cost : min -a^T z + s c = np.vstack([np.zeros((self.size_x(), 1)), -a, np.zeros((self.size_s(), 1))]) A1_diag = block_diag(*([A1]*len(self.gravity_envelope))) A2 = np.vstack([self.computeA2(self.gravity+e) for e in self.gravity_envelope]) T = np.vstack([self.computeT(self.gravity+e, height=self.height) for e in self.gravity_envelope]) A = np.hstack([A1_diag, A2, np.zeros((A2.shape[0], self.size_s()))]) g_s = [] h_s = [] #Torque constraint if self.L_s: g_s.extend(self.L_s) h_s.extend(self.tb_s) #Linear force constraint # <x> <z> <1> # <x> [[ I 0] <= <x> lim*mg 2*<x> [ 1] # <x> [[ -I 0] g_force = np.vstack([np.eye(self.size_x()), -np.eye(self.size_x())]) g_s.append(np.hstack([g_force, np.zeros((2*self.size_x(), self.size_z()+self.size_s()))])) h_s.append(self.force_lim*self.mass*9.81*np.ones((2*self.size_x(), 1))) #Cube constraints if self.C_s: g_s.append(np.vstack(self.C_s)) h_s.append(np.vstack(self.d_s)) #These are additional dist constraints g_s.extend(self.S_s) h_s.extend(self.r_s) #B = diag{[u_i b_i.T].T} blocks = [-np.vstack([u.T, B]) for u, B in zip(u_s, B_s)]*len(self.gravity_envelope) block = block_diag(*blocks) g_contacts = np.hstack([block, np.zeros((size_cones, self.size_z()+self.size_s()))]) h_cones = np.zeros((size_cones, 1)) g_slacks, h_slacks = None, None if self.robust_sphere > 0: g_slacks = np.zeros((4*self.size_s(), self.nrVars())) h_slacks = np.zeros((4*self.size_s(), 1)) for i, contact in enumerate(self.contacts): robusticity = -self.robust_sphere*self.mass*(self.theta_bar+self.sigma_bar*contact.mu) g_contacts[4*i, self.size_x()+self.size_z()+i] = -robusticity h_cones[4*i, 0] = robusticity #Add slack variables cones # || z || < s g_slacks[4*i, self.size_x()+self.size_z()+i] = -1 g_slacks[4*i+1:4*i+1+self.size_z(), self.size_x():self.size_x()+self.size_z()] = -np.eye(self.size_z()) g_s.append(g_contacts) h_s.append(h_cones) if g_slacks is not None: g_s.append(g_slacks) h_s.append(h_slacks) #Force Constraints g_s.extend(self.F_s) h_s.extend(self.f_s) #Concat everything g = np.vstack(g_s) h = np.vstack(h_s) sol = solvers.conelp(matrix(c), G=matrix(g), h=matrix(h), A=matrix(A), b=matrix(T), dims=dims) return sol
def qcl1(A, b): """ Returns the solution u, z of (primal) minimize || u ||_1 subject to || A * u - b ||_2 <= 1 (dual) maximize b^T z - ||z||_2 subject to || A'*z ||_inf <= 1. Exploits structure, assuming A is m by n with m >= n. """ m, n = A.size # Solve equivalent cone LP with variables x = [u; v]: # # minimize [0; 1]' * x # subject to [ I -I ] * x <= [ 0 ] (componentwise) # [-I -I ] * x <= [ 0 ] (componentwise) # [ 0 0 ] * x <= [ 1 ] (SOC) # [-A 0 ] [ -b ]. # # maximize -t + b' * w # subject to z1 - z2 = A'*w # z1 + z2 = 1 # z1 >= 0, z2 >=0, ||w||_2 <= t. c = matrix(n * [0.0] + n * [1.0]) h = matrix(0.0, (2 * n + m + 1, 1)) h[2 * n] = 1.0 h[2 * n + 1:] = -b def G(x, y, alpha=1.0, beta=0.0, trans='N'): y *= beta if trans == 'N': # y += alpha * G * x y[:n] += alpha * (x[:n] - x[n:2 * n]) y[n:2 * n] += alpha * (-x[:n] - x[n:2 * n]) y[2 * n + 1:] -= alpha * A * x[:n] else: # y += alpha * G'*x y[:n] += alpha * (x[:n] - x[n:2 * n] - A.T * x[-m:]) y[n:] -= alpha * (x[:n] + x[n:2 * n]) def Fkkt(W): # Returns a function f(x, y, z) that solves # # [ 0 G' ] [ x ] = [ bx ] # [ G -W'*W ] [ z ] [ bz ]. # First factor # # S = G' * W**-1 * W**-T * G # = [0; -A]' * W3^-2 * [0; -A] + 4 * (W1**2 + W2**2)**-1 # # where # # W1 = diag(d1) with d1 = W['d'][:n] = 1 ./ W['di'][:n] # W2 = diag(d2) with d2 = W['d'][n:] = 1 ./ W['di'][n:] # W3 = beta * (2*v*v' - J), W3^-1 = 1/beta * (2*J*v*v'*J - J) # with beta = W['beta'][0], v = W['v'][0], J = [1, 0; 0, -I]. # As = W3^-1 * [ 0 ; -A ] = 1/beta * ( 2*J*v * v' - I ) * [0; A] beta, v = W['beta'][0], W['v'][0] As = 2 * v * (v[1:].T * A) As[1:, :] *= -1.0 As[1:, :] -= A As /= beta # S = As'*As + 4 * (W1**2 + W2**2)**-1 S = As.T * As d1, d2 = W['d'][:n], W['d'][n:] d = 4.0 * (d1**2 + d2**2)**-1 S[::n + 1] += d lapack.potrf(S) def f(x, y, z): # z := - W**-T * z z[:n] = -div(z[:n], d1) z[n:2 * n] = -div(z[n:2 * n], d2) z[2 * n:] -= 2.0 * v * (v[0] * z[2 * n] - blas.dot(v[1:], z[2 * n + 1:])) z[2 * n + 1:] *= -1.0 z[2 * n:] /= beta # x := x - G' * W**-1 * z x[:n] -= div(z[:n], d1) - div(z[n:2 * n], d2) + As.T * z[-(m + 1):] x[n:] += div(z[:n], d1) + div(z[n:2 * n], d2) # Solve for x[:n]: # # S*x[:n] = x[:n] - (W1**2 - W2**2)(W1**2 + W2**2)^-1 * x[n:] x[:n] -= mul(div(d1**2 - d2**2, d1**2 + d2**2), x[n:]) lapack.potrs(S, x) # Solve for x[n:]: # # (d1**-2 + d2**-2) * x[n:] = x[n:] + (d1**-2 - d2**-2)*x[:n] x[n:] += mul(d1**-2 - d2**-2, x[:n]) x[n:] = div(x[n:], d1**-2 + d2**-2) # z := z + W^-T * G*x z[:n] += div(x[:n] - x[n:2 * n], d1) z[n:2 * n] += div(-x[:n] - x[n:2 * n], d2) z[2 * n:] += As * x[:n] return f dims = {'l': 2 * n, 'q': [m + 1], 's': []} sol = solvers.conelp(c, G, h, dims, kktsolver=Fkkt) if sol['status'] == 'optimal': return sol['x'][:n], sol['z'][-m:] else: return None, None
def l1(P, q): """ Returns the solution u, w of the ell-1 approximation problem (primal) minimize ||P*u - q||_1 (dual) maximize q'*w subject to P'*w = 0 ||w||_infty <= 1. """ m, n = P.size # Solve equivalent LP # # minimize [0; 1]' * [u; v] # subject to [P, -I; -P, -I] * [u; v] <= [q; -q] # # maximize -[q; -q]' * z # subject to [P', -P']*z = 0 # [-I, -I]*z + 1 = 0 # z >= 0 c = matrix(n * [0.0] + m * [1.0]) h = matrix([q, -q]) def Fi(x, y, alpha=1.0, beta=0.0, trans='N'): if trans == 'N': # y := alpha * [P, -I; -P, -I] * x + beta*y u = P * x[:n] y[:m] = alpha * (u - x[n:]) + beta * y[:m] y[m:] = alpha * (-u - x[n:]) + beta * y[m:] else: # y := alpha * [P', -P'; -I, -I] * x + beta*y y[:n] = alpha * P.T * (x[:m] - x[m:]) + beta * y[:n] y[n:] = -alpha * (x[:m] + x[m:]) + beta * y[n:] def Fkkt(W): # Returns a function f(x, y, z) that solves # # [ 0 0 P' -P' ] [ x[:n] ] [ bx[:n] ] # [ 0 0 -I -I ] [ x[n:] ] [ bx[n:] ] # [ P -I -D1^{-1} 0 ] [ z[:m] ] = [ bz[:m] ] # [-P -I 0 -D2^{-1} ] [ z[m:] ] [ bz[m:] ] # # where D1 = diag(di[:m])^2, D2 = diag(di[m:])^2 and di = W['di']. # # On entry bx, bz are stored in x, z. # On exit x, z contain the solution, with z scaled (di .* z is # returned instead of z). # Factor A = 4*P'*D*P where D = d1.*d2 ./(d1+d2) and # d1 = d[:m].^2, d2 = d[m:].^2. di = W['di'] d1, d2 = di[:m]**2, di[m:]**2 D = div(mul(d1, d2), d1 + d2) A = P.T * spdiag(4 * D) * P lapack.potrf(A) def f(x, y, z): # Solve for x[:n]: # # A*x[:n] = bx[:n] + P' * ( ((D1-D2)*(D1+D2)^{-1})*bx[n:] # + (2*D1*D2*(D1+D2)^{-1}) * (bz[:m] - bz[m:]) ). x[:n] += P.T * (mul(div(d1 - d2, d1 + d2), x[n:]) + mul(2 * D, z[:m] - z[m:])) lapack.potrs(A, x) # x[n:] := (D1+D2)^{-1} * (bx[n:] - D1*bz[:m] - D2*bz[m:] # + (D1-D2)*P*x[:n]) u = P * x[:n] x[n:] = div( x[n:] - mul(d1, z[:m]) - mul(d2, z[m:]) + mul(d1 - d2, u), d1 + d2) # z[:m] := d1[:m] .* ( P*x[:n] - x[n:] - bz[:m]) # z[m:] := d2[m:] .* (-P*x[:n] - x[n:] - bz[m:]) z[:m] = mul(di[:m], u - x[n:] - z[:m]) z[m:] = mul(di[m:], -u - x[n:] - z[m:]) return f # Initial primal and dual points from least-squares solution. # uls minimizes ||P*u-q||_2; rls is the LS residual. uls = +q lapack.gels(+P, uls) rls = P * uls[:n] - q # x0 = [ uls; 1.1*abs(rls) ]; s0 = [q;-q] - [P,-I; -P,-I] * x0 x0 = matrix([uls[:n], 1.1 * abs(rls)]) s0 = +h Fi(x0, s0, alpha=-1, beta=1) # z0 = [ (1+w)/2; (1-w)/2 ] where w = (.9/||rls||_inf) * rls # if rls is nonzero and w = 0 otherwise. if max(abs(rls)) > 1e-10: w = .9 / max(abs(rls)) * rls else: w = matrix(0.0, (m, 1)) z0 = matrix([.5 * (1 + w), .5 * (1 - w)]) dims = {'l': 2 * m, 'q': [], 's': []} sol = solvers.conelp(c, Fi, h, dims, kktsolver=Fkkt, primalstart={ 'x': x0, 's': s0 }, dualstart={'z': z0}) return sol['x'][:n], sol['z'][m:] - sol['z'][:m]
def qcl1(A, b): """ Returns the solution u, z of (primal) minimize || u ||_1 subject to || A * u - b ||_2 <= 1 (dual) maximize b^T z - ||z||_2 subject to || A'*z ||_inf <= 1. Exploits structure, assuming A is m by n with m >= n. """ m, n = A.size # Solve equivalent cone LP with variables x = [u; v]: # # minimize [0; 1]' * x # subject to [ I -I ] * x <= [ 0 ] (componentwise) # [-I -I ] * x <= [ 0 ] (componentwise) # [ 0 0 ] * x <= [ 1 ] (SOC) # [-A 0 ] [ -b ]. # # maximize -t + b' * w # subject to z1 - z2 = A'*w # z1 + z2 = 1 # z1 >= 0, z2 >=0, ||w||_2 <= t. c = matrix(n*[0.0] + n*[1.0]) h = matrix( 0.0, (2*n + m + 1, 1)) h[2*n] = 1.0 h[2*n+1:] = -b def G(x, y, alpha = 1.0, beta = 0.0, trans = 'N'): y *= beta if trans=='N': # y += alpha * G * x y[:n] += alpha * (x[:n] - x[n:2*n]) y[n:2*n] += alpha * (-x[:n] - x[n:2*n]) y[2*n+1:] -= alpha * A*x[:n] else: # y += alpha * G'*x y[:n] += alpha * (x[:n] - x[n:2*n] - A.T * x[-m:]) y[n:] -= alpha * (x[:n] + x[n:2*n]) def Fkkt(W): # Returns a function f(x, y, z) that solves # # [ 0 G' ] [ x ] = [ bx ] # [ G -W'*W ] [ z ] [ bz ]. # First factor # # S = G' * W**-1 * W**-T * G # = [0; -A]' * W3^-2 * [0; -A] + 4 * (W1**2 + W2**2)**-1 # # where # # W1 = diag(d1) with d1 = W['d'][:n] = 1 ./ W['di'][:n] # W2 = diag(d2) with d2 = W['d'][n:] = 1 ./ W['di'][n:] # W3 = beta * (2*v*v' - J), W3^-1 = 1/beta * (2*J*v*v'*J - J) # with beta = W['beta'][0], v = W['v'][0], J = [1, 0; 0, -I]. # As = W3^-1 * [ 0 ; -A ] = 1/beta * ( 2*J*v * v' - I ) * [0; A] beta, v = W['beta'][0], W['v'][0] As = 2 * v * (v[1:].T * A) As[1:,:] *= -1.0 As[1:,:] -= A As /= beta # S = As'*As + 4 * (W1**2 + W2**2)**-1 S = As.T * As d1, d2 = W['d'][:n], W['d'][n:] d = 4.0 * (d1**2 + d2**2)**-1 S[::n+1] += d lapack.potrf(S) def f(x, y, z): # z := - W**-T * z z[:n] = -div( z[:n], d1 ) z[n:2*n] = -div( z[n:2*n], d2 ) z[2*n:] -= 2.0*v*( v[0]*z[2*n] - blas.dot(v[1:], z[2*n+1:]) ) z[2*n+1:] *= -1.0 z[2*n:] /= beta # x := x - G' * W**-1 * z x[:n] -= div(z[:n], d1) - div(z[n:2*n], d2) + As.T * z[-(m+1):] x[n:] += div(z[:n], d1) + div(z[n:2*n], d2) # Solve for x[:n]: # # S*x[:n] = x[:n] - (W1**2 - W2**2)(W1**2 + W2**2)^-1 * x[n:] x[:n] -= mul( div(d1**2 - d2**2, d1**2 + d2**2), x[n:]) lapack.potrs(S, x) # Solve for x[n:]: # # (d1**-2 + d2**-2) * x[n:] = x[n:] + (d1**-2 - d2**-2)*x[:n] x[n:] += mul( d1**-2 - d2**-2, x[:n]) x[n:] = div( x[n:], d1**-2 + d2**-2) # z := z + W^-T * G*x z[:n] += div( x[:n] - x[n:2*n], d1) z[n:2*n] += div( -x[:n] - x[n:2*n], d2) z[2*n:] += As*x[:n] return f dims = {'l': 2*n, 'q': [m+1], 's': []} sol = solvers.conelp(c, G, h, dims, kktsolver = Fkkt) if sol['status'] == 'optimal': return sol['x'][:n], sol['z'][-m:] else: return None, None