-
Notifications
You must be signed in to change notification settings - Fork 0
/
pCNSeries.m
292 lines (245 loc) · 8.03 KB
/
pCNSeries.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
% Copyright (c) 2024 Matteo Giordano and Sven Wang
%
% Codes accompanying the article "Statistical algorithms for low-frequency diffusion data: A PDE approach"
% by Matteo Giordano andn Sven Wang
%%
% Contents:
%
% 1. Prior and initialisation
%
% 1.1 Prior specification
% 1.2 pCN initialisation
%
% 2. Bayesian nonparametric inference from low frequency diffusion data with
% truncated Gaussian series priors via the pCN algorithm for posterior
% sampling
%
% 2.1 pCN algorithm
% 2.2 Results
%
% Requires (part of) the output of GenerateObservations.m and
% SeriesDiscretisation.m
%%
% 1. Prior and initialisation
%%
% 1.1 Prior specification
%%
% Prior covariance matrix for Gaussian series prior draws
prior_regularity=1;
prior_variance=500;
prior_cov=zeros(J_basis,J_basis);
for j=1:J_basis
prior_cov(j,j)=prior_variance*lambdas_basis(j)^(-2*prior_regularity);
end
%%
% Sample and plot a prior draw
theta_rand=mvnrnd(zeros(J_basis,1),prior_cov,1)';
% sample Fourier coefficients from prior
F_rand=zeros(1,mesh_nodes_num_prior);
for j=1:J_basis
F_rand = F_rand+theta_rand(j)*e_basis(:,j)';
end
figure()
axes('FontSize', 13, 'NextPlot', 'add');
pdeplot(model_prior,'XYData',F_rand,'ColorMap',jet);
axis equal
colorbar('Fontsize',20)
xticks([-.5,-.25,0,.25,.5])
yticks([-.5,-.25,0,.25,.5])
ax = gca;
ax.FontSize = 20;
%%
% 1.2 pCN initialisation
%%
% choice of the initialiser
% Initialisation at 0
theta_init = zeros(J_basis,1);
% Initialisation at F_0
%theta_init = F0_coeff;
% Challenging initialisation at -F_0
%theta_init = -F0_coeff;
% Random initialisation Initialisation at a prior draw
%rng(1)
%theta_init = mvnrnd(zeros(J_basis,1),prior_cov,1)';
F_init_mesh_prior=zeros(1,mesh_nodes_num_prior);
for j=1:J_basis
F_init_mesh_prior = F_init_mesh_prior+theta_init(j)*e_basis(:,j)';
end
f_init_mesh_prior=f_min + exp(F_init_mesh_prior);
% Specify f_init as a function of (location,state) to pass to elliptic
% PDE solver
F_init_fun=@(location,state) griddata(mesh_nodes_prior(1,:),mesh_nodes_prior(2,:),...
F_init_mesh_prior,location.x,location.y);
f_init_fun=@(location,state) f_min+exp(F_init_fun(location,state));
tic
% Find Neumann eigenpairs for initial pCN state
specifyCoefficients(model,'m',0,'d',1,'c',f_init_fun,'a',0,'f',1);
results = solvepdeeig(model,range);
lambdas_init = results.Eigenvalues;
J_init=length(lambdas_init);
u_init = results.Eigenvectors;
u_init(:,1) = 1/sqrt(vol);
u_init(:,2:J_init)=u_init(:,2:J_init)...
*sqrt(mesh_nodes_num/vol);
toc
% Likelihood of initialisation point
loglik_init = 0;
for m=1:(sample_size-1)
trpdf = 0;
for j=1:J_init
trpdf = trpdf ...
+ exp(-deltaT_obs*lambdas_init(j))*u_init(index_obs_mesh(m),j)...
*u_init(index_obs_mesh(m+1),j);
end
loglik_init = loglik_init + log(abs(trpdf));
end
disp(['Log-likelihood of pCN initialisation = ', num2str(loglik_init)])
disp(['Log-likelihood of f0 = ', num2str(loglik0)])
%%
% 2. Bayesian nonparametric inference from low frequency diffusion data with
% truncated Gaussian series priors via the pCN algorithm for posterior
% sampling
%%
% 2.1 pCN algorithm
%%
% Run pCN
rng(1)
% sets the seed
tic
% Parameters
stepsize=.0001;
% smaller stepsizes imply shorter moves for the pCN proposal
pCN_length=25000;
% number of pCN draws
% Auxiliary variables
pCN_acc_count = zeros(1,pCN_length);
% tracker of acceptance steps
unifs = rand(1,pCN_length);
% i.i.d. Un(0,1) random variables for Metropolis-Hastings updates
pCN_theta = zeros(J_basis,pCN_length);
% initialise matrix to store the pCN chain of Fourier coefficients
pCN_theta(:,1)=theta_init;
% set pCN initialisation point
pCN_loglik = zeros(1,pCN_length);
% initialise tracker of the loglikelihood of the pCN chain
pCN_loglik(1) = loglik_init;
% set initial loglikelihood
loglik_current = pCN_loglik(1);
theta_current = pCN_theta(:,1);
u_current=u_init;
% pCN chain
for MCMC_index=2:pCN_length
disp(["pCN step n. " num2str(MCMC_index)])
% Construct pCN proposal
theta_rand=mvnrnd(zeros(J_basis,1),prior_cov,1)';
theta_proposal=sqrt(1-2*stepsize)*theta_current+sqrt(2*stepsize)*theta_rand;
F_proposal_mesh_prior=zeros(mesh_nodes_num_prior,1);
for j=1:J_basis
F_proposal_mesh_prior = F_proposal_mesh_prior+theta_proposal(j)*e_basis(:,j);
end
% Construct proposal diffusivity function to pass to PDE solver
F_proposal_fun=@(location,state) griddata(mesh_nodes_prior(1,:),...
mesh_nodes_prior(2,:),F_proposal_mesh_prior,location.x,location.y);
f_proposal_fun=@(location,state) f_min+exp(F_proposal_fun(location,state));
% Solve Neumann eigenvalue problem corresponding to proposal
specifyCoefficients(model,'m',0,'d',1,'c',f_proposal_fun,'a',0,'f',1);
results = solvepdeeig(model,range);
lambdas_proposal = results.Eigenvalues;
J_proposal=length(lambdas_proposal);
u_proposal = results.Eigenvectors;
u_proposal(:,1) = 1/sqrt(vol);
u_proposal(:,2:J_proposal)=u_proposal(:,2:J_proposal)...
*sqrt(mesh_nodes_num/vol);
% Compute log-likelihood of proposal
loglik_proposal = 0;
for m=1:(sample_size-1)
trpdf = 0;
for j=1:J_proposal
trpdf = trpdf ...
+ exp(-deltaT_obs*lambdas_proposal(j))*...
u_proposal(index_obs_mesh(m),j)*u_proposal(index_obs_mesh(m+1),j);
end
loglik_proposal = loglik_proposal + log(abs(trpdf));
end
% Compute acceptance probability
alpha=exp(loglik_proposal-loglik_current);
% Metropolis-Hastings update
if unifs(MCMC_index)<alpha % accept proposal
theta_current = theta_proposal;
loglik_current = loglik_proposal;
pCN_acc_count(1,MCMC_index)=pCN_acc_count(1,MCMC_index-1)+1;
u_current = u_proposal;
else
pCN_acc_count(1,MCMC_index)=pCN_acc_count(1,MCMC_index-1);
end
pCN_theta(:,MCMC_index) = theta_current;
pCN_loglik(MCMC_index) = loglik_current;
end
toc
%%
% 2.2 Results
%%
% Acceptance ratio and loglikelihood along the MCMC chain
% Acceptance ratio
accept_ratio=pCN_acc_count./(1:pCN_length);
figure()
axes('FontSize', 20, 'NextPlot', 'add');
plot(accept_ratio(1:pCN_length),'-','LineWidth',5)
yline(.3,'r','LineWidth',2)
legend('Acceptance ratio','Fontsize',20)
xlabel('pCN step','FontSize', 20)
% Log-likelihood
figure()
axes('FontSize', 20, 'NextPlot', 'add');
plot(pCN_loglik,'-', 'LineWidth',2)
%title('Loglikelihood along the MCMC chain','FontSize',20)
xlabel('pCN step','FontSize', 20)
yline(loglik0,'r','LineWidth',2)
ylim([loglik0-25,loglik0+25])
legend('Log-likelihood of f_{\vartheta_m}','Log-likelihood of f_0',...
'Fontsize',20)
%%
% MCMC average and estimation error
burnin=2500;
% Compute MCMC average
theta_mean = mean(pCN_theta(:,(burnin+1):pCN_length),2);
F_mean_mesh_prior=zeros(mesh_nodes_num_prior,1);
for j=1:J_basis
F_mean_mesh_prior = F_mean_mesh_prior +theta_mean(j)*e_basis(:,j);
end
% Plot MCMC average and estimation erorr
figure()
pdeplot(model_prior,'XYData',F0_mesh_prior,'ColorMap',jet)
%title('True F_0','FontSize',20)
clim([min(F0_mesh_prior),max(F0_mesh_prior)])
axis equal
colorbar('Fontsize',20)
xticks([-.5,-.25,0,.25,.5])
yticks([-.5,-.25,0,.25,.5])
ax = gca;
ax.FontSize = 20;
figure()
pdeplot(model_prior,'XYData',F_mean_mesh_prior,'ColorMap',jet)
%title('Posterior mean estimate (via pCN)','FontSize',20)
clim([min(F0_mesh_prior),max(F0_mesh_prior)])
axis equal
colorbar('Fontsize',20)
xticks([-.5,-.25,0,.25,.5])
yticks([-.5,-.25,0,.25,.5])
ax = gca;
ax.FontSize = 20;
figure()
axes('FontSize', 13, 'NextPlot', 'add');
pdeplot(model_prior,'XYData',F0_mesh_prior-F_mean_mesh_prior','ColorMap',hot)
%title('Estimation error','FontSize',20)
axis equal
colorbar('Fontsize',20)
xticks([-.5,-.25,0,.25,.5])
yticks([-.5,-.25,0,.25,.5])
ax = gca;
ax.FontSize = 20;
% Approximate L^2 distance between f_0 and posterior mean
pCN_estim_error = norm(theta_mean - F0_coeff);
disp(['L^2 estim error = ', num2str(pCN_estim_error)])
disp(['L^2 approximation error via projection = ', num2str(approx_error)])
disp(['L^2 norm of F_0 = ', num2str(F0_norm)])