def test_pfcholesky(self): U = matrix(range(1,2*self.symb.n+1),(self.symb.n,2),tc='d')/self.symb.n alpha = matrix([1.2,-0.01]) D = matrix(0.0,(2,2)) D[::3] = alpha random.seed(1) V = matrix([random.random() for i in range(self.symb.n*3)],(self.symb.n,3)) # PF Cholesky from spmatrix Lpf = cp.pfcholesky(self.A,U,alpha,p=amd.order) Vt = +V Lpf.trmm(Vt,trans='T') Lpf.trmm(Vt,trans='N') diff = list( (Vt - (cp.symmetrize(self.A) + U*D*U.T)*V)[:] ) self.assertAlmostEqualLists(diff, len(diff)*[0.0]) Lpf.trsm(Vt,trans='N') Lpf.trsm(Vt,trans='T') diff = list( (Vt-V)[:] ) self.assertAlmostEqualLists(diff, len(diff)*[0.0]) # PF Cholesky from cspmatrix factor L = cp.cspmatrix(self.symb) + self.A Lpf = cp.pfcholesky(L,U,alpha) Vt = +V Lpf.trmm(Vt,trans='T') Lpf.trmm(Vt,trans='N') diff = list( (Vt - (cp.symmetrize(self.A) + U*D*U.T)*V)[:] ) self.assertAlmostEqualLists(diff, len(diff)*[0.0]) Lpf.trsm(Vt,trans='N') Lpf.trsm(Vt,trans='T') diff = list( (Vt-V)[:] ) self.assertAlmostEqualLists(diff, len(diff)*[0.0])
def spy(P,i=None,file=None,scale=None): """Generates sparsity plot using Pylab""" if type(P) is spmatrix: V = chompack.symmetrize(chompack.tril(P)) n = V.size[0] else: if not P._A: raise AttributeError, "SDP data missing" n = +P.n; if i == None: V = chompack.symmetrize(P.V) elif i>=0 and i<=P.m and P._A: r = P._A.CCS[1][P._A.CCS[0][i]:P._A.CCS[0][i+1]] if type(r) is int: I = [r%n]; J = [r/n] else: I,J = misc.ind2sub(n,r) V = chompack.symmetrize(spmatrix(0.,I,J,(n,n))) else: raise ValueError, "index out of range" from math import floor msize = max(1,int(floor(100./n))) if file==None: pylab.ion() else: pylab.ioff() f = pylab.figure(figsize=(6,6)); f.clf() if scale is None: scale = 1.0 I = V.I*scale+1; J = (n-V.J)*scale p = pylab.plot(I,J, 's', linewidth = 1, hold = 'False') pylab.setp(p, markersize = msize, markerfacecolor = 'k') g = pylab.gca() pylab.axis([0.5,n*scale+0.5,0.5,n*scale+0.5]) g.set_aspect('equal') locs,labels = pylab.yticks() locs = locs[locs<=n*scale]; locs = locs[locs>=1] pylab.yticks(locs[::-1]-(locs[-1]-n*scale-1)-locs[0], [str(int(loc)) for loc in locs]) if file: pylab.savefig(file)
def test_cspmatrix(self): Ac = cp.cspmatrix(self.symb) + self.A self.assertTrue(Ac.is_factor is False) self.assertTrue(Ac.size[0] == Ac.size[1]) self.assertTrue(Ac.size[0] == 17) diff = list((self.A - Ac.spmatrix(reordered=False,symmetric=False)).V) self.assertAlmostEqualLists(diff, len(diff)*[0.0]) diff = list(cp.symmetrize(self.A) - Ac.spmatrix(reordered=False,symmetric=True)) self.assertAlmostEqualLists(diff, len(diff)*[0.0]) diff = list(cp.symmetrize(self.A)[self.symb.p,self.symb.p] - Ac.spmatrix(reordered=True,symmetric=True)) self.assertAlmostEqualLists(diff, len(diff)*[0.0]) diff = list(cp.tril(cp.symmetrize(self.A)[self.symb.p,self.symb.p]) - Ac.spmatrix(reordered=True,symmetric=False)) self.assertAlmostEqualLists(diff, len(diff)*[0.0]) diff = list((2*self.A - (2*Ac).spmatrix(reordered=False,symmetric=False)).V) self.assertAlmostEqualLists(diff, len(diff)*[0.0]) diff = list((2*self.A - (Ac+Ac).spmatrix(reordered=False,symmetric=False)).V) self.assertAlmostEqualLists(diff, len(diff)*[0.0]) Ac2 = Ac.copy() Ac2 += Ac diff = list((2*self.A - Ac2.spmatrix(reordered=False,symmetric=False)).V) self.assertAlmostEqualLists(diff, len(diff)*[0.0]) self.assertAlmostEqualLists(list(Ac.diag(reordered=False)), list(self.A[::18])) self.assertAlmostEqualLists(list(Ac.diag(reordered=True)), list(self.A[self.symb.p,self.symb.p][::18]))
def embed_SDP(P,order="AMD",cholmod=False): if not isinstance(P,SDP): raise ValueError, "not an SDP object" if order=='AMD': from cvxopt.amd import order elif order=='METIS': from cvxopt.metis import order else: raise ValueError, "unknown ordering: %s " %(order) p = order(P.V) if cholmod: from cvxopt import cholmod V = +P.V + spmatrix([float(i+1) for i in xrange(P.n)],xrange(P.n),xrange(P.n)) F = cholmod.symbolic(V,p=p) cholmod.numeric(V,F) f = cholmod.getfactor(F) fd = [(j,i) for i,j in enumerate(f[:P.n**2:P.n+1])] fd.sort() ip = matrix([j for _,j in fd]) Ve = chompack.tril(chompack.perm(chompack.symmetrize(f),ip)) Ie = misc.sub2ind((P.n,P.n),Ve.I,Ve.J) else: #Vc,n = chompack.embed(P.V,p) symb = chompack.symbolic(P.V,p) #Ve = chompack.sparse(Vc) Ve = symb.sparsity_pattern(reordered=False) Ie = misc.sub2ind((P.n,P.n),Ve.I,Ve.J) Pe = SDP() Pe._A = +P.A; Pe._b = +P.b Pe._A[:,0] += spmatrix(0.0,Ie,[0 for i in range(len(Ie))],(Pe._A.size[0],1)) Pe._agg_sparsity() Pe._pname = P._pname + "_embed" Pe._ischordal = True; Pe._blockstruct = P._blockstruct return Pe
def test_cspmatrix(self): Ac = cp.cspmatrix(self.symb) + self.A self.assertTrue(Ac.is_factor is False) self.assertTrue(Ac.size[0] == Ac.size[1]) self.assertTrue(Ac.size[0] == 17) diff = list((self.A - Ac.spmatrix(reordered=False, symmetric=False)).V) self.assertAlmostEqualLists(diff, len(diff) * [0.0]) diff = list( cp.symmetrize(self.A) - Ac.spmatrix(reordered=False, symmetric=True)) self.assertAlmostEqualLists(diff, len(diff) * [0.0]) diff = list( cp.symmetrize(self.A)[self.symb.p, self.symb.p] - Ac.spmatrix(reordered=True, symmetric=True)) self.assertAlmostEqualLists(diff, len(diff) * [0.0]) diff = list( cp.tril(cp.symmetrize(self.A)[self.symb.p, self.symb.p]) - Ac.spmatrix(reordered=True, symmetric=False)) self.assertAlmostEqualLists(diff, len(diff) * [0.0]) diff = list((2 * self.A - (2 * Ac).spmatrix(reordered=False, symmetric=False)).V) self.assertAlmostEqualLists(diff, len(diff) * [0.0]) diff = list((2 * self.A - (Ac + Ac).spmatrix(reordered=False, symmetric=False)).V) self.assertAlmostEqualLists(diff, len(diff) * [0.0]) Ac2 = Ac.copy() Ac2 += Ac diff = list( (2 * self.A - Ac2.spmatrix(reordered=False, symmetric=False)).V) self.assertAlmostEqualLists(diff, len(diff) * [0.0]) self.assertAlmostEqualLists(list(Ac.diag(reordered=False)), list(self.A[::18])) self.assertAlmostEqualLists( list(Ac.diag(reordered=True)), list(self.A[self.symb.p, self.symb.p][::18]))
def test_pfcholesky(self): U = matrix(range(1, 2 * self.symb.n + 1), (self.symb.n, 2), tc='d') / self.symb.n alpha = matrix([1.2, -0.01]) D = matrix(0.0, (2, 2)) D[::3] = alpha random.seed(1) V = matrix([random.random() for i in range(self.symb.n * 3)], (self.symb.n, 3)) # PF Cholesky from spmatrix Lpf = cp.pfcholesky(self.A, U, alpha, p=amd.order) Vt = +V Lpf.trmm(Vt, trans='T') Lpf.trmm(Vt, trans='N') diff = list((Vt - (cp.symmetrize(self.A) + U * D * U.T) * V)[:]) self.assertAlmostEqualLists(diff, len(diff) * [0.0]) Lpf.trsm(Vt, trans='N') Lpf.trsm(Vt, trans='T') diff = list((Vt - V)[:]) self.assertAlmostEqualLists(diff, len(diff) * [0.0]) # PF Cholesky from cspmatrix factor L = cp.cspmatrix(self.symb) + self.A Lpf = cp.pfcholesky(L, U, alpha) Vt = +V Lpf.trmm(Vt, trans='T') Lpf.trmm(Vt, trans='N') diff = list((Vt - (cp.symmetrize(self.A) + U * D * U.T) * V)[:]) self.assertAlmostEqualLists(diff, len(diff) * [0.0]) Lpf.trsm(Vt, trans='N') Lpf.trsm(Vt, trans='T') diff = list((Vt - V)[:]) self.assertAlmostEqualLists(diff, len(diff) * [0.0])
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']