def l1(P, q): """ Returns the solution u of the ell-1 approximation problem (primal) minimize ||P*u - q||_1 (dual) maximize q'*w subject to P'*w = 0 ||w||_infty <= 1. """ m, n = P.size # Solve equivalent LP # # minimize [0; 1]' * [u; v] # subject to [P, -I; -P, -I] * [u; v] <= [q; -q] # # maximize -[q; -q]' * z # subject to [P', -P']*z = 0 # [-I, -I]*z + 1 = 0 # z >= 0 c = matrix(n * [0.0] + m * [1.0]) h = matrix([q, -q]) def Fi(x, y, alpha=1.0, beta=0.0, trans='N'): if trans == 'N': # y := alpha * [P, -I; -P, -I] * x + beta*y u = P * x[:n] y[:m] = alpha * (u - x[n:]) + beta * y[:m] y[m:] = alpha * (-u - x[n:]) + beta * y[m:] else: # y := alpha * [P', -P'; -I, -I] * x + beta*y y[:n] = alpha * P.T * (x[:m] - x[m:]) + beta * y[:n] y[n:] = -alpha * (x[:m] + x[m:]) + beta * y[n:] def Fkkt(W): # Returns a function f(x, y, z) that solves # # [ 0 0 P' -P' ] [ x[:n] ] [ bx[:n] ] # [ 0 0 -I -I ] [ x[n:] ] [ bx[n:] ] # [ P -I -W1^2 0 ] [ z[:m] ] = [ bz[:m] ] # [-P -I 0 -W2 ] [ z[m:] ] [ bz[m:] ] # # On entry bx, bz are stored in x, z. # On exit x, z contain the solution, with z scaled (W['di'] .* z is # returned instead of z). d1, d2 = W['d'][:m], W['d'][m:] D = 4 * (d1**2 + d2**2)**-1 A = P.T * spdiag(D) * P lapack.potrf(A) def f(x, y, z): x[:n] += P.T * (mul(div(d2**2 - d1**2, d1**2 + d2**2), x[n:]) + mul(.5 * D, z[:m] - z[m:])) lapack.potrs(A, x) u = P * x[:n] x[n:] = div( x[n:] - div(z[:m], d1**2) - div(z[m:], d2**2) + mul(d1**-2 - d2**-2, u), d1**-2 + d2**-2) z[:m] = div(u - x[n:] - z[:m], d1) z[m:] = div(-u - x[n:] - z[m:], d2) return f # Initial primal and dual points from least-squares solution. # uls minimizes ||P*u-q||_2; rls is the LS residual. uls = +q lapack.gels(+P, uls) rls = P * uls[:n] - q # x0 = [ uls; 1.1*abs(rls) ]; s0 = [q;-q] - [P,-I; -P,-I] * x0 x0 = matrix([uls[:n], 1.1 * abs(rls)]) s0 = +h Fi(x0, s0, alpha=-1, beta=1) # z0 = [ (1+w)/2; (1-w)/2 ] where w = (.9/||rls||_inf) * rls # if rls is nonzero and w = 0 otherwise. if max(abs(rls)) > 1e-10: w = .9 / max(abs(rls)) * rls else: w = matrix(0.0, (m, 1)) z0 = matrix([.5 * (1 + w), .5 * (1 - w)]) dims = {'l': 2 * m, 'q': [], 's': []} sol = solvers.conelp(c, Fi, h, dims, kktsolver=Fkkt, primalstart={ 'x': x0, 's': s0 }, dualstart={'z': z0}) return sol['x'][:n], sol['status']
def l1blas(P, q): """ Returns the solution u of the ell-1 approximation problem (primal) minimize ||P*u - q||_1 (dual) maximize q'*w subject to P'*w = 0 ||w||_infty <= 1. """ m, n = P.size # Solve equivalent LP # # minimize [0; 1]' * [u; v] # subject to [P, -I; -P, -I] * [u; v] <= [q; -q] # # maximize -[q; -q]' * z # subject to [P', -P']*z = 0 # [-I, -I]*z + 1 = 0 # z >= 0 c = matrix(n * [0.0] + m * [1.0]) h = matrix([q, -q]) u = matrix(0.0, (m, 1)) Ps = matrix(0.0, (m, n)) A = matrix(0.0, (n, n)) def Fi(x, y, alpha=1.0, beta=0.0, trans='N'): if trans == 'N': # y := alpha * [P, -I; -P, -I] * x + beta*y blas.gemv(P, x, u) y[:m] = alpha * (u - x[n:]) + beta * y[:m] y[m:] = alpha * (-u - x[n:]) + beta * y[m:] else: # y := alpha * [P', -P'; -I, -I] * x + beta*y blas.copy(x[:m] - x[m:], u) blas.gemv(P, u, y, alpha=alpha, beta=beta, trans='T') y[n:] = -alpha * (x[:m] + x[m:]) + beta * y[n:] def Fkkt(W): # Returns a function f(x, y, z) that solves # # [ 0 0 P' -P' ] [ x[:n] ] [ bx[:n] ] # [ 0 0 -I -I ] [ x[n:] ] [ bx[n:] ] # [ P -I -D1^{-1} 0 ] [ z[:m] ] = [ bz[:m] ] # [-P -I 0 -D2^{-1} ] [ z[m:] ] [ bz[m:] ] # # where D1 = diag(di[:m])^2, D2 = diag(di[m:])^2 and di = W['di']. # # On entry bx, bz are stored in x, z. # On exit x, z contain the solution, with z scaled (di .* z is # returned instead of z). # Factor A = 4*P'*D*P where D = d1.*d2 ./(d1+d2) and # d1 = d[:m].^2, d2 = d[m:].^2. di = W['di'] d1, d2 = di[:m]**2, di[m:]**2 D = div(mul(d1, d2), d1 + d2) Ds = spdiag(2 * sqrt(D)) base.gemm(Ds, P, Ps) blas.syrk(Ps, A, trans='T') lapack.potrf(A) 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:]) return f # Initial primal and dual points from least-squares solution. # uls minimizes ||P*u-q||_2; rls is the LS residual. uls = +q lapack.gels(+P, uls) rls = P * uls[:n] - q # x0 = [ uls; 1.1*abs(rls) ]; s0 = [q;-q] - [P,-I; -P,-I] * x0 x0 = matrix([uls[:n], 1.1 * abs(rls)]) s0 = +h Fi(x0, s0, alpha=-1, beta=1) # z0 = [ (1+w)/2; (1-w)/2 ] where w = (.9/||rls||_inf) * rls # if rls is nonzero and w = 0 otherwise. if max(abs(rls)) > 1e-10: w = .9 / max(abs(rls)) * rls else: w = matrix(0.0, (m, 1)) z0 = matrix([.5 * (1 + w), .5 * (1 - w)]) dims = {'l': 2 * m, 'q': [], 's': []} sol = solvers.conelp(c, Fi, h, dims, kktsolver=Fkkt, primalstart={ 'x': x0, 's': s0 }, dualstart={'z': z0}) return sol['x'][:n], sol['status']
def qcl1(A, b): """ Returns the solution u, z of (primal) minimize || u ||_1 subject to || A * u - b ||_2 <= 1 (dual) maximize b^T z - ||z||_2 subject to || A'*z ||_inf <= 1. Exploits structure, assuming A is m by n with m >= n. """ m, n = A.size # Solve equivalent cone LP with variables x = [u; v]: # # minimize [0; 1]' * x # subject to [ I -I ] * x <= [ 0 ] (componentwise) # [-I -I ] * x <= [ 0 ] (componentwise) # [ 0 0 ] * x <= [ 1 ] (SOC) # [-A 0 ] [ -b ]. # # maximize -t + b' * w # subject to z1 - z2 = A'*w # z1 + z2 = 1 # z1 >= 0, z2 >=0, ||w||_2 <= t. c = matrix(n*[0.0] + n*[1.0]) h = matrix( 0.0, (2*n + m + 1, 1)) h[2*n] = 1.0 h[2*n+1:] = -b def G(x, y, alpha = 1.0, beta = 0.0, trans = 'N'): y *= beta if trans=='N': # y += alpha * G * x y[:n] += alpha * (x[:n] - x[n:2*n]) y[n:2*n] += alpha * (-x[:n] - x[n:2*n]) y[2*n+1:] -= alpha * A*x[:n] else: # y += alpha * G'*x y[:n] += alpha * (x[:n] - x[n:2*n] - A.T * x[-m:]) y[n:] -= alpha * (x[:n] + x[n:2*n]) def Fkkt(W): # Returns a function f(x, y, z) that solves # # [ 0 G' ] [ x ] = [ bx ] # [ G -W'*W ] [ z ] [ bz ]. # First factor # # S = G' * W**-1 * W**-T * G # = [0; -A]' * W3^-2 * [0; -A] + 4 * (W1**2 + W2**2)**-1 # # where # # W1 = diag(d1) with d1 = W['d'][:n] = 1 ./ W['di'][:n] # W2 = diag(d2) with d2 = W['d'][n:] = 1 ./ W['di'][n:] # W3 = beta * (2*v*v' - J), W3^-1 = 1/beta * (2*J*v*v'*J - J) # with beta = W['beta'][0], v = W['v'][0], J = [1, 0; 0, -I]. # As = W3^-1 * [ 0 ; -A ] = 1/beta * ( 2*J*v * v' - I ) * [0; A] beta, v = W['beta'][0], W['v'][0] As = 2 * v * (v[1:].T * A) As[1:,:] *= -1.0 As[1:,:] -= A As /= beta # S = As'*As + 4 * (W1**2 + W2**2)**-1 S = As.T * As d1, d2 = W['d'][:n], W['d'][n:] d = 4.0 * (d1**2 + d2**2)**-1 S[::n+1] += d lapack.potrf(S) def f(x, y, z): # z := - W**-T * z z[:n] = -div( z[:n], d1 ) z[n:2*n] = -div( z[n:2*n], d2 ) z[2*n:] -= 2.0*v*( v[0]*z[2*n] - blas.dot(v[1:], z[2*n+1:]) ) z[2*n+1:] *= -1.0 z[2*n:] /= beta # x := x - G' * W**-1 * z x[:n] -= div(z[:n], d1) - div(z[n:2*n], d2) + As.T * z[-(m+1):] x[n:] += div(z[:n], d1) + div(z[n:2*n], d2) # Solve for x[:n]: # # S*x[:n] = x[:n] - (W1**2 - W2**2)(W1**2 + W2**2)^-1 * x[n:] x[:n] -= mul( div(d1**2 - d2**2, d1**2 + d2**2), x[n:]) lapack.potrs(S, x) # Solve for x[n:]: # # (d1**-2 + d2**-2) * x[n:] = x[n:] + (d1**-2 - d2**-2)*x[:n] x[n:] += mul( d1**-2 - d2**-2, x[:n]) x[n:] = div( x[n:], d1**-2 + d2**-2) # z := z + W^-T * G*x z[:n] += div( x[:n] - x[n:2*n], d1) z[n:2*n] += div( -x[:n] - x[n:2*n], d2) z[2*n:] += As*x[:n] return f dims = {'l': 2*n, 'q': [m+1], 's': []} sol = solvers.conelp(c, G, h, dims, kktsolver = Fkkt) if sol['status'] == 'optimal': return sol['x'][:n], sol['z'][-m:] else: return None, None
# The small linear cone program of section 8.1 (Linear cone programs). from kvxopt import matrix, solvers c = matrix([-6., -4., -5.]) G = matrix([[ 16., 7., 24., -8., 8., -1., 0., -1., 0., 0., 7., -5., 1., -5., 1., -7., 1., -7., -4.], [-14., 2., 7., -13., -18., 3., 0., 0., -1., 0., 3., 13., -6., 13., 12., -10., -6., -10., -28.], [ 5., 0., -15., 12., -6., 17., 0., 0., 0., -1., 9., 6., -6., 6., -7., -7., -6., -7., -11.]]) h = matrix( [ -3., 5., 12., -2., -14., -13., 10., 0., 0., 0., 68., -30., -19., -30., 99., 23., -19., 23., 10.] ) dims = {'l': 2, 'q': [4, 4], 's': [3]} sol = solvers.conelp(c, G, h, dims) print("\nStatus: " + sol['status']) print("\nx = \n") print(sol['x']) print("\nz = \n") print(sol['z'])
def mcsdp(w): """ Returns solution x, z to (primal) minimize sum(x) subject to w + diag(x) >= 0 (dual) maximize -tr(w*z) subject to diag(z) = 1 z >= 0. """ n = w.size[0] def Fs(x, y, alpha=1.0, beta=0.0, trans='N'): """ y := alpha*(-diag(x)) + beta*y. """ if trans == 'N': # x is a vector; y is a matrix. blas.scal(beta, y) blas.axpy(x, y, alpha=-alpha, incy=n + 1) else: # x is a matrix; y is a vector. blas.scal(beta, y) blas.axpy(x, y, alpha=-alpha, incx=n + 1) def cngrnc(r, x, alpha=1.0): """ Congruence transformation x := alpha * r'*x*r. r and x are square matrices. """ # Scale diagonal of x by 1/2. x[::n + 1] *= 0.5 # a := tril(x)*r a = +r tx = matrix(x, (n, n)) blas.trmm(tx, a, side='L') # x := alpha*(a*r' + r*a') blas.syr2k(r, a, tx, trans='T', alpha=alpha) x[:] = tx[:] def Fkkt(W): rti = W['rti'][0] # t = rti*rti' as a nonsymmetric matrix. t = matrix(0.0, (n, n)) blas.gemm(rti, rti, t, transB='T') # Cholesky factorization of tsq = t.*t. tsq = t**2 lapack.potrf(tsq) def f(x, y, z): """ Solve -diag(z) = bx -diag(x) - inv(rti*rti') * z * inv(rti*rti') = bs On entry, x and z contain bx and bs. On exit, they contain the solution, with z scaled (inv(rti)'*z*inv(rti) is returned instead of z). We first solve ((rti*rti') .* (rti*rti')) * x = bx - diag(t*bs*t) and take z = -rti' * (diag(x) + bs) * rti. """ # tbst := t * zs * t = t * bs * t tbst = matrix(z, (n, n)) cngrnc(t, tbst) # x := x - diag(tbst) = bx - diag(rti*rti' * bs * rti*rti') x -= tbst[::n + 1] # x := (t.*t)^{-1} * x = (t.*t)^{-1} * (bx - diag(t*bs*t)) lapack.potrs(tsq, x) # z := z + diag(x) = bs + diag(x) z[::n + 1] += x # z := -rti' * z * rti = -rti' * (diag(x) + bs) * rti cngrnc(rti, z, alpha=-1.0) return f c = matrix(1.0, (n, 1)) # Initial feasible x: x = 1.0 - min(lambda(w)). lmbda = matrix(0.0, (n, 1)) lapack.syevx(+w, lmbda, range='I', il=1, iu=1) x0 = matrix(-lmbda[0] + 1.0, (n, 1)) s0 = +w s0[::n + 1] += x0 # Initial feasible z is identity. z0 = matrix(0.0, (n, n)) z0[::n + 1] = 1.0 dims = {'l': 0, 'q': [], 's': [n]} sol = solvers.conelp(c, Fs, w[:], dims, kktsolver=Fkkt, primalstart={ 'x': x0, 's': s0[:] }, dualstart={'z': z0[:]}) return sol['x'], matrix(sol['z'], (n, n))