Пример #1
0
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      
Пример #2
0
def sparse_chol(M, perm=None, retF=False, retP=True, retL=True):

    # Quick check that M is square
    if M.size[0] != M.size[1]:
        raise Exception('M must be square.')

    # Set the factorisation to use LL' instead of LDL'
    cholmod.options['supernodal'] = 2

    if not perm is None:
        # Make an expression for the factorisation
        F = cholmod.symbolic(M, p=perm)
    else:
        # Make an expression for the factorisation
        F = cholmod.symbolic(M)

    # Calculate the factorisation
    cholmod.numeric(M, F)

    # Empty factorisation object
    factorisation = {}

    if retF:

        # Calculate the factorisation again (buggy if returning L for
        # some reason)
        F2 = cholmod.symbolic(M, p=perm)
        cholmod.numeric(M, F2)

        # If we want to return the F object, add it to the dictionary
        factorisation['F'] = F2

    if retP:

        # Set p to [0,...,n-1]
        P = cvxopt.matrix(range(M.size[0]), (M.size[0], 1), tc='d')

        # Solve and replace p with the true permutation used
        cholmod.solve(F, P, sys=7)

        # Convert p into an integer array; more useful that way
        P = cvxopt.matrix(np.array(P).astype(np.int64), tc='i')

        # If we want to return the permutation, add it to the dictionary
        factorisation['P'] = P

    if retL:

        # Get the sparse cholesky factor
        L = cholmod.getfactor(F)

        # If we want to return the factor, add it to the dictionary
        factorisation['L'] = L

    # Return P and L
    return (factorisation)
Пример #3
0
def eval(obj):
    try:
        s = cholmod.options['supernodal']
    except KeyError:
        s = 2  # set to default.
    cholmod.options['supernodal'] = 0
    A = cvxopt.base.sparse(obj)
    F = cholmod.symbolic(A)
    cholmod.numeric(A, F)
    Di = matrix(1.0, (4, 1))
    cholmod.solve(F, Di, sys=6)
    # Reset state.
    cholmod.options['supernodal'] = s
    return -sum(cvxopt.base.log(Di))
Пример #4
0
def eval(obj):
    try:
        s = cholmod.options['supernodal']
    except KeyError:
        s = 2 # set to default.
    cholmod.options['supernodal'] = 0
    A = cvxopt.base.sparse(obj)
    F = cholmod.symbolic(A)
    cholmod.numeric(A, F)
    Di = matrix(1.0, (4,1))
    cholmod.solve(F, Di, sys=6)
    # Reset state.
    cholmod.options['supernodal'] = s
    return -sum(cvxopt.base.log(Di))
Пример #5
0
def sp_det_sym(M):

    # Change to the LL' decomposition
    prevopts = cholmod.options['supernodal']
    cholmod.options['supernodal'] = 2

    # Obtain decomposition of M
    F = cholmod.symbolic(M)
    cholmod.numeric(M, F)

    # Restore previous options
    cholmod.options['supernodal'] = prevopts

    # As PMP'=LL' and det(P)=1 for all permutations
    # it follows det(M)=det(L)^2=product(diag(L))^2
    return (np.exp(2 * sum(cvxopt.log(cholmod.diag(F)))))
Пример #6
0
def covsel(Y):
    """
    Returns the solution of

         minimize    -log det K + Tr(KY)
         subject to  K_{ij}=0,  (i,j) not in indices listed in I,J.

    Y is a symmetric sparse matrix with nonzero diagonal elements.
    I = Y.I,  J = Y.J.
    """

    I, J = Y.I, Y.J
    n, m = Y.size[0], len(I)
    N = I + J*n         # non-zero positions for one-argument indexing
    D = [k for k in range(m) if I[k]==J[k]]  # position of diagonal elements

    # starting point: symmetric identity with nonzero pattern I,J
    K = spmatrix(0.0, I, J)
    K[::n+1] = 1.0

    # Kn is used in the line search
    Kn = spmatrix(0.0, I, J)

    # symbolic factorization of K
    F = cholmod.symbolic(K)

    # Kinv will be the inverse of K
    Kinv = matrix(0.0, (n,n))

    for iters in range(100):

        # numeric factorization of K
        cholmod.numeric(K, F)
        d = cholmod.diag(F)

        # compute Kinv by solving K*X = I
        Kinv[:] = 0.0
        Kinv[::n+1] = 1.0
        cholmod.solve(F, Kinv)

        # solve Newton system
        grad = 2*(Y.V - Kinv[N])
        hess = 2*(mul(Kinv[I,J],Kinv[J,I]) + mul(Kinv[I,I],Kinv[J,J]))
        v = -grad
        lapack.posv(hess,v)

        # stopping criterion
        sqntdecr = -blas.dot(grad,v)
        print("Newton decrement squared:%- 7.5e" %sqntdecr)
        if (sqntdecr < 1e-12):
            print("number of iterations: ", iters+1)
            break

        # line search
        dx = +v
        dx[D] *= 2      # scale the diagonal elems
        f = -2.0 * sum(log(d))    # f = -log det K
        s = 1
        for lsiter in range(50):
            Kn.V = K.V + s*dx
            try:
                cholmod.numeric(Kn, F)
            except ArithmeticError:
                s *= 0.5
            else:
                d = cholmod.diag(F)
                fn = -2.0 * sum(log(d)) + 2*s*blas.dot(v,Y.V)
                if (fn < f - 0.01*s*sqntdecr):
                     break
                s *= 0.5

        K.V = Kn.V

    return K
