Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
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]