annotate pyCSalgos/SL0/EllipseProj.py @ 68:cab8a215f9a1 tip

Minor
author Nic Cleju <nikcleju@gmail.com>
date Tue, 09 Jul 2013 14:50:09 +0300
parents a8d96e67717e
children
rev   line source
nikcleju@66 1 # -*- coding: utf-8 -*-
nikcleju@66 2 """
nikcleju@66 3
nikcleju@66 4 Author: Nicolae Cleju
nikcleju@66 5 """
nikcleju@66 6 __author__ = "Nicolae Cleju"
nikcleju@66 7 __license__ = "GPL"
nikcleju@66 8 __email__ = "nikcleju@gmail.com"
nikcleju@66 9
nikcleju@66 10
nikcleju@66 11 import numpy
nikcleju@66 12 import scipy
nikcleju@66 13 import math
nikcleju@67 14 #import cvxpy
nikcleju@66 15
nikcleju@66 16 class EllipseProjDaiError(Exception):
nikcleju@66 17 # def __init__(self, e):
nikcleju@66 18 # self._e = e
nikcleju@66 19 pass
nikcleju@66 20
nikcleju@66 21 def ellipse_proj_cvxpy(A,b,p,epsilon):
nikcleju@66 22 b = b.reshape((b.size,1))
nikcleju@66 23 p = p.reshape((p.size,1))
nikcleju@66 24 A = cvxpy.matrix(A)
nikcleju@66 25 b = cvxpy.matrix(b)
nikcleju@66 26 p = cvxpy.matrix(p)
nikcleju@66 27
nikcleju@66 28 x = cvxpy.variable(p.shape[0],1) # Create optimization variable
nikcleju@66 29 prog = cvxpy.program(cvxpy.minimize(cvxpy.norm2(p - x)), # Create problem instance
nikcleju@66 30 [cvxpy.leq(cvxpy.norm2(b-A*x),epsilon)])
nikcleju@66 31 #prog.solve(quiet=True) # Get optimal value
nikcleju@66 32 prog.solve() # Get optimal value
nikcleju@66 33 return numpy.array(x.value).flatten()
nikcleju@66 34
nikcleju@66 35 def ellipse_proj_dai(A,x,s,eps):
nikcleju@66 36
nikcleju@66 37 A_pinv = numpy.linalg.pinv(A)
nikcleju@66 38
nikcleju@66 39 AA = numpy.dot(A.T, A)
nikcleju@66 40 bb = -numpy.dot(x.T,A)
nikcleju@66 41 alpha = eps*eps - numpy.inner(x,x)
nikcleju@66 42
nikcleju@66 43 direction = numpy.dot(A_pinv,(numpy.dot(A,s)-x))
nikcleju@66 44 s0 = s - (1.0 - eps/numpy.linalg.norm(numpy.dot(A,direction))) * direction
nikcleju@66 45
nikcleju@66 46 a = s
nikcleju@66 47 xk = s0
nikcleju@66 48 m1 = 1
nikcleju@66 49 m2 = 1
nikcleju@66 50 c1 = 0.1
nikcleju@66 51 c2 = 0.8
nikcleju@66 52 done = False
nikcleju@66 53 k = 0
nikcleju@66 54 while not done and k < 50:
nikcleju@66 55
nikcleju@66 56 uk = numpy.dot(AA,xk) + bb
nikcleju@66 57 vk = a - xk
nikcleju@66 58
nikcleju@66 59 zk = uk - (numpy.inner(uk,vk)/numpy.inner(vk,vk))*vk
nikcleju@66 60 vtav = numpy.inner(vk,numpy.dot(AA,vk))
nikcleju@66 61 vtv = numpy.inner(vk,vk)
nikcleju@66 62 ztaz = numpy.inner(zk,numpy.dot(AA,zk))
nikcleju@66 63 ztz = numpy.inner(zk,zk)
nikcleju@66 64 vtaz = numpy.inner(vk,numpy.dot(AA,zk))
nikcleju@66 65 gammak1 = 1.0/(0.5 * ( vtav/vtv + ztaz/ztz + math.sqrt((vtaz/vtv - ztaz/ztz)**2 + 4*vtaz**2/vtv/ztz)))
nikcleju@66 66
nikcleju@66 67 pk = vk / numpy.linalg.norm(vk)
nikcleju@66 68 qk = zk / numpy.linalg.norm(zk)
nikcleju@66 69 Hk = numpy.zeros((pk.size,2))
nikcleju@66 70 Hk[:,0] = pk
nikcleju@66 71 Hk[:,1] = qk
nikcleju@66 72 Ak = numpy.dot(Hk.T, numpy.dot(AA,Hk))
nikcleju@66 73 bk = numpy.dot(Hk.T,uk)
nikcleju@66 74
nikcleju@66 75 #al = numpy.dot(Hk, numpy.dot(Hk.T, a))
nikcleju@66 76 al = numpy.array([numpy.linalg.norm(vk), 0])
nikcleju@66 77 D,Q = numpy.linalg.eig(Ak)
nikcleju@66 78 Q = Q.T
nikcleju@66 79 ah = numpy.dot(Q,al) + (1.0/D) * numpy.dot(Q,bk)
nikcleju@66 80
nikcleju@66 81 l1 = D[0]
nikcleju@66 82 l2 = D[1]
nikcleju@66 83 Qbk = numpy.dot(Q,bk)
nikcleju@66 84 beta = numpy.dot(Qbk.T, (1.0/D) * Qbk)
nikcleju@66 85 hstar1s = numpy.roots(numpy.array([ (l1-l2)**2*l1,
nikcleju@66 86 2*(l1-l2)*l2*ah[0]*l1,
nikcleju@66 87 -(l1-l2)**2*beta + l2**2*ah[0]**2*l1 + l1**2*l2*ah[1]**2,
nikcleju@66 88 -2*beta*(l1-l2)*l2*ah[0],
nikcleju@66 89 -beta*l2**2*ah[0]**2]))
nikcleju@66 90 hstar2s = numpy.zeros_like(hstar1s)
nikcleju@66 91 i_s = []
nikcleju@66 92 illcond = False # flag if ill conditioned problem (numerical errros)
nikcleju@66 93 for i in range(hstar1s.size):
nikcleju@66 94
nikcleju@66 95 # Protect against bad conditioning (ratio of two very small values)
nikcleju@66 96 if numpy.abs(l1*ah[1]) > 1e-6 and numpy.abs((l1-l2) + l2*ah[0]/hstar1s[i]) > 1e-6:
nikcleju@66 97
nikcleju@66 98 # Ignore small imaginary parts
nikcleju@66 99 if numpy.abs(numpy.imag(hstar1s[i])) < 1e-10:
nikcleju@66 100 hstar1s[i] = numpy.real(hstar1s[i])
nikcleju@66 101
nikcleju@66 102 hstar2s[i] = l1*ah[1] / ((l1-l2)*hstar1s[i] + l2*ah[0]) * hstar1s[i]
nikcleju@66 103
nikcleju@66 104 # Ignore small imaginary parts
nikcleju@66 105 if numpy.abs(numpy.imag(hstar2s[i])) < 1e-10:
nikcleju@66 106 hstar2s[i] = numpy.real(hstar2s[i])
nikcleju@66 107
nikcleju@66 108 if (ah[0] - hstar1s[i]) / (l1*hstar1s[i]) > 0 and (ah[1] - hstar2s[i]) / (l2*hstar2s[i]) > 0:
nikcleju@66 109 i_s.append(i)
nikcleju@66 110
nikcleju@66 111 else:
nikcleju@66 112 # Cannot rely on hstar2s[i] calculation since it is the ratio of two small numbers
nikcleju@66 113 # Do a vertical projection instead
nikcleju@66 114 hstar1 = ah[0]
nikcleju@66 115 hstar2 = numpy.sign(ah[1]) * math.sqrt((beta - l1*ah[0]**2)/l2)
nikcleju@66 116 illcond = True # Flag, so we don't take i_s[] into account anymore
nikcleju@66 117
nikcleju@66 118 if illcond:
nikcleju@66 119 print "Ill conditioned problem, do vertical projection instead"
nikcleju@66 120 # hstar1 and hstar2 are already set above, nothing to do here
nikcleju@66 121 else:
nikcleju@66 122 if len(i_s) > 1:
nikcleju@66 123 hstar1 = hstar1s[i_s[0]].real
nikcleju@66 124 hstar2 = hstar2s[i_s[0]].real
nikcleju@66 125 elif len(i_s) == 0:
nikcleju@66 126 # Again do vertical projection
nikcleju@66 127 hstar1 = ah[0]
nikcleju@66 128 hstar2 = numpy.sign(ah[1]) * math.sqrt((beta - l1*ah[0]**2)/l2)
nikcleju@66 129 else:
nikcleju@66 130 # Everything is ok
nikcleju@66 131 hstar1 = hstar1s[i_s].real
nikcleju@66 132 hstar2 = hstar2s[i_s].real
nikcleju@66 133
nikcleju@66 134 ahstar = numpy.array([hstar1, hstar2]).flatten()
nikcleju@66 135 alstar = numpy.dot(Q.T, ahstar - (1.0/D) * numpy.dot(Q,bk))
nikcleju@66 136 alstar1 = alstar[0]
nikcleju@66 137 alstar2 = alstar[1]
nikcleju@66 138 etak = 1 - alstar1/numpy.linalg.norm(vk) + numpy.inner(uk,vk)/vtv*alstar2/numpy.linalg.norm(zk)
nikcleju@66 139 gammak2 = -alstar2/numpy.linalg.norm(zk)/etak
nikcleju@66 140 if k % (m1+m2) < m1:
nikcleju@66 141 gammak = gammak2
nikcleju@66 142 else:
nikcleju@66 143 gammak = c1*gammak1 + c2*gammak2
nikcleju@66 144
nikcleju@66 145 # Safeguard:
nikcleju@66 146 if gammak < 0:
nikcleju@66 147 gammak = gammak1
nikcleju@66 148
nikcleju@66 149 ck = xk - gammak * uk
nikcleju@66 150 wk = ck - a
nikcleju@66 151
nikcleju@66 152 ga = numpy.dot(AA,a) + bb
nikcleju@66 153 qa = numpy.inner(a,numpy.dot(AA,a)) + 2*numpy.inner(bb,a)
nikcleju@66 154 # Check if delta < 0 but very small (possibly numerical errors)
nikcleju@66 155 if (numpy.inner(ga,wk)/numpy.inner(wk, numpy.dot(AA,wk)))**2 - (qa-alpha)/numpy.inner(wk, numpy.dot(AA,wk)) < 0 and abs((numpy.inner(ga,wk)/numpy.inner(wk, numpy.dot(AA,wk)))**2 - (qa-alpha)/numpy.inner(wk, numpy.dot(AA,wk))) < 1e-10:
nikcleju@66 156 etak = -numpy.inner(ga,wk)/numpy.inner(wk, numpy.dot(AA,wk))
nikcleju@66 157 else:
nikcleju@66 158 assert ((numpy.inner(ga,wk)/numpy.inner(wk, numpy.dot(AA,wk)))**2 - (qa-alpha)/numpy.inner(wk, numpy.dot(AA,wk)) >= 0)
nikcleju@66 159 etak = -numpy.inner(ga,wk)/numpy.inner(wk, numpy.dot(AA,wk)) - math.sqrt((numpy.inner(ga,wk)/numpy.inner(wk, numpy.dot(AA,wk)))**2 - (qa-alpha)/numpy.inner(wk, numpy.dot(AA,wk)))
nikcleju@66 160 xk = a + etak * wk
nikcleju@66 161
nikcleju@66 162 if (1 - numpy.inner(uk,vk) / numpy.linalg.norm(uk) / numpy.linalg.norm(vk)) <= 0.01:
nikcleju@66 163 done = True
nikcleju@66 164 k = k+1
nikcleju@66 165
nikcleju@66 166 return xk
nikcleju@66 167
nikcleju@66 168
nikcleju@66 169 def ellipse_proj_proj(A,x,s,eps,L2):
nikcleju@66 170 A_pinv = numpy.linalg.pinv(A)
nikcleju@66 171 u,singvals,v = numpy.linalg.svd(A, full_matrices=0)
nikcleju@66 172 singvals = numpy.flipud(singvals)
nikcleju@66 173 s_orig = s
nikcleju@66 174
nikcleju@66 175 for j in range(L2):
nikcleju@66 176 direction = numpy.dot(A_pinv,(numpy.dot(A,s)-x))
nikcleju@66 177
nikcleju@66 178 if (numpy.linalg.norm(numpy.dot(A,direction)) >= eps):
nikcleju@66 179
nikcleju@66 180 P = numpy.dot(numpy.dot(u,v), s)
nikcleju@66 181 sproj = s - (1.0 - eps/numpy.linalg.norm(numpy.dot(A,direction))) * direction
nikcleju@66 182 P0 = numpy.dot(numpy.dot(u,v), sproj)
nikcleju@66 183
nikcleju@66 184 tangent = (P0 * (singvals**2)).reshape((1,P.size))
nikcleju@66 185 uu,ss,vv = numpy.linalg.svd(tangent)
nikcleju@66 186 svd = vv[1:,:]
nikcleju@66 187 P1 = numpy.linalg.solve(numpy.vstack((tangent,svd)), numpy.vstack((numpy.array([[eps]]), numpy.dot(svd, P).reshape((svd.shape[0],1)))))
nikcleju@66 188
nikcleju@66 189 # Take only a smaller step
nikcleju@66 190 #P1 = P0.reshape((P0.size,1)) + 0.1*(P1-P0.reshape((P0.size,1)))
nikcleju@66 191
nikcleju@66 192 #s = numpy.dot(A_pinv,P1).flatten() + numpy.dot(A_pinv,numpy.dot(A,s)).flatten()
nikcleju@66 193 s = numpy.dot(numpy.linalg.pinv(numpy.dot(u,v)),P1).flatten() + (s-numpy.dot(A_pinv,numpy.dot(A,s)).flatten())
nikcleju@66 194
nikcleju@66 195 #assert(numpy.linalg.norm(x - numpy.dot(A,s)) < eps + 1e-6)
nikcleju@66 196
nikcleju@66 197 direction = numpy.dot(A_pinv,(numpy.dot(A,s)-x))
nikcleju@66 198 if (numpy.linalg.norm(numpy.dot(A,direction)) >= eps):
nikcleju@66 199 s = s - (1.0 - eps/numpy.linalg.norm(numpy.dot(A,direction))) * direction
nikcleju@66 200
nikcleju@66 201 return s
nikcleju@66 202
nikcleju@66 203 def ellipse_proj_logbarrier(A,b,p,epsilon,verbose=False):
nikcleju@66 204 return l1qc_logbarrier(numpy.zeros_like(p), p, A, A.T, b, epsilon, lbtol=1e-3, mu=10, cgtol=1e-8, cgmaxiter=200, verbose=verbose)
nikcleju@66 205
nikcleju@66 206 def l1qc_newton(x0, p, A, At, b, epsilon, tau, newtontol, newtonmaxiter, cgtol, cgmaxiter, verbose=False):
nikcleju@66 207 # Newton algorithm for log-barrier subproblems for l1 minimization
nikcleju@66 208 # with quadratic constraints.
nikcleju@66 209 #
nikcleju@66 210 # Usage:
nikcleju@66 211 # [xp,up,niter] = l1qc_newton(x0, u0, A, At, b, epsilon, tau,
nikcleju@66 212 # newtontol, newtonmaxiter, cgtol, cgmaxiter)
nikcleju@66 213 #
nikcleju@66 214 # x0,u0 - starting points
nikcleju@66 215 #
nikcleju@66 216 # A - Either a handle to a function that takes a N vector and returns a K
nikcleju@66 217 # vector , or a KxN matrix. If A is a function handle, the algorithm
nikcleju@66 218 # operates in "largescale" mode, solving the Newton systems via the
nikcleju@66 219 # Conjugate Gradients algorithm.
nikcleju@66 220 #
nikcleju@66 221 # At - Handle to a function that takes a K vector and returns an N vector.
nikcleju@66 222 # If A is a KxN matrix, At is ignored.
nikcleju@66 223 #
nikcleju@66 224 # b - Kx1 vector of observations.
nikcleju@66 225 #
nikcleju@66 226 # epsilon - scalar, constraint relaxation parameter
nikcleju@66 227 #
nikcleju@66 228 # tau - Log barrier parameter.
nikcleju@66 229 #
nikcleju@66 230 # newtontol - Terminate when the Newton decrement is <= newtontol.
nikcleju@66 231 # Default = 1e-3.
nikcleju@66 232 #
nikcleju@66 233 # newtonmaxiter - Maximum number of iterations.
nikcleju@66 234 # Default = 50.
nikcleju@66 235 #
nikcleju@66 236 # cgtol - Tolerance for Conjugate Gradients; ignored if A is a matrix.
nikcleju@66 237 # Default = 1e-8.
nikcleju@66 238 #
nikcleju@66 239 # cgmaxiter - Maximum number of iterations for Conjugate Gradients; ignored
nikcleju@66 240 # if A is a matrix.
nikcleju@66 241 # Default = 200.
nikcleju@66 242 #
nikcleju@66 243 # Written by: Justin Romberg, Caltech
nikcleju@66 244 # Email: jrom@acm.caltech.edu
nikcleju@66 245 # Created: October 2005
nikcleju@66 246 #
nikcleju@66 247
nikcleju@66 248 # check if the matrix A is implicit or explicit
nikcleju@66 249 #largescale = isa(A,'function_handle');
nikcleju@66 250 if hasattr(A, '__call__'):
nikcleju@66 251 largescale = True
nikcleju@66 252 else:
nikcleju@66 253 largescale = False
nikcleju@66 254
nikcleju@66 255 # line search parameters
nikcleju@66 256 alpha = 0.01
nikcleju@66 257 beta = 0.5
nikcleju@66 258
nikcleju@66 259 #if (~largescale), AtA = A'*A; end
nikcleju@66 260 if not largescale:
nikcleju@66 261 AtA = numpy.dot(A.T,A)
nikcleju@66 262
nikcleju@66 263 # initial point
nikcleju@66 264 x = x0.copy()
nikcleju@66 265 #u = u0.copy()
nikcleju@66 266 #if (largescale), r = A(x) - b; else r = A*x - b; end
nikcleju@66 267 if largescale:
nikcleju@66 268 r = A(x) - b
nikcleju@66 269 else:
nikcleju@66 270 r = numpy.dot(A,x) - b
nikcleju@66 271
nikcleju@66 272 #fu1 = x - u
nikcleju@66 273 #fu2 = -x - u
nikcleju@66 274 fe = 1.0/2*(numpy.vdot(r,r) - epsilon**2)
nikcleju@66 275 #f = u.sum() - (1.0/tau)*(numpy.log(-fu1).sum() + numpy.log(-fu2).sum() + math.log(-fe))
nikcleju@66 276 f = numpy.linalg.norm(p-x)**2 - (1.0/tau) * math.log(-fe)
nikcleju@66 277
nikcleju@66 278 niter = 0
nikcleju@66 279 done = 0
nikcleju@66 280 while not done:
nikcleju@66 281
nikcleju@66 282 #if (largescale), atr = At(r); else atr = A'*r; end
nikcleju@66 283 if largescale:
nikcleju@66 284 atr = At(r)
nikcleju@66 285 else:
nikcleju@66 286 atr = numpy.dot(A.T,r)
nikcleju@66 287
nikcleju@66 288 ##ntgz = 1./fu1 - 1./fu2 + 1/fe*atr;
nikcleju@66 289 #ntgz = 1.0/fu1 - 1.0/fu2 + 1.0/fe*atr
nikcleju@66 290 ntgz = 1.0/fe*atr
nikcleju@66 291 ##ntgu = -tau - 1./fu1 - 1./fu2;
nikcleju@66 292 #ntgu = -tau - 1.0/fu1 - 1.0/fu2
nikcleju@66 293 ##gradf = -(1/tau)*[ntgz; ntgu];
nikcleju@66 294 #gradf = -(1.0/tau)*numpy.concatenate((ntgz, ntgu),0)
nikcleju@66 295 gradf = 2*x + 2*p -(1.0/tau)*ntgz
nikcleju@66 296
nikcleju@66 297 ##sig11 = 1./fu1.^2 + 1./fu2.^2;
nikcleju@66 298 #sig11 = 1.0/(fu1**2) + 1.0/(fu2**2)
nikcleju@66 299 ##sig12 = -1./fu1.^2 + 1./fu2.^2;
nikcleju@66 300 #sig12 = -1.0/(fu1**2) + 1.0/(fu2**2)
nikcleju@66 301 ##sigx = sig11 - sig12.^2./sig11;
nikcleju@66 302 #sigx = sig11 - (sig12**2)/sig11
nikcleju@66 303
nikcleju@66 304 ##w1p = ntgz - sig12./sig11.*ntgu;
nikcleju@66 305 #w1p = ntgz - sig12/sig11*ntgu
nikcleju@66 306 #w1p = -tau * (2*x + 2*p) + ntgz
nikcleju@66 307 w1p = -gradf
nikcleju@66 308 if largescale:
nikcleju@66 309 #h11pfun = @(z) sigx.*z - (1/fe)*At(A(z)) + 1/fe^2*(atr'*z)*atr;
nikcleju@66 310 h11pfun = lambda z: sigx*z - (1.0/fe)*At(A(z)) + 1.0/(fe**2)*numpy.dot(numpy.dot(atr.T,z),atr)
nikcleju@66 311 dx,cgres,cgiter = cgsolve(h11pfun, w1p, cgtol, cgmaxiter, 0)
nikcleju@66 312 if (cgres > 1.0/2):
nikcleju@66 313 if verbose:
nikcleju@66 314 print 'Cannot solve system. Returning previous iterate. (See Section 4 of notes for more information.)'
nikcleju@66 315 xp = x.copy()
nikcleju@66 316 up = u.copy()
nikcleju@66 317 return xp,up,niter
nikcleju@66 318 #end
nikcleju@66 319 Adx = A(dx)
nikcleju@66 320 else:
nikcleju@66 321 ##H11p = diag(sigx) - (1/fe)*AtA + (1/fe)^2*atr*atr';
nikcleju@66 322 # Attention: atr is column vector, so atr*atr' means outer(atr,atr)
nikcleju@66 323 #H11p = numpy.diag(sigx) - (1.0/fe)*AtA + (1.0/fe)**2*numpy.outer(atr,atr)
nikcleju@66 324 H11p = 2 * numpy.eye(x.size) - (1.0/fe)*AtA + (1.0/fe)**2*numpy.outer(atr,atr)
nikcleju@66 325 #opts.POSDEF = true; opts.SYM = true;
nikcleju@66 326 #[dx,hcond] = linsolve(H11p, w1p, opts);
nikcleju@66 327 #if (hcond < 1e-14)
nikcleju@66 328 # disp('Matrix ill-conditioned. Returning previous iterate. (See Section 4 of notes for more information.)');
nikcleju@66 329 # xp = x; up = u;
nikcleju@66 330 # return
nikcleju@66 331 #end
nikcleju@66 332 try:
nikcleju@66 333 dx = scipy.linalg.solve(H11p, w1p, sym_pos=True)
nikcleju@66 334 #dx = numpy.linalg.solve(H11p, w1p)
nikcleju@66 335 hcond = 1.0/numpy.linalg.cond(H11p)
nikcleju@66 336 except scipy.linalg.LinAlgError:
nikcleju@66 337 if verbose:
nikcleju@66 338 print 'Matrix ill-conditioned. Returning previous iterate. (See Section 4 of notes for more information.)'
nikcleju@66 339 xp = x.copy()
nikcleju@66 340 #up = u.copy()
nikcleju@66 341 #return xp,up,niter
nikcleju@66 342 return xp,niter
nikcleju@66 343 if hcond < 1e-14:
nikcleju@66 344 if verbose:
nikcleju@66 345 print 'Matrix ill-conditioned. Returning previous iterate. (See Section 4 of notes for more information.)'
nikcleju@66 346 xp = x.copy()
nikcleju@66 347 #up = u.copy()
nikcleju@66 348 #return xp,up,niter
nikcleju@66 349 return xp,niter
nikcleju@66 350
nikcleju@66 351 #Adx = A*dx;
nikcleju@66 352 Adx = numpy.dot(A,dx)
nikcleju@66 353 #end
nikcleju@66 354 ##du = (1./sig11).*ntgu - (sig12./sig11).*dx;
nikcleju@66 355 #du = (1.0/sig11)*ntgu - (sig12/sig11)*dx;
nikcleju@66 356
nikcleju@66 357 # minimum step size that stays in the interior
nikcleju@66 358 ##ifu1 = find((dx-du) > 0); ifu2 = find((-dx-du) > 0);
nikcleju@66 359 #ifu1 = numpy.nonzero((dx-du)>0)
nikcleju@66 360 #ifu2 = numpy.nonzero((-dx-du)>0)
nikcleju@66 361 #aqe = Adx'*Adx; bqe = 2*r'*Adx; cqe = r'*r - epsilon^2;
nikcleju@66 362 aqe = numpy.dot(Adx.T,Adx)
nikcleju@66 363 bqe = 2*numpy.dot(r.T,Adx)
nikcleju@66 364 cqe = numpy.vdot(r,r) - epsilon**2
nikcleju@66 365 #smax = min(1,min([...
nikcleju@66 366 # -fu1(ifu1)./(dx(ifu1)-du(ifu1)); -fu2(ifu2)./(-dx(ifu2)-du(ifu2)); ...
nikcleju@66 367 # (-bqe+sqrt(bqe^2-4*aqe*cqe))/(2*aqe)
nikcleju@66 368 # ]));
nikcleju@66 369 #smax = min(1,numpy.concatenate( (-fu1[ifu1]/(dx[ifu1]-du[ifu1]) , -fu2[ifu2]/(-dx[ifu2]-du[ifu2]) , numpy.array([ (-bqe + math.sqrt(bqe**2-4*aqe*cqe))/(2*aqe) ]) ) , 0).min())
nikcleju@66 370 smax = min(1,numpy.array([ (-bqe + math.sqrt(bqe**2-4*aqe*cqe))/(2*aqe) ] ).min())
nikcleju@66 371
nikcleju@66 372 s = 0.99 * smax
nikcleju@66 373
nikcleju@66 374 # backtracking line search
nikcleju@66 375 suffdec = 0
nikcleju@66 376 backiter = 0
nikcleju@66 377 while not suffdec:
nikcleju@66 378 #xp = x + s*dx; up = u + s*du; rp = r + s*Adx;
nikcleju@66 379 xp = x + s*dx
nikcleju@66 380 #up = u + s*du
nikcleju@66 381 rp = r + s*Adx
nikcleju@66 382 #fu1p = xp - up; fu2p = -xp - up; fep = 1/2*(rp'*rp - epsilon^2);
nikcleju@66 383 #fu1p = xp - up
nikcleju@66 384 #fu2p = -xp - up
nikcleju@66 385 fep = 0.5*(numpy.vdot(rp,rp) - epsilon**2)
nikcleju@66 386 ##fp = sum(up) - (1/tau)*(sum(log(-fu1p)) + sum(log(-fu2p)) + log(-fep));
nikcleju@66 387 #fp = up.sum() - (1.0/tau)*(numpy.log(-fu1p).sum() + numpy.log(-fu2p).sum() + math.log(-fep))
nikcleju@66 388 fp = numpy.linalg.norm(p-xp)**2 - (1.0/tau) * math.log(-fep)
nikcleju@66 389 #flin = f + alpha*s*(gradf'*[dx; du]);
nikcleju@66 390 flin = f + alpha*s*numpy.dot(gradf.T , dx)
nikcleju@66 391 #suffdec = (fp <= flin);
nikcleju@66 392 if fp <= flin:
nikcleju@66 393 suffdec = True
nikcleju@66 394 else:
nikcleju@66 395 suffdec = False
nikcleju@66 396
nikcleju@66 397 s = beta*s
nikcleju@66 398 backiter = backiter + 1
nikcleju@66 399 if (backiter > 132):
nikcleju@66 400 if verbose:
nikcleju@66 401 print 'Stuck on backtracking line search, returning previous iterate. (See Section 4 of notes for more information.)'
nikcleju@66 402 xp = x.copy()
nikcleju@66 403 #up = u.copy()
nikcleju@66 404 #return xp,up,niter
nikcleju@66 405 return xp,niter
nikcleju@66 406 #end
nikcleju@66 407 #end
nikcleju@66 408
nikcleju@66 409 # set up for next iteration
nikcleju@66 410 ##x = xp; u = up; r = rp;
nikcleju@66 411 x = xp.copy()
nikcleju@66 412 #u = up.copy()
nikcleju@66 413 r = rp.copy()
nikcleju@66 414 ##fu1 = fu1p; fu2 = fu2p; fe = fep; f = fp;
nikcleju@66 415 #fu1 = fu1p.copy()
nikcleju@66 416 #fu2 = fu2p.copy()
nikcleju@66 417 fe = fep
nikcleju@66 418 f = fp
nikcleju@66 419
nikcleju@66 420 ##lambda2 = -(gradf'*[dx; du]);
nikcleju@66 421 #lambda2 = -numpy.dot(gradf.T , numpy.concatenate((dx,du),0))
nikcleju@66 422 lambda2 = -numpy.dot(gradf.T , dx)
nikcleju@66 423 ##stepsize = s*norm([dx; du]);
nikcleju@66 424 #stepsize = s * numpy.linalg.norm(numpy.concatenate((dx,du),0))
nikcleju@66 425 stepsize = s * numpy.linalg.norm(dx)
nikcleju@66 426 niter = niter + 1
nikcleju@66 427 #done = (lambda2/2 < newtontol) | (niter >= newtonmaxiter);
nikcleju@66 428 if lambda2/2.0 < newtontol or niter >= newtonmaxiter:
nikcleju@66 429 done = 1
nikcleju@66 430 else:
nikcleju@66 431 done = 0
nikcleju@66 432
nikcleju@66 433 #disp(sprintf('Newton iter = #d, Functional = #8.3f, Newton decrement = #8.3f, Stepsize = #8.3e', ...
nikcleju@66 434 if verbose:
nikcleju@66 435 print 'Newton iter = ',niter,', Functional = ',f,', Newton decrement = ',lambda2/2.0,', Stepsize = ',stepsize
nikcleju@66 436
nikcleju@66 437 if verbose:
nikcleju@66 438 if largescale:
nikcleju@66 439 print ' CG Res = ',cgres,', CG Iter = ',cgiter
nikcleju@66 440 else:
nikcleju@66 441 print ' H11p condition number = ',hcond
nikcleju@66 442 #end
nikcleju@66 443
nikcleju@66 444 #end
nikcleju@66 445 #return xp,up,niter
nikcleju@66 446 return xp,niter
nikcleju@66 447
nikcleju@66 448 #function xp = l1qc_logbarrier(x0, A, At, b, epsilon, lbtol, mu, cgtol, cgmaxiter)
nikcleju@66 449 def l1qc_logbarrier(x0, p, A, At, b, epsilon, lbtol=1e-3, mu=10, cgtol=1e-8, cgmaxiter=200, verbose=False):
nikcleju@66 450 # Solve quadratically constrained l1 minimization:
nikcleju@66 451 # min ||x||_1 s.t. ||Ax - b||_2 <= \epsilon
nikcleju@66 452 #
nikcleju@66 453 # Reformulate as the second-order cone program
nikcleju@66 454 # min_{x,u} sum(u) s.t. x - u <= 0,
nikcleju@66 455 # -x - u <= 0,
nikcleju@66 456 # 1/2(||Ax-b||^2 - \epsilon^2) <= 0
nikcleju@66 457 # and use a log barrier algorithm.
nikcleju@66 458 #
nikcleju@66 459 # Usage: xp = l1qc_logbarrier(x0, A, At, b, epsilon, lbtol, mu, cgtol, cgmaxiter)
nikcleju@66 460 #
nikcleju@66 461 # x0 - Nx1 vector, initial point.
nikcleju@66 462 #
nikcleju@66 463 # A - Either a handle to a function that takes a N vector and returns a K
nikcleju@66 464 # vector , or a KxN matrix. If A is a function handle, the algorithm
nikcleju@66 465 # operates in "largescale" mode, solving the Newton systems via the
nikcleju@66 466 # Conjugate Gradients algorithm.
nikcleju@66 467 #
nikcleju@66 468 # At - Handle to a function that takes a K vector and returns an N vector.
nikcleju@66 469 # If A is a KxN matrix, At is ignored.
nikcleju@66 470 #
nikcleju@66 471 # b - Kx1 vector of observations.
nikcleju@66 472 #
nikcleju@66 473 # epsilon - scalar, constraint relaxation parameter
nikcleju@66 474 #
nikcleju@66 475 # lbtol - The log barrier algorithm terminates when the duality gap <= lbtol.
nikcleju@66 476 # Also, the number of log barrier iterations is completely
nikcleju@66 477 # determined by lbtol.
nikcleju@66 478 # Default = 1e-3.
nikcleju@66 479 #
nikcleju@66 480 # mu - Factor by which to increase the barrier constant at each iteration.
nikcleju@66 481 # Default = 10.
nikcleju@66 482 #
nikcleju@66 483 # cgtol - Tolerance for Conjugate Gradients; ignored if A is a matrix.
nikcleju@66 484 # Default = 1e-8.
nikcleju@66 485 #
nikcleju@66 486 # cgmaxiter - Maximum number of iterations for Conjugate Gradients; ignored
nikcleju@66 487 # if A is a matrix.
nikcleju@66 488 # Default = 200.
nikcleju@66 489 #
nikcleju@66 490 # Written by: Justin Romberg, Caltech
nikcleju@66 491 # Email: jrom@acm.caltech.edu
nikcleju@66 492 # Created: October 2005
nikcleju@66 493 #
nikcleju@66 494
nikcleju@66 495
nikcleju@66 496 # Check if epsilon > 0. If epsilon is 0, the algorithm fails. You should run the algo with equality constraint instead
nikcleju@66 497 if epsilon == 0:
nikcleju@66 498 raise l1qcInputValueError('Epsilon should be > 0!')
nikcleju@66 499
nikcleju@66 500 #largescale = isa(A,'function_handle');
nikcleju@66 501 if hasattr(A, '__call__'):
nikcleju@66 502 largescale = True
nikcleju@66 503 else:
nikcleju@66 504 largescale = False
nikcleju@66 505
nikcleju@66 506 # if (nargin < 6), lbtol = 1e-3; end
nikcleju@66 507 # if (nargin < 7), mu = 10; end
nikcleju@66 508 # if (nargin < 8), cgtol = 1e-8; end
nikcleju@66 509 # if (nargin < 9), cgmaxiter = 200; end
nikcleju@66 510 # Nic: added them as optional parameteres
nikcleju@66 511
nikcleju@66 512 newtontol = lbtol
nikcleju@66 513 newtonmaxiter = 150
nikcleju@66 514
nikcleju@66 515 #N = length(x0);
nikcleju@66 516 N = x0.size
nikcleju@66 517
nikcleju@66 518 # starting point --- make sure that it is feasible
nikcleju@66 519 if largescale:
nikcleju@66 520 if numpy.linalg.norm(A(x0) - b) > epsilon:
nikcleju@66 521 if verbose:
nikcleju@66 522 print 'Starting point infeasible; using x0 = At*inv(AAt)*y.'
nikcleju@66 523 #AAt = @(z) A(At(z));
nikcleju@66 524 AAt = lambda z: A(At(z))
nikcleju@66 525 # TODO: implement cgsolve
nikcleju@66 526 w,cgres,cgiter = cgsolve(AAt, b, cgtol, cgmaxiter, 0)
nikcleju@66 527 if (cgres > 1.0/2):
nikcleju@66 528 if verbose:
nikcleju@66 529 print 'A*At is ill-conditioned: cannot find starting point'
nikcleju@66 530 xp = x0.copy()
nikcleju@66 531 return xp
nikcleju@66 532 #end
nikcleju@66 533 x0 = At(w)
nikcleju@66 534 #end
nikcleju@66 535 else:
nikcleju@66 536 if numpy.linalg.norm( numpy.dot(A,x0) - b ) > epsilon:
nikcleju@66 537 if verbose:
nikcleju@66 538 print 'Starting point infeasible; using x0 = At*inv(AAt)*y.'
nikcleju@66 539 #opts.POSDEF = true; opts.SYM = true;
nikcleju@66 540 #[w, hcond] = linsolve(A*A', b, opts);
nikcleju@66 541 #if (hcond < 1e-14)
nikcleju@66 542 # disp('A*At is ill-conditioned: cannot find starting point');
nikcleju@66 543 # xp = x0;
nikcleju@66 544 # return;
nikcleju@66 545 #end
nikcleju@66 546 try:
nikcleju@66 547 w = scipy.linalg.solve(numpy.dot(A,A.T), b, sym_pos=True)
nikcleju@66 548 #w = numpy.linalg.solve(numpy.dot(A,A.T), b)
nikcleju@66 549 hcond = 1.0/numpy.linalg.cond(numpy.dot(A,A.T))
nikcleju@66 550 except scipy.linalg.LinAlgError:
nikcleju@66 551 if verbose:
nikcleju@66 552 print 'A*At is ill-conditioned: cannot find starting point'
nikcleju@66 553 xp = x0.copy()
nikcleju@66 554 return xp
nikcleju@66 555 if hcond < 1e-14:
nikcleju@66 556 if verbose:
nikcleju@66 557 print 'A*At is ill-conditioned: cannot find starting point'
nikcleju@66 558 xp = x0.copy()
nikcleju@66 559 return xp
nikcleju@66 560 #x0 = A'*w;
nikcleju@66 561 x0 = numpy.dot(A.T, w)
nikcleju@66 562 #end
nikcleju@66 563 #end
nikcleju@66 564 x = x0.copy()
nikcleju@66 565 #u = (0.95)*numpy.abs(x0) + (0.10)*numpy.abs(x0).max()
nikcleju@66 566
nikcleju@66 567 #disp(sprintf('Original l1 norm = #.3f, original functional = #.3f', sum(abs(x0)), sum(u)));
nikcleju@66 568 if verbose:
nikcleju@66 569 #print 'Original l1 norm = ',numpy.abs(x0).sum(),'original functional = ',u.sum()
nikcleju@66 570 print 'Original distance ||p-x|| = ',numpy.linalg.norm(p-x)
nikcleju@66 571 # choose initial value of tau so that the duality gap after the first
nikcleju@66 572 # step will be about the origial norm
nikcleju@66 573 #tau = max(((2*N+1.0)/numpy.abs(x0).sum()), 1)
nikcleju@66 574 # Nic:
nikcleju@66 575 tau = max(((2*N+1.0)/numpy.linalg.norm(p-x0)**2), 1)
nikcleju@66 576
nikcleju@66 577 lbiter = math.ceil((math.log(2*N+1)-math.log(lbtol)-math.log(tau))/math.log(mu))
nikcleju@66 578 #disp(sprintf('Number of log barrier iterations = #d\n', lbiter));
nikcleju@66 579 if verbose:
nikcleju@66 580 print 'Number of log barrier iterations = ',lbiter
nikcleju@66 581
nikcleju@66 582 totaliter = 0
nikcleju@66 583
nikcleju@66 584 # Added by Nic, to fix some crashing
nikcleju@66 585 if lbiter == 0:
nikcleju@66 586 xp = numpy.zeros(x0.size)
nikcleju@66 587 #end
nikcleju@66 588
nikcleju@66 589 #for ii = 1:lbiter
nikcleju@66 590 for ii in numpy.arange(lbiter):
nikcleju@66 591
nikcleju@66 592 #xp,up,ntiter = l1qc_newton(x, u, A, At, b, epsilon, tau, newtontol, newtonmaxiter, cgtol, cgmaxiter)
nikcleju@66 593 xp,ntiter = l1qc_newton(x, p, A, At, b, epsilon, tau, newtontol, newtonmaxiter, cgtol, cgmaxiter, verbose=verbose)
nikcleju@66 594 totaliter = totaliter + ntiter
nikcleju@66 595
nikcleju@66 596 #disp(sprintf('\nLog barrier iter = #d, l1 = #.3f, functional = #8.3f, tau = #8.3e, total newton iter = #d\n', ...
nikcleju@66 597 # ii, sum(abs(xp)), sum(up), tau, totaliter));
nikcleju@66 598 if verbose:
nikcleju@66 599 #print 'Log barrier iter = ',ii,', l1 = ',numpy.abs(xp).sum(),', functional = ',up.sum(),', tau = ',tau,', total newton iter = ',totaliter
nikcleju@66 600 print 'Log barrier iter = ',ii,', l1 = ',numpy.abs(xp).sum(),', functional = ',numpy.linalg.norm(p-xp),', tau = ',tau,', total newton iter = ',totaliter
nikcleju@66 601 x = xp.copy()
nikcleju@66 602 #u = up.copy()
nikcleju@66 603
nikcleju@66 604 tau = mu*tau
nikcleju@66 605
nikcleju@66 606 #end
nikcleju@66 607 return xp