0001 function [V] = left_divide(E,I,tol,~,V)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 if ischar(E) && strcmp(E,'UNIT_TEST'); do_unit_test; return; end
0024
0025 if nargin<3;
0026 tol=1e-8;
0027 end
0028 do_pcg = false;
0029 if isstruct(tol);
0030 fmdl = tol;
0031 try
0032 do_pcg = fmdl.left_divide.do_pcg;
0033 catch
0034 end
0035 try
0036 tol = fmdl.left_divide.tol;
0037 catch
0038 tol = 1e-8;
0039 end
0040 try
0041 V = fmdl.left_divide.V_initial;
0042 catch
0043 sz= [size(E),size(I)];
0044 V = eidors_obj('get-cache', sz, 'left_divide_V');
0045 if isempty(V); V = zeros(size(E,1),size(I,2)); end
0046 end
0047 end
0048
0049 if ~do_pcg
0050 try
0051 V= non_iterative(E,I);
0052 catch excp
0053
0054 if ~strcmp(excp.identifier , 'MATLAB:nomem')
0055 rethrow(excp);
0056 end
0057
0058 eidors_msg('Memory exhausted for inverse. Trying PCG',2);
0059 V=iterative_solve(E,I,tol,V,fmdl);
0060 end
0061 else
0062 V=iterative_solve(E,I,tol,V,fmdl);
0063 end
0064
0065 function V= non_iterative(E,I);
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078 if issparse(E)
0079
0080 inotzeros = logical(any(I,2));
0081
0082 [Qi,R] = qr(I(inotzeros,:),0);
0083 rnotzeros = logical(any(R,2));
0084
0085
0086
0087
0088
0089 R= R(rnotzeros,:);
0090 Q = zeros(size(I,1), size(R,1));
0091 Q(inotzeros,:) = Qi(:,rnotzeros);
0092
0093
0094
0095
0096
0097 V= (E \ Q)*R;
0098
0099 else
0100 if isreal(E)
0101 try
0102
0103
0104
0105 opts.SYM=true;
0106 opts.POSDEF=true;
0107
0108 V= linsolve(E,I,opts);
0109 catch Mexcp
0110
0111
0112 if(strcmp(Mexcp.identifier,'MATLAB:posdef'))
0113
0114 warning('EIDORS:leftDivideSymmetry',...
0115 ['left_divide is optimised for symmetric ',...
0116 'positive definite matrices.']);
0117
0118 else
0119 warning(['Error with linsolve in left_divide, trying backslash.\n',...
0120 'Error identifier: ',Mexcp.identifier]);
0121 end
0122
0123
0124 V=E\I;
0125 end
0126 else
0127
0128 V=E\I;
0129 end
0130 end
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150 function V=iterative_solve(E,I,tol,V,fmdl)
0151
0152 [n_nodes,n_stims] = size(I);
0153 if isreal(E)
0154 opts.droptol = tol*100;
0155 opts.type = 'ict';
0156 U = ichol(E, opts);
0157 L = U';
0158 cgsolver = @pcg;
0159 else
0160 opts.droptol = tol/10;
0161 [L,U] = ilu(E, opts);
0162 cgsolver = @bicgstab;
0163 end
0164
0165 for i=1:n_stims
0166 [V(:,i),~] = feval( cgsolver, E,I(:,i), ...
0167 tol*norm(I(:,i)),n_nodes,L,U,V(:,i));
0168 end
0169 sz= [size(E),size(I)];
0170 eidors_obj('set-cache', sz, 'left_divide_V', V);
0171
0172
0173
0174 function do_unit_test
0175
0176
0177
0178 inv_solve('UNIT_TEST')
0179 fwd_solve_1st_order('UNIT_TEST')
0180
0181
0182 s=warning('QUERY','EIDORS:leftDivideSymmetry');
0183 warning('OFF','EIDORS:leftDivideSymmetry')
0184 lastwarn('')
0185 A=rand(1e3);
0186 b=rand(1e3);
0187
0188 left_divide(A,b);
0189 [~, LASTID] = lastwarn;
0190 unit_test_cmp('sym warn',LASTID,'EIDORS:leftDivideSymmetry')
0191 warning(s);
0192
0193
0194 imdl=mk_common_model('n3r2',[16,2]);
0195 img=mk_image(imdl,1);
0196 img.elem_data=1+0.1*rand(size(img.elem_data));
0197 J = calc_jacobian(img);
0198 RtR = calc_RtR_prior(imdl);
0199 W = calc_meas_icov(imdl);
0200 hp = calc_hyperparameter(imdl);
0201 LHS = (J'*W*J + hp^2*RtR);
0202 RHS = J'*W;
0203 unit_test_cmp('dense chol',LHS\RHS,left_divide(LHS,RHS),1e-13)
0204
0205
0206 function do_timing_unit_tests
0207
0208
0209
0210
0211
0212 Nel = 64;
0213 for mn = 1:4; switch mn
0214 case 1;
0215 fmdl = mk_common_model('d2c0',64);
0216 fmdl = fmdl.fwd_model;
0217 case 2;
0218 fmdl = mk_common_model('l2c0',64);
0219 fmdl = fmdl.fwd_model;
0220 case 3;
0221 fmdl = mk_circ_tank(16, linspace(-1,1,41), {'planes',Nel, 21});
0222 fmdl.solve = @eidors_default;
0223 fmdl.system_mat = @eidors_default;
0224 case 4;
0225 fmdl = mk_circ_tank(32, linspace(-1,1,41), {'planes',Nel, 21});
0226 fmdl.solve = @eidors_default;
0227 fmdl.system_mat = @eidors_default;
0228 end
0229 stim= mk_stim_patterns(Nel,1,[0,3],[0,3],{},1);
0230 for sp = 1:2; switch sp;
0231 case 1;
0232 fmdl.stimulation = stim;
0233 case 2;
0234 SSMM = stim_meas_list(stim);
0235 [~,idx] = sort(rand(size(SSMM,1),1));
0236 fmdl.stimulation = stim_meas_list(SSMM(idx,:));
0237 end;
0238 img = mk_image(fmdl,1);
0239
0240 s_mat = calc_system_mat(img);
0241 idx= 1:size(s_mat.E,1);
0242 idx(img.fwd_model.gnd_node) = [];
0243 E = s_mat.E(idx,idx);
0244 pp= fwd_model_parameters( img.fwd_model, 'skip_VOLUME' );
0245 I = pp.QQ(idx,:);
0246
0247 inotzeros = logical(any(I,2));
0248 [Qi,R] = qr(I(inotzeros,:),0);
0249 rnotzeros = logical(any(R,2));
0250 R= R(rnotzeros,:);
0251 Q = sparse(size(I,1), size(R,1));
0252 Q(inotzeros,:) = Qi(:,rnotzeros);
0253 t=[];
0254 tic; T = E \ Q; t(end+1) = toc;
0255 tic; V = T * R; t(end+1) = toc;
0256 tic; T = full(E \ Q); t(end+1) = toc;
0257 tic; V = T * R; t(end+1) = toc;
0258 tic; T = E \ full(Q); t(end+1) = toc;
0259 tic; V = T * R; t(end+1) = toc;
0260 disp(t)
0261 end
0262 end