def f(x, y, z): # Solve for x[:n]: # # A*x[:n] = bx[:n] + P' * ( ((D1-D2)*(D1+D2)^{-1})*bx[n:] # + (2*D1*D2*(D1+D2)^{-1}) * (bz[:m] - bz[m:]) ). blas.copy((mul(div(d1 - d2, d1 + d2), x[n:]) + mul(2 * D, z[:m] - z[m:])), u) blas.gemv(P, u, x, beta=1.0, trans='T') lapack.potrs(A, x) # x[n:] := (D1+D2)^{-1} * (bx[n:] - D1*bz[:m] - D2*bz[m:] # + (D1-D2)*P*x[:n]) base.gemv(P, x, u) x[n:] = div( x[n:] - mul(d1, z[:m]) - mul(d2, z[m:]) + mul(d1 - d2, u), d1 + d2) # z[:m] := d1[:m] .* ( P*x[:n] - x[n:] - bz[:m]) # z[m:] := d2[m:] .* (-P*x[:n] - x[n:] - bz[m:]) z[:m] = mul(di[:m], u - x[n:] - z[:m]) z[m:] = mul(di[m:], -u - x[n:] - z[m:])
def Fgp(x = None, z = None): if x is None: return mnl, matrix(0.0, (n,1)) f = matrix(0.0, (mnl+1,1)) Df = matrix(0.0, (mnl+1,n)) # y = F*x+g blas.copy(g, y) base.gemv(F, x, y, beta=1.0) if z is not None: H = matrix(0.0, (n,n)) for i, start, stop in ind: # yi := exp(yi) = exp(Fi*x+gi) ymax = max(y[start:stop]) y[start:stop] = base.exp(y[start:stop] - ymax) # fi = log sum yi = log sum exp(Fi*x+gi) ysum = blas.asum(y, n=stop-start, offset=start) f[i] = ymax + math.log(ysum) # yi := yi / sum(yi) = exp(Fi*x+gi) / sum(exp(Fi*x+gi)) blas.scal(1.0/ysum, y, n=stop-start, offset=start) # gradfi := Fi' * yi # = Fi' * exp(Fi*x+gi) / sum(exp(Fi*x+gi)) base.gemv(F, y, Df, trans='T', m=stop-start, incy=mnl+1, offsetA=start, offsetx=start, offsety=i) if z is not None: # Hi = Fi' * (diag(yi) - yi*yi') * Fi # = Fisc' * Fisc # where # Fisc = diag(yi)^1/2 * (I - 1*yi') * Fi # = diag(yi)^1/2 * (Fi - 1*gradfi') Fsc[:K[i], :] = F[start:stop, :] for k in range(start,stop): blas.axpy(Df, Fsc, n=n, alpha=-1.0, incx=mnl+1, incy=Fsc.size[0], offsetx=i, offsety=k-start) blas.scal(math.sqrt(y[k]), Fsc, inc=Fsc.size[0], offset=k-start) # H += z[i]*Hi = z[i] * Fisc' * Fisc blas.syrk(Fsc, H, trans='T', k=stop-start, alpha=z[i], beta=1.0) if z is None: return f, Df return f, Df, H
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
def _gen_randsdp(self,V,m,d,seed): """ Random data generator """ setseed(seed) n = self._n V = chompack.tril(V) N = len(V) I = V.I; J = V.J Il = misc.sub2ind((n,n),I,J) Id = matrix([i for i in range(len(Il)) if I[i]==J[i]]) # generate random y with norm 1 y0 = normal(m,1) y0 /= blas.nrm2(y0) # generate random S0, X0 S0 = mk_rand(V,cone='posdef',seed=seed) X0 = mk_rand(V,cone='completable',seed=seed) # generate random A1,...,Am if type(d) is float: nz = min(max(1, int(round(d*N))), N) A = sparse([[spmatrix(normal(N,1),Il,[0 for i in range(N)],(n**2,1))], [spmatrix(normal(nz*m,1), [i for j in range(m) for i in random.sample(Il,nz)], [j for j in range(m) for i in range(nz)],(n**2,m))]]) elif type(d) is list: if len(d) == m: nz = [min(max(1, int(round(v*N))), N) for v in d] nnz = sum(nz) A = sparse([[spmatrix(normal(N,1),Il,[0 for i in range(N)],(n**2,1))], [spmatrix(normal(nnz,1), [i for j in range(m) for i in random.sample(Il,nz[j])], [j for j in range(m) for i in range(nz[j])],(n**2,m))]]) else: raise TypeError # compute A0 u = +S0.V for k in range(m): base.gemv(A[:,k+1][Il],matrix(y0[k]),u,beta=1.0,trans='N') A[Il,0] = u self._A = A # compute b X0[Il[Id]] *= 0.5 self._b = matrix(0.,(m,1)) u = matrix(0.) for k in range(m): base.gemv(A[:,k+1][Il],X0.V,u,trans='T',alpha=2.0) self._b[k] = u
def Gf(u, v, alpha=1.0, beta=0.0, trans='N'): if trans == 'N': # v[:m] := alpha * G * u[0] + beta * v[:m] base.gemv(G, u[0], v, alpha=alpha, beta=beta) # v[m:] := alpha * [-u[1], -A(u[0])'; -A(u[0]), -u[2]] # + beta * v[m:] blas.scal(beta, v, offset=m) v[m + I11] -= alpha * u[1][:] v[m + I21] -= alpha * A * u[0] v[m + I22] -= alpha * u[2][:] else: # v[0] := alpha * ( G.T * u[:m] - 2.0 * A.T * u[m + I21] ) # + beta v[1] base.gemv(G, u, v[0], trans='T', alpha=alpha, beta=beta) base.gemv(A, u[m + I21], v[0], trans='T', alpha=-2.0 * alpha, beta=1.0) # v[1] := -alpha * u[m + I11] + beta * v[1] blas.scal(beta, v[1]) blas.axpy(u[m + I11], v[1], alpha=-alpha) # v[2] := -alpha * u[m + I22] + beta * v[2] blas.scal(beta, v[2]) blas.axpy(u[m + I22], v[2], alpha=-alpha)
def Gf(u, v, alpha = 1.0, beta = 0.0, trans = 'N'): if trans == 'N': # v[:m] := alpha * G * u[0] + beta * v[:m] base.gemv(G, u[0], v, alpha = alpha, beta = beta) # v[m:] := alpha * [-u[1], -A(u[0])'; -A(u[0]), -u[2]] # + beta * v[m:] blas.scal(beta, v, offset = m) v[m + I11] -= alpha * u[1][:] v[m + I21] -= alpha * A * u[0] v[m + I22] -= alpha * u[2][:] else: # v[0] := alpha * ( G.T * u[:m] - 2.0 * A.T * u[m + I21] ) # + beta v[1] base.gemv(G, u, v[0], trans = 'T', alpha = alpha, beta = beta) base.gemv(A, u[m + I21], v[0], trans = 'T', alpha = -2.0*alpha, beta = 1.0) # v[1] := -alpha * u[m + I11] + beta * v[1] blas.scal(beta, v[1]) blas.axpy(u[m + I11], v[1], alpha = -alpha) # v[2] := -alpha * u[m + I22] + beta * v[2] blas.scal(beta, v[2]) blas.axpy(u[m + I22], v[2], alpha = -alpha)
def G(x, y, alpha=1.0, beta=0.0, trans='N'): """ Implements the linear operator [ -DX E -d -I ] [ 0 0 0 -I ] [ 0 -e_1' 0 0 ] G = [ -P_1' 0 0 0 ] [ . . . . ] [ 0 -e_k' 0 0 ] [ -P_k' 0 0 0 ] and its adjoint G'. """ if trans == 'N': tmp = +y[:m] # y[:m] = alpha*(-DXw + Et - d*b - v) + beta*y[:m] base.gemv(E, x[n:n + k], tmp, alpha=alpha, beta=beta) blas.axpy(x[n + k + 1:], tmp, alpha=-alpha) blas.axpy(d, tmp, alpha=-alpha * x[n + k]) y[:m] = tmp base.gemv(X, x[:n], tmp, alpha=alpha, beta=0.0) tmp = mul(d, tmp) y[:m] -= tmp # y[m:2*m] = -v y[m:2 * m] = -alpha * x[n + k + 1:] + beta * y[m:2 * m] # SOC 1,...,k for i in range(k): l = 2 * m + i * (n + 1) y[l] = -alpha * x[n + i] + beta * y[l] y[l + 1:l + 1 + n] = -alpha * P[i] * x[:n] + beta * y[l + 1:l + 1 + n] else: tmp1 = mul(d, x[:m]) tmp2 = y[:n] blas.gemv(X, tmp1, tmp2, trans='T', alpha=-alpha, beta=beta) for i in range(k): l = 2 * m + 1 + i * (n + 1) blas.gemv(P[i], x[l:l + n], tmp2, trans='T', alpha=-alpha, beta=1.0) y[:n] = tmp2 tmp2 = y[n:n + k] base.gemv(E, x[:m], tmp2, trans='T', alpha=alpha, beta=beta) blas.axpy(x[2 * m:2 * m + k * (1 + n):n + 1], tmp2, alpha=-alpha) y[n:n + k] = tmp2 y[n + k] = -alpha * blas.dot(d, x[:m]) + beta * y[n + k] y[n + k + 1:] = -alpha * (x[:m] + x[m:2 * m]) + beta * y[n + k + 1:]
def checksol(sol, A, B, C = None, d = None, G = None, h = None): """ Check optimality conditions C * x + G' * z + A'(Z) + d = 0 G * x <= h z >= 0, || Z || < = 1 z' * (h - G*x) = 0 tr (Z' * (A(x) + B)) = || A(x) + B ||_*. """ p, q = B.size n = A.size[1] if G is None: G = spmatrix([], [], [], (0, n)) if h is None: h = matrix(0.0, (0, 1)) m = h.size[0] if C is None: C = spmatrix(0.0, [], [], (n,n)) if d is None: d = matrix(0.0, (n, 1)) if sol['status'] is 'optimal': res = +d base.symv(C, sol['x'], res, beta = 1.0) base.gemv(G, sol['z'], res, beta = 1.0, trans = 'T') base.gemv(A, sol['Z'], res, beta = 1.0, trans = 'T') print "Dual residual: %e" %blas.nrm2(res) if m: print "Minimum primal slack (scalar inequalities): %e" \ %min(h - G*sol['x']) print "Minimum dual slack (scalar inequalities): %e" \ %min(sol['z']) if p: s = matrix(0.0, (p,1)) X = matrix(A*sol['x'], (p, q)) + B lapack.gesvd(+X, s) nrmX = sum(s) lapack.gesvd(+sol['Z'], s) nrmZ = max(s) print "Norm of Z: %e" %nrmZ print "Nuclear norm of A(x) + B: %e" %nrmX print "Inner product of Z and A(x) + B: %e" \ %blas.dot(sol['Z'], X) elif sol['status'] is 'primal infeasible': res = matrix(0.0, (n,1)) base.gemv(G, sol['z'], res, beta = 1.0, trans = 'T') print "Dual residual: %e" %blas.nrm2(res) print "h' * z = %e" %blas.dot(h, sol['z']) print "Minimum dual slack (scalar inequalities): %e" \ %min(sol['z']) else: pass
def checksol(sol, A, B, C=None, d=None, G=None, h=None): """ Check optimality conditions C * x + G' * z + A'(Z) + d = 0 G * x <= h z >= 0, || Z || < = 1 z' * (h - G*x) = 0 tr (Z' * (A(x) + B)) = || A(x) + B ||_*. """ p, q = B.size n = A.size[1] if G is None: G = spmatrix([], [], [], (0, n)) if h is None: h = matrix(0.0, (0, 1)) m = h.size[0] if C is None: C = spmatrix(0.0, [], [], (n, n)) if d is None: d = matrix(0.0, (n, 1)) if sol['status'] is 'optimal': res = +d base.symv(C, sol['x'], res, beta=1.0) base.gemv(G, sol['z'], res, beta=1.0, trans='T') base.gemv(A, sol['Z'], res, beta=1.0, trans='T') print "Dual residual: %e" % blas.nrm2(res) if m: print "Minimum primal slack (scalar inequalities): %e" \ %min(h - G*sol['x']) print "Minimum dual slack (scalar inequalities): %e" \ %min(sol['z']) if p: s = matrix(0.0, (p, 1)) X = matrix(A * sol['x'], (p, q)) + B lapack.gesvd(+X, s) nrmX = sum(s) lapack.gesvd(+sol['Z'], s) nrmZ = max(s) print "Norm of Z: %e" % nrmZ print "Nuclear norm of A(x) + B: %e" % nrmX print "Inner product of Z and A(x) + B: %e" \ %blas.dot(sol['Z'], X) elif sol['status'] is 'primal infeasible': res = matrix(0.0, (n, 1)) base.gemv(G, sol['z'], res, beta=1.0, trans='T') print "Dual residual: %e" % blas.nrm2(res) print "h' * z = %e" % blas.dot(h, sol['z']) print "Minimum dual slack (scalar inequalities): %e" \ %min(sol['z']) else: pass
def f(x, y, z): # Solve for x[:n]: # # A*x[:n] = bx[:n] + P' * ( ((D1-D2)*(D1+D2)^{-1})*bx[n:] # + (2*D1*D2*(D1+D2)^{-1}) * (bz[:m] - bz[m:]) ). blas.copy(( mul( div(d1-d2, d1+d2), x[n:]) + mul( 2*D, z[:m]-z[m:] ) ), u) blas.gemv(P, u, x, beta = 1.0, trans = 'T') lapack.potrs(A, x) # x[n:] := (D1+D2)^{-1} * (bx[n:] - D1*bz[:m] - D2*bz[m:] # + (D1-D2)*P*x[:n]) base.gemv(P, x, u) x[n:] = div( x[n:] - mul(d1, z[:m]) - mul(d2, z[m:]) + mul(d1-d2, u), d1+d2 ) # z[:m] := d1[:m] .* ( P*x[:n] - x[n:] - bz[:m]) # z[m:] := d2[m:] .* (-P*x[:n] - x[n:] - bz[m:]) z[:m] = mul(di[:m], u-x[n:]-z[:m]) z[m:] = mul(di[m:], -u-x[n:]-z[m:])
def G(x, y, alpha = 1.0, beta = 0.0, trans = 'N'): """ Implements the linear operator [ -DX E -d -I ] [ 0 0 0 -I ] [ 0 -e_1' 0 0 ] G = [ -P_1' 0 0 0 ] [ . . . . ] [ 0 -e_k' 0 0 ] [ -P_k' 0 0 0 ] and its adjoint G'. """ if trans == 'N': tmp = +y[:m] # y[:m] = alpha*(-DXw + Et - d*b - v) + beta*y[:m] base.gemv(E, x[n:n+k], tmp, alpha = alpha, beta = beta) blas.axpy(x[n+k+1:], tmp, alpha = -alpha) blas.axpy(d, tmp, alpha = -alpha*x[n+k]) y[:m] = tmp base.gemv(X, x[:n], tmp, alpha = alpha, beta = 0.0) tmp = mul(d,tmp) y[:m] -= tmp # y[m:2*m] = -v y[m:2*m] = -alpha * x[n+k+1:] + beta * y[m:2*m] # SOC 1,...,k for i in range(k): l = 2*m+i*(n+1) y[l] = -alpha * x[n+i] + beta * y[l] y[l+1:l+1+n] = -alpha * P[i] * x[:n] + beta * y[l+1:l+1+n]; else: tmp1 = mul(d,x[:m]) tmp2 = y[:n] blas.gemv(X, tmp1, tmp2, trans = 'T', alpha = -alpha, beta = beta) for i in range(k): l = 2*m+1+i*(n+1) blas.gemv(P[i], x[l:l+n], tmp2, trans = 'T', alpha = -alpha, beta = 1.0) y[:n] = tmp2 tmp2 = y[n:n+k] base.gemv(E, x[:m], tmp2, trans = 'T', alpha = alpha, beta = beta) blas.axpy(x[2*m:2*m+k*(1+n):n+1], tmp2, alpha = -alpha) y[n:n+k] = tmp2 y[n+k] = -alpha * blas.dot(d,x[:m]) + beta * y[n+k] y[n+k+1:] = -alpha * (x[:m] + x[m:2*m]) + beta * y[n+k+1:]
def f(x, y, z): """ Solve C * ux + G' * uzl - 2*A'(uzs21) = bx -uzs11 = bX1 -uzs22 = bX2 G * ux - D^2 * uzl = bzl [ -uX1 -A(ux)' ] [ uzs11 uzs21' ] [ ] - T * [ ] * T = bzs. [ -A(ux) -uX2 ] [ uzs21 uzs22 ] On entry, x = (bx, bX1, bX2) and z = [ bzl; bzs[:] ]. On exit, x = (ux, uX1, uX2) and z = [ D*uzl; (r'*uzs*r)[:] ]. Define X = uzs21, Z = T * uzs * T: C * ux + G' * uzl - 2*A'(X) = bx [ 0 X' ] [ bX1 0 ] T * [ ] * T - Z = T * [ ] * T [ X 0 ] [ 0 bX2 ] G * ux - D^2 * uzl = bzl [ -uX1 -A(ux)' ] [ Z11 Z21' ] [ ] - [ ] = bzs [ -A(ux) -uX2 ] [ Z21 Z22 ] Return x = (ux, uX1, uX2), z = [ D*uzl; (rti'*Z*rti)[:] ]. We use the congruence transformation [ V1 0 ] [ T11 T21' ] [ V1' 0 ] [ I S' ] [ ] [ ] [ ] = [ ] [ 0 V2' ] [ T21 T22 ] [ 0 V2 ] [ S I ] and the factorization X + S * X' * S = L( L'(X) ) to write this as C * ux + G' * uzl - 2*A'(X) = bx L'(V2^-1 * X * V1^-1) - L^-1(V2' * Z21 * V1') = bX G * ux - D^2 * uzl = bzl [ -uX1 -A(ux)' ] [ Z11 Z21' ] [ ] - [ ] = bzs, [ -A(ux) -uX2 ] [ Z21 Z22 ] or C * ux + Gs' * uuzl - 2*As'(XX) = bx XX - ZZ21 = bX Gs * ux - uuzl = D^-1 * bzl -As(ux) - ZZ21 = bbzs_21 -uX1 - Z11 = bzs_11 -uX2 - Z22 = bzs_22 if we introduce scaled variables uuzl = D * uzl XX = L'(V2^-1 * X * V1^-1) = L'(V2^-1 * uzs21 * V1^-1) ZZ21 = L^-1(V2' * Z21 * V1') and define bbzs_21 = L^-1(V2' * bzs_21 * V1') [ bX1 0 ] bX = L^-1( V2' * (T * [ ] * T)_21 * V1'). [ 0 bX2 ] Eliminating Z21 gives C * ux + Gs' * uuzl - 2*As'(XX) = bx Gs * ux - uuzl = D^-1 * bzl -As(ux) - XX = bbzs_21 - bX -uX1 - Z11 = bzs_11 -uX2 - Z22 = bzs_22 and eliminating uuzl and XX gives H * ux = bx + Gs' * D^-1 * bzl + 2*As'(bX - bbzs_21) Gs * ux - uuzl = D^-1 * bzl -As(ux) - XX = bbzs_21 - bX -uX1 - Z11 = bzs_11 -uX2 - Z22 = bzs_22. In summary, we can use the following algorithm: 1. bXX := bX - bbzs21 [ bX1 0 ] = L^-1( V2' * ((T * [ ] * T)_21 - bzs_21) * V1') [ 0 bX2 ] 2. Solve H * ux = bx + Gs' * D^-1 * bzl + 2*As'(bXX). 3. From ux, compute uuzl = Gs*ux - D^-1 * bzl and X = V2 * L^-T(-As(ux) + bXX) * V1. 4. Return ux, uuzl, rti' * Z * rti = r' * [ -bX1, X'; X, -bX2 ] * r and uX1 = -Z11 - bzs_11, uX2 = -Z22 - bzs_22. """ # Save bzs_11, bzs_22, bzs_21. lapack.lacpy(z, bz11, uplo = 'L', m = q, n = q, ldA = p+q, offsetA = m) lapack.lacpy(z, bz21, m = p, n = q, ldA = p+q, offsetA = m+q) lapack.lacpy(z, bz22, uplo = 'L', m = p, n = p, ldA = p+q, offsetA = m + (p+q+1)*q) # zl := D^-1 * zl # = D^-1 * bzl blas.tbmv(W['di'], z, n = m, k = 0, ldA = 1) # zs := r' * [ bX1, 0; 0, bX2 ] * r. # zs := [ bX1, 0; 0, bX2 ] blas.scal(0.0, z, offset = m) lapack.lacpy(x[1], z, uplo = 'L', m = q, n = q, ldB = p+q, offsetB = m) lapack.lacpy(x[2], z, uplo = 'L', m = p, n = p, ldB = p+q, offsetB = m + (p+q+1)*q) # scale diagonal of zs by 1/2 blas.scal(0.5, z, inc = p+q+1, offset = m) # a := tril(zs)*r blas.copy(r, a) blas.trmm(z, a, side = 'L', m = p+q, n = p+q, ldA = p+q, ldB = p+q, offsetA = m) # zs := a'*r + r'*a blas.syr2k(r, a, z, trans = 'T', n = p+q, k = p+q, ldB = p+q, ldC = p+q, offsetC = m) # bz21 := L^-1( V2' * ((r * zs * r')_21 - bz21) * V1') # # [ bX1 0 ] # = L^-1( V2' * ((T * [ ] * T)_21 - bz21) * V1'). # [ 0 bX2 ] # a = [ r21 r22 ] * z # = [ r21 r22 ] * r' * [ bX1, 0; 0, bX2 ] * r # = [ T21 T22 ] * [ bX1, 0; 0, bX2 ] * r blas.symm(z, r, a, side = 'R', m = p, n = p+q, ldA = p+q, ldC = p+q, offsetB = q) # bz21 := -bz21 + a * [ r11, r12 ]' # = -bz21 + (T * [ bX1, 0; 0, bX2 ] * T)_21 blas.gemm(a, r, bz21, transB = 'T', m = p, n = q, k = p+q, beta = -1.0, ldA = p+q, ldC = p) # bz21 := V2' * bz21 * V1' # = V2' * (-bz21 + (T*[bX1, 0; 0, bX2]*T)_21) * V1' blas.gemm(V2, bz21, tmp, transA = 'T', m = p, n = q, k = p, ldB = p) blas.gemm(tmp, V1, bz21, transB = 'T', m = p, n = q, k = q, ldC = p) # bz21[:] := D * (I-P) * bz21[:] # = L^-1 * bz21[:] # = bXX[:] blas.copy(bz21, tmp) base.gemv(P, bz21, tmp, alpha = -1.0, beta = 1.0) base.gemv(D, tmp, bz21) # Solve H * ux = bx + Gs' * D^-1 * bzl + 2*As'(bXX). # x[0] := x[0] + Gs'*zl + 2*As'(bz21) # = bx + G' * D^-1 * bzl + 2 * As'(bXX) blas.gemv(Gs, z, x[0], trans = 'T', alpha = 1.0, beta = 1.0) blas.gemv(As, bz21, x[0], trans = 'T', alpha = 2.0, beta = 1.0) # x[0] := H \ x[0] # = ux lapack.potrs(H, x[0]) # uuzl = Gs*ux - D^-1 * bzl blas.gemv(Gs, x[0], z, alpha = 1.0, beta = -1.0) # bz21 := V2 * L^-T(-As(ux) + bz21) * V1 # = X blas.gemv(As, x[0], bz21, alpha = -1.0, beta = 1.0) blas.tbsv(DV, bz21, n = p*q, k = 0, ldA = 1) blas.copy(bz21, tmp) base.gemv(P, tmp, bz21, alpha = -1.0, beta = 1.0, trans = 'T') blas.gemm(V2, bz21, tmp) blas.gemm(tmp, V1, bz21) # zs := -zs + r' * [ 0, X'; X, 0 ] * r # = r' * [ -bX1, X'; X, -bX2 ] * r. # a := bz21 * [ r11, r12 ] # = X * [ r11, r12 ] blas.gemm(bz21, r, a, m = p, n = p+q, k = q, ldA = p, ldC = p+q) # z := -z + [ r21, r22 ]' * a + a' * [ r21, r22 ] # = rti' * uzs * rti blas.syr2k(r, a, z, trans = 'T', beta = -1.0, n = p+q, k = p, offsetA = q, offsetC = m, ldB = p+q, ldC = p+q) # uX1 = -Z11 - bzs_11 # = -(r*zs*r')_11 - bzs_11 # uX2 = -Z22 - bzs_22 # = -(r*zs*r')_22 - bzs_22 blas.copy(bz11, x[1]) blas.copy(bz22, x[2]) # scale diagonal of zs by 1/2 blas.scal(0.5, z, inc = p+q+1, offset = m) # a := r*tril(zs) blas.copy(r, a) blas.trmm(z, a, side = 'R', m = p+q, n = p+q, ldA = p+q, ldB = p+q, offsetA = m) # x[1] := -x[1] - a[:q,:] * r[:q, :]' - r[:q,:] * a[:q,:]' # = -bzs_11 - (r*zs*r')_11 blas.syr2k(a, r, x[1], n = q, alpha = -1.0, beta = -1.0) # x[2] := -x[2] - a[q:,:] * r[q:, :]' - r[q:,:] * a[q:,:]' # = -bzs_22 - (r*zs*r')_22 blas.syr2k(a, r, x[2], n = p, alpha = -1.0, beta = -1.0, offsetA = q, offsetB = q) # scale diagonal of zs by 1/2 blas.scal(2.0, z, inc = p+q+1, offset = m)
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 f(x, y, z): """ Solve C * ux + G' * uzl - 2*A'(uzs21) = bx -uzs11 = bX1 -uzs22 = bX2 G * ux - D^2 * uzl = bzl [ -uX1 -A(ux)' ] [ uzs11 uzs21' ] [ ] - T * [ ] * T = bzs. [ -A(ux) -uX2 ] [ uzs21 uzs22 ] On entry, x = (bx, bX1, bX2) and z = [ bzl; bzs[:] ]. On exit, x = (ux, uX1, uX2) and z = [ D*uzl; (r'*uzs*r)[:] ]. Define X = uzs21, Z = T * uzs * T: C * ux + G' * uzl - 2*A'(X) = bx [ 0 X' ] [ bX1 0 ] T * [ ] * T - Z = T * [ ] * T [ X 0 ] [ 0 bX2 ] G * ux - D^2 * uzl = bzl [ -uX1 -A(ux)' ] [ Z11 Z21' ] [ ] - [ ] = bzs [ -A(ux) -uX2 ] [ Z21 Z22 ] Return x = (ux, uX1, uX2), z = [ D*uzl; (rti'*Z*rti)[:] ]. We use the congruence transformation [ V1 0 ] [ T11 T21' ] [ V1' 0 ] [ I S' ] [ ] [ ] [ ] = [ ] [ 0 V2' ] [ T21 T22 ] [ 0 V2 ] [ S I ] and the factorization X + S * X' * S = L( L'(X) ) to write this as C * ux + G' * uzl - 2*A'(X) = bx L'(V2^-1 * X * V1^-1) - L^-1(V2' * Z21 * V1') = bX G * ux - D^2 * uzl = bzl [ -uX1 -A(ux)' ] [ Z11 Z21' ] [ ] - [ ] = bzs, [ -A(ux) -uX2 ] [ Z21 Z22 ] or C * ux + Gs' * uuzl - 2*As'(XX) = bx XX - ZZ21 = bX Gs * ux - uuzl = D^-1 * bzl -As(ux) - ZZ21 = bbzs_21 -uX1 - Z11 = bzs_11 -uX2 - Z22 = bzs_22 if we introduce scaled variables uuzl = D * uzl XX = L'(V2^-1 * X * V1^-1) = L'(V2^-1 * uzs21 * V1^-1) ZZ21 = L^-1(V2' * Z21 * V1') and define bbzs_21 = L^-1(V2' * bzs_21 * V1') [ bX1 0 ] bX = L^-1( V2' * (T * [ ] * T)_21 * V1'). [ 0 bX2 ] Eliminating Z21 gives C * ux + Gs' * uuzl - 2*As'(XX) = bx Gs * ux - uuzl = D^-1 * bzl -As(ux) - XX = bbzs_21 - bX -uX1 - Z11 = bzs_11 -uX2 - Z22 = bzs_22 and eliminating uuzl and XX gives H * ux = bx + Gs' * D^-1 * bzl + 2*As'(bX - bbzs_21) Gs * ux - uuzl = D^-1 * bzl -As(ux) - XX = bbzs_21 - bX -uX1 - Z11 = bzs_11 -uX2 - Z22 = bzs_22. In summary, we can use the following algorithm: 1. bXX := bX - bbzs21 [ bX1 0 ] = L^-1( V2' * ((T * [ ] * T)_21 - bzs_21) * V1') [ 0 bX2 ] 2. Solve H * ux = bx + Gs' * D^-1 * bzl + 2*As'(bXX). 3. From ux, compute uuzl = Gs*ux - D^-1 * bzl and X = V2 * L^-T(-As(ux) + bXX) * V1. 4. Return ux, uuzl, rti' * Z * rti = r' * [ -bX1, X'; X, -bX2 ] * r and uX1 = -Z11 - bzs_11, uX2 = -Z22 - bzs_22. """ # Save bzs_11, bzs_22, bzs_21. lapack.lacpy(z, bz11, uplo='L', m=q, n=q, ldA=p + q, offsetA=m) lapack.lacpy(z, bz21, m=p, n=q, ldA=p + q, offsetA=m + q) lapack.lacpy(z, bz22, uplo='L', m=p, n=p, ldA=p + q, offsetA=m + (p + q + 1) * q) # zl := D^-1 * zl # = D^-1 * bzl blas.tbmv(W['di'], z, n=m, k=0, ldA=1) # zs := r' * [ bX1, 0; 0, bX2 ] * r. # zs := [ bX1, 0; 0, bX2 ] blas.scal(0.0, z, offset=m) lapack.lacpy(x[1], z, uplo='L', m=q, n=q, ldB=p + q, offsetB=m) lapack.lacpy(x[2], z, uplo='L', m=p, n=p, ldB=p + q, offsetB=m + (p + q + 1) * q) # scale diagonal of zs by 1/2 blas.scal(0.5, z, inc=p + q + 1, offset=m) # a := tril(zs)*r blas.copy(r, a) blas.trmm(z, a, side='L', m=p + q, n=p + q, ldA=p + q, ldB=p + q, offsetA=m) # zs := a'*r + r'*a blas.syr2k(r, a, z, trans='T', n=p + q, k=p + q, ldB=p + q, ldC=p + q, offsetC=m) # bz21 := L^-1( V2' * ((r * zs * r')_21 - bz21) * V1') # # [ bX1 0 ] # = L^-1( V2' * ((T * [ ] * T)_21 - bz21) * V1'). # [ 0 bX2 ] # a = [ r21 r22 ] * z # = [ r21 r22 ] * r' * [ bX1, 0; 0, bX2 ] * r # = [ T21 T22 ] * [ bX1, 0; 0, bX2 ] * r blas.symm(z, r, a, side='R', m=p, n=p + q, ldA=p + q, ldC=p + q, offsetB=q) # bz21 := -bz21 + a * [ r11, r12 ]' # = -bz21 + (T * [ bX1, 0; 0, bX2 ] * T)_21 blas.gemm(a, r, bz21, transB='T', m=p, n=q, k=p + q, beta=-1.0, ldA=p + q, ldC=p) # bz21 := V2' * bz21 * V1' # = V2' * (-bz21 + (T*[bX1, 0; 0, bX2]*T)_21) * V1' blas.gemm(V2, bz21, tmp, transA='T', m=p, n=q, k=p, ldB=p) blas.gemm(tmp, V1, bz21, transB='T', m=p, n=q, k=q, ldC=p) # bz21[:] := D * (I-P) * bz21[:] # = L^-1 * bz21[:] # = bXX[:] blas.copy(bz21, tmp) base.gemv(P, bz21, tmp, alpha=-1.0, beta=1.0) base.gemv(D, tmp, bz21) # Solve H * ux = bx + Gs' * D^-1 * bzl + 2*As'(bXX). # x[0] := x[0] + Gs'*zl + 2*As'(bz21) # = bx + G' * D^-1 * bzl + 2 * As'(bXX) blas.gemv(Gs, z, x[0], trans='T', alpha=1.0, beta=1.0) blas.gemv(As, bz21, x[0], trans='T', alpha=2.0, beta=1.0) # x[0] := H \ x[0] # = ux lapack.potrs(H, x[0]) # uuzl = Gs*ux - D^-1 * bzl blas.gemv(Gs, x[0], z, alpha=1.0, beta=-1.0) # bz21 := V2 * L^-T(-As(ux) + bz21) * V1 # = X blas.gemv(As, x[0], bz21, alpha=-1.0, beta=1.0) blas.tbsv(DV, bz21, n=p * q, k=0, ldA=1) blas.copy(bz21, tmp) base.gemv(P, tmp, bz21, alpha=-1.0, beta=1.0, trans='T') blas.gemm(V2, bz21, tmp) blas.gemm(tmp, V1, bz21) # zs := -zs + r' * [ 0, X'; X, 0 ] * r # = r' * [ -bX1, X'; X, -bX2 ] * r. # a := bz21 * [ r11, r12 ] # = X * [ r11, r12 ] blas.gemm(bz21, r, a, m=p, n=p + q, k=q, ldA=p, ldC=p + q) # z := -z + [ r21, r22 ]' * a + a' * [ r21, r22 ] # = rti' * uzs * rti blas.syr2k(r, a, z, trans='T', beta=-1.0, n=p + q, k=p, offsetA=q, offsetC=m, ldB=p + q, ldC=p + q) # uX1 = -Z11 - bzs_11 # = -(r*zs*r')_11 - bzs_11 # uX2 = -Z22 - bzs_22 # = -(r*zs*r')_22 - bzs_22 blas.copy(bz11, x[1]) blas.copy(bz22, x[2]) # scale diagonal of zs by 1/2 blas.scal(0.5, z, inc=p + q + 1, offset=m) # a := r*tril(zs) blas.copy(r, a) blas.trmm(z, a, side='R', m=p + q, n=p + q, ldA=p + q, ldB=p + q, offsetA=m) # x[1] := -x[1] - a[:q,:] * r[:q, :]' - r[:q,:] * a[:q,:]' # = -bzs_11 - (r*zs*r')_11 blas.syr2k(a, r, x[1], n=q, alpha=-1.0, beta=-1.0) # x[2] := -x[2] - a[q:,:] * r[q:, :]' - r[q:,:] * a[q:,:]' # = -bzs_22 - (r*zs*r')_22 blas.syr2k(a, r, x[2], n=p, alpha=-1.0, beta=-1.0, offsetA=q, offsetB=q) # scale diagonal of zs by 1/2 blas.scal(2.0, z, inc=p + q + 1, offset=m)
def F(W): """ Custom solver for the system [ It 0 0 Xt' 0 At1' ... Atk' ][ dwt ] [ rwt ] [ 0 0 0 -d' 0 0 ... 0 ][ db ] [ rb ] [ 0 0 0 -I -I 0 ... 0 ][ dv ] [ rv ] [ Xt -d -I -Wl1^-2 ][ dzl1 ] [ rl1 ] [ 0 0 -I -Wl2^-2 ][ dzl2 ] = [ rl2 ] [ At1 0 0 -W1^-2 ][ dz1 ] [ r1 ] [ | | | . ][ | ] [ | ] [ Atk 0 0 -Wk^-2 ][ dzk ] [ rk ] where It = [ I 0 ] Xt = [ -D*X E ] Ati = [ 0 -e_i' ] [ 0 0 ] [ -Pi 0 ] dwt = [ dw ] rwt = [ rw ] [ dt ] [ rt ]. """ # scalings and 'intermediate' vectors # db = inv(Wl1)^2 + inv(Wl2)^2 db = W['di'][:m]**2 + W['di'][m:2*m]**2 dbi = div(1.0,db) # dt = I - inv(Wl1)*Dbi*inv(Wl1) dt = 1.0 - mul(W['di'][:m]**2,dbi) dtsqrt = sqrt(dt) # lam = Dt*inv(Wl1)*d lam = mul(dt,mul(W['di'][:m],d)) # lt = E'*inv(Wl1)*lam lt = matrix(0.0,(k,1)) base.gemv(E, mul(W['di'][:m],lam), lt, trans = 'T') # Xs = sqrt(Dt)*inv(Wl1)*X tmp = mul(dtsqrt,W['di'][:m]) Xs = spmatrix(tmp,range(m),range(m))*X # Es = D*sqrt(Dt)*inv(Wl1)*E Es = spmatrix(mul(d,tmp),range(m),range(m))*E # form Ab = I + sum((1/bi)^2*(Pi'*Pi + 4*(v'*v + 1)*Pi'*y*y'*Pi)) + Xs'*Xs # and Bb = -sum((1/bi)^2*(4*ui*v'*v*Pi'*y*ei')) - Xs'*Es # and D2 = Es'*Es + sum((1/bi)^2*(1+4*ui^2*(v'*v - 1)) Ab = matrix(0.0,(n,n)) Ab[::n+1] = 1.0 base.syrk(Xs,Ab,trans = 'T', beta = 1.0) Bb = matrix(0.0,(n,k)) Bb = -Xs.T*Es # inefficient!? D2 = spmatrix(0.0,range(k),range(k)) base.syrk(Es,D2,trans = 'T', partial = True) d2 = +D2.V del D2 py = matrix(0.0,(n,1)) for i in range(k): binvsq = (1.0/W['beta'][i])**2 Ab += binvsq*Pt[i] dvv = blas.dot(W['v'][i],W['v'][i]) blas.gemv(P[i], W['v'][i][1:], py, trans = 'T', alpha = 1.0, beta = 0.0) blas.syrk(py, Ab, alpha = 4*binvsq*(dvv+1), beta = 1.0) Bb[:,i] -= 4*binvsq*W['v'][i][0]*dvv*py d2[i] += binvsq*(1+4*(W['v'][i][0]**2)*(dvv-1)) d2i = div(1.0,d2) d2isqrt = sqrt(d2i) # compute a = alpha - lam'*inv(Wl1)*E*inv(D2)*E'*inv(Wl1)*lam alpha = blas.dot(lam,mul(W['di'][:m],d)) tmp = matrix(0.0,(k,1)) base.gemv(E,mul(W['di'][:m],lam), tmp, trans = 'T') tmp = mul(tmp, d2isqrt) #tmp = inv(D2)^(1/2)*E'*inv(Wl1)*lam a = alpha - blas.dot(tmp,tmp) # compute M12 = X'*D*inv(Wl1)*lam + Bb*inv(D2)*E'*inv(Wl1)*lam tmp = mul(tmp, d2isqrt) M12 = matrix(0.0,(n,1)) blas.gemv(Bb,tmp,M12, alpha = 1.0) tmp = mul(d,mul(W['di'][:m],lam)) blas.gemv(X,tmp,M12, trans = 'T', alpha = 1.0, beta = 1.0) # form and factor M sBb = Bb * spmatrix(d2isqrt,range(k), range(k)) base.syrk(sBb, Ab, alpha = -1.0, beta = 1.0) M = matrix([[Ab, M12.T],[M12, a]]) lapack.potrf(M) def f(x,y,z): # residuals rwt = x[:n+k] rb = x[n+k] rv = x[n+k+1:n+k+1+m] iw_rl1 = mul(W['di'][:m],z[:m]) iw_rl2 = mul(W['di'][m:2*m],z[m:2*m]) ri = [z[2*m+i*(n+1):2*m+(i+1)*(n+1)] for i in range(k)] # compute 'derived' residuals # rbwt = rwt + sum(Ai'*inv(Wi)^2*ri) + [-X'*D; E']*inv(Wl1)^2*rl1 rbwt = +rwt for i in range(k): tmp = +ri[i] qscal(tmp,W['beta'][i],W['v'][i],inv=True) qscal(tmp,W['beta'][i],W['v'][i],inv=True) rbwt[n+i] -= tmp[0] blas.gemv(P[i], tmp[1:], rbwt, trans = 'T', alpha = -1.0, beta = 1.0) tmp = mul(W['di'][:m],iw_rl1) tmp2 = matrix(0.0,(k,1)) base.gemv(E,tmp,tmp2,trans='T') rbwt[n:] += tmp2 tmp = mul(d,tmp) # tmp = D*inv(Wl1)^2*rl1 blas.gemv(X,tmp,rbwt,trans='T', alpha = -1.0, beta = 1.0) # rbb = rb - d'*inv(Wl1)^2*rl1 rbb = rb - sum(tmp) # rbv = rv - inv(Wl2)*rl2 - inv(Wl1)^2*rl1 rbv = rv - mul(W['di'][m:2*m],iw_rl2) - mul(W['di'][:m],iw_rl1) # [rtw;rtt] = rbwt + [-X'*D; E']*inv(Wl1)^2*inv(Db)*rbv tmp = mul(W['di'][:m]**2, mul(dbi,rbv)) rtt = +rbwt[n:] base.gemv(E, tmp, rtt, trans = 'T', alpha = 1.0, beta = 1.0) rtw = +rbwt[:n] tmp = mul(d,tmp) blas.gemv(X, tmp, rtw, trans = 'T', alpha = -1.0, beta = 1.0) # rtb = rbb - d'*inv(Wl1)^2*inv(Db)*rbv rtb = rbb - sum(tmp) # solve M*[dw;db] = [rtw - Bb*inv(D2)*rtt; rtb + lt'*inv(D2)*rtt] tmp = mul(d2i,rtt) tmp2 = matrix(0.0,(n,1)) blas.gemv(Bb,tmp,tmp2) dwdb = matrix([rtw - tmp2,rtb + blas.dot(mul(d2i,lt),rtt)]) lapack.potrs(M,dwdb) # compute dt = inv(D2)*(rtt - Bb'*dw + lt*db) tmp2 = matrix(0.0,(k,1)) blas.gemv(Bb, dwdb[:n], tmp2, trans='T') dt = mul(d2i, rtt - tmp2 + lt*dwdb[-1]) # compute dv = inv(Db)*(rbv + inv(Wl1)^2*(E*dt - D*X*dw - d*db)) dv = matrix(0.0,(m,1)) blas.gemv(X,dwdb[:n],dv,alpha = -1.0) dv = mul(d,dv) - d*dwdb[-1] base.gemv(E, dt, dv, beta = 1.0) tmp = +dv # tmp = E*dt - D*X*dw - d*db dv = mul(dbi, rbv + mul(W['di'][:m]**2,dv)) # compute wdz1 = inv(Wl1)*(E*dt - D*X*dw - d*db - dv - rl1) wdz1 = mul(W['di'][:m], tmp - dv) - iw_rl1 # compute wdz2 = - inv(Wl2)*(dv + rl2) wdz2 = - mul(W['di'][m:2*m],dv) - iw_rl2 # compute wdzi = inv(Wi)*([-ei'*dt; -Pi*dw] - ri) wdzi = [] tmp = matrix(0.0,(n,1)) for i in range(k): blas.gemv(P[i],dwdb[:n],tmp, alpha = -1.0, beta = 0.0) tmp1 = matrix([-dt[i],tmp]) blas.axpy(ri[i],tmp1,alpha = -1.0) qscal(tmp1,W['beta'][i],W['v'][i],inv=True) wdzi.append(tmp1) # solution x[:n] = dwdb[:n] x[n:n+k] = dt x[n+k] = dwdb[-1] x[n+k+1:] = dv z[:m] = wdz1 z[m:2*m] = wdz2 for i in range(k): z[2*m+i*(n+1):2*m+(i+1)*(n+1)] = wdzi[i] return f
def f(x,y,z): # residuals rwt = x[:n+k] rb = x[n+k] rv = x[n+k+1:n+k+1+m] iw_rl1 = mul(W['di'][:m],z[:m]) iw_rl2 = mul(W['di'][m:2*m],z[m:2*m]) ri = [z[2*m+i*(n+1):2*m+(i+1)*(n+1)] for i in range(k)] # compute 'derived' residuals # rbwt = rwt + sum(Ai'*inv(Wi)^2*ri) + [-X'*D; E']*inv(Wl1)^2*rl1 rbwt = +rwt for i in range(k): tmp = +ri[i] qscal(tmp,W['beta'][i],W['v'][i],inv=True) qscal(tmp,W['beta'][i],W['v'][i],inv=True) rbwt[n+i] -= tmp[0] blas.gemv(P[i], tmp[1:], rbwt, trans = 'T', alpha = -1.0, beta = 1.0) tmp = mul(W['di'][:m],iw_rl1) tmp2 = matrix(0.0,(k,1)) base.gemv(E,tmp,tmp2,trans='T') rbwt[n:] += tmp2 tmp = mul(d,tmp) # tmp = D*inv(Wl1)^2*rl1 blas.gemv(X,tmp,rbwt,trans='T', alpha = -1.0, beta = 1.0) # rbb = rb - d'*inv(Wl1)^2*rl1 rbb = rb - sum(tmp) # rbv = rv - inv(Wl2)*rl2 - inv(Wl1)^2*rl1 rbv = rv - mul(W['di'][m:2*m],iw_rl2) - mul(W['di'][:m],iw_rl1) # [rtw;rtt] = rbwt + [-X'*D; E']*inv(Wl1)^2*inv(Db)*rbv tmp = mul(W['di'][:m]**2, mul(dbi,rbv)) rtt = +rbwt[n:] base.gemv(E, tmp, rtt, trans = 'T', alpha = 1.0, beta = 1.0) rtw = +rbwt[:n] tmp = mul(d,tmp) blas.gemv(X, tmp, rtw, trans = 'T', alpha = -1.0, beta = 1.0) # rtb = rbb - d'*inv(Wl1)^2*inv(Db)*rbv rtb = rbb - sum(tmp) # solve M*[dw;db] = [rtw - Bb*inv(D2)*rtt; rtb + lt'*inv(D2)*rtt] tmp = mul(d2i,rtt) tmp2 = matrix(0.0,(n,1)) blas.gemv(Bb,tmp,tmp2) dwdb = matrix([rtw - tmp2,rtb + blas.dot(mul(d2i,lt),rtt)]) lapack.potrs(M,dwdb) # compute dt = inv(D2)*(rtt - Bb'*dw + lt*db) tmp2 = matrix(0.0,(k,1)) blas.gemv(Bb, dwdb[:n], tmp2, trans='T') dt = mul(d2i, rtt - tmp2 + lt*dwdb[-1]) # compute dv = inv(Db)*(rbv + inv(Wl1)^2*(E*dt - D*X*dw - d*db)) dv = matrix(0.0,(m,1)) blas.gemv(X,dwdb[:n],dv,alpha = -1.0) dv = mul(d,dv) - d*dwdb[-1] base.gemv(E, dt, dv, beta = 1.0) tmp = +dv # tmp = E*dt - D*X*dw - d*db dv = mul(dbi, rbv + mul(W['di'][:m]**2,dv)) # compute wdz1 = inv(Wl1)*(E*dt - D*X*dw - d*db - dv - rl1) wdz1 = mul(W['di'][:m], tmp - dv) - iw_rl1 # compute wdz2 = - inv(Wl2)*(dv + rl2) wdz2 = - mul(W['di'][m:2*m],dv) - iw_rl2 # compute wdzi = inv(Wi)*([-ei'*dt; -Pi*dw] - ri) wdzi = [] tmp = matrix(0.0,(n,1)) for i in range(k): blas.gemv(P[i],dwdb[:n],tmp, alpha = -1.0, beta = 0.0) tmp1 = matrix([-dt[i],tmp]) blas.axpy(ri[i],tmp1,alpha = -1.0) qscal(tmp1,W['beta'][i],W['v'][i],inv=True) wdzi.append(tmp1) # solution x[:n] = dwdb[:n] x[n:n+k] = dt x[n+k] = dwdb[-1] x[n+k+1:] = dv z[:m] = wdz1 z[m:2*m] = wdz2 for i in range(k): z[2*m+i*(n+1):2*m+(i+1)*(n+1)] = wdzi[i]
def f(x, y, z): # residuals rwt = x[:n + k] rb = x[n + k] rv = x[n + k + 1:n + k + 1 + m] iw_rl1 = mul(W['di'][:m], z[:m]) iw_rl2 = mul(W['di'][m:2 * m], z[m:2 * m]) ri = [ z[2 * m + i * (n + 1):2 * m + (i + 1) * (n + 1)] for i in range(k) ] # compute 'derived' residuals # rbwt = rwt + sum(Ai'*inv(Wi)^2*ri) + [-X'*D; E']*inv(Wl1)^2*rl1 rbwt = +rwt for i in range(k): tmp = +ri[i] qscal(tmp, W['beta'][i], W['v'][i], inv=True) qscal(tmp, W['beta'][i], W['v'][i], inv=True) rbwt[n + i] -= tmp[0] blas.gemv(P[i], tmp[1:], rbwt, trans='T', alpha=-1.0, beta=1.0) tmp = mul(W['di'][:m], iw_rl1) tmp2 = matrix(0.0, (k, 1)) base.gemv(E, tmp, tmp2, trans='T') rbwt[n:] += tmp2 tmp = mul(d, tmp) # tmp = D*inv(Wl1)^2*rl1 blas.gemv(X, tmp, rbwt, trans='T', alpha=-1.0, beta=1.0) # rbb = rb - d'*inv(Wl1)^2*rl1 rbb = rb - sum(tmp) # rbv = rv - inv(Wl2)*rl2 - inv(Wl1)^2*rl1 rbv = rv - mul(W['di'][m:2 * m], iw_rl2) - mul(W['di'][:m], iw_rl1) # [rtw;rtt] = rbwt + [-X'*D; E']*inv(Wl1)^2*inv(Db)*rbv tmp = mul(W['di'][:m]**2, mul(dbi, rbv)) rtt = +rbwt[n:] base.gemv(E, tmp, rtt, trans='T', alpha=1.0, beta=1.0) rtw = +rbwt[:n] tmp = mul(d, tmp) blas.gemv(X, tmp, rtw, trans='T', alpha=-1.0, beta=1.0) # rtb = rbb - d'*inv(Wl1)^2*inv(Db)*rbv rtb = rbb - sum(tmp) # solve M*[dw;db] = [rtw - Bb*inv(D2)*rtt; rtb + lt'*inv(D2)*rtt] tmp = mul(d2i, rtt) tmp2 = matrix(0.0, (n, 1)) blas.gemv(Bb, tmp, tmp2) dwdb = matrix([rtw - tmp2, rtb + blas.dot(mul(d2i, lt), rtt)]) lapack.potrs(M, dwdb) # compute dt = inv(D2)*(rtt - Bb'*dw + lt*db) tmp2 = matrix(0.0, (k, 1)) blas.gemv(Bb, dwdb[:n], tmp2, trans='T') dt = mul(d2i, rtt - tmp2 + lt * dwdb[-1]) # compute dv = inv(Db)*(rbv + inv(Wl1)^2*(E*dt - D*X*dw - d*db)) dv = matrix(0.0, (m, 1)) blas.gemv(X, dwdb[:n], dv, alpha=-1.0) dv = mul(d, dv) - d * dwdb[-1] base.gemv(E, dt, dv, beta=1.0) tmp = +dv # tmp = E*dt - D*X*dw - d*db dv = mul(dbi, rbv + mul(W['di'][:m]**2, dv)) # compute wdz1 = inv(Wl1)*(E*dt - D*X*dw - d*db - dv - rl1) wdz1 = mul(W['di'][:m], tmp - dv) - iw_rl1 # compute wdz2 = - inv(Wl2)*(dv + rl2) wdz2 = -mul(W['di'][m:2 * m], dv) - iw_rl2 # compute wdzi = inv(Wi)*([-ei'*dt; -Pi*dw] - ri) wdzi = [] tmp = matrix(0.0, (n, 1)) for i in range(k): blas.gemv(P[i], dwdb[:n], tmp, alpha=-1.0, beta=0.0) tmp1 = matrix([-dt[i], tmp]) blas.axpy(ri[i], tmp1, alpha=-1.0) qscal(tmp1, W['beta'][i], W['v'][i], inv=True) wdzi.append(tmp1) # solution x[:n] = dwdb[:n] x[n:n + k] = dt x[n + k] = dwdb[-1] x[n + k + 1:] = dv z[:m] = wdz1 z[m:2 * m] = wdz2 for i in range(k): z[2 * m + i * (n + 1):2 * m + (i + 1) * (n + 1)] = wdzi[i]
def _gen_randsdp(self, V, m, d, seed): """ Random data generator """ setseed(seed) n = self._n V = chompack.tril(V) N = len(V) I = V.I J = V.J Il = misc.sub2ind((n, n), I, J) Id = matrix([i for i in xrange(len(Il)) if I[i] == J[i]]) # generate random y with norm 1 y0 = normal(m, 1) y0 /= blas.nrm2(y0) # generate random S0, X0 S0 = mk_rand(V, cone='posdef', seed=seed) X0 = mk_rand(V, cone='completable', seed=seed) # generate random A1,...,Am if type(d) is float: nz = min(max(1, int(round(d * N))), N) A = sparse( [[ spmatrix(normal(N, 1), Il, [0 for i in xrange(N)], (n**2, 1)) ], [ spmatrix( normal(nz * m, 1), [i for j in xrange(m) for i in random.sample(Il, nz)], [j for j in xrange(m) for i in xrange(nz)], (n**2, m)) ]]) elif type(d) is list: if len(d) == m: nz = [min(max(1, int(round(v * N))), N) for v in d] nnz = sum(nz) A = sparse( [[ spmatrix(normal(N, 1), Il, [0 for i in xrange(N)], (n**2, 1)) ], [ spmatrix(normal(nnz, 1), [ i for j in xrange(m) for i in random.sample(Il, nz[j]) ], [j for j in xrange(m) for i in xrange(nz[j])], (n**2, m)) ]]) else: raise TypeError # compute A0 u = +S0.V for k in xrange(m): base.gemv(A[:, k + 1][Il], matrix(y0[k]), u, beta=1.0, trans='N') A[Il, 0] = u self._A = A # compute b X0[Il[Id]] *= 0.5 self._b = matrix(0., (m, 1)) u = matrix(0.) for k in xrange(m): base.gemv(A[:, k + 1][Il], X0.V, u, trans='T', alpha=2.0) self._b[k] = u
def Fgp(x=None, z=None): if x is None: return mnl, matrix(0.0, (n, 1)) f = matrix(0.0, (mnl + 1, 1)) Df = matrix(0.0, (mnl + 1, n)) # y = F*x+g blas.copy(g, y) base.gemv(F, x, y, beta=1.0) if z is not None: H = matrix(0.0, (n, n)) for i, start, stop in ind: # yi := exp(yi) = exp(Fi*x+gi) ymax = max(y[start:stop]) y[start:stop] = base.exp(y[start:stop] - ymax) # fi = log sum yi = log sum exp(Fi*x+gi) ysum = blas.asum(y, n=stop - start, offset=start) f[i] = ymax + math.log(ysum) # yi := yi / sum(yi) = exp(Fi*x+gi) / sum(exp(Fi*x+gi)) blas.scal(1.0 / ysum, y, n=stop - start, offset=start) # gradfi := Fi' * yi # = Fi' * exp(Fi*x+gi) / sum(exp(Fi*x+gi)) base.gemv(F, y, Df, trans='T', m=stop - start, incy=mnl + 1, offsetA=start, offsetx=start, offsety=i) if z is not None: # Hi = Fi' * (diag(yi) - yi*yi') * Fi # = Fisc' * Fisc # where # Fisc = diag(yi)^1/2 * (I - 1*yi') * Fi # = diag(yi)^1/2 * (Fi - 1*gradfi') Fsc[:K[i], :] = F[start:stop, :] for k in range(start, stop): blas.axpy(Df, Fsc, n=n, alpha=-1.0, incx=mnl + 1, incy=Fsc.size[0], offsetx=i, offsety=k - start) blas.scal(math.sqrt(y[k]), Fsc, inc=Fsc.size[0], offset=k - start) # H += z[i]*Hi = z[i] * Fisc' * Fisc blas.syrk(Fsc, H, trans='T', k=stop - start, alpha=z[i], beta=1.0) if z is None: return f, Df return f, Df, H
def fA(x, y, trans='N', alpha=1.0, beta=0.0): base.gemv(A, x, y, trans=trans, alpha=alpha, beta=beta)
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)
def F(W): """ Custom solver for the system [ It 0 0 Xt' 0 At1' ... Atk' ][ dwt ] [ rwt ] [ 0 0 0 -d' 0 0 ... 0 ][ db ] [ rb ] [ 0 0 0 -I -I 0 ... 0 ][ dv ] [ rv ] [ Xt -d -I -Wl1^-2 ][ dzl1 ] [ rl1 ] [ 0 0 -I -Wl2^-2 ][ dzl2 ] = [ rl2 ] [ At1 0 0 -W1^-2 ][ dz1 ] [ r1 ] [ | | | . ][ | ] [ | ] [ Atk 0 0 -Wk^-2 ][ dzk ] [ rk ] where It = [ I 0 ] Xt = [ -D*X E ] Ati = [ 0 -e_i' ] [ 0 0 ] [ -Pi 0 ] dwt = [ dw ] rwt = [ rw ] [ dt ] [ rt ]. """ # scalings and 'intermediate' vectors # db = inv(Wl1)^2 + inv(Wl2)^2 db = W['di'][:m]**2 + W['di'][m:2 * m]**2 dbi = div(1.0, db) # dt = I - inv(Wl1)*Dbi*inv(Wl1) dt = 1.0 - mul(W['di'][:m]**2, dbi) dtsqrt = sqrt(dt) # lam = Dt*inv(Wl1)*d lam = mul(dt, mul(W['di'][:m], d)) # lt = E'*inv(Wl1)*lam lt = matrix(0.0, (k, 1)) base.gemv(E, mul(W['di'][:m], lam), lt, trans='T') # Xs = sqrt(Dt)*inv(Wl1)*X tmp = mul(dtsqrt, W['di'][:m]) Xs = spmatrix(tmp, range(m), range(m)) * X # Es = D*sqrt(Dt)*inv(Wl1)*E Es = spmatrix(mul(d, tmp), range(m), range(m)) * E # form Ab = I + sum((1/bi)^2*(Pi'*Pi + 4*(v'*v + 1)*Pi'*y*y'*Pi)) + Xs'*Xs # and Bb = -sum((1/bi)^2*(4*ui*v'*v*Pi'*y*ei')) - Xs'*Es # and D2 = Es'*Es + sum((1/bi)^2*(1+4*ui^2*(v'*v - 1)) Ab = matrix(0.0, (n, n)) Ab[::n + 1] = 1.0 base.syrk(Xs, Ab, trans='T', beta=1.0) Bb = matrix(0.0, (n, k)) Bb = -Xs.T * Es # inefficient!? D2 = spmatrix(0.0, range(k), range(k)) base.syrk(Es, D2, trans='T', partial=True) d2 = +D2.V del D2 py = matrix(0.0, (n, 1)) for i in range(k): binvsq = (1.0 / W['beta'][i])**2 Ab += binvsq * Pt[i] dvv = blas.dot(W['v'][i], W['v'][i]) blas.gemv(P[i], W['v'][i][1:], py, trans='T', alpha=1.0, beta=0.0) blas.syrk(py, Ab, alpha=4 * binvsq * (dvv + 1), beta=1.0) Bb[:, i] -= 4 * binvsq * W['v'][i][0] * dvv * py d2[i] += binvsq * (1 + 4 * (W['v'][i][0]**2) * (dvv - 1)) d2i = div(1.0, d2) d2isqrt = sqrt(d2i) # compute a = alpha - lam'*inv(Wl1)*E*inv(D2)*E'*inv(Wl1)*lam alpha = blas.dot(lam, mul(W['di'][:m], d)) tmp = matrix(0.0, (k, 1)) base.gemv(E, mul(W['di'][:m], lam), tmp, trans='T') tmp = mul(tmp, d2isqrt) #tmp = inv(D2)^(1/2)*E'*inv(Wl1)*lam a = alpha - blas.dot(tmp, tmp) # compute M12 = X'*D*inv(Wl1)*lam + Bb*inv(D2)*E'*inv(Wl1)*lam tmp = mul(tmp, d2isqrt) M12 = matrix(0.0, (n, 1)) blas.gemv(Bb, tmp, M12, alpha=1.0) tmp = mul(d, mul(W['di'][:m], lam)) blas.gemv(X, tmp, M12, trans='T', alpha=1.0, beta=1.0) # form and factor M sBb = Bb * spmatrix(d2isqrt, range(k), range(k)) base.syrk(sBb, Ab, alpha=-1.0, beta=1.0) M = matrix([[Ab, M12.T], [M12, a]]) lapack.potrf(M) def f(x, y, z): # residuals rwt = x[:n + k] rb = x[n + k] rv = x[n + k + 1:n + k + 1 + m] iw_rl1 = mul(W['di'][:m], z[:m]) iw_rl2 = mul(W['di'][m:2 * m], z[m:2 * m]) ri = [ z[2 * m + i * (n + 1):2 * m + (i + 1) * (n + 1)] for i in range(k) ] # compute 'derived' residuals # rbwt = rwt + sum(Ai'*inv(Wi)^2*ri) + [-X'*D; E']*inv(Wl1)^2*rl1 rbwt = +rwt for i in range(k): tmp = +ri[i] qscal(tmp, W['beta'][i], W['v'][i], inv=True) qscal(tmp, W['beta'][i], W['v'][i], inv=True) rbwt[n + i] -= tmp[0] blas.gemv(P[i], tmp[1:], rbwt, trans='T', alpha=-1.0, beta=1.0) tmp = mul(W['di'][:m], iw_rl1) tmp2 = matrix(0.0, (k, 1)) base.gemv(E, tmp, tmp2, trans='T') rbwt[n:] += tmp2 tmp = mul(d, tmp) # tmp = D*inv(Wl1)^2*rl1 blas.gemv(X, tmp, rbwt, trans='T', alpha=-1.0, beta=1.0) # rbb = rb - d'*inv(Wl1)^2*rl1 rbb = rb - sum(tmp) # rbv = rv - inv(Wl2)*rl2 - inv(Wl1)^2*rl1 rbv = rv - mul(W['di'][m:2 * m], iw_rl2) - mul(W['di'][:m], iw_rl1) # [rtw;rtt] = rbwt + [-X'*D; E']*inv(Wl1)^2*inv(Db)*rbv tmp = mul(W['di'][:m]**2, mul(dbi, rbv)) rtt = +rbwt[n:] base.gemv(E, tmp, rtt, trans='T', alpha=1.0, beta=1.0) rtw = +rbwt[:n] tmp = mul(d, tmp) blas.gemv(X, tmp, rtw, trans='T', alpha=-1.0, beta=1.0) # rtb = rbb - d'*inv(Wl1)^2*inv(Db)*rbv rtb = rbb - sum(tmp) # solve M*[dw;db] = [rtw - Bb*inv(D2)*rtt; rtb + lt'*inv(D2)*rtt] tmp = mul(d2i, rtt) tmp2 = matrix(0.0, (n, 1)) blas.gemv(Bb, tmp, tmp2) dwdb = matrix([rtw - tmp2, rtb + blas.dot(mul(d2i, lt), rtt)]) lapack.potrs(M, dwdb) # compute dt = inv(D2)*(rtt - Bb'*dw + lt*db) tmp2 = matrix(0.0, (k, 1)) blas.gemv(Bb, dwdb[:n], tmp2, trans='T') dt = mul(d2i, rtt - tmp2 + lt * dwdb[-1]) # compute dv = inv(Db)*(rbv + inv(Wl1)^2*(E*dt - D*X*dw - d*db)) dv = matrix(0.0, (m, 1)) blas.gemv(X, dwdb[:n], dv, alpha=-1.0) dv = mul(d, dv) - d * dwdb[-1] base.gemv(E, dt, dv, beta=1.0) tmp = +dv # tmp = E*dt - D*X*dw - d*db dv = mul(dbi, rbv + mul(W['di'][:m]**2, dv)) # compute wdz1 = inv(Wl1)*(E*dt - D*X*dw - d*db - dv - rl1) wdz1 = mul(W['di'][:m], tmp - dv) - iw_rl1 # compute wdz2 = - inv(Wl2)*(dv + rl2) wdz2 = -mul(W['di'][m:2 * m], dv) - iw_rl2 # compute wdzi = inv(Wi)*([-ei'*dt; -Pi*dw] - ri) wdzi = [] tmp = matrix(0.0, (n, 1)) for i in range(k): blas.gemv(P[i], dwdb[:n], tmp, alpha=-1.0, beta=0.0) tmp1 = matrix([-dt[i], tmp]) blas.axpy(ri[i], tmp1, alpha=-1.0) qscal(tmp1, W['beta'][i], W['v'][i], inv=True) wdzi.append(tmp1) # solution x[:n] = dwdb[:n] x[n:n + k] = dt x[n + k] = dwdb[-1] x[n + k + 1:] = dv z[:m] = wdz1 z[m:2 * m] = wdz2 for i in range(k): z[2 * m + i * (n + 1):2 * m + (i + 1) * (n + 1)] = wdzi[i] return f
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