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);