Пример #7
0
# Read in ffx variance
sigma2 = pandas.read_csv('true_ffxvar.csv', header=None).values

ZtZ = cvxopt.spmatrix.trans(Z2) * Z2

# Use minimum degree ordering
P = amd.order(ZtZ)

# Set the factorisation to use LL' instead of LDL'
cholmod.options['supernodal'] = 2

# Make an expression for the factorisation
F = cholmod.symbolic(ZtZ, p=P)

# Calculate the factorisation
cholmod.numeric(ZtZ, F)

# Get the sparse cholesky factorisation
L = cholmod.getfactor(F)
LLt = L * cvxopt.spmatrix.trans(L)

# Create initial lambda
# Work out how many lambda components needed
f1_n_lamcomps = np.int64(f1_nv * (f1_nv + 1) / 2)
f2_n_lamcomps = np.int64(f2_nv * (f2_nv + 1) / 2)

# Work out triangular indices for lambda (blocks starting from (0,0))
r_inds_f1_block, c_inds_f1_block = np.tril_indices(f1_nv)
r_inds_f2_block, c_inds_f2_block = np.tril_indices(f2_nv)

# Repeat the factor 1 block for each level of factor 1
Пример #8
0
def solve(A, b, C, L, dims, proxqp=None, sigma=1.0, rho=1.0, **kwargs):
    """
    
    Solves the SDP

        min.  < c, x > 
        s.t.  A(x) = b
              x >= 0

    and its dual

        max.  -< b, y > 
        s.t.  s >= 0.
             c + A'(y) = s 
    
    
    Input arguments.
    
        A   is an N x M sparse matrix where N = sum_i ns[i]**2 and M = sum_j ms[j]
            and ns and ms are the SDP variable sizes and constraint block lengths respectively.
            
            The expression A(x) = b can be written as A.T*xtilde = b, where
            xtilde is a stacked vector of vectorized versions of xi.
        
        b   is a stacked vector containing constraint vectors of 
                        size m_i x 1.
    
        C   is a stacked vector containing vectorized 'd' matrices 
            c_k of size n_k**2 x 1, representing symmetric matrices.



        L  is an N X P sparse matrix, where L.T*X = 0 represents the consistency
            constraints. If an index k appears in different cliques i,j, and
            in converted form are indexed by it, jt, then L[it,l] = 1, 
            L[jt,l] = -1 for some l.
            
        dims    is a dictionary containing conic dimensions.
            dims['l'] contains number of linear variables under nonnegativity constrant
            dims['q'] contains a list of quadratic cone orders (not implemented!)
            dims['s'] contains a list of semidefinite cone matrix orders
        
        proxqp   is either a function pointer to a prox implementation, or, if 
                the problem has block-diagonal correlative sparsity, a pointer 
                to the prox implementation of a single clique. The choices are:
                
                proxqp_general : solves prox for general sparsity pattern
                
                proxqp_clique : solves prox for a single dense clique with 
                                only semidefinite variables.
                
                proxqp_clique_SNL : solves prox for sensor network localization 
                                    problem
        
        sigma is a nonnegative constant (step size)
        
        rho is a nonnegative constaint between 0 and 2 (overrelaxation parameter)
        
        In addition, the following paramters are optional:
        
            maxiter : maximum number of iterations (default 100)
            
            reltol : relative tolerance (default 0.01). 
                        If rp < reltol and rd < reltol and iteration < maxiter, 
                        solver breaks and returns current value.
                        
            adaptive : boolean toggle on whether adaptive step size should be 
                        used. (default False)
            
            mu, tau, tauscale : parameters for adaptive step size (see paper)

            multiprocess : number of parallel processes (default 1). 
                            if multiprocess = 1, no parallelization is used.
                            
            blockdiagonal : boolean toggle on whether problem has block diagonal
                            correlative sparsity. Note that even if the problem
                            does have block-diagonal correlative sparsity, if
                            this parameter is set to False, then general mode 
                            is used. (default False)
                            

            verbose : toggle printout (default True)
            
            log_cputime : toggle whether cputime should be logged.
	    
	    
    The output is returned in a dictionary with the following files:
        
        x : primal variable in stacked form (X = [x0, ..., x_{N-1}]) where
            xk is the vectorized form of the nk x nk submatrix variable.
        
        y, z : iterates in Spingarn's method
        
        cputime, walltime : total cputime and walltime, respectively, spent in 
                            main loop. If log_cputime is False, then cputime is 
                            returned as 0.
        
        primal, rprimal, rdual : evolution of primal optimal value, primal 
                                residual, and dual residual (resp.)
        
        sigma : evolution of step size sigma (changes if adaptive step size is used.)
    

    """

    solvers.options['show_progress'] = False
    maxiter = kwargs.get('maxiter', 100)
    reltol = kwargs.get('reltol', 0.01)
    adaptive = kwargs.get('adaptive', False)
    mu = kwargs.get('mu', 2.0)
    tau = kwargs.get('tau', 1.5)
    multiprocess = kwargs.get('multiprocess', 1)
    tauscale = kwargs.get('tauscale', 0.9)
    blockdiagonal = kwargs.get('blockdiagonal', False)
    verbose = kwargs.get('verbose', True)
    log_cputime = kwargs.get('log_cputime', True)

    if log_cputime:
        try:
            import psutil
        except (ImportError):
            assert False, "Python package psutil required to log cputime. Package can be downloaded at http://code.google.com/p/psutil/"

    #format variables
    nl, ns = dims['l'], dims['s']
    C = C[nl:]
    L = L[nl:, :]
    As, bs = [], []
    cons = []
    offset = 0
    for k in xrange(len(ns)):
        Atmp = sparse(A[nl + offset:nl + offset + ns[k]**2, :])
        J = list(set(list(Atmp.J)))
        Atmp = Atmp[:, J]
        if len(sparse(Atmp).V) == Atmp[:].size[0]: Atmp = matrix(Atmp)
        else: Atmp = sparse(Atmp)
        As.append(Atmp)
        bs.append(b[J])
        cons.append(J)

        offset += ns[k]**2

    if blockdiagonal:
        if sum([len(c) for c in cons]) > len(b):
            print "Problem does not have block-diagonal correlative sparsity. Switching to general mode."
            blockdiagonal = False

    #If not block-diagonal correlative sprasity, represent A as a list of lists:
    #   A[i][j] is a matrix (or spmatrix) if ith clique involves jth constraint block
    #Otherwise, A is a list of matrices, where A[i] involves the ith clique and
    #ith constraint block only.

    if not blockdiagonal:
        while sum([len(c) for c in cons]) > len(b):
            tobreak = False
            for i in xrange(len(cons)):
                for j in xrange(i):
                    ci, cj = set(cons[i]), set(cons[j])
                    s1 = ci.intersection(cj)
                    if len(s1) > 0:
                        s2 = ci.difference(cj)
                        s3 = cj.difference(ci)
                        cons.append(list(s1))
                        if len(s2) > 0:
                            s2 = list(s2)
                            if not (s2 in cons): cons.append(s2)
                        if len(s3) > 0:
                            s3 = list(s3)
                            if not (s3 in cons): cons.append(s3)

                        cons.pop(i)
                        cons.pop(j)
                        tobreak = True

                        break
                if tobreak: break

        As, bs = [], []
        for i in xrange(len(cons)):
            J = cons[i]
            bs.append(b[J])
            Acol = []
            offset = 0
            for k in xrange(len(ns)):
                Atmp = sparse(A[nl + offset:nl + offset + ns[k]**2, J])
                if len(Atmp.V) == 0:
                    Acol.append(0)
                elif len(Atmp.V) == Atmp[:].size[0]:
                    Acol.append(matrix(Atmp))
                else:
                    Acol.append(Atmp)
                offset += ns[k]**2
            As.append(Acol)

    ms = [len(i) for i in bs]
    bs = matrix(bs)
    meq = L.size[1]

    if (not blockdiagonal) and multiprocess > 1:
        print "Multiprocessing mode can only be used if correlative sparsity is block diagonal. Switching to sequential mode."
        multiprocess = 1

    assert rho > 0 and rho < 2, 'Overrelaxaton parameter (rho) must be (strictly) between 0 and 2'

    # create routine for projecting on { x | L*x = 0 }
    #{ x | L*x = 0 } -> P = I - L*(L.T*L)i *L.T
    LTL = spmatrix([], [], [], (meq, meq))
    offset = 0
    for k in ns:
        Lk = L[offset:offset + k**2, :]
        base.syrk(Lk, LTL, trans='T', beta=1.0)
        offset += k**2
    LTLi = cholmod.symbolic(LTL, amd.order(LTL))
    cholmod.numeric(LTL, LTLi)

    #y = y - L*LTLi*L.T*y
    nssq = sum(matrix([nsk**2 for nsk in ns]))

    def proj(y, ip=True):
        if not ip: y = +y
        tmp = matrix(0.0, size=(meq, 1))

        ypre = +y
        base.gemv(L,y,tmp,trans='T',\
            m = nssq, n = meq, beta = 1)

        cholmod.solve(LTLi, tmp)
        base.gemv(L,tmp,y,beta=1.0,alpha=-1.0,trans='N',\
            m = nssq, n = meq)
        if not ip: return y

    time_to_solve = 0

    #initialize variables
    X = C * 0.0
    Y = +X
    Z = +X
    dualS = +X
    dualy = +b
    PXZ = +X

    proxargs = {
        'C': C,
        'A': As,
        'b': bs,
        'Z': Z,
        'X': X,
        'sigma': sigma,
        'dualS': dualS,
        'dualy': dualy,
        'ns': ns,
        'ms': ms,
        'multiprocess': multiprocess
    }

    if blockdiagonal: proxqp = proxqp_blockdiagonal(proxargs, proxqp)
    else: proxqp = proxqp_general

    if log_cputime: utime = psutil.cpu_times()[0]
    wtime = time.time()
    primal = []
    rpvec, rdvec = [], []
    sigmavec = []
    for it in xrange(maxiter):
        pv, gap = proxqp(proxargs)

        blas.copy(Z, Y)
        blas.axpy(X, Y, alpha=-2.0)
        proj(Y, ip=True)

        #PXZ = sigma*(X-Z)
        blas.copy(X, PXZ)
        blas.scal(sigma, PXZ)
        blas.axpy(Z, PXZ, alpha=-sigma)

        #z = z + rho*(y-x)
        blas.axpy(X, Y, alpha=1.0)
        blas.axpy(Y, Z, alpha=-rho)

        xzn = blas.nrm2(PXZ)
        xn = blas.nrm2(X)
        xyn = blas.nrm2(Y)
        proj(PXZ, ip=True)

        rdual = blas.nrm2(PXZ)
        rpri = sqrt(abs(xyn**2 - rdual**2)) / sigma

        if log_cputime: cputime = psutil.cpu_times()[0] - utime
        else: cputime = 0

        walltime = time.time() - wtime

        if rpri / max(xn, 1.0) < reltol and rdual / max(1.0, xzn) < reltol:
            break

        rpvec.append(rpri / max(xn, 1.0))
        rdvec.append(rdual / max(1.0, xzn))
        primal.append(pv)
        if adaptive:
            if (rdual / xzn * mu < rpri / xn):
                sigmanew = sigma * tau
            elif (rpri / xn * mu < rdual / xzn):
                sigmanew = sigma / tau
            else:
                sigmanew = sigma
            if it % 10 == 0 and it > 0 and tau > 1.0:
                tauscale *= 0.9
                tau = 1 + (tau - 1) * tauscale
            sigma = max(min(sigmanew, 10.0), 0.1)
        sigmavec.append(sigma)
        if verbose:
            if log_cputime:
                print "%d: primal = %e, gap = %e, (rp,rd) = (%e,%e), sigma = %f, (cputime,walltime) = (%f, %f)" % (
                    it, pv, gap, rpri / max(xn, 1.0), rdual / max(1.0, xzn),
                    sigma, cputime, walltime)
            else:
                print "%d: primal = %e, gap = %e, (rp,rd) = (%e,%e), sigma = %f, walltime = %f" % (
                    it, pv, gap, rpri / max(xn, 1.0), rdual / max(1.0, xzn),
                    sigma, walltime)

    sol = {}
    sol['x'] = X
    sol['y'] = Y
    sol['z'] = Z
    sol['cputime'] = cputime
    sol['walltime'] = walltime
    sol['primal'] = primal
    sol['rprimal'] = rpvec
    sol['rdual'] = rdvec
    sol['sigma'] = sigmavec
    return sol
