-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdacefit.m
More file actions
298 lines (267 loc) · 8.85 KB
/
Copy pathdacefit.m
File metadata and controls
298 lines (267 loc) · 8.85 KB
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
293
294
295
296
297
298
function [dmodel, perf] = dacefit(S, Y, regr, corr, theta0, lob, upb)
%DACEFIT Constrained non-linear least-squares fit of a given correlation
% model to the provided data set and regression model
%
% Call
% [dmodel, perf] = dacefit(S, Y, regr, corr, theta0)
% [dmodel, perf] = dacefit(S, Y, regr, corr, theta0, lob, upb)
%
% Input
% S, Y : Data points (S(i,:), Y(i,:)), i = 1,...,m
% regr : Function handle to a regression model
% corr : Function handle to a correlation function
% theta0 : Initial guess on theta, the correlation function parameters
% lob,upb : If present, then lower and upper bounds on theta
% Otherwise, theta0 is used for theta
%
% Output
% dmodel : DACE model: a struct with the elements
% regr : function handle to the regression model
% corr : function handle to the correlation function
% theta : correlation function parameters
% beta : generalized least squares estimate
% gamma : correlation factors
% sigma2 : maximum likelihood estimate of the process variance
% S : scaled design sites
% Ssc : scaling factors for design arguments
% Ysc : scaling factors for design ordinates
% C : Cholesky factor of correlation matrix
% Ft : Decorrelated regression matrix
% G : From QR factorization: Ft = Q*G' .
% perf : struct with performance information. Elements
% nv : Number of evaluations of objective function
% perf : (q+2)*nv array, where q is the number of elements
% in theta, and the columns hold current values of
% [theta; psi(theta); type]
% |type| = 1, 2 or 3, indicate 'start', 'explore' or 'move'
% A negative value for type indicates an uphill step
% hbn@imm.dtu.dk
% Last update September 3, 2002
% Check design points
[m n] = size(S); % number of design sites and their dimension
sY = size(Y);
if min(sY) == 1, Y = Y(:); lY = max(sY); sY = size(Y);
else, lY = sY(1); end
if m ~= lY
error('S and Y must have the same number of rows'), end
% Check correlation parameters
lth = length(theta0);
if nargin > 5 % optimization case
if length(lob) ~= lth | length(upb) ~= lth
error('theta0, lob and upb must have the same length'), end
if any(lob <= 0) | any(upb < lob)
error('The bounds must satisfy 0 < lob <= upb'), end
else % given theta
if any(theta0 <= 0)
error('theta0 must be strictly positive'), end
end
% Normalize data
mS = mean(S); sS = std(S);
mY = mean(Y); sY = std(Y);
% 02.08.27: Check for 'missing dimension'
j = find(sS == 0);
if ~isempty(j), sS(j) = 1; end
j = find(sY == 0);
if ~isempty(j), sY(j) = 1; end
S = (S - repmat(mS,m,1)) ./ repmat(sS,m,1);
Y = (Y - repmat(mY,m,1)) ./ repmat(sY,m,1);
% Calculate distances D between points
mzmax = m*(m-1) / 2; % number of non-zero distances
ij = zeros(mzmax, 2); % initialize matrix with indices
D = zeros(mzmax, n); % initialize matrix with distances
ll = 0;
for k = 1 : m-1
ll = ll(end) + (1 : m-k);
ij(ll,:) = [repmat(k, m-k, 1) (k+1 : m)']; % indices for sparse matrix
D(ll,:) = repmat(S(k,:), m-k, 1) - S(k+1:m,:); % differences between points
end
if min(sum(abs(D),2) ) == 0
error('Multiple design sites are not allowed'), end
% Regression matrix
F = feval(regr, S); [mF p] = size(F);
if mF ~= m, error('number of rows in F and S do not match'), end
if p > mF, error('least squares problem is underdetermined'), end
% parameters for objective function
par = struct('corr',corr, 'regr',regr, 'y',Y, 'F',F, ...
'D', D, 'ij',ij, 'scS',sS);
% Determine theta
if nargin > 5
% Bound constrained non-linear optimization
[theta f fit perf] = boxmin(theta0, lob, upb, par);
if isinf(f)
error('Bad parameter region. Try increasing upb'), end
else
% Given theta
theta = theta0(:);
[f fit] = objfunc(theta, par);
perf = struct('perf',[theta; f; 1], 'nv',1);
if isinf(f)
error('Bad point. Try increasing theta0'), end
end
% Return values
dmodel = struct('regr',regr, 'corr',corr, 'theta',theta.', ...
'beta',fit.beta, 'gamma',fit.gamma, 'sigma2',sY.^2.*fit.sigma2, ...
'S',S, 'Ssc',[mS; sS], 'Ysc',[mY; sY], ...
'C',fit.C, 'Ft',fit.Ft, 'G',fit.G);
% >>>>>>>>>>>>>>>> Auxiliary functions ====================
function [obj, fit] = objfunc(theta, par)
% Initialize
obj = inf;
fit = struct('sigma2',NaN, 'beta',NaN, 'gamma',NaN, ...
'C',NaN, 'Ft',NaN, 'G',NaN);
m = size(par.F,1);
% Set up R
r = feval(par.corr, theta, par.D);
idx = find(r > 0); o = (1 : m)';
mu = (10+m)*eps;
R = sparse([par.ij(idx,1); o], [par.ij(idx,2); o], ...
[r(idx); ones(m,1)+mu]);
% Cholesky factorization with check for pos. def.
[C rd] = chol(R);
if rd, return, end % not positive definite
% Get least squares solution
C = C'; Ft = C \ par.F;
[Q G] = qr(Ft,0);
if rcond(G) < 1e-10
% Check F
if cond(par.F) > 1e15
T = sprintf('F is too ill conditioned\nPoor combination of regression model and design sites');
error(T)
else % Matrix Ft is too ill conditioned
return
end
end
Yt = C \ par.y; beta = G \ (Q'*Yt);
rho = Yt - Ft*beta; sigma2 = sum(rho.^2)/m;
detR = prod( full(diag(C)) .^ (2/m) );
obj = sum(sigma2) * detR;
if nargout > 1
fit = struct('sigma2',sigma2, 'beta',beta, 'gamma',rho' / C, ...
'C',C, 'Ft',Ft, 'G',G');
end
% --------------------------------------------------------
function [t, f, fit, perf] = boxmin(t0, lo, up, par)
%BOXMIN Minimize with positive box constraints
% Initialize
[t, f, fit, itpar] = start(t0, lo, up, par);
if ~isinf(f)
% Iterate
p = length(t);
if p <= 2, kmax = 2; else, kmax = min(p,4); end
for k = 1 : kmax
th = t;
[t, f, fit, itpar] = explore(t, f, fit, itpar, par);
[t, f, fit, itpar] = move(th, t, f, fit, itpar, par);
end
end
perf = struct('nv',itpar.nv, 'perf',itpar.perf(:,1:itpar.nv));
% --------------------------------------------------------
function [t, f, fit, itpar] = start(t0, lo, up, par)
% Get starting point and iteration parameters
% Initialize
t = t0(:); lo = lo(:); up = up(:); p = length(t);
D = 2 .^ ([1:p]'/(p+2));
ee = find(up == lo); % Equality constraints
if ~isempty(ee)
D(ee) = ones(length(ee),1); t(ee) = up(ee);
end
ng = find(t < lo | up < t); % Free starting values
if ~isempty(ng)
t(ng) = (lo(ng) .* up(ng).^7).^(1/8); % Starting point
end
ne = find(D ~= 1);
% Check starting point and initialize performance info
[f fit] = objfunc(t,par); nv = 1;
itpar = struct('D',D, 'ne',ne, 'lo',lo, 'up',up, ...
'perf',zeros(p+2,200*p), 'nv',1);
itpar.perf(:,1) = [t; f; 1];
if isinf(f) % Bad parameter region
return
end
if length(ng) > 1 % Try to improve starting guess
d0 = 16; d1 = 2; q = length(ng);
th = t; fh = f; jdom = ng(1);
for k = 1 : q
j = ng(k); fk = fh; tk = th;
DD = ones(p,1); DD(ng) = repmat(1/d1,q,1); DD(j) = 1/d0;
alpha = min(log(lo(ng) ./ th(ng)) ./ log(DD(ng))) / 5;
v = DD .^ alpha; tk = th;
for rept = 1 : 4
tt = tk .* v;
[ff fitt] = objfunc(tt,par); nv = nv+1;
itpar.perf(:,nv) = [tt; ff; 1];
if ff <= fk
tk = tt; fk = ff;
if ff <= f
t = tt; f = ff; fit = fitt; jdom = j;
end
else
itpar.perf(end,nv) = -1; break
end
end
end % improve
% Update Delta
if jdom > 1
D([1 jdom]) = D([jdom 1]);
itpar.D = D;
end
end % free variables
itpar.nv = nv;
% --------------------------------------------------------
function [t, f, fit, itpar] = explore(t, f, fit, itpar, par)
% Explore step
nv = itpar.nv; ne = itpar.ne;
for k = 1 : length(ne)
j = ne(k); tt = t; DD = itpar.D(j);
if t(j) == itpar.up(j)
atbd = 1; tt(j) = t(j) / sqrt(DD);
elseif t(j) == itpar.lo(j)
atbd = 1; tt(j) = t(j) * sqrt(DD);
else
atbd = 0; tt(j) = min(itpar.up(j), t(j)*DD);
end
[ff fitt] = objfunc(tt,par); nv = nv+1;
itpar.perf(:,nv) = [tt; ff; 2];
if ff < f
t = tt; f = ff; fit = fitt;
else
itpar.perf(end,nv) = -2;
if ~atbd % try decrease
tt(j) = max(itpar.lo(j), t(j)/DD);
[ff fitt] = objfunc(tt,par); nv = nv+1;
itpar.perf(:,nv) = [tt; ff; 2];
if ff < f
t = tt; f = ff; fit = fitt;
else
itpar.perf(end,nv) = -2;
end
end
end
end % k
itpar.nv = nv;
% --------------------------------------------------------
function [t, f, fit, itpar] = move(th, t, f, fit, itpar, par)
% Pattern move
nv = itpar.nv; ne = itpar.ne; p = length(t);
v = t ./ th;
if all(v == 1)
itpar.D = itpar.D([2:p 1]).^.2;
return
end
% Proper move
rept = 1;
while rept
tt = min(itpar.up, max(itpar.lo, t .* v));
[ff fitt] = objfunc(tt,par); nv = nv+1;
itpar.perf(:,nv) = [tt; ff; 3];
if ff < f
t = tt; f = ff; fit = fitt;
v = v .^ 2;
else
itpar.perf(end,nv) = -3;
rept = 0;
end
if any(tt == itpar.lo | tt == itpar.up), rept = 0; end
end
itpar.nv = nv;
itpar.D = itpar.D([2:p 1]).^.25;