def syr2(X, u, v, alpha=1.0, beta=1.0, reordered=False): r""" Computes the projected rank 2 update of a cspmatrix X .. math:: X := \alpha*P(u v^T + v u^T) + \beta X. """ assert X.is_factor is False, "cspmatrix factor object" symb = X.symb n = symb.n snptr = symb.snptr snode = symb.snode blkval = X.blkval blkptr = symb.blkptr relptr = symb.relptr snrowidx = symb.snrowidx sncolptr = symb.sncolptr if symb.p is not None and reordered is False: up = u[symb.p] vp = v[symb.p] else: up = u vp = v for k in range(symb.Nsn): nn = snptr[k + 1] - snptr[k] na = relptr[k + 1] - relptr[k] nj = na + nn for i in range(nn): blas.scal(beta, blkval, n=nj - i, offset=blkptr[k] + (nj + 1) * i) uk = up[snrowidx[sncolptr[k]:sncolptr[k + 1]]] vk = vp[snrowidx[sncolptr[k]:sncolptr[k + 1]]] blas.syr2(uk, vk, blkval, n=nn, offsetA=blkptr[k], ldA=nj, alpha=alpha) blas.ger(uk, vk, blkval, m=na, n=nn, offsetx=nn, offsetA=blkptr[k] + nn, ldA=nj, alpha=alpha) blas.ger(vk, uk, blkval, m=na, n=nn, offsetx=nn, offsetA=blkptr[k] + nn, ldA=nj, alpha=alpha) return
def syr2(X, u, v, alpha = 1.0, beta = 1.0, reordered=False): r""" Computes the projected rank 2 update of a cspmatrix X .. math:: X := \alpha*P(u v^T + v u^T) + \beta X. """ assert X.is_factor is False, "cspmatrix factor object" symb = X.symb n = symb.n snptr = symb.snptr snode = symb.snode blkval = X.blkval blkptr = symb.blkptr relptr = symb.relptr snrowidx = symb.snrowidx sncolptr = symb.sncolptr if symb.p is not None and reordered is False: up = u[symb.p] vp = v[symb.p] else: up = u vp = v for k in range(symb.Nsn): nn = snptr[k+1]-snptr[k] na = relptr[k+1]-relptr[k] nj = na + nn for i in range(nn): blas.scal(beta, blkval, n = nj-i, offset = blkptr[k]+(nj+1)*i) uk = up[snrowidx[sncolptr[k]:sncolptr[k+1]]] vk = vp[snrowidx[sncolptr[k]:sncolptr[k+1]]] blas.syr2(uk, vk, blkval, n = nn, offsetA = blkptr[k], ldA = nj, alpha = alpha) blas.ger(uk, vk, blkval, m = na, n = nn, offsetx = nn, offsetA = blkptr[k]+nn, ldA = nj, alpha = alpha) blas.ger(vk, uk, blkval, m = na, n = nn, offsetx = nn, offsetA = blkptr[k]+nn, ldA = nj, alpha = alpha) return
def kernel_matrix(X, kernel, sigma=1.0, theta=1.0, degree=1, V=None, width=None): """ Computes the kernel matrix or a partial kernel matrix. Input arguments. X is an N x n matrix. kernel is a string with values 'linear', 'rfb', 'poly', or 'tanh'. 'linear': k(u,v) = u'*v/sigma. 'rbf': k(u,v) = exp(-||u - v||^2 / (2*sigma)). 'poly': k(u,v) = (u'*v/sigma)**degree. 'tanh': k(u,v) = tanh(u'*v/sigma - theta). kernel is a sigma and theta are positive numbers. degree is a positive integer. V is an N x N sparse matrix (default is None). width is a positive integer (default is None). Output. Q, an N x N matrix or sparse matrix. If V is a sparse matrix, a partial kernel matrix with the sparsity pattern V is returned. If width is specified and V = 'band', a partial kernel matrix with band sparsity is returned (width is the half-bandwidth). a, an N x 1 matrix with the products <xi,xi>/sigma. """ N, n = X.size #### dense (full) kernel matrix if V is None: if verbose: print("building kernel matrix ..") # Qij = xi'*xj / sigma Q = matrix(0.0, (N, N)) blas.syrk(X, Q, alpha=1.0 / sigma) a = Q[::N + 1] # ai = ||xi||**2 / sigma if kernel == 'linear': pass elif kernel == 'rbf': # Qij := Qij - 0.5 * ( ai + aj ) # = -||xi - xj||^2 / (2*sigma) ones = matrix(1.0, (N, 1)) blas.syr2(a, ones, Q, alpha=-0.5) Q = exp(Q) elif kernel == 'tanh': Q = exp(Q - theta) Q = div(Q - Q**-1, Q + Q**-1) elif kernel == 'poly': Q = Q**degree else: raise ValueError('invalid kernel type') #### general sparse partial kernel matrix elif type(V) is cvxopt.base.spmatrix: if verbose: print("building projected kernel matrix ...") Q = +V base.syrk(X, Q, partial=True, alpha=1.0 / sigma) # ai = ||xi||**2 / sigma a = matrix(Q[::N + 1], (N, 1)) if kernel == 'linear': pass elif kernel == 'rbf': ones = matrix(1.0, (N, 1)) # Qij := Qij - 0.5 * ( ai + aj ) # = -||xi - xj||^2 / (2*sigma) p = chompack.maxcardsearch(V) symb = chompack.symbolic(Q, p) Qc = chompack.cspmatrix(symb) + Q chompack.syr2(Qc, a, ones, alpha=-0.5) Q = Qc.spmatrix(reordered=False) Q.V = exp(Q.V) elif kernel == 'tanh': v = +Q.V v = exp(v - theta) v = div(v - v**-1, v + v**-1) Q.V = v elif kernel == 'poly': Q.V = Q.V**degree else: raise ValueError('invalid kernel type') #### banded partial kernel matrix elif V == 'band' and width is not None: # Lower triangular part of band matrix with bandwidth 2*w+1. if verbose: print("building projected kernel matrix ...") I = [i for k in range(N) for i in range(k, min(width + k + 1, N))] J = [k for k in range(N) for i in range(min(width + 1, N - k))] V = matrix(0.0, (len(I), 1)) oy = 0 for k in range(N): # V[:,k] = Xtrain[k:k+w, :] * Xtrain[k,:].T m = min(width + 1, N - k) blas.gemv(X, X, V, m=m, ldA=N, incx=N, offsetA=k, offsetx=k, offsety=oy) oy += m blas.scal(1.0 / sigma, V) # ai = ||xi||**2 / sigma a = matrix(V[[i for i in range(len(I)) if I[i] == J[i]]], (N, 1)) if kernel == 'linear': Q = spmatrix(V, I, J, (N, N)) elif kernel == 'rbf': Q = spmatrix(V, I, J, (N, N)) ones = matrix(1.0, (N, 1)) # Qij := Qij - 0.5 * ( ai + aj ) # = -||xi - xj||^2 / (2*sigma) symb = chompack.symbolic(Q) Qc = chompack.cspmatrix(symb) + Q chompack.syr2(Qc, a, ones, alpha=-0.5) Q = Qc.spmatrix(reordered=False) Q.V = exp(Q.V) elif kernel == 'tanh': V = exp(V - theta) V = div(V - V**-1, V + V**-1) Q = spmatrix(V, I, J, (N, N)) elif kernel == 'poly': Q = spmatrix(V**degree, I, J, (N, N)) else: raise ValueError('invalid kernel type') else: raise TypeError('invalid type V') return Q, a
def edmcompletion(A, reordered = True, **kwargs): """ Euclidean distance matrix completion. The routine takes an EDM-completable cspmatrix :math:`A` and returns a dense EDM :math:`X` that satisfies .. math:: P( X ) = A :param A: :py:class:`cspmatrix` :param reordered: boolean """ assert isinstance(A, cspmatrix) and A.is_factor is False, "A must be a cspmatrix" tol = kwargs.get('tol',1e-15) X = matrix(A.spmatrix(reordered = True, symmetric = True)) symb = A.symb n = symb.n snptr = symb.snptr sncolptr = symb.sncolptr snrowidx = symb.snrowidx # visit supernodes in reverse (descending) order for k in range(symb.Nsn-1,-1,-1): nn = snptr[k+1]-snptr[k] beta = snrowidx[sncolptr[k]:sncolptr[k+1]] nj = len(beta) if nj-nn == 0: continue alpha = beta[nn:] nu = beta[:nn] eta = matrix([matrix(range(beta[kk]+1,beta[kk+1])) for kk in range(nj-1)] + [matrix(range(beta[-1]+1,n))]) ne = len(eta) # Compute Yaa, Yan, Yea, Ynn, Yee Yaa = -0.5*X[alpha,alpha] - 0.5*X[alpha[0],alpha[0]] blas.syr2(X[alpha,alpha[0]], matrix(1.0,(nj-nn,1)), Yaa, alpha = 0.5) Ynn = -0.5*X[nu,nu] - 0.5*X[alpha[0],alpha[0]] blas.syr2(X[nu,alpha[0]], matrix(1.0,(nn,1)), Ynn, alpha = 0.5) Yee = -0.5*X[eta,eta] - 0.5*X[alpha[0],alpha[0]] blas.syr2(X[eta,alpha[0]], matrix(1.0,(ne,1)), Yee, alpha = 0.5) Yan = -0.5*X[alpha,nu] - 0.5*X[alpha[0],alpha[0]] Yan += 0.5*matrix(1.0,(nj-nn,1))*X[alpha[0],nu] Yan += 0.5*X[alpha,alpha[0]]*matrix(1.0,(1,nn)) Yea = -0.5*X[eta,alpha] - 0.5*X[alpha[0],alpha[0]] Yea += 0.5*matrix(1.0,(ne,1))*X[alpha[0],alpha] Yea += 0.5*X[eta,alpha[0]]*matrix(1.0,(1,nj-nn)) # EVD: Yaa = Z*diag(w)*Z.T w = matrix(0.0,(Yaa.size[0],1)) Z = matrix(0.0,Yaa.size) lapack.syevr(Yaa, w, jobz='V', range='A', uplo='L', Z=Z) # Pseudo-inverse: Yp = pinv(Yaa) lambda_max = max(w) Yp = Z*spmatrix([1.0/wi if wi > lambda_max*tol else 0.0 for wi in w],range(len(w)),range(len(w)))*Z.T # Compute update tmp = -2.0*Yea*Yp*Yan + matrix(1.0,(ne,1))*Ynn[::nn+1].T + Yee[::ne+1]*matrix(1.0,(1,nn)) X[eta,nu] = tmp X[nu,eta] = tmp.T if reordered: return X else: return X[symb.ip,symb.ip]