Пример #9
0
    def factor(W, H=None, Df=None):

        if F['firstcall']:
            if type(G) is matrix:
                F['Gs'] = matrix(0.0, G.size)
            else:
                F['Gs'] = spmatrix(0.0, G.I, G.J, G.size)
            if mnl:
                if type(Df) is matrix:
                    F['Dfs'] = matrix(0.0, Df.size)
                else:
                    F['Dfs'] = spmatrix(0.0, Df.I, Df.J, Df.size)
            if (mnl and type(Df) is matrix) or type(G) is matrix or \
                    type(H) is matrix:
                F['S'] = matrix(0.0, (n, n))
                F['K'] = matrix(0.0, (p, p))
            else:
                F['S'] = spmatrix([], [], [], (n, n), 'd')
                F['Sf'] = None
                if type(A) is matrix:
                    F['K'] = matrix(0.0, (p, p))
                else:
                    F['K'] = spmatrix([], [], [], (p, p), 'd')

        # Dfs = Wnl^{-1} * Df
        if mnl:
            base.gemm(spmatrix(W['dnli'], list(range(mnl)),
                               list(range(mnl))), Df, F['Dfs'], partial=True)

        # Gs = Wl^{-1} * G.
        base.gemm(spmatrix(W['di'], list(range(ml)), list(range(ml))),
                  G, F['Gs'], partial=True)

        if F['firstcall']:
            base.syrk(F['Gs'], F['S'], trans='T')
            if mnl:
                base.syrk(F['Dfs'], F['S'], trans='T', beta=1.0)
            if H is not None:
                F['S'] += H
            try:
                if type(F['S']) is matrix:
                    lapack.potrf(F['S'])
                else:
                    F['Sf'] = cholmod.symbolic(F['S'])
                    cholmod.numeric(F['S'], F['Sf'])
            except ArithmeticError:
                F['singular'] = True
                if type(A) is matrix and type(F['S']) is spmatrix:
                    F['S'] = matrix(0.0, (n, n))
                base.syrk(F['Gs'], F['S'], trans='T')
                if mnl:
                    base.syrk(F['Dfs'], F['S'], trans='T', beta=1.0)
                base.syrk(A, F['S'], trans='T', beta=1.0)
                if H is not None:
                    F['S'] += H
                if type(F['S']) is matrix:
                    lapack.potrf(F['S'])
                else:
                    F['Sf'] = cholmod.symbolic(F['S'])
                    cholmod.numeric(F['S'], F['Sf'])
            F['firstcall'] = False

        else:
            base.syrk(F['Gs'], F['S'], trans='T', partial=True)
            if mnl:
                base.syrk(F['Dfs'], F['S'], trans='T', beta=1.0,
                          partial=True)
            if H is not None:
                F['S'] += H
            if F['singular']:
                base.syrk(A, F['S'], trans='T', beta=1.0, partial=True)
            if type(F['S']) is matrix:
                lapack.potrf(F['S'])
            else:
                cholmod.numeric(F['S'], F['Sf'])

        if type(F['S']) is matrix:
            # Asct := L^{-1}*A'.  Factor K = Asct'*Asct.
            if type(A) is matrix:
                Asct = A.T
            else:
                Asct = matrix(A.T)
            blas.trsm(F['S'], Asct)
            blas.syrk(Asct, F['K'], trans='T')
            lapack.potrf(F['K'])

        else:
            # Asct := L^{-1}*P*A'.  Factor K = Asct'*Asct.
            if type(A) is matrix:
                Asct = A.T
                cholmod.solve(F['Sf'], Asct, sys=7)
                cholmod.solve(F['Sf'], Asct, sys=4)
                blas.syrk(Asct, F['K'], trans='T')
                lapack.potrf(F['K'])
            else:
                Asct = cholmod.spsolve(F['Sf'], A.T, sys=7)
                Asct = cholmod.spsolve(F['Sf'], Asct, sys=4)
                base.syrk(Asct, F['K'], trans='T')
                Kf = cholmod.symbolic(F['K'])
                cholmod.numeric(F['K'], Kf)

        def solve(x, y, z):

            # Solve
            #
            #     [ H          A'  GG'*W^{-1} ]   [ ux   ]   [ bx        ]
            #     [ A          0   0          ] * [ uy   ] = [ by        ]
            #     [ W^{-T}*GG  0   -I         ]   [ W*uz ]   [ W^{-T}*bz ]
            #
            # and return ux, uy, W*uz.
            #
            # If not F['singular']:
            #
            #     K*uy = A * S^{-1} * ( bx + GG'*W^{-1}*W^{-T}*bz ) - by
            #     S*ux = bx + GG'*W^{-1}*W^{-T}*bz - A'*uy
            #     W*uz = W^{-T} * ( GG*ux - bz ).
            #
            # If F['singular']:
            #
            #     K*uy = A * S^{-1} * ( bx + GG'*W^{-1}*W^{-T}*bz + A'*by )
            #            - by
            #     S*ux = bx + GG'*W^{-1}*W^{-T}*bz + A'*by - A'*y.
            #     W*uz = W^{-T} * ( GG*ux - bz ).

            # z := W^{-1} * z = W^{-1} * bz
            scale(z, W, trans='T', inverse='I')

            # If not F['singular']:
            #     x := L^{-1} * P * (x + GGs'*z)
            #        = L^{-1} * P * (x + GG'*W^{-1}*W^{-T}*bz)
            #
            # If F['singular']:
            #     x := L^{-1} * P * (x + GGs'*z + A'*y))
            #        = L^{-1} * P * (x + GG'*W^{-1}*W^{-T}*bz + A'*y)

            if mnl:
                base.gemv(F['Dfs'], z, x, trans='T', beta=1.0)
            base.gemv(F['Gs'], z, x, offsetx=mnl, trans='T',
                      beta=1.0)
            if F['singular']:
                base.gemv(A, y, x, trans='T', beta=1.0)
            if type(F['S']) is matrix:
                blas.trsv(F['S'], x)
            else:
                cholmod.solve(F['Sf'], x, sys=7)
                cholmod.solve(F['Sf'], x, sys=4)

            # y := K^{-1} * (Asc*x - y)
            #    = K^{-1} * (A * S^{-1} * (bx + GG'*W^{-1}*W^{-T}*bz) - by)
            #      (if not F['singular'])
            #    = K^{-1} * (A * S^{-1} * (bx + GG'*W^{-1}*W^{-T}*bz +
            #      A'*by) - by)
            #      (if F['singular']).

            base.gemv(Asct, x, y, trans='T', beta=-1.0)
            if type(F['K']) is matrix:
                lapack.potrs(F['K'], y)
            else:
                cholmod.solve(Kf, y)

            # x := P' * L^{-T} * (x - Asc'*y)
            #    = S^{-1} * (bx + GG'*W^{-1}*W^{-T}*bz - A'*y)
            #      (if not F['singular'])
            #    = S^{-1} * (bx + GG'*W^{-1}*W^{-T}*bz + A'*by - A'*y)
            #      (if F['singular'])

            base.gemv(Asct, y, x, alpha=-1.0, beta=1.0)
            if type(F['S']) is matrix:
                blas.trsv(F['S'], x, trans='T')
            else:
                cholmod.solve(F['Sf'], x, sys=5)
                cholmod.solve(F['Sf'], x, sys=8)

            # W*z := GGs*x - z = W^{-T} * (GG*x - bz)
            if mnl:
                base.gemv(F['Dfs'], x, z, beta=-1.0)
            base.gemv(F['Gs'], x, z, beta=-1.0, offsety=mnl)

        return solve
