|
@@ -5,26 +5,29 @@ import pylab
|
5
|
5
|
import pprint
|
6
|
6
|
from scipy.optimize import nnls
|
7
|
7
|
|
|
8
|
+import matplotlib.pyplot as plt
|
|
9
|
+
|
8
|
10
|
def PhiB(mux, muy, minVal, maxVal, x):
|
9
|
11
|
phib = mux * np.abs( np.sum(np.log( x-minVal)) )
|
10
|
|
- #phib += np.abs( np.log(1. - maxVal / np.sum(x)) )
|
11
|
12
|
return phib
|
12
|
|
- #phib += np.log std::log(maxVal - x.segment(ib*block, block).sum());
|
13
|
|
-
|
14
|
13
|
|
15
|
|
- #template < typename Scalar >
|
16
|
|
- #Scalar PhiB2 (const Scalar& minVal, const Scalar& maxVal, const VectorXr x,
|
17
|
|
- # const int& block, const int &nblocks) {
|
18
|
|
- # Scalar phib = std::abs((x.array() - minVal).log().sum());
|
19
|
|
- # //phib += std::abs((maxVal - x.array()).log().sum()*muy);
|
20
|
|
- # for (int ib=0; ib<nblocks; ++ib) {
|
21
|
|
- # //HiSegments(ib) = x.segment(ib*block, block).sum();
|
22
|
|
- # phib += Scalar(block)*std::log(maxVal - x.segment(ib*block, block).sum());
|
23
|
|
- # }
|
24
|
|
- # return phib;
|
25
|
|
- #}
|
26
|
|
-
|
27
|
|
-def logBarrier(A, b, T2Bins, x_0=0, xr=0, alpha=10, mu1=10, mu2=10, smooth=False, MAXITER=70, fignum=1000, sigma=1, callback=None):
|
|
14
|
+def curvaturefd(x, y, t):
|
|
15
|
+ x1 = np.gradient(x,t)
|
|
16
|
+ x2 = np.gradient(x1,t)
|
|
17
|
+ y1 = np.gradient(y,t)
|
|
18
|
+ y2 = np.gradient(y1,t)
|
|
19
|
+ return np.abs(x1*y2 - y1*x2) / np.power(x1**2 + y1**2, 3./2)
|
|
20
|
+
|
|
21
|
+def curvatureg(x, y):
|
|
22
|
+ from scipy.ndimage import gaussian_filter1d
|
|
23
|
+ #first and second derivative
|
|
24
|
+ x1 = gaussian_filter1d(x, sigma=1, order=1)#, mode='constant', cval=x[-1])
|
|
25
|
+ x2 = gaussian_filter1d(x1, sigma=1, order=1)#, mode='constant', cval=y[-1])
|
|
26
|
+ y1 = gaussian_filter1d(y, sigma=1, order=1)#, mode='constant', cval=x1[-1])
|
|
27
|
+ y2 = gaussian_filter1d(y1, sigma=1, order=1)#, mode='constant', cval=y1[-1])
|
|
28
|
+ return np.abs(x1*y2 - y1*x2) / np.power(x1**2 + y1**2, 3./2)
|
|
29
|
+
|
|
30
|
+def logBarrier(A, b, T2Bins, lambdastar, x_0=0, xr=0, alpha=10, mu1=10, mu2=10, smooth=False, MAXITER=70, fignum=1000, sigma=1, callback=None):
|
28
|
31
|
"""Impliments a log barrier Tikhonov solution to a linear system of equations
|
29
|
32
|
Ax = b s.t. x_min < x < x_max. A log-barrier term is used for the constraint
|
30
|
33
|
"""
|
|
@@ -35,13 +38,11 @@ def logBarrier(A, b, T2Bins, x_0=0, xr=0, alpha=10, mu1=10, mu2=10, smooth=False
|
35
|
38
|
Wd = (np.eye(len(b)) / (sigma)) # Wd = eye( sigma )
|
36
|
39
|
WdTWd = (np.eye(len(b)) / (sigma**2)) # Wd = eye( sigma )
|
37
|
40
|
|
38
|
|
- #print ("calculating AT WdT.Wd A ") # AT WdTWd A with known data matrix
|
39
|
|
- #print (" A.shape" , np.shape(A), np.shape(b))
|
40
|
41
|
ATWdTWdA = np.dot(A.conj().transpose(), np.dot( WdTWd, A )) # TODO, implicit calculation instead?
|
41
|
42
|
N = np.shape(A)[1] # number of model
|
42
|
43
|
M = np.shape(A)[0] # number of data
|
43
|
|
- SIGMA = .25 #.25 #.125 # .25 #.01#3e-1
|
44
|
|
- EPSILON = 1e-35 # was 35
|
|
44
|
+ SIGMA = .25
|
|
45
|
+ EPSILON = 1e-35
|
45
|
46
|
|
46
|
47
|
# reference model
|
47
|
48
|
if np.size(xr) == 1:
|
|
@@ -54,9 +55,8 @@ def logBarrier(A, b, T2Bins, x_0=0, xr=0, alpha=10, mu1=10, mu2=10, smooth=False
|
54
|
55
|
x = 1e-10 + x_0
|
55
|
56
|
|
56
|
57
|
# Construct model constraint base
|
57
|
|
- #print ("constructing Phim")
|
58
|
58
|
Phim_base = np.zeros( [N , N] )
|
59
|
|
- a1 = 1.0 # smallest
|
|
59
|
+ a1 = .05 # smallest too
|
60
|
60
|
|
61
|
61
|
# calculate largest term
|
62
|
62
|
D1 = 1./abs(T2Bins[1]-T2Bins[0])
|
|
@@ -64,56 +64,53 @@ def logBarrier(A, b, T2Bins, x_0=0, xr=0, alpha=10, mu1=10, mu2=10, smooth=False
|
64
|
64
|
#a2 = 1. #(1./(2.*D1+D2)) # smooth
|
65
|
65
|
|
66
|
66
|
if smooth == "Both":
|
67
|
|
- #print ("SMOOTH")
|
68
|
|
- # Smooth model
|
69
|
|
- print ("Both small and smooth model")
|
|
67
|
+ #print ("Both small and smooth model")
|
70
|
68
|
for ip in range(N):
|
71
|
69
|
D1 = 0.
|
72
|
70
|
D2 = 0.
|
73
|
|
- DMAX = 2./(T2Bins[1]-T2Bins[0])
|
74
|
71
|
if ip > 0:
|
75
|
|
- D1 = 1./abs(T2Bins[ip]-T2Bins[ip-1])
|
|
72
|
+ #D1 = np.sqrt(1./abs(T2Bins[ip]-T2Bins[ip-1]))**.5
|
|
73
|
+ D1 = (1./abs(T2Bins[ip]-T2Bins[ip-1])) #**2
|
76
|
74
|
if ip < N-1:
|
77
|
|
- D2 = 1./abs(T2Bins[ip+1]-T2Bins[ip])
|
|
75
|
+ #D2 = np.sqrt(1./abs(T2Bins[ip+1]-T2Bins[ip]))**.5
|
|
76
|
+ D2 = (1./abs(T2Bins[ip+1]-T2Bins[ip])) #**2
|
78
|
77
|
if ip > 0:
|
79
|
|
- Phim_base[ip,ip-1] = -(D1) # smooth in log space
|
|
78
|
+ Phim_base[ip,ip-1] = -(D1)
|
80
|
79
|
if ip == 0:
|
81
|
|
- Phim_base[ip,ip ] = (D1+D2) + a1 # Encourage a little low model, no a1
|
|
80
|
+ Phim_base[ip,ip ] = 2.*(D1+D2)
|
82
|
81
|
elif ip == N-1:
|
83
|
|
- Phim_base[ip,ip ] = (D1+D2) + a1 # Penalize long decays
|
|
82
|
+ Phim_base[ip,ip ] = 2.*(D1+D2)
|
84
|
83
|
else:
|
85
|
|
- Phim_base[ip,ip ] = (D1+D2) + a1 # Smooth and small
|
|
84
|
+ Phim_base[ip,ip ] = 2.*(D1+D2)
|
86
|
85
|
if ip < N-1:
|
87
|
|
- Phim_base[ip,ip+1] = -(D2) # smooth in log space
|
88
|
|
-
|
89
|
|
- #Phim_base /= np.max(Phim_base)
|
90
|
|
- #Phim_base += a1*np.eye(N)
|
|
86
|
+ Phim_base[ip,ip+1] = -(D2)
|
|
87
|
+ Phim_base /= np.max(Phim_base) # normalize
|
|
88
|
+ Phim_base += a1*np.eye(N)
|
91
|
89
|
|
92
|
90
|
elif smooth == "Smooth":
|
93
|
|
- print ("Smooth model")
|
|
91
|
+ #print ("Smooth model")
|
94
|
92
|
for ip in range(N):
|
95
|
93
|
if ip > 0:
|
96
|
94
|
Phim_base[ip,ip-1] = -1 # smooth in log space
|
97
|
95
|
if ip == 0:
|
98
|
|
- Phim_base[ip,ip ] = 1.0 # Encourage a little low model
|
|
96
|
+ Phim_base[ip,ip ] = 2.05 # Encourage a little low model
|
99
|
97
|
elif ip == N-1:
|
100
|
|
- Phim_base[ip,ip ] = 8.0 # Penalize long decays
|
|
98
|
+ Phim_base[ip,ip ] = 2.5 # Penalize long decays
|
101
|
99
|
else:
|
102
|
|
- Phim_base[ip,ip ] = 2.0 # Smooth and small
|
|
100
|
+ Phim_base[ip,ip ] = 2.1 # Smooth and small
|
103
|
101
|
if ip < N-1:
|
104
|
102
|
Phim_base[ip,ip+1] = -1 # smooth in log space
|
105
|
|
- #print(Phim_base)
|
106
|
103
|
|
107
|
|
- else:
|
108
|
|
- print ("SMALLEST")
|
109
|
|
- # Smallest model
|
|
104
|
+ elif smooth == "Smallest":
|
110
|
105
|
for ip in range(N):
|
111
|
106
|
Phim_base[ip,ip ] = 1.
|
|
107
|
+ else:
|
|
108
|
+ print("non valid model constraint:", smooth)
|
|
109
|
+ exit()
|
112
|
110
|
|
113
|
111
|
Phi_m = alpha*Phim_base
|
114
|
112
|
WmTWm = Phim_base # np.dot(Phim_base, Phim_base.T)
|
115
|
113
|
b_pre = np.dot(A, x)
|
116
|
|
-
|
117
|
114
|
phid = np.linalg.norm( np.dot(Wd, (b-b_pre)) )**2
|
118
|
115
|
phim = np.linalg.norm( np.dot(Phim_base, (x-xr)) )**2
|
119
|
116
|
|
|
@@ -121,24 +118,28 @@ def logBarrier(A, b, T2Bins, x_0=0, xr=0, alpha=10, mu1=10, mu2=10, smooth=False
|
121
|
118
|
phib = PhiB(mu1, mu2, 0, 1e8, x)
|
122
|
119
|
mu1 = ((phid + alpha*phim) / phib)
|
123
|
120
|
|
124
|
|
- #print ("iteration", -1, mu1, mu2, phib, phid, phim, len(b))
|
|
121
|
+ PHIM = []
|
|
122
|
+ PHID = []
|
|
123
|
+ MOD = []
|
|
124
|
+
|
|
125
|
+ ALPHA = []
|
|
126
|
+ ALPHA.append(alpha)
|
125
|
127
|
for i in range(MAXITER):
|
126
|
|
-
|
127
|
|
- b_pre = np.dot(A, x)
|
128
|
|
- phid = np.linalg.norm(np.dot(Wd, (b-b_pre)))**2
|
129
|
|
- # technically phim should not be on WmTWm matrix. So no need to square result.
|
130
|
|
- phim = np.linalg.norm(np.dot(Phim_base, (x-xr)))#**2
|
131
|
|
- phib = PhiB(mu1, mu2, 0, 1e8, x)
|
|
128
|
+
|
132
|
129
|
Phi_m = alpha*Phim_base
|
133
|
130
|
|
|
131
|
+ # reset mu1 at each iteration
|
|
132
|
+ # Calvetti -> No ; Li -> Yes
|
|
133
|
+ # without this, non monotonic convergence occurs...which is OK if you really trust your noise
|
134
|
134
|
mu1 = ((phid + alpha*phim) / phib)
|
135
|
135
|
|
136
|
136
|
WmTWm = Phim_base # np.dot(Phim_base, Phim_base.T)
|
137
|
|
- #ztilde = x
|
138
|
|
- #print("ztilde", ztilde)
|
139
|
137
|
phid_old = phid
|
140
|
138
|
inner = 0
|
141
|
|
- First = True
|
|
139
|
+
|
|
140
|
+ First = True # guarantee entry
|
|
141
|
+
|
|
142
|
+ xp = np.copy(x) # prior step x
|
142
|
143
|
|
143
|
144
|
while ( (phib / (phid+alpha*phim)) > EPSILON or First==True ):
|
144
|
145
|
|
|
@@ -154,14 +155,14 @@ def logBarrier(A, b, T2Bins, x_0=0, xr=0, alpha=10, mu1=10, mu2=10, smooth=False
|
154
|
155
|
AA = ATWdTWdA + mu1*X2 + mu2*Y2 + Phi_m
|
155
|
156
|
M = np.eye( N ) * (1./np.diag(ATWdTWdA + mu1*X2 + mu2*Y2 + Phi_m))
|
156
|
157
|
|
157
|
|
- # Solve system (newton step)
|
158
|
|
- b2 = np.dot(A.transpose(), np.dot(WdTWd, b-b_pre) ) + 2.*mu1*np.diag(X1) + 2.*mu2*np.diag(Y1) - alpha*np.dot(WmTWm,(x-xr))
|
159
|
|
- ztilde = iter.cg(AA, b2, M=M) # tol=1e-3*phid, maxiter=200, callback=callback) #, tol=1e-2, maxiter) #, x0=x) #, tol=ttol) #, M=M, x0=x)
|
160
|
|
- h = (ztilde[0])
|
|
158
|
+ # Solve system (newton step) (Li)
|
|
159
|
+ b2 = np.dot(A.conj().transpose(), np.dot(WdTWd, b-b_pre) ) + 2.*mu1*np.diag(X1) + 2.*mu2*np.diag(Y1) - alpha*np.dot(WmTWm,(x-xr))
|
|
160
|
+ ztilde = iter.cg(AA, b2, M = M)
|
|
161
|
+ h = (ztilde[0].real)
|
161
|
162
|
|
162
|
|
- # Solve system (direct solution)
|
|
163
|
+ # Solve system (direct solution) (Calvetti)
|
163
|
164
|
#b2 = np.dot(A.conj().transpose(), np.dot(WdTWd, b)) + 2.*mu1*np.diag(X1) + 2.*mu2*np.diag(Y1) - alpha*np.dot(WmTWm,(x-xr))
|
164
|
|
- #ztilde = iter.cg(AA, b2, x0=x) #, tol=1e-2) #, x0=x) #, tol=ttol) #, M=M, x0=x)
|
|
165
|
+ #ztilde = iter.cg(AA, b2, M=M, x0=x)
|
165
|
166
|
#h = (ztilde[0].real - x)
|
166
|
167
|
|
167
|
168
|
# step size
|
|
@@ -169,8 +170,7 @@ def logBarrier(A, b, T2Bins, x_0=0, xr=0, alpha=10, mu1=10, mu2=10, smooth=False
|
169
|
170
|
|
170
|
171
|
##########################################################
|
171
|
172
|
# Update and fix any over/under stepping
|
172
|
|
- x = x+d*h
|
173
|
|
- #x = np.max( ( (minVal+1e-120)*np.ones(N), x+d*h), 0)
|
|
173
|
+ x += d*h
|
174
|
174
|
|
175
|
175
|
# Determine mu steps to take
|
176
|
176
|
s1 = mu1 * (np.dot(X2, ztilde[0].real) - 2.*np.diag(X1))
|
|
@@ -181,32 +181,87 @@ def logBarrier(A, b, T2Bins, x_0=0, xr=0, alpha=10, mu1=10, mu2=10, smooth=False
|
181
|
181
|
mu2 = SIGMA/N * np.abs(np.dot(s2, x))
|
182
|
182
|
|
183
|
183
|
b_pre = np.dot(A, x)
|
184
|
|
- phid = np.linalg.norm(np.dot(Wd, (b-b_pre)))**2
|
185
|
|
- phim = np.linalg.norm(np.dot(Phim_base, (x-xr)))#**2
|
|
184
|
+ phid = np.linalg.norm( np.dot(Wd, (b-b_pre)))**2
|
|
185
|
+ phim = np.linalg.norm( np.dot(Phim_base, (x-xr)) )**2
|
186
|
186
|
phib = PhiB(mu1, mu2, minVal, maxVal, x)
|
187
|
187
|
inner += 1
|
188
|
188
|
|
|
189
|
+ PHIM.append(phim)
|
|
190
|
+ PHID.append(phid)
|
|
191
|
+ MOD.append(np.copy(x))
|
|
192
|
+
|
189
|
193
|
# determine alpha
|
190
|
194
|
scale = (len(b)/phid)
|
191
|
|
- alpha *= scale #**(1/6)
|
192
|
|
-
|
193
|
|
- score = np.sqrt(phid/(len(b)+1.)) # unbiased
|
194
|
|
-
|
195
|
|
- # check stopping criteria
|
196
|
|
- if score < 1:
|
197
|
|
- print ("*overshot* optimal solution found") #, alpha, score)
|
198
|
|
- break
|
199
|
|
- if score < 1.1: # or np.linalg.norm(x_old-x) < 1e-5 or phid > phid_old:
|
200
|
|
- #print ("overshoot")
|
201
|
|
- #alpha *= 10
|
202
|
|
- print ("optimal solution found") #, alpha, score)
|
203
|
|
- break
|
204
|
|
- if i > 10 and (np.sqrt(phid_old/(len(b)+1.)) - score) < 1e-2: # 1e-2
|
205
|
|
- print ("slow convergence") #, alpha, score, i, scale, score-np.sqrt(phid_old/len(b)))
|
206
|
|
- break
|
207
|
|
-
|
208
|
|
- print ( "alpha","phid", "iter", "search", "prior" )
|
209
|
|
- print ( alpha, score, i, scale, np.sqrt(phid_old/(len(b)+1)))
|
|
195
|
+ #alpha *= np.sqrt(scale)
|
|
196
|
+ alpha *= min(scale, .95) # was .85...
|
|
197
|
+ ALPHA.append(alpha)
|
|
198
|
+ #alpha = ALPHA[i+1]
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+# if np.sqrt(phid/len(b)) < 0.97:
|
|
202
|
+# ibreak = -1
|
|
203
|
+# print ("------------overshot--------------------", alpha, np.sqrt(phid/len(b)), ibreak)
|
|
204
|
+# alpha *= 2. #0
|
|
205
|
+# x -= d*h
|
|
206
|
+# b_pre = np.dot(A, x)
|
|
207
|
+# phid = np.linalg.norm( np.dot(Wd, (b-b_pre)))**2
|
|
208
|
+# phim = np.linalg.norm( np.dot(Phim_base, (x-xr)) )#**2
|
|
209
|
+# mu1 = ((phid + alpha*phim) / phib)
|
|
210
|
+ if lambdastar == "discrepency":
|
|
211
|
+ if np.sqrt(phid/len(b)) < 1.00 or alpha < 1e-5:
|
|
212
|
+ ibreak = 1
|
|
213
|
+ print ("optimal solution found", alpha, np.sqrt(phid/len(b)), ibreak)
|
|
214
|
+ break
|
|
215
|
+ # slow convergence, bail and use L-curve
|
|
216
|
+ # TI- only use L-curve. Otherwise results for perlin noise are too spurious for paper.
|
|
217
|
+ if lambdastar == "lcurve":
|
|
218
|
+ if i>20 and ((np.sqrt(phid_old/len(b))-np.sqrt(phid/len(b))) < 1e-4):
|
|
219
|
+ #if np.sqrt(phid/len(b)) < 3.0 and ((np.sqrt(phid_old/len(b))-np.sqrt(phid/len(b))) < 1e-3):
|
|
220
|
+ ibreak = 1
|
|
221
|
+ MOD = np.array(MOD)
|
|
222
|
+ print ("###########################") #slow convergence", alpha, "phid_old", np.sqrt(phid_old/len(b)), "phid", np.sqrt(phid/len(b)), ibreak)
|
|
223
|
+ print ("Using L-curve criteria")
|
|
224
|
+ kappa = curvaturefd(np.log(np.array(PHIM)), np.log(np.array(PHID)), ALPHA[0:-1])
|
|
225
|
+ #kappa2 = curvatureg(np.log(np.array(PHIM)), np.log(np.array(PHID)))
|
|
226
|
+ #kappa = curvature( np.array(PHIM), np.array(PHID))
|
|
227
|
+ x = MOD[ np.argmax(kappa) ]
|
|
228
|
+ b_pre = np.dot(A, x)
|
|
229
|
+ phid = np.linalg.norm( np.dot(Wd, (b-b_pre)))**2
|
|
230
|
+ phim = np.linalg.norm( np.dot(Phim_base, (x-xr)) )**2
|
|
231
|
+ mu1 = ((phid + alpha*phim) / phib)
|
|
232
|
+ print ("L-curve selected", alpha, "phid_old", np.sqrt(phid_old/len(b)), "phid", np.sqrt(phid/len(b)), ibreak)
|
|
233
|
+ print ("###########################")
|
|
234
|
+ if np.sqrt(phid/len(b)) <= 1:
|
|
235
|
+ ibreak=0
|
|
236
|
+
|
|
237
|
+ #plt.figure()
|
|
238
|
+ #plt.plot( (np.array(PHIM)), np.log(np.array(PHID)/len(b)), '.-')
|
|
239
|
+ #plt.plot( ((np.array(PHIM))[np.argmax(kappa)]) , np.log( (np.array(PHID)/len(b))[np.argmax(kappa)] ), '.', markersize=12)
|
|
240
|
+ #plt.axhline()
|
|
241
|
+ #plt.plot( np.array(PHIM), np.array(PHID), '.-')
|
|
242
|
+ #plt.plot( np.array(PHIM)[np.argmax(kappa)], np.array(PHID)[np.argmax(kappa)], '.', markersize=12)
|
|
243
|
+ #plt.savefig('lcurve.pdf')
|
|
244
|
+ break
|
|
245
|
+
|
|
246
|
+ PHIM = np.array(PHIM)
|
|
247
|
+ PHID = np.array(PHID)
|
|
248
|
+
|
|
249
|
+ if (i == MAXITER-1 ):
|
|
250
|
+ ibreak = 2
|
|
251
|
+ print("Reached max iterations!!", alpha, np.sqrt(phid/len(b)), ibreak)
|
|
252
|
+ kappa = curvaturefd(np.log(np.array(PHIM)), np.log(np.array(PHID)), ALPHA[0:-1])
|
|
253
|
+ x = MOD[ np.argmax(kappa) ]
|
|
254
|
+ b_pre = np.dot(A, x)
|
|
255
|
+ phid = np.linalg.norm( np.dot(Wd, (b-b_pre)))**2
|
|
256
|
+ phim = np.linalg.norm( np.dot(Phim_base, (x-xr)) )**2
|
|
257
|
+ mu1 = ((phid + alpha*phim) / phib)
|
|
258
|
+
|
|
259
|
+ if lambdastar == "lcurve":
|
|
260
|
+ return x, ibreak, np.sqrt(phid/len(b)), PHIM, PHID/len(b), np.argmax(kappa)
|
|
261
|
+ else:
|
|
262
|
+ return x, ibreak, np.sqrt(phid/len(b))
|
|
263
|
+
|
210
|
264
|
|
211
|
|
- return x
|
212
|
265
|
|
|
266
|
+if __name__ == "__main__":
|
|
267
|
+ print("Test")
|