def test_completion_fu(self): L = cp.cspmatrix(self.symb) + self.A cp.cholesky(L) L2 = L.copy() cp.projected_inverse(L2) cp.completion(L2, factored_updates=True) diff = list((L.spmatrix() - L2.spmatrix()).V) self.assertAlmostEqualLists(diff, len(diff) * [0.0])
def test_completion_fu(self): L = cp.cspmatrix(self.symb) + self.A cp.cholesky(L) L2 = L.copy() cp.projected_inverse(L2) cp.completion(L2, factored_updates = True) diff = list((L.spmatrix()-L2.spmatrix()).V) self.assertAlmostEqualLists(diff, len(diff)*[0.0])
def mk_rand(V, cone='posdef', seed=0): """ Generates random matrix U with sparsity pattern V. - U is positive definite if cone is 'posdef'. - U is completable if cone is 'completable'. """ if not (cone == 'posdef' or cone == 'completable'): raise ValueError, "cone must be 'posdef' (default) or 'completable' " from cvxopt import amd setseed(seed) n = V.size[0] U = +V U.V *= 0.0 for i in xrange(n): u = normal(n, 1) / sqrt(n) base.syrk(u, U, beta=1.0, partial=True) # test if U is in cone: if not, add multiple of identity t = 0.1 Ut = +U p = amd.order(Ut) # Vc, NF = chompack.embed(U,p) symb = chompack.symbolic(U, p) Vc = chompack.cspmatrix(symb) + U while True: # Uc = chompack.project(Vc,Ut) Uc = chompack.cspmatrix(symb) + Ut try: if cone == 'posdef': # positive definite? # Y = chompack.cholesky(Uc) Y = Uc.copy() chompack.cholesky(Y) elif cone == 'completable': # completable? # Y = chompack.completion(Uc) Y = Uc.copy() chompack.completion(Y) # Success: Ut is in cone U = +Ut break except: Ut = U + spmatrix(t, xrange(n), xrange(n), (n, n)) t *= 2.0 return U
def mk_rand(V,cone='posdef',seed=0): """ Generates random matrix U with sparsity pattern V. - U is positive definite if cone is 'posdef'. - U is completable if cone is 'completable'. """ if not (cone=='posdef' or cone=='completable'): raise ValueError("cone must be 'posdef' (default) or 'completable' ") from cvxopt import amd setseed(seed) n = V.size[0] U = +V U.V *= 0.0 for i in range(n): u = normal(n,1)/sqrt(n) base.syrk(u,U,beta=1.0,partial=True) # test if U is in cone: if not, add multiple of identity t = 0.1; Ut = +U p = amd.order(Ut) # Vc, NF = chompack.embed(U,p) symb = chompack.symbolic(U,p) Vc = chompack.cspmatrix(symb) + U while True: # Uc = chompack.project(Vc,Ut) Uc = chompack.cspmatrix(symb) + Ut try: if cone=='posdef': # positive definite? # Y = chompack.cholesky(Uc) Y = Uc.copy() chompack.cholesky(Y) elif cone=='completable': # completable? # Y = chompack.completion(Uc) Y = Uc.copy() chompack.completion(Y) # Success: Ut is in cone U = +Ut break except: Ut = U + spmatrix(t,range(n),range(n),(n,n)) t*=2.0 return U
def completion(X): """ Returns maximum-determinant positive definite completion of X if it exists, and otherwise an exception is raised. """ from cvxopt.amd import order n = X.size[0] Xt = chompack.tril(X) p = order(Xt) # Xc,N = chompack.embed(Xt,p) # L = chompack.completion(Xc) symb = chompack.symbolic(Xt,p) L = chompack.cspmatrix(symb) + Xt chompack.completion(L) Xt = matrix(0.,(n,n)) Xt[::n+1] = 1. # chompack.solve(L, Xt, mode=0) # chompack.solve(L, Xt, mode=1) chompack.trsm(L, Xt) chompack.trsm(L, Xt, trans = 'T') return Xt
def completion(X): """ Returns maximum-determinant positive definite completion of X if it exists, and otherwise an exception is raised. """ from cvxopt.amd import order n = X.size[0] Xt = chompack.tril(X) p = order(Xt) # Xc,N = chompack.embed(Xt,p) # L = chompack.completion(Xc) symb = chompack.symbolic(Xt, p) L = chompack.cspmatrix(symb) + Xt chompack.completion(L) Xt = matrix(0., (n, n)) Xt[::n + 1] = 1. # chompack.solve(L, Xt, mode=0) # chompack.solve(L, Xt, mode=1) chompack.trsm(L, Xt) chompack.trsm(L, Xt, trans='T') return Xt
def softmargin_completion(Q, d, gamma): """ Solves the QP minimize (1/2)*y'*Qc^{-1}*y + gamma*sum(v) subject to diag(d)*(y + b*ones) + v >= 1 v >= 0 (with variables y, b, v) and its dual, the 'soft-margin' SVM problem, maximize -(1/2)*z'*Qc*z + d'*z subject to 0 <= diag(d)*z <= gamma*ones sum(z) = 0 (with variables z). Qc is the max determinant completion of Q. Input arguments. Q is a sparse N x N sparse matrix with chordal sparsity pattern and a positive definite completion d is an N-vector of labels -1 or 1. gamma is a positive parameter. F is the chompack pattern corresponding to Q. If F is None, the pattern is computed. Output. z, y, b, v, optval, L, iters """ if verbose: solvers.options['show_progress'] = True else: solvers.options['show_progress'] = False N = Q.size[0] p = chompack.maxcardsearch(Q) symb = chompack.symbolic(Q, p) Qc = chompack.cspmatrix(symb) + Q # Qinv is the inverse of the max. determinant p.d. completion of Q Lc = Qc.copy() chompack.completion(Lc) Qinv = Lc.copy() chompack.llt(Qinv) Qinv = Qinv.spmatrix(reordered=False) Qinv = chompack.symmetrize(Qinv) def P(u, v, alpha=1.0, beta=0.0): """ v := alpha * [ Qc^-1, 0, 0; 0, 0, 0; 0, 0, 0 ] * u + beta * v """ v *= beta base.symv(Qinv, u, v, alpha=alpha, beta=1.0) def G(u, v, alpha=1.0, beta=0.0, trans='N'): """ If trans is 'N': v := alpha * [ -diag(d), -d, -I; 0, 0, -I ] * u + beta * v. If trans is 'T': v := alpha * [ -diag(d), 0; -d', 0; -I, -I ] * u + beta * v. """ v *= beta if trans is 'N': v[:N] -= alpha * (base.mul(d, u[:N] + u[N]) + u[-N:]) v[-N:] -= alpha * u[-N:] else: v[:N] -= alpha * base.mul(d, u[:N]) v[N] -= alpha * blas.dot(d, u, n=N) v[-N:] -= alpha * (u[:N] + u[N:]) K = spmatrix(0.0, Qinv.I, Qinv.J) dy1, dy2 = matrix(0.0, (N, 1)), matrix(0.0, (N, 1)) def Fkkt(W): """ Custom KKT solver for [ Qinv 0 0 -D 0 ] [ ux_y ] [ bx_y ] [ 0 0 0 -d' 0 ] [ ux_b ] [ bx_b ] [ 0 0 0 -I -I ] [ ux_v ] = [ bx_v ] [ -D -d -I -D1 0 ] [ uz_z ] [ bz_z ] [ 0 0 -I 0 -D2 ] [ uz_w ] [ bz_w ] with D1 = diag(d1), D2 = diag(d2), d1 = W['d'][:N]**2, d2 = W['d'][N:])**2. """ d1, d2 = W['d'][:N]**2, W['d'][N:]**2 d3, d4 = (d1 + d2)**-1, (d1**-1 + d2**-1)**-1 # Factor the chordal matrix K = Qinv + (D_1+D_2)^-1. K.V = Qinv.V K[::N + 1] = K[::N + 1] + d3 L = chompack.cspmatrix(symb) + K chompack.cholesky(L) # Solve (Qinv + (D1+D2)^-1) * dy2 = (D1 + D2)^{-1} * 1 blas.copy(d3, dy2) chompack.trsm(L, dy2, trans='N') chompack.trsm(L, dy2, trans='T') def g(x, y, z): # Solve # # [ K d3 ] [ ux_y ] # [ ] [ ] = # [ d3' 1'*d3 ] [ ux_b ] # # [ bx_y ] [ D ] # [ ] - [ ] * D3 * (D2 * bx_v + bx_z - bx_w). # [ bx_b ] [ d' ] x[:N] -= mul(d, mul(d3, mul(d2, x[-N:]) + z[:N] - z[-N:])) x[N] -= blas.dot(d, mul(d3, mul(d2, x[-N:]) + z[:N] - z[-N:])) # Solve dy1 := K^-1 * x[:N] blas.copy(x, dy1, n=N) chompack.trsm(L, dy1, trans='N') chompack.trsm(L, dy1, trans='T') # Find ux_y = dy1 - ux_b * dy2 s.t # # d3' * ( dy1 - ux_b * dy2 + ux_b ) = x[N] # # i.e. x[N] := ( x[N] - d3'* dy1 ) / ( d3'* ( 1 - dy2 ) ). x[N] = ( x[N] - blas.dot(d3, dy1) ) / \ ( blas.asum(d3) - blas.dot(d3, dy2) ) x[:N] = dy1 - x[N] * dy2 # ux_v = D4 * ( bx_v - D1^-1 (bz_z + D * (ux_y + ux_b)) # - D2^-1 * bz_w ) x[-N:] = mul( d4, x[-N:] - div(z[:N] + mul(d, x[:N] + x[N]), d1) - div(z[N:], d2)) # uz_z = - D1^-1 * ( bx_z - D * ( ux_y + ux_b ) - ux_v ) # uz_w = - D2^-1 * ( bx_w - uz_w ) z[:N] += base.mul(d, x[:N] + x[N]) + x[-N:] z[-N:] += x[-N:] blas.scal(-1.0, z) # Return W['di'] * uz blas.tbmv(W['di'], z, n=2 * N, k=0, ldA=1) return g q = matrix(0.0, (2 * N + 1, 1)) if weights is 'proportional': dlist = list(d) C1 = 0.5 * N * gamma / dlist.count(1) C2 = 0.5 * N * gamma / dlist.count(-1) gvec = matrix([C1 if w == 1 else C2 for w in dlist], (N, 1)) del dlist q[-N:] = gvec elif weights is 'equal': q[-N:] = gamma h = matrix(0.0, (2 * N, 1)) h[:N] = -1.0 sol = solvers.coneqp(P, q, G, h, kktsolver=Fkkt) u = matrix(0.0, (N, 1)) y, b, v = sol['x'][:N], sol['x'][N], sol['x'][N + 1:] z = mul(d, sol['z'][:N]) base.symv(Qinv, y, u) optval = 0.5 * blas.dot(y, u) + gamma * sum(v) return y, b, v, z, optval, Lc, sol['iterations']
print("Computing Cholesky factorization..") L = A.copy() # make a copy of A cholesky(L) # compute Cholesky factorization; overwrites L print("Computing Cholesky product..") At = L.copy() # make a copy of L llt(At) # compute Cholesky product; overwrites At print("Computing projected inverse..") Y = L.copy() # make a copy of L projected_inverse(Y) # compute projected inverse; overwrites Y print("Computing completion..") Lc = Y.copy() # make a copy of Y completion(Lc, factored_updates = False) # compute completion; overwrites Lc print("Computing completion with factored updates..") Lc2 = Y.copy() # make a copy of Y completion(Lc2, factored_updates = True) # compute completion (with factored updates); overwrites Lc2 print("Applying Hessian factors..") U = At.copy() fupd = False hessian(L, Y, U, adj = False, inv = False, factored_updates = fupd) hessian(L, Y, U, adj = True, inv = False, factored_updates = fupd) hessian(L, Y, U, adj = True, inv = True, factored_updates = fupd) hessian(L, Y, U, adj = False, inv = True, factored_updates = fupd) print("\nEvaluating errors:\n") # Compute norm of error: A - L*L.T
def solve_phase1(self,kktsolver='chol',MM = 1e5): """ Solves primal Phase I problem using the feasible start solver. Returns primal feasible X. """ from cvxopt import cholmod, amd k = 1e-3 # compute Schur complement matrix Id = [i*(self.n+1) for i in range(self.n)] As = self._A[:,1:] As[Id,:] /= sqrt(2.0) M = spmatrix([],[],[],(self.m,self.m)) base.syrk(As,M,trans='T') u = +self.b # compute least-norm solution F = cholmod.symbolic(M) cholmod.numeric(M,F) cholmod.solve(F,u) x = 0.5*self._A[:,1:]*u X0 = spmatrix(x[self.V[:].I],self.V.I,self.V.J,(self.n,self.n)) # test feasibility p = amd.order(self.V) #Xc,Nf = chompack.embed(X0,p) #E = chompack.project(Xc,spmatrix(1.0,range(self.n),range(self.n))) symb = chompack.symbolic(self.V,p) Xc = chompack.cspmatrix(symb) + X0 try: # L = chompack.completion(Xc) L = Xc.copy() chompack.completion(L) # least-norm solution is feasible return X0,None except: pass # create Phase I SDP object trA = matrix(0.0,(self.m+1,1)) e = matrix(1.0,(self.n,1)) Aa = self._A[Id,1:] base.gemv(Aa,e,trA,trans='T') trA[-1] = MM P1 = SDP() P1._A = misc.phase1_sdp(self._A,trA) P1._b = matrix([self.b-k*trA[:self.m],MM]) P1._agg_sparsity() # find feasible starting point for Phase I problem tMIN = 0.0 tMAX = 1.0 while True: t = (tMIN+tMAX)/2.0 #Xt = chompack.copy(Xc) #chompack.axpy(E,Xt,t) Xt = Xc.copy() + spmatrix(t,list(range(self.n)),list(range(self.n))) try: # L = chompack.completion(Xt) L = Xt.copy() chompack.completion(L) tMAX = t if tMAX - tMIN < 1e-1: break except: tMAX *= 2.0 tMIN = t tt = t + 1.0 U = X0 + spmatrix(tt,list(range(self.n,)),list(range(self.n))) trU = sum(U[:][Id]) Z0 = spdiag([U,spmatrix([tt+k,MM-trU],[0,1],[0,1],(2,2))]) sol = P1.solve_feas(primalstart = {'x':Z0}, kktsolver = kktsolver) s = sol['x'][-2,-2] - k if s > 0: return None,P1 else: sol.pop('y') sol.pop('s') X0 = sol.pop('x')[:self.n,:self.n]\ - spmatrix(s,list(range(self.n)),list(range(self.n))) return X0,sol
def solve_phase1(self, kktsolver='chol', MM=1e5): """ Solves primal Phase I problem using the feasible start solver. Returns primal feasible X. """ from cvxopt import cholmod, amd k = 1e-3 # compute Schur complement matrix Id = [i * (self.n + 1) for i in range(self.n)] As = self._A[:, 1:] As[Id, :] /= sqrt(2.0) M = spmatrix([], [], [], (self.m, self.m)) base.syrk(As, M, trans='T') u = +self.b # compute least-norm solution F = cholmod.symbolic(M) cholmod.numeric(M, F) cholmod.solve(F, u) x = 0.5 * self._A[:, 1:] * u X0 = spmatrix(x[self.V[:].I], self.V.I, self.V.J, (self.n, self.n)) # test feasibility p = amd.order(self.V) #Xc,Nf = chompack.embed(X0,p) #E = chompack.project(Xc,spmatrix(1.0,range(self.n),range(self.n))) symb = chompack.symbolic(self.V, p) Xc = chompack.cspmatrix(symb) + X0 try: # L = chompack.completion(Xc) L = Xc.copy() chompack.completion(L) # least-norm solution is feasible return X0 except: pass # create Phase I SDP object trA = matrix(0.0, (self.m + 1, 1)) e = matrix(1.0, (self.n, 1)) Aa = self._A[Id, 1:] base.gemv(Aa, e, trA, trans='T') trA[-1] = MM P1 = SDP() P1._A = misc.phase1_sdp(self._A, trA) P1._b = matrix([self.b - k * trA[:self.m], MM]) P1._agg_sparsity() # find feasible starting point for Phase I problem tMIN = 0.0 tMAX = 1.0 while True: t = (tMIN + tMAX) / 2.0 #Xt = chompack.copy(Xc) #chompack.axpy(E,Xt,t) Xt = Xc.copy() + spmatrix(t, range(self.n), range(self.n)) try: # L = chompack.completion(Xt) L = Xt.copy() chompack.completion(L) tMAX = t if tMAX - tMIN < 1e-1: break except: tMAX *= 2.0 tMIN = t tt = t + 1.0 U = X0 + spmatrix(tt, range(self.n, ), range(self.n)) trU = sum(U[:][Id]) Z0 = spdiag([U, spmatrix([tt + k, MM - trU], [0, 1], [0, 1], (2, 2))]) sol = P1.solve_feas(primalstart={'x': Z0}, kktsolver=kktsolver) s = sol['x'][-2, -2] - k if s > 0: return None, P1 else: sol.pop('y') sol.pop('s') X0 = sol.pop('x')[:self.n,:self.n]\ - spmatrix(s,range(self.n),range(self.n)) return X0, sol