Пример #10
0
    def F(W):

        for j in xrange(N):

            # SVD R[j] = U[j] * diag(sig[j]) * Vt[j]
            lapack.gesvd(+W['r'][j],
                         sv[j],
                         jobu='A',
                         jobvt='A',
                         U=U[j],
                         Vt=Vt[j])

            # Vt[j] := diag(sig[j])^-1 * Vt[j]
            for k in xrange(ns[j]):
                blas.tbsv(sv[j], Vt[j], n=ns[j], k=0, ldA=1, offsetx=k * ns[j])

            # Gamma[j] is an ns[j] x ns[j] symmetric matrix
            #
            #  (sig[j] * sig[j]') ./  sqrt(1 + rho * (sig[j] * sig[j]').^2)

            # S = sig[j] * sig[j]'
            S = matrix(0.0, (ns[j], ns[j]))
            blas.syrk(sv[j], S)
            Gamma[j][:] = div(S, sqrt(1.0 + rho * S**2))[:]
            symmetrize(Gamma[j], ns[j])

            # As represents the scaled mapping
            #
            #     As(x) = A(u * (Gamma .* x) * u')
            #    As'(y) = Gamma .* (u' * A'(y) * u)
            #
            # stored in a similar format as A, except that we use packed
            # storage for the columns of As[i][j].

            for i in xrange(M):

                if (type(A[i][j]) is matrix) or (type(A[i][j]) is spmatrix):

                    # As[i][j][:,k] = vec(
                    #     (U[j]' * mat( A[i][j][:,k] ) * U[j]) .* Gamma[j])

                    copy(A[i][j], As[i][j])
                    As[i][j] = matrix(As[i][j])
                    for k in xrange(ms[i]):
                        cngrnc(U[j],
                               As[i][j],
                               trans='T',
                               offsetx=k * (ns[j]**2),
                               n=ns[j])
                        blas.tbmv(Gamma[j],
                                  As[i][j],
                                  n=ns[j]**2,
                                  k=0,
                                  ldA=1,
                                  offsetx=k * (ns[j]**2))

                    # pack As[i][j] in place
                    #pack_ip(As[i][j], ns[j])
                    for k in xrange(As[i][j].size[1]):
                        tmp = +As[i][j][:, k]
                        misc.pack2(tmp, {'l': 0, 'q': [], 's': [ns[j]]})
                        As[i][j][:, k] = tmp

                else:
                    As[i][j] = 0.0

        # H is an m times m block matrix with i, k block
        #
        #      Hik = sum_j As[i,j]' * As[k,j]
        #
        # of size ms[i] x ms[k].  Hik = 0 if As[i,j] or As[k,j]
        # are zero for all j

        H = spmatrix([], [], [], (sum(ms), sum(ms)))
        rowid = 0
        for i in xrange(M):
            colid = 0
            for k in xrange(i + 1):
                sparse_block = True
                Hik = matrix(0.0, (ms[i], ms[k]))
                for j in xrange(N):
                    if (type(As[i][j]) is matrix) and \
                        (type(As[k][j]) is matrix):
                        sparse_block = False
                        # Hik += As[i,j]' * As[k,j]
                        if i == k:
                            blas.syrk(As[i][j],
                                      Hik,
                                      trans='T',
                                      beta=1.0,
                                      k=ns[j] * (ns[j] + 1) / 2,
                                      ldA=ns[j]**2)
                        else:
                            blas.gemm(As[i][j],
                                      As[k][j],
                                      Hik,
                                      transA='T',
                                      beta=1.0,
                                      k=ns[j] * (ns[j] + 1) / 2,
                                      ldA=ns[j]**2,
                                      ldB=ns[j]**2)
                if not (sparse_block):
                    H[rowid:rowid+ms[i], colid:colid+ms[k]] \
                        = sparse(Hik)
                colid += ms[k]
            rowid += ms[i]

        HF = cholmod.symbolic(H)
        cholmod.numeric(H, HF)

        def solve(x, y, z):
            """
            Returns solution of 

                rho * ux + A'(uy) - r^-T * uz * r^-1 = bx
                A(ux)                                = by
                -ux               - r * uz * r'      = bz.

            On entry, x = bx, y = by, z = bz.
            On exit, x = ux, y = uy, z = uz.
            """

            # bz is a copy of z in the format of x
            blas.copy(z, bz)
            # x := x + rho * bz
            #    = bx + rho * bz
            blas.axpy(bz, x, alpha=rho)

            # x := Gamma .* (u' * x * u)
            #    = Gamma .* (u' * (bx + rho * bz) * u)
            offsetj = 0
            for j in xrange(N):
                cngrnc(U[j], x, trans='T', offsetx=offsetj, n=ns[j])
                blas.tbmv(Gamma[j], x, n=ns[j]**2, k=0, ldA=1, offsetx=offsetj)
                offsetj += ns[j]**2

            # y := y - As(x)
            #   := by - As( Gamma .* u' * (bx + rho * bz) * u)

            blas.copy(x, xp)

            offsetj = 0
            for j in xrange(N):
                misc.pack2(xp, {'l': offsetj, 'q': [], 's': [ns[j]]})
                offsetj += ns[j]**2

            offseti = 0
            for i in xrange(M):
                offsetj = 0
                for j in xrange(N):
                    if type(As[i][j]) is matrix:
                        blas.gemv(As[i][j],
                                  xp,
                                  y,
                                  trans='T',
                                  alpha=-1.0,
                                  beta=1.0,
                                  m=ns[j] * (ns[j] + 1) / 2,
                                  n=ms[i],
                                  ldA=ns[j]**2,
                                  offsetx=offsetj,
                                  offsety=offseti)
                    offsetj += ns[j]**2
                offseti += ms[i]
            # y := -y - A(bz)
            #    = -by - A(bz) + As(Gamma .*  (u' * (bx + rho * bz) * u)

            Af(bz, y, alpha=-1.0, beta=-1.0)

            # y := H^-1 * y
            #    = H^-1 ( -by - A(bz) + As(Gamma.* u'*(bx + rho*bz)*u) )
            #    = uy

            cholmod.solve(HF, y)

            # bz = Vt' * vz * Vt
            #    = uz where
            # vz := Gamma .* ( As'(uy)  - x )
            #     = Gamma .* ( As'(uy)  - Gamma .* (u'*(bx + rho *bz)*u) )
            #     = Gamma.^2 .* ( u' * (A'(uy) - bx - rho * bz) * u ).
            blas.copy(x, xp)

            offsetj = 0
            for j in xrange(N):

                # xp is -x[j] = -Gamma .* (u' * (bx + rho*bz) * u)
                # in packed storage
                misc.pack2(xp, {'l': offsetj, 'q': [], 's': [ns[j]]})
                offsetj += ns[j]**2
            blas.scal(-1.0, xp)

            offsetj = 0
            for j in xrange(N):
                # xp +=  As'(uy)

                offseti = 0
                for i in xrange(M):
                    if type(As[i][j]) is matrix:
                        blas.gemv(As[i][j], y, xp, alpha = 1.0,
                             beta = 1.0, m = ns[j]*(ns[j]+1)/2, \
                                n = ms[i],ldA = ns[j]**2, \
                                offsetx = offseti, offsety = offsetj)
                    offseti += ms[i]

                # bz[j] is xp unpacked and multiplied with Gamma
                #unpack(xp, bz[j], ns[j])

                misc.unpack(xp,
                            bz, {
                                'l': 0,
                                'q': [],
                                's': [ns[j]]
                            },
                            offsetx=offsetj,
                            offsety=offsetj)

                blas.tbmv(Gamma[j],
                          bz,
                          n=ns[j]**2,
                          k=0,
                          ldA=1,
                          offsetx=offsetj)

                # bz = Vt' * bz * Vt
                #    = uz

                cngrnc(Vt[j], bz, trans='T', offsetx=offsetj, n=ns[j])
                symmetrize(bz, ns[j], offset=offsetj)
                offsetj += ns[j]**2

            # x = -bz - r * uz * r'
            blas.copy(z, x)
            blas.copy(bz, z)
            offsetj = 0
            for j in xrange(N):
                cngrnc(+W['r'][j], bz, offsetx=offsetj, n=ns[j])
                offsetj += ns[j]**2
            blas.axpy(bz, x)
            blas.scal(-1.0, x)

        return solve
