0001 function [alpha, img, dv, opt] = line_search_onm2(imgk, dx, data1, img1, N, W, hps2RtR, hpt2LLt, dv0, opt, retry, pf_max)
0002
0003
0004
0005
0006
0007 perturb = calc_perturb(imgk, dx, opt);
0008
0009 if nargin < 11
0010 retry = 0;
0011 end
0012
0013 if nargin < 12
0014 pf_max = length(perturb)-2;
0015 end
0016
0017
0018 if ~isfield(opt, 'fwd_solutions')
0019 opt.fwd_solutions = 0;
0020 end
0021 x = imgk.elem_data;
0022
0023 if(perturb(1) ~= 0)
0024 error('first perturbation min(inv_model.inv_solve_abs_{GN,CG,core}.line_search.perturb) expects alpha=0');
0025 end
0026
0027
0028 img = imgk;
0029
0030
0031
0032
0033 if opt.verbose > 1
0034 fprintf(' i = ');
0035 fprintf(' [%d] \t', 1:length(perturb));
0036 fprintf('\n');
0037 fprintf(' alpha = ');
0038 fprintf(' %8.3g\t', perturb);
0039 fprintf('\n');
0040 fprintf(' ');
0041 end
0042 mlist= ones(size(perturb))*NaN;
0043 for i = 1:length(perturb)
0044 if (i == 1) && (~isempty(dv0))
0045
0046 dv = dv0;
0047 else
0048
0049 img.elem_data = x + perturb(i)*dx;
0050 [dv, opt] = feval(opt.line_search_dv_func, img, data1, N, opt);
0051 end
0052
0053 de = feval(opt.line_search_de_func, img, img1, opt);
0054
0055 if any(isnan(dv) | isinf(dv))
0056 warning(sprintf('%d of %d elements in dv are NaN or Inf', ...
0057 length(dv), ...
0058 length(find(isnan(dv) | isinf(dv)))));
0059 mlist(i) = +Inf;
0060 elseif any(isnan(de) | isinf(de))
0061 warning(sprintf('%d of %d elements in de are NaN or Inf', ...
0062 length(de), ...
0063 length(find(isnan(de) | isinf(de)))));
0064 mlist(i) = +Inf;
0065 else
0066
0067 mlist(i) = feval(opt.residual_func, dv, de, W, hps2RtR, hpt2LLt);
0068 if any(isnan(mlist(i)) | isinf(mlist(i)))
0069 mlist(i) = +Inf;
0070 end
0071 end
0072 if opt.verbose > 1
0073 fprintf(' %8.3g\t',mlist(i));
0074 end
0075 if mlist(i)/mlist(1) > 1e10
0076 if opt.verbose > 1
0077 for j=(i+1):length(perturb)
0078 fprintf(' [skip]\t');
0079 end
0080 end
0081 break
0082 end
0083 end
0084 if opt.verbose > 1
0085 fprintf('\n');
0086 end
0087
0088 if isinf(mlist)
0089 warning('encoutered NaN or +-Inf residuals, something has gone wrong in the line search, converting to large numbers and carrying on');
0090 end
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105 goodi = find((~isnan(mlist)) & (~isinf(mlist)));
0106 alpha=perturb(end);
0107 meas_err = +Inf;
0108 if length(goodi) > 2
0109
0110 p_rng = range(perturb(goodi));
0111 pfx = log10(perturb(goodi)/p_rng);
0112 pfx(1) = -100;
0113 pf= polyfit(pfx, mlist(goodi), length(goodi)-2);
0114
0115
0116 FF = @(pf, x) polyval(pf, log10(x/p_rng));
0117 alpha = fminbnd(@(x) FF(pf, x), perturb(min(goodi)), perturb(end));
0118
0119 img.elem_data = x + alpha*dx;
0120 [dv, opt] = feval(opt.line_search_dv_func, img, data1, N, opt);
0121 de = feval(opt.line_search_de_func, img, img1, opt);
0122 meas_err = feval(opt.residual_func, dv, de, W, hps2RtR, hpt2LLt);
0123 if opt.verbose > 1
0124 fprintf(' step size = %0.3g, misfit = %0.3g, expected = %0.3g\n', alpha, meas_err, FF(pf, alpha));
0125 end
0126
0127
0128
0129
0130 est_err = meas_err / FF(pf, alpha);
0131 if (opt.verbose > 1) && ((est_err > 1.3) || (est_err < 0.5))
0132 fprintf(' step misfit missed estimate (%0.1fx est)\n', est_err);
0133 fprintf(' consider stronger regularization?\n');
0134 end
0135 else
0136
0137
0138 pf = [];
0139 FF = @(pf, x) -(mlist(1) - mlist(end))*0.8*log10(x) + mlist(end);
0140 end
0141
0142 alpha1 = alpha;
0143 meas_err1 = meas_err;
0144
0145
0146
0147 if meas_err > min(mlist)
0148 [meas_err,mi]= min(mlist);
0149 alpha= perturb(mi);
0150 img.elem_data = x + alpha*dx;
0151 dv = [];
0152 if (length(goodi) > 2) && (opt.verbose > 1)
0153 fprintf(' did not like our step selection - choose one of perturb values\n');
0154 end
0155 end
0156
0157 if opt.verbose > 1
0158 max_alpha_str = '';
0159 if alpha > perturb(end)-eps
0160 max_alpha_str = ' (max)';
0161 end
0162 fprintf(' step size = %0.3g%s, misfit = %0.3g selected\n', alpha, max_alpha_str, meas_err);
0163 end
0164
0165
0166
0167 if opt.line_search_args.plot
0168 clf;
0169 plot_line_optimize(perturb, mlist, alpha, meas_err, alpha1, meas_err1, FF, pf);
0170 if isfield(opt,'fig_prefix')
0171 k=1;
0172 print('-dpdf',sprintf('%s-ls%d-retry%d',opt.fig_prefix,k,retry));
0173 print('-dpng',sprintf('%s-ls%d-retry%d',opt.fig_prefix,k,retry));
0174 saveas(gcf,sprintf('%s-ls%d-retry%d.fig',opt.fig_prefix,k,retry));
0175 end
0176 end
0177
0178
0179 if meas_err >= mlist(1)
0180 if mlist(1)*1.05 < mlist(goodi(end))
0181
0182 if opt.verbose > 1
0183 fprintf(' reducing perturbations /10: bad step\n');
0184 end
0185
0186
0187 perturb = perturb/10;
0188 elseif perturb(end) > 1.0-10*eps
0189 if opt.verbose > 1
0190 fprintf(' expanding perturbations x10: ... but we''d be searching past alpha=1.0, giving up\n');
0191 end
0192 return
0193 elseif perturb(end)*10 > 1.0-10*eps
0194 if opt.verbose > 1
0195 fprintf(' expanding perturbations (limit alpha=1.0): bad step\n');
0196 end
0197 perturb = perturb/perturb(end);
0198 else
0199
0200
0201 if opt.verbose > 1
0202 fprintf(' expanding perturbations x10: bad step\n');
0203 end
0204
0205
0206 perturb = perturb*10;
0207 end
0208 else
0209
0210 if all(mlist(goodi)/mlist(1)-1 > -10*opt.dtol) && ...
0211 (perturb(end)*10 < 1.0+10*eps)
0212 if opt.verbose > 1
0213 fprintf(' expand perturbations x10 for next iteration\n');
0214 fprintf(' (didn''t make much progress this iteration)\n');
0215 end
0216 opt.line_search_args.perturb = opt.line_search_args.perturb*10;
0217 else
0218
0219
0220 if opt.verbose > 1
0221 fprintf(' update perturbations around step = %0.3g (limit alpha=1.0)\n', alpha);
0222 end
0223 if alpha/perturb(end)*2 > 1.0 - 10*eps
0224 perturb = perturb/perturb(end);
0225 else
0226 perturb = perturb*(alpha/perturb(end))*2;
0227 end
0228 end
0229 end
0230
0231
0232 perturb = perturb .* exp(randn(size(perturb))*0.01);
0233
0234 if perturb(end) > 1.0 - eps
0235 perturb = perturb/perturb(end);
0236 end
0237 opt.line_search_args.perturb = perturb;
0238
0239
0240
0241
0242
0243 if alpha == 0 && retry < 5
0244 if opt.verbose > 1
0245 fprintf(' retry#%d (attempt with new perturbations)\n', retry+1);
0246 end
0247 [alpha, img, dv, opt] = line_search_onm2(imgk, dx, data1, img1, N, W, hps2RtR, hpt2LLt, dv0, opt, retry+1, pf_max);
0248 end
0249
0250
0251
0252
0253
0254
0255 function perturb = calc_perturb(imgk, dx_in, opt)
0256 if opt.verbose > 1
0257 disp(' line search (finite precision) limits');
0258 end
0259
0260
0261
0262
0263
0264
0265
0266 if ~isfield(imgk, 'current_params')
0267 imgk.current_params = {'conductivity'};
0268 end
0269 if ~isfield(imgk, 'params_sel')
0270 imgk.params_sel = {[1:length(imgk.elem_data)]};
0271 end
0272 if ~iscell(imgk.current_params)
0273 imgk.current_params = {imgk.current_params};
0274 end
0275 if ~iscell(imgk.params_sel)
0276 imgk.params_sel = {imgk.params_sel};
0277 end
0278
0279 if isfield(imgk, 'inv_model') && isfield(imgk.inv_model, 'fwd_model')
0280 md = max(range(imgk.inv_model.fwd_model.nodes));
0281 end
0282
0283
0284 max_alpha = +inf;
0285 min_alpha = +inf;
0286 for i=1:length(imgk.current_params)
0287 p = imgk.current_params{i};
0288 s = imgk.params_sel{i};
0289 x = imgk.elem_data(s);
0290 dx = dx_in(s);
0291
0292 is_mvmt = (length(p) >= 8) && strcmp(p(end-7:end),'movement');
0293 if strcmp(p(1:4), 'log_')
0294 lp = log(realmax/2);
0295 ln = -inf;
0296
0297 if is_mvmt
0298 lp = log(md);
0299 end
0300 elseif strcmp(p(1:6), 'log10_')
0301 lp = log10(realmax/2);
0302 ln = -inf;
0303
0304 if is_mvmt
0305 lp = log10(md);
0306 end
0307 else
0308 lp = +realmax/2;
0309 ln = -realmax/2;
0310 if is_mvmt
0311 lp = +md;
0312 lp = -md;
0313 end
0314 end
0315
0316
0317 au=(lp-x)./dx; au(dx<=0)=NaN; au(isnan(au))=+inf; au=min(au);
0318 a_max = au;
0319 au=(ln-x)./dx; au(dx>=0)=NaN; au(isnan(au))=+inf; au=min(au);
0320 if (au < a_max)
0321 a_max = au;
0322 end
0323
0324
0325 if is_mvmt
0326 al=1e-3./abs(dx);
0327
0328 else
0329 al=eps(x)./abs(dx);
0330 end
0331 al(isinf(al))=NaN; al(isnan(al))=realmax; al=min(al);
0332 if isnan(al)
0333 a_min = 0;
0334 else
0335 a_min = al;
0336 end
0337 if opt.verbose > 1
0338 fprintf(' %s: alpha range = %0.3g -- %0.3g\n', p, a_min, a_max);
0339 end
0340
0341 if a_max < max_alpha
0342 max_alpha = a_max;
0343 end
0344 if a_min < min_alpha
0345 min_alpha = a_min;
0346 end
0347 end
0348
0349
0350 p=sort(opt.line_search_args.perturb);
0351
0352 if (p(end) > max_alpha) || (p(2) < min_alpha)
0353 p(p<realmin/2) = [];
0354 p=log10(p); ap=log10(max_alpha); an=log10(min_alpha);
0355 if range(p) > ap-an
0356 p=p*(ap-an)/range(p);
0357 end
0358 if p(end) > ap
0359 p=p-(max(p)-ap);
0360 elseif p(1) < an
0361 p=p+(an-min(p));
0362 end
0363 p=[0 10.^p];
0364 if opt.verbose > 1
0365 fprintf(' alpha (before) = ');
0366 fprintf('%0.3g ', sort(opt.line_search_args.perturb));
0367 fprintf('\n');
0368 fprintf(' alpha (after) = ');
0369 fprintf('%0.3g ', p);
0370 fprintf('\n');
0371 end
0372 else
0373 if opt.verbose > 1
0374 fprintf(' alpha (unchanged) = ');
0375 fprintf('%0.3g ', p);
0376 fprintf('\n');
0377 end
0378 end
0379 perturb=p;
0380
0381
0382
0383
0384
0385
0386
0387 function plot_line_optimize(perturb, mlist, alpha, meas_err, alpha1, meas_err1, FF, pf)
0388 semilogx(perturb(2:end),mlist(2:end),'xk', 'MarkerSize',10);
0389 hold on;
0390 semilogx(alpha, meas_err,'or', 'MarkerSize',10);
0391 semilogx(alpha1, FF(pf, alpha1), 'ob', 'MarkerSize',10);
0392 semilogx(alpha1, meas_err1, 'xb', 'MarkerSize',10);
0393
0394 if isnan(perturb(2))
0395 perturb(2) = perturb(end)/10;
0396 end
0397 p= logspace(log10(perturb(2)),log10(perturb(end)),50);
0398 semilogx(p, FF(pf, p),'k','linewidth',2);
0399 semilogx(p, p*0+mlist(1),'k--','linewidth',1);
0400
0401 legend('perturb', 'selected ', '1st est', '1st act', 'fit', '\alpha=0');
0402 legend('Location', 'EastOutside');
0403 m = [mlist meas_err meas_err1];
0404 mi=find(isnan(m) | isinf(m)); m(mi) = [];
0405 mr = range(m);
0406 if mr < max(m)*1e-14
0407 mr = 1e-14;
0408 end
0409 axis([perturb(2) perturb(end) min(m)-mr*0.2 max(m)+mr*0.2]);
0410 xlabel('step size \alpha');
0411 ylabel('normalized residuals');
0412 title({sprintf('best alpha = %1.2e',alpha), ...
0413 sprintf('norm w/o step = %0.4e',mlist(1))});
0414
0415 drawnow;
0416
0417 function x=range(y)
0418 x=max(y)-min(y);