PageRenderTime 29ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/blopex_tools/matlab/lobpcg/lobpcg.m

http://blopex.googlecode.com/
MATLAB | 991 lines | 713 code | 58 blank | 220 comment | 84 complexity | 3a2c35a7129498eb1fe8e9cc1d7f3f99 MD5 | raw file
  1. function [blockVectorX,lambda,varargout] = ...
  2. lobpcg(blockVectorX,operatorA,varargin)
  3. %LOBPCG solves Hermitian partial eigenproblems using preconditioning
  4. %
  5. % [blockVectorX,lambda]=lobpcg(blockVectorX,operatorA)
  6. %
  7. % outputs the array of algebraic smallest eigenvalues lambda and
  8. % corresponding matrix of orthonormalized eigenvectors blockVectorX of the
  9. % Hermitian (full or sparse) operator operatorA using input matrix
  10. % blockVectorX as an initial guess, without preconditioning, somewhat
  11. % similar to
  12. %
  13. % opts.issym=1;opts.isreal=1;K=size(blockVectorX,2);
  14. % [blockVectorX,lambda]=eigs(operatorA,K,'SR',opts);
  15. %
  16. % for real symmetric operator operatorA, or
  17. %
  18. % K=size(blockVectorX,2);[blockVectorX,lambda]=eigs(operatorA,K,'SR');
  19. % for Hermitian operator operatorA.
  20. %
  21. % [blockVectorX,lambda,failureFlag]=lobpcg(blockVectorX,operatorA)
  22. % also returns a convergence flag.
  23. % If failureFlag is 0 then all the eigenvalues converged; otherwise not all
  24. % converged.
  25. %
  26. % [blockVectorX,lambda,failureFlag,lambdaHistory,residualNormsHistory]=...
  27. % lobpcg(blockVectorX,'operatorA','operatorB','operatorT',blockVectorY,...
  28. % residualTolerance,maxIterations,verbosityLevel);
  29. %
  30. % computes smallest eigenvalues lambda and corresponding eigenvectors
  31. % blockVectorX of the generalized eigenproblem Ax=lambda Bx, where
  32. % Hermitian operators operatorA and operatorB are given as functions, as
  33. % well as a preconditioner, operatorT. The operators operatorB and
  34. % operatorT must be in addition POSITIVE DEFINITE. To compute the largest
  35. % eigenpairs of operatorA, simply apply the code to operatorA multiplied by
  36. % -1. The code does not involve ANY matrix factorizations of operratorA and
  37. % operatorB, thus, e.g., it preserves the sparsity and the structure of
  38. % operatorA and operatorB.
  39. %
  40. % residualTolerance and maxIterations control tolerance and max number of
  41. % steps, and verbosityLevel = 0, 1, or 2 controls the amount of printed
  42. % info. lambdaHistory is a matrix with all iterative lambdas, and
  43. % residualNormsHistory are matrices of the history of 2-norms of residuals
  44. %
  45. % Required input:
  46. % blockVectorX - initial approximation to eigenvectors, full or sparse
  47. % matrix n-by-blockSize. blockVectorX must be full rank.
  48. % operatorA - the operator of the problem, can be given as a matrix or as
  49. % an M-file
  50. %
  51. % Optional function input:
  52. % operatorB - the second operator, if solving a generalized eigenproblem,
  53. % can be given as a matrix or as an M-file; by default, or if empty,
  54. % operatorB=I.
  55. % operatorT - preconditioner, must be given by an M-file; by default,
  56. % operatorT=I.
  57. %
  58. % Optional constraints input:
  59. % blockVectorY - a full or sparse n-by-sizeY matrix of constraints, where
  60. % sizeY < n. The iterations will be performed in the (operatorB-)
  61. % orthogonal complement of the column-space of blockVectorY. blockVectorY
  62. % must be full rank.
  63. %
  64. % Optional scalar input parameters:
  65. % residualTolerance - tolerance, by default,
  66. % residualTolerance=n*sqrt(eps) maxIterations - max number of iterations,
  67. % by default, maxIterations = min(n,20) verbosityLevel - either 0 (no
  68. % info), 1, or 2 (with pictures); by default, verbosityLevel = 0.
  69. %
  70. % Required output: blockVectorX and lambda are computed blockSize
  71. % eigenpairs, where blockSize=size(blockVectorX,2) for the initial guess
  72. % blockVectorX if it is full rank.
  73. %
  74. % Optional output: failureFlag, lambdaHistory and residualNormsHistory are
  75. % described above.
  76. %
  77. % Functions operatorA(blockVectorX), operatorB(blockVectorX) and
  78. % operatorT(blockVectorX) must support blockVectorX being a matrix, not
  79. % just a column vector.
  80. %
  81. % Every iteration involves one application of operatorA and operatorB, and
  82. % one of operatorT.
  83. %
  84. % Main memory requirements: 6 (9 if isempty(operatorB)=0) matrices of the
  85. % same size as blockVectorX, 2 matrices of the same size as blockVectorY
  86. % (if present), and two square matrices of the size 3*blockSize.
  87. %
  88. % The following
  89. % Example:
  90. %
  91. % operatorA = 100.*delsq(numgrid('S',21)); [n,n]=size(operatorA);
  92. % [blockVectorX,lambda,failureFlag]=lobpcg(randn(n,10),operatorA,1e-5,50,2);
  93. %
  94. % attempts to compute 10 first eigenpairs of the Poisson operator
  95. % in a 2x2 square with the mesh size 1/10 without preconditioning,
  96. % but not all eigenpairs converge after 50 steps, so failureFlag=1.
  97. %
  98. % The next
  99. % Example:
  100. %
  101. % operatorA = 100.*delsq(numgrid('S',21)); [n,n]=size(operatorA);
  102. % blockVectorY=[];lambda_all=[];
  103. % for j=1:5
  104. % [blockVectorX,lambda]=...
  105. % lobpcg(randn(n,2),operatorA,blockVectorY,1e-5,200,2);
  106. % blockVectorY=[blockVectorY,blockVectorX];
  107. % lambda_all=[lambda_all' lambda']';
  108. % end
  109. %
  110. % attemps to compute the same eigenpairs by calling the code 5 times
  111. % with blockSize=2 using orthogonalization to the previously founded
  112. % eigenvectors.
  113. %
  114. %The following M-script:
  115. %
  116. % global R_cholinc
  117. % operatorA = 100.*delsq(numgrid('S',21)); [n,n]=size(operatorA);
  118. % R_cholinc=cholinc(operatorA,1e-3);
  119. % [blockVectorX,lambda,failureFlag]=...
  120. % lobpcg(randn(n,10),operatorA,[],'precsol',1e-5,50,2);
  121. %
  122. % computes the same eigenpairs in less then 25 steps, so that failureFlag=0
  123. % using the preconditioner function precsol:
  124. %
  125. % function blockVectorX=precsol(V)
  126. % global R_cholinc
  127. % blockVectorX=R_cholinc\(R_cholinc'\V);
  128. % In this example, operatorB=[] must be present in the input parameters.
  129. % [blockVectorX,lambda,failureFlag]=...
  130. % lobpcg(randn(n,10),operatorA,speye(n),'precsol',1e-5,50,2);
  131. %
  132. %produces similar answers, but is somewhat slower and needs more memory.
  133. %
  134. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  135. %
  136. % This main function LOBPCG is a version of
  137. % the preconditioned conjugate gradient method (Algorithm 5.1) described in
  138. % A. V. Knyazev, Toward the Optimal Preconditioned Eigensolver:
  139. % Locally Optimal Block Preconditioned Conjugate Gradient Method,
  140. % SIAM Journal on Scientific Computing 23 (2001), no. 2, pp. 517-541.
  141. % http://dx.doi.org/10.1137/S1064827500366124
  142. %
  143. % Known bugs/features:
  144. %
  145. % - an excessively small requested tolerance may result in often restarts
  146. % and instability. The code is not written to produce an eps-level
  147. % accuracy! Use common sense.
  148. %
  149. % - the code may be very sensitive to the number of eigenpairs computed,
  150. % if there is a cluster of eigenvalues not completely included, cf.
  151. %
  152. % operatorA=diag([1 1.99 2:99]);
  153. % [blockVectorX,lambda]=lobpcg(randn(100,1),operatorA,1e-10,80,2);
  154. % [blockVectorX,lambda]=lobpcg(randn(100,2),operatorA,1e-10,80,2);
  155. % [blockVectorX,lambda]=lobpcg(randn(100,3),operatorA,1e-10,80,2);
  156. %
  157. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  158. % The main distribution site:
  159. % http://math.ucdenver.edu/~aknyazev/
  160. %
  161. % A C-version of this code is a part of the
  162. % http://code.google.com/p/blopex/
  163. % package and is directly available, e.g., in PETSc and HYPRE.
  164. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  165. % License: GNU LGPL ver 2.1 or above
  166. % Copyright (c) 2000-2010 A.V. Knyazev, BLOPEX team
  167. % $Revision: 4.12 $ $Date: 14-Mar-2010
  168. % Tested in MATLAB 6.5-7.9.0.529 and Octave 3.2.3.
  169. %Begin
  170. % Check if we are in MATLAB or Octave. ver('MATLAB') will return an empty
  171. % struct if we are in Octave. Used below to suppress the graphics.
  172. version=ver('MATLAB');
  173. if all(size(version)==0)
  174. matlabFlag=0;
  175. else
  176. matlabFlag=1;
  177. end
  178. % constants
  179. CONVENTIONAL_CONSTRAINTS = 1;
  180. SYMMETRIC_CONSTRAINTS = 2;
  181. %Initial settings
  182. failureFlag = 1;
  183. if nargin < 2
  184. error('BLOPEX:lobpcg:NotEnoughInputs',...
  185. strcat('There must be at least 2 input agruments: ',...
  186. 'blockVectorX and operatorA'));
  187. end
  188. if nargin > 8
  189. warning('BLOPEX:lobpcg:TooManyInputs',...
  190. strcat('There must be at most 8 input agruments ',...
  191. 'unless arguments are passed to a function'));
  192. end
  193. if ischar(blockVectorX)
  194. error('BLOPEX:lobpcg:FirstInputString',...
  195. 'The first input argument blockVectorX cannot be a string');
  196. end
  197. [n,blockSize]=size(blockVectorX);
  198. if blockSize > n
  199. error('BLOPEX:lobpcg:FirstInputFat',...
  200. 'The first input argument blockVectorX must be tall, not fat');
  201. end
  202. if n < 6
  203. error('BLOPEX:lobpcg:MatrixTooSmall',...
  204. 'The code does not work for matrices of small sizes');
  205. end
  206. if ~ischar(operatorA)
  207. nA = size(operatorA,1);
  208. if any(size(operatorA) ~= nA)
  209. error('BLOPEX:lobpcg:MatrixNotSquare',...
  210. 'operatorA must be a square matrix or a string');
  211. end
  212. if size(operatorA) ~= n
  213. error('BLOPEX:lobpcg:MatrixWrongSize',...
  214. ['The size ' int2str(size(operatorA))...
  215. ' of operatorA is not the same as ' int2str(n)...
  216. ' - the number of rows of blockVectorX']);
  217. end
  218. end
  219. count_string = 0;
  220. operatorT = [];
  221. operatorB = [];
  222. residualTolerance = [];
  223. maxIterations = [];
  224. verbosityLevel = [];
  225. blockVectorY = []; sizeY = 0;
  226. for j = 1:nargin-2
  227. if isequal(size(varargin{j}),[n,n])
  228. if isempty(operatorB)
  229. operatorB = varargin{j};
  230. else
  231. error('BLOPEX:lobpcg:TooManyMatrixInputs',...
  232. strcat('Too many matrix input arguments. ',...
  233. 'Preconditioner operatorT must be an M-function'));
  234. end
  235. elseif isequal(size(varargin{j},1),n) && size(varargin{j},2) < n
  236. if isempty(blockVectorY)
  237. blockVectorY = varargin{j};
  238. sizeY=size(blockVectorY,2);
  239. else
  240. error('BLOPEX:lobpcg:WrongConstraintsFormat',...
  241. 'Something wrong with blockVectorY input argument');
  242. end
  243. elseif ischar(varargin{j})
  244. if count_string == 0
  245. if isempty(operatorB)
  246. operatorB = varargin{j};
  247. count_string = count_string + 1;
  248. else
  249. operatorT = varargin{j};
  250. end
  251. elseif count_string == 1
  252. operatorT = varargin{j};
  253. else
  254. error('BLOPEX:lobpcg:TooManyStringInputs',...
  255. 'Too many string input arguments');
  256. end
  257. elseif isequal(size(varargin{j}),[n,n])
  258. error('BLOPEX:lobpcg:WrongPreconditionerFormat',...
  259. 'Preconditioner operatorT must be an M-function');
  260. elseif max(size(varargin{j})) == 1
  261. if isempty(residualTolerance)
  262. residualTolerance = varargin{j};
  263. elseif isempty(maxIterations)
  264. maxIterations = varargin{j};
  265. elseif isempty(verbosityLevel)
  266. verbosityLevel = varargin{j};
  267. else
  268. error('BLOPEX:lobpcg:TooManyScalarInputs',...
  269. 'Too many scalar parameters, need only three');
  270. end
  271. elseif isempty(varargin{j})
  272. if isempty(operatorB)
  273. count_string = count_string + 1;
  274. elseif ~isempty(operatorT)
  275. count_string = count_string + 1;
  276. elseif ~isempty(blockVectorY)
  277. error('BLOPEX:lobpcg:UnrecognizedEmptyInput',...
  278. ['Unrecognized empty input argument number ' int2str(j+2)]);
  279. end
  280. else
  281. error('BLOPEX:lobpcg:UnrecognizedInput',...
  282. ['Input argument number ' int2str(j+2) ' not recognized.']);
  283. end
  284. end
  285. if verbosityLevel
  286. if issparse(blockVectorX)
  287. fprintf(['The sparse initial guess with %i colunms '...
  288. 'and %i raws is detected \n'],n,blockSize);
  289. else
  290. fprintf(['The full initial guess with %i colunms '...
  291. 'and %i raws is detected \n'],n,blockSize);
  292. end
  293. if ischar(operatorA)
  294. fprintf('The main operator is detected as an M-function %s \n',...
  295. operatorA);
  296. elseif issparse(operatorA)
  297. fprintf('The main operator is detected as a sparse matrix \n');
  298. else
  299. fprintf('The main operator is detected as a full matrix \n');
  300. end
  301. if isempty(operatorB)
  302. fprintf('Solving standard eigenvalue problem, not generalized \n');
  303. elseif ischar(operatorB)
  304. fprintf(['The second operator of the generalized eigenproblem \n'...
  305. 'is detected as an M-function %s \n'],operatorB);
  306. elseif issparse(operatorB)
  307. fprintf(strcat('The second operator of the generalized',...
  308. 'eigenproblem \n is detected as a sparse matrix \n'));
  309. else
  310. fprintf(strcat('The second operator of the generalized',...
  311. 'eigenproblem \n is detected as a full matrix \n'));
  312. end
  313. if isempty(operatorT)
  314. fprintf('No preconditioner is detected \n');
  315. else
  316. fprintf('The preconditioner is detected as an M-function %s \n',...
  317. operatorT);
  318. end
  319. if isempty(blockVectorY)
  320. fprintf('No matrix of constraints is detected \n')
  321. elseif issparse(blockVectorY)
  322. fprintf('The sparse matrix of %i constraints is detected \n',sizeY);
  323. else
  324. fprintf('The full matrix of %i constraints is detected \n',sizeY);
  325. end
  326. if issparse(blockVectorY) ~= issparse(blockVectorX)
  327. warning('BLOPEX:lobpcg:SparsityInconsistent',...
  328. strcat('The sparsity formats of the initial guess and ',...
  329. 'the constraints are inconsistent'));
  330. end
  331. end
  332. % Set defaults
  333. if isempty(residualTolerance)
  334. residualTolerance = sqrt(eps)*n;
  335. end
  336. if isempty(maxIterations)
  337. maxIterations = min(n,20);
  338. end
  339. if isempty(verbosityLevel)
  340. verbosityLevel = 0;
  341. end
  342. if verbosityLevel
  343. fprintf('Tolerance %e and maximum number of iterations %i \n',...
  344. residualTolerance,maxIterations)
  345. end
  346. %constraints preprocessing
  347. if isempty(blockVectorY)
  348. constraintStyle = 0;
  349. else
  350. % constraintStyle = SYMMETRIC_CONSTRAINTS; % more accurate?
  351. constraintStyle = CONVENTIONAL_CONSTRAINTS;
  352. end
  353. if constraintStyle == CONVENTIONAL_CONSTRAINTS
  354. if isempty(operatorB)
  355. gramY = blockVectorY'*blockVectorY;
  356. else
  357. if ~ischar(operatorB)
  358. blockVectorBY = operatorB*blockVectorY;
  359. else
  360. blockVectorBY = feval(operatorB,blockVectorY);
  361. end
  362. gramY=blockVectorY'*blockVectorBY;
  363. end
  364. gramY=(gramY'+gramY)*0.5;
  365. if isempty(operatorB)
  366. blockVectorX = blockVectorX - ...
  367. blockVectorY*(gramY\(blockVectorY'*blockVectorX));
  368. else
  369. blockVectorX =blockVectorX - ...
  370. blockVectorY*(gramY\(blockVectorBY'*blockVectorX));
  371. end
  372. elseif constraintStyle == SYMMETRIC_CONSTRAINTS
  373. if ~isempty(operatorB)
  374. if ~ischar(operatorB)
  375. blockVectorY = operatorB*blockVectorY;
  376. else
  377. blockVectorY = feval(operatorB,blockVectorY);
  378. end
  379. end
  380. if isempty(operatorT)
  381. gramY = blockVectorY'*blockVectorY;
  382. else
  383. blockVectorTY = feval(operatorT,blockVectorY);
  384. gramY = blockVectorY'*blockVectorTY;
  385. end
  386. gramY=(gramY'+gramY)*0.5;
  387. if isempty(operatorT)
  388. blockVectorX = blockVectorX - ...
  389. blockVectorY*(gramY\(blockVectorY'*blockVectorX));
  390. else
  391. blockVectorX = blockVectorX - ...
  392. blockVectorTY*(gramY\(blockVectorY'*blockVectorX));
  393. end
  394. end
  395. %Making the initial vectors (operatorB-) orthonormal
  396. if isempty(operatorB)
  397. %[blockVectorX,gramXBX] = qr(blockVectorX,0);
  398. gramXBX=blockVectorX'*blockVectorX;
  399. if ~isreal(gramXBX)
  400. gramXBX=(gramXBX+gramXBX')*0.5;
  401. end
  402. [gramXBX,cholFlag]=chol(gramXBX);
  403. if cholFlag ~= 0
  404. error('BLOPEX:lobpcg:ConstraintsTooTight',...
  405. 'The initial approximation after constraints is not full rank');
  406. end
  407. blockVectorX = blockVectorX/gramXBX;
  408. else
  409. %[blockVectorX,blockVectorBX] = orth(operatorB,blockVectorX);
  410. if ~ischar(operatorB)
  411. blockVectorBX = operatorB*blockVectorX;
  412. else
  413. blockVectorBX = feval(operatorB,blockVectorX);
  414. end
  415. gramXBX=blockVectorX'*blockVectorBX;
  416. if ~isreal(gramXBX)
  417. gramXBX=(gramXBX+gramXBX')*0.5;
  418. end
  419. [gramXBX,cholFlag]=chol(gramXBX);
  420. if cholFlag ~= 0
  421. error('BLOPEX:lobpcg:InitialNotFullRank',...
  422. sprintf('%s\n%s', ...
  423. 'The initial approximation after constraints is not full rank',...
  424. 'or/and operatorB is not positive definite'));
  425. end
  426. blockVectorX = blockVectorX/gramXBX;
  427. blockVectorBX = blockVectorBX/gramXBX;
  428. end
  429. % Checking if the problem is big enough for the algorithm,
  430. % i.e. n-sizeY > 5*blockSize
  431. % Theoretically, the algorithm should be able to run if
  432. % n-sizeY > 3*blockSize,
  433. % but the extreme cases might be unstable, so we use 5 instead of 3 here.
  434. if n-sizeY < 5*blockSize
  435. error('BLOPEX:lobpcg:MatrixTooSmall',...
  436. sprintf('%s\n%s', ...
  437. 'The problem size is too small, relative to the block size.',...
  438. 'Try using eig() or eigs() instead.'));
  439. end
  440. % Preallocation
  441. residualNormsHistory=zeros(blockSize,maxIterations);
  442. lambdaHistory=zeros(blockSize,maxIterations+1);
  443. condestGhistory=zeros(1,maxIterations+1);
  444. blockVectorBR=zeros(n,blockSize);
  445. blockVectorAR=zeros(n,blockSize);
  446. blockVectorP=zeros(n,blockSize);
  447. blockVectorAP=zeros(n,blockSize);
  448. blockVectorBP=zeros(n,blockSize);
  449. %Initial settings for the loop
  450. if ~ischar(operatorA)
  451. blockVectorAX = operatorA*blockVectorX;
  452. else
  453. blockVectorAX = feval(operatorA,blockVectorX);
  454. end
  455. gramXAX = full(blockVectorX'*blockVectorAX);
  456. gramXAX = (gramXAX + gramXAX')*0.5;
  457. % eig(...,'chol') uses only the diagonal and upper triangle -
  458. % not true in MATLAB
  459. % Octave v3.2.3, eig() does not support inputting 'chol'
  460. [coordX,gramXAX]=eig(gramXAX,eye(blockSize));
  461. lambda=diag(gramXAX); %eig returms eigenvalues on the diagonal
  462. if issparse(blockVectorX)
  463. coordX=sparse(coordX);
  464. end
  465. blockVectorX = blockVectorX*coordX;
  466. blockVectorAX = blockVectorAX*coordX;
  467. if ~isempty(operatorB)
  468. blockVectorBX = blockVectorBX*coordX;
  469. end
  470. clear coordX
  471. condestGhistory(1)=-log10(eps)/2; %if too small cause unnecessary restarts
  472. lambdaHistory(1:blockSize,1)=lambda;
  473. activeMask = true(blockSize,1);
  474. % currentBlockSize = blockSize; %iterate all
  475. %
  476. % restart=1;%steepest descent
  477. %The main part of the method is the loop of the CG method: begin
  478. for iterationNumber=1:maxIterations
  479. % %Computing the active residuals
  480. % if isempty(operatorB)
  481. % if currentBlockSize > 1
  482. % blockVectorR(:,activeMask)=blockVectorAX(:,activeMask) - ...
  483. % blockVectorX(:,activeMask)*spdiags(lambda(activeMask),0,currentBlockSize,currentBlockSize);
  484. % else
  485. % blockVectorR(:,activeMask)=blockVectorAX(:,activeMask) - ...
  486. % blockVectorX(:,activeMask)*lambda(activeMask);
  487. % %to make blockVectorR full when lambda is just a scalar
  488. % end
  489. % else
  490. % if currentBlockSize > 1
  491. % blockVectorR(:,activeMask)=blockVectorAX(:,activeMask) - ...
  492. % blockVectorBX(:,activeMask)*spdiags(lambda(activeMask),0,currentBlockSize,currentBlockSize);
  493. % else
  494. % blockVectorR(:,activeMask)=blockVectorAX(:,activeMask) - ...
  495. % blockVectorBX(:,activeMask)*lambda(activeMask);
  496. % %to make blockVectorR full when lambda is just a scalar
  497. % end
  498. % end
  499. %Computing all residuals
  500. if isempty(operatorB)
  501. if blockSize > 1
  502. blockVectorR = blockVectorAX - ...
  503. blockVectorX*spdiags(lambda,0,blockSize,blockSize);
  504. else
  505. blockVectorR = blockVectorAX - blockVectorX*lambda;
  506. %to make blockVectorR full when lambda is just a scalar
  507. end
  508. else
  509. if blockSize > 1
  510. blockVectorR=blockVectorAX - ...
  511. blockVectorBX*spdiags(lambda,0,blockSize,blockSize);
  512. else
  513. blockVectorR = blockVectorAX - blockVectorBX*lambda;
  514. %to make blockVectorR full when lambda is just a scalar
  515. end
  516. end
  517. %Satisfying the constraints for the active residulas
  518. if constraintStyle == SYMMETRIC_CONSTRAINTS
  519. if isempty(operatorT)
  520. blockVectorR(:,activeMask) = blockVectorR(:,activeMask) - ...
  521. blockVectorY*(gramY\(blockVectorY'*...
  522. blockVectorR(:,activeMask)));
  523. else
  524. blockVectorR(:,activeMask) = blockVectorR(:,activeMask) - ...
  525. blockVectorY*(gramY\(blockVectorTY'*...
  526. blockVectorR(:,activeMask)));
  527. end
  528. end
  529. residualNorms=full(sqrt(sum(conj(blockVectorR).*blockVectorR)'));
  530. residualNormsHistory(1:blockSize,iterationNumber)=residualNorms;
  531. %index antifreeze
  532. activeMask = full(residualNorms > residualTolerance) & activeMask;
  533. %activeMask = full(residualNorms > residualTolerance);
  534. %above allows vectors back into active, which causes problems with frosen Ps
  535. %activeMask = full(residualNorms > 0); %iterate all, ignore freeze
  536. currentBlockSize = sum(activeMask);
  537. if currentBlockSize == 0
  538. failureFlag=0; %all eigenpairs converged
  539. break
  540. end
  541. %Applying the preconditioner operatorT to the active residulas
  542. if ~isempty(operatorT)
  543. blockVectorR(:,activeMask) = ...
  544. feval(operatorT,blockVectorR(:,activeMask));
  545. end
  546. if constraintStyle == CONVENTIONAL_CONSTRAINTS
  547. if isempty(operatorB)
  548. blockVectorR(:,activeMask) = blockVectorR(:,activeMask) - ...
  549. blockVectorY*(gramY\(blockVectorY'*...
  550. blockVectorR(:,activeMask)));
  551. else
  552. blockVectorR(:,activeMask) = blockVectorR(:,activeMask) - ...
  553. blockVectorY*(gramY\(blockVectorBY'*...
  554. blockVectorR(:,activeMask)));
  555. end
  556. end
  557. %Making active (preconditioned) residuals orthogonal to blockVectorX
  558. if isempty(operatorB)
  559. blockVectorR(:,activeMask) = blockVectorR(:,activeMask) - ...
  560. blockVectorX*(blockVectorX'*blockVectorR(:,activeMask));
  561. else
  562. blockVectorR(:,activeMask) = blockVectorR(:,activeMask) - ...
  563. blockVectorX*(blockVectorBX'*blockVectorR(:,activeMask));
  564. end
  565. %Making active residuals orthonormal
  566. if isempty(operatorB)
  567. %[blockVectorR(:,activeMask),gramRBR]=...
  568. %qr(blockVectorR(:,activeMask),0); %to increase stability
  569. gramRBR=blockVectorR(:,activeMask)'*blockVectorR(:,activeMask);
  570. if ~isreal(gramRBR)
  571. gramRBR=(gramRBR+gramRBR')*0.5;
  572. end
  573. [gramRBR,cholFlag]=chol(gramRBR);
  574. if cholFlag == 0
  575. blockVectorR(:,activeMask) = blockVectorR(:,activeMask)/gramRBR;
  576. else
  577. warning('BLOPEX:lobpcg:ResidualNotFullRank',...
  578. 'The residual is not full rank.');
  579. break
  580. end
  581. else
  582. if ~ischar(operatorB)
  583. blockVectorBR(:,activeMask) = ...
  584. operatorB*blockVectorR(:,activeMask);
  585. else
  586. blockVectorBR(:,activeMask) = ...
  587. feval(operatorB,blockVectorR(:,activeMask));
  588. end
  589. gramRBR=blockVectorR(:,activeMask)'*blockVectorBR(:,activeMask);
  590. if ~isreal(gramRBR)
  591. gramRBR=(gramRBR+gramRBR')*0.5;
  592. end
  593. [gramRBR,cholFlag]=chol(gramRBR);
  594. if cholFlag == 0
  595. blockVectorR(:,activeMask) = ...
  596. blockVectorR(:,activeMask)/gramRBR;
  597. blockVectorBR(:,activeMask) = ...
  598. blockVectorBR(:,activeMask)/gramRBR;
  599. else
  600. warning('BLOPEX:lobpcg:ResidualNotFullRankOrElse',...
  601. strcat('The residual is not full rank or/and operatorB ',...
  602. 'is not positive definite.'));
  603. break
  604. end
  605. end
  606. clear gramRBR;
  607. if ~ischar(operatorA)
  608. blockVectorAR(:,activeMask) = operatorA*blockVectorR(:,activeMask);
  609. else
  610. blockVectorAR(:,activeMask) = ...
  611. feval(operatorA,blockVectorR(:,activeMask));
  612. end
  613. if iterationNumber > 1
  614. %Making active conjugate directions orthonormal
  615. if isempty(operatorB)
  616. %[blockVectorP(:,activeMask),gramPBP] = qr(blockVectorP(:,activeMask),0);
  617. gramPBP=blockVectorP(:,activeMask)'*blockVectorP(:,activeMask);
  618. if ~isreal(gramPBP)
  619. gramPBP=(gramPBP+gramPBP')*0.5;
  620. end
  621. [gramPBP,cholFlag]=chol(gramPBP);
  622. if cholFlag == 0
  623. blockVectorP(:,activeMask) = ...
  624. blockVectorP(:,activeMask)/gramPBP;
  625. blockVectorAP(:,activeMask) = ...
  626. blockVectorAP(:,activeMask)/gramPBP;
  627. else
  628. warning('BLOPEX:lobpcg:DirectionNotFullRank',...
  629. 'The direction matrix is not full rank.');
  630. break
  631. end
  632. else
  633. gramPBP=blockVectorP(:,activeMask)'*blockVectorBP(:,activeMask);
  634. if ~isreal(gramPBP)
  635. gramPBP=(gramPBP+gramPBP')*0.5;
  636. end
  637. [gramPBP,cholFlag]=chol(gramPBP);
  638. if cholFlag == 0
  639. blockVectorP(:,activeMask) = ...
  640. blockVectorP(:,activeMask)/gramPBP;
  641. blockVectorAP(:,activeMask) = ...
  642. blockVectorAP(:,activeMask)/gramPBP;
  643. blockVectorBP(:,activeMask) = ...
  644. blockVectorBP(:,activeMask)/gramPBP;
  645. else
  646. warning('BLOPEX:lobpcg:DirectionNotFullRank',...
  647. strcat('The direction matrix is not full rank ',...
  648. 'or/and operatorB is not positive definite.'));
  649. break
  650. end
  651. end
  652. clear gramPBP
  653. end
  654. condestGmean = mean(condestGhistory(max(1,iterationNumber-10-...
  655. round(log(currentBlockSize))):iterationNumber));
  656. % restart=1;
  657. % The Raileight-Ritz method for [blockVectorX blockVectorR blockVectorP]
  658. if residualNorms > eps^0.6
  659. explicitGramFlag = 0;
  660. else
  661. explicitGramFlag = 1; %suggested by Garrett Moran, private
  662. end
  663. activeRSize=size(blockVectorR(:,activeMask),2);
  664. if iterationNumber == 1
  665. activePSize=0;
  666. restart=1;
  667. else
  668. activePSize=size(blockVectorP(:,activeMask),2);
  669. restart=0;
  670. end
  671. gramXAR=full(blockVectorAX'*blockVectorR(:,activeMask));
  672. gramRAR=full(blockVectorAR(:,activeMask)'*blockVectorR(:,activeMask));
  673. gramRAR=(gramRAR'+gramRAR)*0.5;
  674. if explicitGramFlag
  675. gramXAX=full(blockVectorAX'*blockVectorX);
  676. gramXAX=(gramXAX'+gramXAX)*0.5;
  677. if isempty(operatorB)
  678. gramXBX=full(blockVectorX'*blockVectorX);
  679. gramRBR=full(blockVectorR(:,activeMask)'*...
  680. blockVectorR(:,activeMask));
  681. gramXBR=full(blockVectorX'*blockVectorR(:,activeMask));
  682. else
  683. gramXBX=full(blockVectorBX'*blockVectorX);
  684. gramRBR=full(blockVectorBR(:,activeMask)'*...
  685. blockVectorR(:,activeMask));
  686. gramXBR=full(blockVectorBX'*blockVectorR(:,activeMask));
  687. end
  688. gramXBX=(gramXBX'+gramXBX)*0.5;
  689. gramRBR=(gramRBR'+gramRBR)*0.5;
  690. end
  691. for cond_try=1:2, %cond_try == 2 when restart
  692. if ~restart
  693. gramXAP=full(blockVectorAX'*blockVectorP(:,activeMask));
  694. gramRAP=full(blockVectorAR(:,activeMask)'*...
  695. blockVectorP(:,activeMask));
  696. gramPAP=full(blockVectorAP(:,activeMask)'*...
  697. blockVectorP(:,activeMask));
  698. gramPAP=(gramPAP'+gramPAP)*0.5;
  699. if explicitGramFlag
  700. gramA = [ gramXAX gramXAR gramXAP
  701. gramXAR' gramRAR gramRAP
  702. gramXAP' gramRAP' gramPAP ];
  703. else
  704. gramA = [ diag(lambda) gramXAR gramXAP
  705. gramXAR' gramRAR gramRAP
  706. gramXAP' gramRAP' gramPAP ];
  707. end
  708. clear gramXAP gramRAP gramPAP
  709. if isempty(operatorB)
  710. gramXBP=full(blockVectorX'*blockVectorP(:,activeMask));
  711. gramRBP=full(blockVectorR(:,activeMask)'*...
  712. blockVectorP(:,activeMask));
  713. else
  714. gramXBP=full(blockVectorBX'*blockVectorP(:,activeMask));
  715. gramRBP=full(blockVectorBR(:,activeMask)'*...
  716. blockVectorP(:,activeMask));
  717. %or blockVectorR(:,activeMask)'*blockVectorBP(:,activeMask);
  718. end
  719. if explicitGramFlag
  720. if isempty(operatorB)
  721. gramPBP=full(blockVectorP(:,activeMask)'*...
  722. blockVectorP(:,activeMask));
  723. else
  724. gramPBP=full(blockVectorBP(:,activeMask)'*...
  725. blockVectorP(:,activeMask));
  726. end
  727. gramPBP=(gramPBP'+gramPBP)*0.5;
  728. gramB = [ gramXBX gramXBR gramXBP
  729. gramXBR' gramRBR gramRBP
  730. gramXBP' gramRBP' gramPBP ];
  731. clear gramPBP
  732. else
  733. gramB=[eye(blockSize) zeros(blockSize,activeRSize) gramXBP
  734. zeros(blockSize,activeRSize)' eye(activeRSize) gramRBP
  735. gramXBP' gramRBP' eye(activePSize) ];
  736. end
  737. clear gramXBP gramRBP;
  738. else
  739. if explicitGramFlag
  740. gramA = [ gramXAX gramXAR
  741. gramXAR' gramRAR ];
  742. gramB = [ gramXBX gramXBR
  743. gramXBR' eye(activeRSize) ];
  744. clear gramXAX gramXBX gramXBR
  745. else
  746. gramA = [ diag(lambda) gramXAR
  747. gramXAR' gramRAR ];
  748. gramB = eye(blockSize+activeRSize);
  749. end
  750. clear gramXAR gramRAR;
  751. end
  752. condestG = log10(cond(gramB))+1;
  753. if (condestG/condestGmean > 2 && condestG > 2 )|| condestG > 8
  754. %black magic - need to guess the restart
  755. if verbosityLevel
  756. fprintf('Restart on step %i as condestG %5.4e \n',...
  757. iterationNumber,condestG);
  758. end
  759. if cond_try == 1 && ~restart
  760. restart=1; %steepest descent restart for stability
  761. else
  762. warning('BLOPEX:lobpcg:IllConditioning',...
  763. 'Gramm matrix ill-conditioned: results unpredictable');
  764. end
  765. else
  766. break
  767. end
  768. end
  769. [gramA,gramB]=eig(gramA,gramB);
  770. lambda=diag(gramB(1:blockSize,1:blockSize));
  771. coordX=gramA(:,1:blockSize);
  772. clear gramA gramB
  773. if issparse(blockVectorX)
  774. coordX=sparse(coordX);
  775. end
  776. if ~restart
  777. blockVectorP = blockVectorR(:,activeMask)*...
  778. coordX(blockSize+1:blockSize+activeRSize,:) + ...
  779. blockVectorP(:,activeMask)*...
  780. coordX(blockSize+activeRSize+1:blockSize + ...
  781. activeRSize+activePSize,:);
  782. blockVectorAP = blockVectorAR(:,activeMask)*...
  783. coordX(blockSize+1:blockSize+activeRSize,:) + ...
  784. blockVectorAP(:,activeMask)*...
  785. coordX(blockSize+activeRSize+1:blockSize + ...
  786. activeRSize+activePSize,:);
  787. if ~isempty(operatorB)
  788. blockVectorBP = blockVectorBR(:,activeMask)*...
  789. coordX(blockSize+1:blockSize+activeRSize,:) + ...
  790. blockVectorBP(:,activeMask)*...
  791. coordX(blockSize+activeRSize+1:blockSize+activeRSize+activePSize,:);
  792. end
  793. else %use block steepest descent
  794. blockVectorP = blockVectorR(:,activeMask)*...
  795. coordX(blockSize+1:blockSize+activeRSize,:);
  796. blockVectorAP = blockVectorAR(:,activeMask)*...
  797. coordX(blockSize+1:blockSize+activeRSize,:);
  798. if ~isempty(operatorB)
  799. blockVectorBP = blockVectorBR(:,activeMask)*...
  800. coordX(blockSize+1:blockSize+activeRSize,:);
  801. end
  802. end
  803. blockVectorX = blockVectorX*coordX(1:blockSize,:) + blockVectorP;
  804. blockVectorAX=blockVectorAX*coordX(1:blockSize,:) + blockVectorAP;
  805. if ~isempty(operatorB)
  806. blockVectorBX=blockVectorBX*coordX(1:blockSize,:) + blockVectorBP;
  807. end
  808. clear coordX
  809. %%end RR
  810. lambdaHistory(1:blockSize,iterationNumber+1)=lambda;
  811. condestGhistory(iterationNumber+1)=condestG;
  812. if verbosityLevel
  813. fprintf('Iteration %i current block size %i \n',...
  814. iterationNumber,currentBlockSize);
  815. fprintf('Eigenvalues lambda %17.16e \n',lambda);
  816. fprintf('Residual Norms %e \n',residualNorms');
  817. end
  818. end
  819. %The main step of the method was the CG cycle: end
  820. %Postprocessing
  821. %Making sure blockVectorX's "exactly" satisfy the blockVectorY constrains??
  822. %Making sure blockVectorX's are "exactly" othonormalized by final "exact" RR
  823. if isempty(operatorB)
  824. gramXBX=full(blockVectorX'*blockVectorX);
  825. else
  826. if ~ischar(operatorB)
  827. blockVectorBX = operatorB*blockVectorX;
  828. else
  829. blockVectorBX = feval(operatorB,blockVectorX);
  830. end
  831. gramXBX=full(blockVectorX'*blockVectorBX);
  832. end
  833. gramXBX=(gramXBX'+gramXBX)*0.5;
  834. if ~ischar(operatorA)
  835. blockVectorAX = operatorA*blockVectorX;
  836. else
  837. blockVectorAX = feval(operatorA,blockVectorX);
  838. end
  839. gramXAX = full(blockVectorX'*blockVectorAX);
  840. gramXAX = (gramXAX + gramXAX')*0.5;
  841. %Raileigh-Ritz for blockVectorX, which is already operatorB-orthonormal
  842. [coordX,gramXBX] = eig(gramXAX,gramXBX);
  843. lambda=diag(gramXBX);
  844. if issparse(blockVectorX)
  845. coordX=sparse(coordX);
  846. end
  847. blockVectorX = blockVectorX*coordX;
  848. blockVectorAX = blockVectorAX*coordX;
  849. if ~isempty(operatorB)
  850. blockVectorBX = blockVectorBX*coordX;
  851. end
  852. %Computing all residuals
  853. if isempty(operatorB)
  854. if blockSize > 1
  855. blockVectorR = blockVectorAX - ...
  856. blockVectorX*spdiags(lambda,0,blockSize,blockSize);
  857. else
  858. blockVectorR = blockVectorAX - blockVectorX*lambda;
  859. %to make blockVectorR full when lambda is just a scalar
  860. end
  861. else
  862. if blockSize > 1
  863. blockVectorR=blockVectorAX - ...
  864. blockVectorBX*spdiags(lambda,0,blockSize,blockSize);
  865. else
  866. blockVectorR = blockVectorAX - blockVectorBX*lambda;
  867. %to make blockVectorR full when lambda is just a scalar
  868. end
  869. end
  870. residualNorms=full(sqrt(sum(conj(blockVectorR).*blockVectorR)'));
  871. residualNormsHistory(1:blockSize,iterationNumber)=residualNorms;
  872. if verbosityLevel
  873. fprintf('Final Eigenvalues lambda %17.16e \n',lambda);
  874. fprintf('Final Residual Norms %e \n',residualNorms');
  875. end
  876. if verbosityLevel == 2
  877. whos
  878. if matlabFlag==1;
  879. figure(491)
  880. semilogy((residualNormsHistory(1:blockSize,1:iterationNumber-1))');
  881. title('Residuals for Different Eigenpairs','fontsize',16);
  882. ylabel('Eucledian norm of residuals','fontsize',16);
  883. xlabel('Iteration number','fontsize',16);
  884. axis tight;
  885. %axis([0 maxIterations+1 1e-15 1e3])
  886. set(gca,'FontSize',14);
  887. figure(492);
  888. semilogy((lambdaHistory(1:blockSize,1:iterationNumber)-...
  889. repmat(lambda,1,iterationNumber))');
  890. title('Eigenvalue errors for Different Eigenpairs','fontsize',16);
  891. ylabel('Estimated eigenvalue errors','fontsize',16);
  892. xlabel('Iteration number','fontsize',16);
  893. axis tight;
  894. %axis([0 maxIterations+1 1e-15 1e3])
  895. set(gca,'FontSize',14);
  896. drawnow;
  897. end
  898. end
  899. varargout(1)={failureFlag};
  900. varargout(2)={lambdaHistory(1:blockSize,1:iterationNumber)};
  901. varargout(3)={residualNormsHistory(1:blockSize,1:iterationNumber-1)};
  902. return