Пример #11
0
from cvxopt import matrix, spmatrix, cholmod

A = spmatrix([10, 3, 5, -2, 5, 2], [0, 2, 1, 3, 2, 3], [0, 0, 1, 1, 2, 3])
X = matrix(range(8), (4,2), 'd')
F = cholmod.symbolic(A)
cholmod.numeric(A, F)
cholmod.solve(F, X)
print(X)
P = cvxopt.matrix(P)
print(cvxopt.matrix(list(map(lambda x: x != 1, abs(P))), P.size))
Пример #12
0
def covsel(Y):
    """
    Returns the solution of
 
        minimize    -log det K + tr(KY)
        subject to  K_ij = 0  if (i,j) not in zip(I, J).

    Y is a symmetric sparse matrix with nonzero diagonal elements.
    I = Y.I,  J = Y.J.
    """

    cholmod.options['supernodal'] = 2

    I, J = Y.I, Y.J
    n, m = Y.size[0], len(I) 
    # non-zero positions for one-argument indexing 
    N = I + J*n         
    # position of diagonal elements
    D = [ k for k in range(m) if I[k]==J[k] ]  

    # starting point: symmetric identity with nonzero pattern I,J
    K = spmatrix(0.0, I, J) 
    K[::n+1] = 1.0

    # Kn is used in the line search
    Kn = spmatrix(0.0, I, J)

    # symbolic factorization of K 
    F = cholmod.symbolic(K)

    # Kinv will be the inverse of K
    Kinv = matrix(0.0, (n,n))

    for iters in range(100):

        # numeric factorization of K
        cholmod.numeric(K, F)
        d = cholmod.diag(F)

        # compute Kinv by solving K*X = I 
        Kinv[:] = 0.0
        Kinv[::n+1] = 1.0
        cholmod.solve(F, Kinv)
        
        # solve Newton system
        grad = 2 * (Y.V - Kinv[N])
        hess = 2 * ( mul(Kinv[I,J], Kinv[J,I]) + 
               mul(Kinv[I,I], Kinv[J,J]) )
        v = -grad
        lapack.posv(hess,v) 
                                                  
        # stopping criterion
        sqntdecr = -blas.dot(grad,v) 
        print("Newton decrement squared:%- 7.5e" %sqntdecr)
        if (sqntdecr < 1e-12):
            print("number of iterations: %d" %(iters+1))
            break

        # line search
        dx = +v
        dx[D] *= 2      
        f = -2.0*sum(log(d))      # f = -log det K
        s = 1
        for lsiter in range(50):
            Kn.V = K.V + s*dx
            try: 
                cholmod.numeric(Kn, F)
            except ArithmeticError: 
                s *= 0.5
            else:
                d = cholmod.diag(F)
                fn = -2.0 * sum(log(d)) + 2*s*blas.dot(v,Y.V)
                if (fn < f - 0.01*s*sqntdecr): break
                else: s *= 0.5

        K.V = Kn.V

    return K
Пример #13
0
    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
Пример #14
0
    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