0001 function [X, C, evalue, residuums, micro_res, objective, elapsed_time] = block_eigenvalue(A, p, rr, opts)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 nn = A.size_col;
0043 d = A.order;
0044
0045 if ~isfield( opts, 'maxiter'); opts.maxiter = 3; end
0046 if ~isfield( opts, 'maxrank'); opts.maxrank = 40; end
0047 if ~isfield( opts, 'tol'); opts.tol = 1e-8; end
0048 if ~isfield( opts, 'tolLOBPCG'); opts.tolLOBPCG = 1e-6; end
0049 if ~isfield( opts, 'maxiterLOBPCG'); opts.maxiterLOBPCG = 2000; end
0050 if ~isfield( opts, 'verbose'); opts.verbose = 1; end
0051 if ~isfield( opts, 'precInner'); opts.precInner = true; end
0052 if ~isfield( opts, 'X0'); useX0 = 0; else useX0 = 1; end
0053
0054 if p == 1
0055 tolLOBPCGmod = opts.tolLOBPCG;
0056 else
0057 tolLOBPCGmod = 0.00001;
0058 end
0059
0060
0061 if ~useX0
0062 X = TTeMPS_rand( rr, nn );
0063
0064 X = orthogonalize( X, X.order );
0065
0066 X.U{d} = rand( X.rank(d), X.size(d), X.rank(d+1), p );
0067 C = cell( 1, p );
0068 C{1} = X.U{d}(:,:,:,1);
0069 for i = 2:p
0070 C{i} = X.U{d}(:,:,:,i);
0071 end
0072
0073 else
0074 X = opts.X0;
0075 X.U{d} = rand( X.rank(d), X.size(d), X.rank(d+1), p );
0076 C = cell( 1, p );
0077 C{1} = X.U{d}(:,:,:,1);
0078 for i = 2:p
0079 C{i} = X.U{d}(:,:,:,i);
0080 end;
0081 end
0082
0083 evalue = [];
0084 residuums = zeros(p,2*opts.maxiter);
0085 micro_res = [];
0086 resi_norm = zeros(p,1);
0087 objective = [];
0088 tic;
0089 elapsed_time = [];
0090
0091
0092 for i = 1:opts.maxiter
0093
0094 disp(sprintf('Iteration %i:', i));
0095
0096 fprintf(1, 'RIGHT-TO-LEFT SWEEP. ---------------\n')
0097
0098 for mu = d:-1:2
0099 sz = [X.rank(mu), X.size(mu), X.rank(mu+1)];
0100
0101 if opts.verbose
0102 fprintf(1,'Current core: %i. Current iterate (first eigenvalue): \n', mu);
0103 disp(X);
0104 fprintf(1,'Running LOBPCG: system size %i, tol %g ... ', prod(sz), max(opts.tolLOBPCG, min( tolLOBPCGmod, sqrt(sum(residuums(:,2*(i-1)+1).^2))/sqrt(p)*tolLOBPCGmod )))
0105 else
0106 fprintf(1,'%i ',mu);
0107 end
0108
0109 [left, right] = Afun_prepare( A, X, mu );
0110
0111 if opts.precInner
0112 if prod(sz) < 5*p;
0113 Amat = zeros( prod(sz) );
0114 for i_mat = 1:prod(sz)
0115 Amat(:,i_mat) = Afun_block_optim( A, [zeros(i_mat-1,1); 1; zeros(prod(sz)-i_mat,1)], sz, left, right, mu);
0116 end
0117 [vmat,emat] = eig(Amat);
0118 [emat,sortind] = sort(diag(emat),'ascend');
0119 vmat = vmat(:, sortind);
0120 L = emat(1:p);
0121 V = vmat(:, 1:p);
0122
0123 disp('Reduced system too small for LOBPCG, using eig instead');
0124 disp(['Current Eigenvalue approx: ', num2str( L(1:p)')]);
0125
0126
0127 else
0128 expB = constr_precond_inner( A, X, mu );
0129 [V,L,failureFlag,Lhist ] = lobpcg( rand( prod(sz), p), ...
0130 @(y) Afun_block_optim( A, y, sz, left, right, mu), [], ...
0131 @(y) apply_local_precond( A, y, sz, expB), ...
0132 max(opts.tolLOBPCG, min( tolLOBPCGmod, sqrt(sum(residuums(:,2*(i-1)+1).^2))/sqrt(p)*tolLOBPCGmod )), ...
0133 opts.maxiterLOBPCG, 0);
0134 if opts.verbose
0135 if failureFlag
0136 fprintf(1,'NOT CONVERGED within %i steps!\n', opts.maxiterLOBPCG)
0137 else
0138 fprintf(1,'converged after %i steps!\n', size(Lhist,2));
0139 end
0140 disp(['Current Eigenvalue approx: ', num2str( L(1:p)')]);
0141 end
0142 end
0143 else
0144 if prod(sz) < 25;
0145 Amat = zeros( prod(sz) );
0146 for i_mat = 1:prod(sz)
0147 Amat(:,i_mat) = Afun_block_optim( A, [zeros(i_mat-1,1); 1; zeros(prod(sz)-i_mat,1)], sz, left, right, mu);
0148 end
0149 [vmat,emat] = eig(Amat);
0150 [emat,sortind] = sort(diag(emat),'ascend');
0151 vmat = vmat(:, sortind);
0152 L = emat(1:p);
0153 V = vmat(:, 1:p);
0154
0155 disp('Condition number!')
0156 cond(Amat)
0157
0158 disp('Reduced system too small for LOBPCG, using eig instead');
0159 disp(['Current Eigenvalue approx: ', num2str( L(1:p)')]);
0160
0161 else
0162 X0 = rand( prod(sz), p);
0163 X0 = orth(X0);
0164 [V,L,failureFlag,Lhist ] = lobpcg( X0, ...
0165 @(y) Afun_block_optim( A, y, sz, left, right, mu), ...
0166 opts.tolLOBPCG, opts.maxiterLOBPCG, 0);
0167 end
0168 end
0169
0170 evalue = [evalue, L(1:p)];
0171 objective = [objective, sum(evalue(:,end))];
0172 elapsed_time = [elapsed_time, toc];
0173
0174 X.U{mu} = reshape( V, [sz, p] );
0175 lamX = X;
0176 lamX.U{mu} = repmat( reshape(L, [1 1 1 p]), [X.rank(mu), X.size(mu), X.rank(mu+1), 1]).*lamX.U{mu};
0177 res_new = apply(A, X) - lamX
0178
0179 for j = 1:p
0180 X.U{mu} = reshape( V(:,j), sz );
0181 res = apply(A, X) - L(j)*X;
0182 resi_norm(j) = norm(res);
0183 residuums(j,2*(i-1)+1) = resi_norm(j);
0184
0185 end
0186
0187
0188 micro_res = [micro_res, resi_norm];
0189
0190
0191 V = reshape( V, [sz, p] );
0192 V = permute( V, [1, 4, 2, 3] );
0193 V = reshape( V, [sz(1)*p, sz(2)*sz(3)] );
0194
0195 [U,S,V] = svd( V, 'econ' );
0196
0197 if p == 1
0198 s = length(diag(S));
0199 else
0200 s = trunc_singular( diag(S), opts.tol, true, opts.maxrank );
0201 end
0202
0203 V = V(:,1:s)';
0204 X.U{mu} = reshape( V, [s, sz(2), sz(3)] );
0205
0206 W = U(:,1:s)*S(1:s,1:s);
0207 W = reshape( W, [sz(1), p, s]);
0208 W = permute( W, [1, 3, 2]);
0209 for k = 1:p
0210 C{k} = tensorprod_ttemps( X.U{mu-1}, W(:,:,k)', 3);
0211 end
0212
0213 X.U{mu-1} = C{1};
0214
0215 if opts.verbose
0216 disp( ['Augmented system of size (', num2str( [sz(1)*p, sz(2)*sz(3)]), '). Cut-off tol: ', num2str(opts.tol) ])
0217 disp( sprintf( 'Number of SVs: %i. Truncated to: %i => %g %%', length(diag(S)), s, s/length(diag(S))*100))
0218 disp(' ')
0219 end
0220 end
0221
0222
0223
0224 fprintf(1, '--------------- finshed sweep. ---------------\n')
0225 disp(['Current residuum: ', num2str(residuums(:,2*(i-1)+1).')])
0226 disp(' ')
0227 disp(' ')
0228 fprintf(1, '--------------- LEFT-TO-RIGHT SWEEP. ---------------\n')
0229
0230 for mu = 1:d-1
0231 sz = [X.rank(mu), X.size(mu), X.rank(mu+1)];
0232
0233 if opts.verbose
0234 fprintf(1,'Current core: %i. Current iterate (first eigenvalue): \n', mu);
0235 disp(X);
0236 fprintf(1,'Running LOBPCG: system size %i, tol %g ... ', prod(sz), max(opts.tolLOBPCG, min( tolLOBPCGmod, sqrt(sum(residuums(:,2*(i-1)+2).^2))/sqrt(p)*tolLOBPCGmod )))
0237 else
0238 fprintf(1,'%i ',mu);
0239 end
0240
0241 [left, right] = Afun_prepare( A, X, mu );
0242
0243 if opts.precInner
0244 expB = constr_precond_inner( A, X, mu );
0245 X0 = rand( prod(sz), p);
0246 X0 = orth(X0);
0247 [U,L,failureFlag,Lhist ] = lobpcg( X0 , ...
0248 @(y) Afun_block_optim( A, y, sz, left, right, mu), [], ...
0249 @(y) apply_local_precond( A, y, sz, expB), ...
0250 max(opts.tolLOBPCG, min( tolLOBPCGmod, sqrt(sum(residuums(:,2*(i-1)+2).^2))/sqrt(p)*tolLOBPCGmod )), ...
0251 opts.maxiterLOBPCG, 0);
0252 else
0253 if prod(sz) < 25;
0254 Amat = zeros( prod(sz) );
0255 for i_mat = 1:prod(sz)
0256 Amat(:,i_mat) = Afun_block_optim( A, [zeros(i_mat-1,1); 1; zeros(prod(sz)-i_mat,1)], sz, left, right, mu);
0257 end
0258 [vmat,emat] = eig(Amat);
0259 [emat,sortind] = sort(diag(emat),'ascend');
0260 vmat = vmat(:, sortind);
0261 L = emat(1:p);
0262 U = vmat(:, 1:p);
0263
0264 disp('Reduced system too small for LOBPCG, using eig instead');
0265 disp(['Current Eigenvalue approx: ', num2str( L(1:p)')]);
0266 else
0267 X0 = rand( prod(sz), p);
0268 X0 = orth(X0);
0269 [U,L,failureFlag,Lhist ] = lobpcg( X0 , ...
0270 @(y) Afun_block_optim( A, y, sz, left, right, mu), ...
0271 opts.tolLOBPCG, opts.maxiterLOBPCG, 0);
0272 end
0273 end
0274
0275 if opts.verbose
0276 if failureFlag
0277 fprintf(1,'NOT CONVERGED within %i steps!\n', opts.maxiterLOBPCG)
0278 else
0279 fprintf(1,'converged after %i steps!\n', size(Lhist,2));
0280 end
0281 disp(['Current Eigenvalue approx: ', num2str( L(1:p)')]);
0282 end
0283 evalue = [evalue, L(1:p)];
0284 objective = [objective, sum(evalue(:,end))];
0285 elapsed_time = [elapsed_time, toc];
0286
0287 for j = 1:p
0288 X.U{mu} = reshape( U(:,j), sz );
0289 res = apply(A, X) - L(j)*X;
0290 resi_norm(j) = norm(res);
0291 residuums(j,2*(i-1)+2) = resi_norm(j);
0292 end
0293 micro_res = [micro_res, resi_norm];
0294
0295
0296 U = reshape( U, [sz, p] );
0297 U = permute( U, [1, 2, 4, 3] );
0298 U = reshape( U, [sz(1)*sz(2), p*sz(3)] );
0299
0300 [U,S,V] = svd( U, 'econ' );
0301 if p == 1
0302 s = length(diag(S));
0303 else
0304 s = trunc_singular( diag(S), opts.tol, true, opts.maxrank );
0305 end
0306
0307 U = U(:,1:s);
0308 X.U{mu} = reshape( U, [sz(1), sz(2), s] );
0309 W = S(1:s,1:s)*V(:,1:s)';
0310 W = reshape( W, [s, p, sz(3)]);
0311 W = permute( W, [1, 3, 2]);
0312
0313 for k = 1:p
0314 C{k} = tensorprod_ttemps( X.U{mu+1}, W(:,:,k), 1);
0315 end
0316
0317 X.U{mu+1} = C{1};
0318
0319 if opts.verbose
0320 disp( ['Augmented system of size (', num2str( [sz(1)*sz(2), p*sz(3)]), '). Cut-off tol: ', num2str(opts.tol) ])
0321 disp( sprintf( 'Number of SVs: %i. Truncated to: %i => %g %%', length(diag(S)), s, s/length(diag(S))*100))
0322 disp(' ')
0323 end
0324 end
0325
0326 fprintf(1, '--------------- finshed sweep. ---------------\n')
0327 disp(['Current residuum: ', num2str(residuums(:,2*(i-1)+2).')])
0328 disp(' ')
0329 disp(' ')
0330 end
0331
0332 evs = zeros(p,1);
0333
0334 for i=1:p
0335 evec = X;
0336 evec.U{d} = C{i};
0337 evs(i) = innerprod( evec, apply(A, evec));
0338 end
0339 evalue = [evalue, evs];
0340
0341 end
0342
0343 function [left, right] = Afun_prepare( A, x, idx )
0344 y = A.apply(x);
0345 if idx == 1
0346 right = innerprod( x, y, 'RL', idx+1 );
0347 left = [];
0348 elseif idx == x.order
0349 left = innerprod( x, y, 'LR', idx-1 );
0350 right = [];
0351 else
0352 left = innerprod( x, y, 'LR', idx-1 );
0353 right = innerprod( x, y, 'RL', idx+1 );
0354 end
0355 end
0356
0357 function res = Afun_block_optim( A, U, sz, left, right, mu )
0358
0359 p = size(U, 2);
0360
0361 V = reshape( U, [sz, p] );
0362 V = A.apply( V, mu );
0363
0364 if mu == 1
0365 tmp = reshape( permute( V, [3 1 2 4] ), [size(V, 3), sz(1)*sz(2)*p]);
0366 tmp = right * tmp;
0367 tmp = reshape( tmp, [size(right, 1), sz(1), sz(2), p]);
0368 tmp = ipermute( tmp, [3 1 2 4] );
0369 elseif mu == A.order
0370 tmp = reshape( V, [size(V,1), sz(2)*sz(3)*p]);
0371 tmp = left * tmp;
0372 tmp = reshape( tmp, [size(left, 1), sz(2), sz(3), p]);
0373 else
0374 tmp = reshape( permute( V, [3 1 2 4] ), [size(V, 3), size(V, 1)*sz(2)*p]);
0375 tmp = right * tmp;
0376 tmp = reshape( tmp, [size(right, 1), size(V, 1), sz(2), p]);
0377 tmp = ipermute( tmp, [3 1 2 4] );
0378
0379 tmp = reshape( tmp, [size(V, 1), sz(2)*sz(3)*p]);
0380 tmp = left * tmp;
0381 tmp = reshape( tmp, [size(left, 1), sz(2), sz(3), p]);
0382
0383 end
0384
0385 res = reshape( tmp, [prod(sz), p] );
0386
0387
0388 end
0389
0390 function res = apply_local_precond( A, U, sz, expB)
0391
0392 p = size(U, 2);
0393
0394 x = reshape( U, [sz, p] );
0395 res = zeros( [sz, p] );
0396
0397 for i = 1:size( expB, 1)
0398 tmp = reshape( x, [sz(1), sz(2)*sz(3)*p] );
0399 tmp = reshape( expB{1,i}*tmp, [sz(1), sz(2), sz(3), p] );
0400
0401 tmp = reshape( permute( tmp, [2 1 3 4] ), [sz(2), sz(1)*sz(3)*p] );
0402 tmp = ipermute( reshape( expB{2,i}*tmp, [sz(2), sz(1), sz(3), p] ), [2 1 3 4] );
0403
0404 tmp = reshape( permute( tmp, [3 1 2 4] ), [sz(3), sz(1)*sz(2)*p] );
0405 tmp = ipermute( reshape( expB{3,i}*tmp, [sz(3), sz(1), sz(2), p] ), [3 1 2 4] );
0406
0407 res = res + tmp;
0408 end
0409 res = reshape( res, [prod(sz), p] );
0410
0411 end
0412