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 |