Actual source code: power.c
1: /*
3: SLEPc eigensolver: "power"
5: Method: Power Iteration
7: Algorithm:
9: This solver implements the power iteration for finding dominant
10: eigenpairs. It also includes the following well-known methods:
11: - Inverse Iteration: when used in combination with shift-and-invert
12: spectral transformation.
13: - Rayleigh Quotient Iteration (RQI): also with shift-and-invert plus
14: a variable shift.
16: References:
18: [1] "Single Vector Iteration Methods in SLEPc", SLEPc Technical Report
19: STR-2, available at http://www.grycap.upv.es/slepc.
21: Last update: Feb 2009
23: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
24: SLEPc - Scalable Library for Eigenvalue Problem Computations
25: Copyright (c) 2002-2013, Universitat Politecnica de Valencia, Spain
27: This file is part of SLEPc.
29: SLEPc is free software: you can redistribute it and/or modify it under the
30: terms of version 3 of the GNU Lesser General Public License as published by
31: the Free Software Foundation.
33: SLEPc is distributed in the hope that it will be useful, but WITHOUT ANY
34: WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
35: FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
36: more details.
38: You should have received a copy of the GNU Lesser General Public License
39: along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
40: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
41: */
43: #include <slepc-private/epsimpl.h> /*I "slepceps.h" I*/
44: #include <slepcblaslapack.h>
46: PetscErrorCode EPSSolve_Power(EPS);
47: PetscErrorCode EPSSolve_TS_Power(EPS);
49: typedef struct {
50: EPSPowerShiftType shift_type;
51: } EPS_POWER;
55: PetscErrorCode EPSSetUp_Power(EPS eps)
56: {
58: EPS_POWER *power = (EPS_POWER*)eps->data;
59: PetscBool flg;
60: STMatMode mode;
63: if (eps->ncv) {
64: if (eps->ncv<eps->nev) SETERRQ(PetscObjectComm((PetscObject)eps),1,"The value of ncv must be at least nev");
65: } else eps->ncv = eps->nev;
66: if (eps->mpd) { PetscInfo(eps,"Warning: parameter mpd ignored\n"); }
67: if (!eps->max_it) eps->max_it = PetscMax(2000,100*eps->n);
68: if (!eps->which) { EPSSetWhichEigenpairs_Default(eps); }
69: if (eps->which!=EPS_LARGEST_MAGNITUDE && eps->which !=EPS_TARGET_MAGNITUDE) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Wrong value of eps->which");
70: if (power->shift_type != EPS_POWER_SHIFT_CONSTANT) {
71: PetscObjectTypeCompareAny((PetscObject)eps->st,&flg,STSINVERT,STCAYLEY,"");
72: if (!flg) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Variable shifts only allowed in shift-and-invert or Cayley ST");
73: STGetMatMode(eps->st,&mode);
74: if (mode == ST_MATMODE_INPLACE) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"ST matrix mode inplace does not work with variable shifts");
75: }
76: if (eps->extraction) { PetscInfo(eps,"Warning: extraction type ignored\n"); }
77: if (eps->balance!=EPS_BALANCE_NONE) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Balancing not supported in this solver");
78: if (eps->arbitrary) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Arbitrary selection of eigenpairs not supported in this solver");
79: EPSAllocateSolution(eps);
80: if (eps->leftvecs) {
81: EPSSetWorkVecs(eps,3);
82: } else {
83: EPSSetWorkVecs(eps,2);
84: }
86: /* dispatch solve method */
87: if (eps->leftvecs) eps->ops->solve = EPSSolve_TS_Power;
88: else eps->ops->solve = EPSSolve_Power;
89: return(0);
90: }
94: PetscErrorCode EPSSolve_Power(EPS eps)
95: {
96: #if defined(SLEPC_MISSING_LAPACK_LAEV2)
98: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"LAEV2 - Lapack routine is unavailable");
99: #else
101: EPS_POWER *power = (EPS_POWER*)eps->data;
102: PetscInt i;
103: Vec v,y,e;
104: Mat A;
105: PetscReal relerr,norm,rt1,rt2,cs1,anorm;
106: PetscScalar theta,rho,delta,sigma,alpha2,beta1,sn1;
107: PetscBool breakdown,*select = NULL,hasnorm;
110: v = eps->V[0];
111: y = eps->work[1];
112: e = eps->work[0];
114: /* prepare for selective orthogonalization of converged vectors */
115: if (power->shift_type != EPS_POWER_SHIFT_CONSTANT && eps->nev>1) {
116: STGetOperators(eps->st,0,&A);
117: MatHasOperation(A,MATOP_NORM,&hasnorm);
118: if (hasnorm) {
119: MatNorm(A,NORM_INFINITY,&anorm);
120: PetscMalloc(eps->nev*sizeof(PetscBool),&select);
121: }
122: }
124: EPSGetStartVector(eps,0,v,NULL);
125: STGetShift(eps->st,&sigma); /* original shift */
126: rho = sigma;
128: while (eps->reason == EPS_CONVERGED_ITERATING) {
129: eps->its = eps->its + 1;
131: /* y = OP v */
132: STApply(eps->st,v,y);
134: /* theta = (v,y)_B */
135: IPInnerProduct(eps->ip,v,y,&theta);
137: if (power->shift_type == EPS_POWER_SHIFT_CONSTANT) { /* direct & inverse iteration */
139: /* approximate eigenvalue is the Rayleigh quotient */
140: eps->eigr[eps->nconv] = theta;
142: /* compute relative error as ||y-theta v||_2/|theta| */
143: VecCopy(y,e);
144: VecAXPY(e,-theta,v);
145: VecNorm(e,NORM_2,&norm);
146: relerr = norm / PetscAbsScalar(theta);
148: } else { /* RQI */
150: /* delta = ||y||_B */
151: IPNorm(eps->ip,y,&norm);
152: delta = norm;
154: /* compute relative error */
155: if (rho == 0.0) relerr = PETSC_MAX_REAL;
156: else relerr = 1.0 / (norm*PetscAbsScalar(rho));
158: /* approximate eigenvalue is the shift */
159: eps->eigr[eps->nconv] = rho;
161: /* compute new shift */
162: if (relerr<eps->tol) {
163: rho = sigma; /* if converged, restore original shift */
164: STSetShift(eps->st,rho);
165: } else {
166: rho = rho + theta/(delta*delta); /* Rayleigh quotient R(v) */
167: if (power->shift_type == EPS_POWER_SHIFT_WILKINSON) {
168: /* beta1 is the norm of the residual associated to R(v) */
169: VecAXPY(v,-theta/(delta*delta),y);
170: VecScale(v,1.0/delta);
171: IPNorm(eps->ip,v,&norm);
172: beta1 = norm;
174: /* alpha2 = (e'*A*e)/(beta1*beta1), where e is the residual */
175: STGetOperators(eps->st,0,&A);
176: MatMult(A,v,e);
177: VecDot(v,e,&alpha2);
178: alpha2 = alpha2 / (beta1 * beta1);
180: /* choose the eigenvalue of [rho beta1; beta1 alpha2] closest to rho */
181: PetscFPTrapPush(PETSC_FP_TRAP_OFF);
182: PetscStackCallBLAS("LAPACKlaev2",LAPACKlaev2_(&rho,&beta1,&alpha2,&rt1,&rt2,&cs1,&sn1));
183: PetscFPTrapPop();
184: if (PetscAbsScalar(rt1-rho) < PetscAbsScalar(rt2-rho)) rho = rt1;
185: else rho = rt2;
186: }
187: /* update operator according to new shift */
188: PetscPushErrorHandler(PetscIgnoreErrorHandler,NULL);
189: STSetShift(eps->st,rho);
190: PetscPopErrorHandler();
191: if (ierr) {
192: eps->eigr[eps->nconv] = rho;
193: relerr = PETSC_MACHINE_EPSILON;
194: rho = sigma;
195: STSetShift(eps->st,rho);
196: }
197: }
198: }
200: eps->errest[eps->nconv] = relerr;
201: EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,eps->nconv+1);
203: /* purge previously converged eigenvectors */
204: if (select) {
205: for (i=0;i<eps->nconv;i++) {
206: if (PetscAbsScalar(rho-eps->eigr[i])>eps->its*anorm/1000) select[i] = PETSC_TRUE;
207: else select[i] = PETSC_FALSE;
208: }
209: IPOrthogonalize(eps->ip,eps->nds,eps->defl,eps->nconv,select,eps->V,y,NULL,&norm,NULL);
210: } else {
211: IPOrthogonalize(eps->ip,eps->nds,eps->defl,eps->nconv,NULL,eps->V,y,NULL,&norm,NULL);
212: }
214: /* v = y/||y||_B */
215: VecCopy(y,v);
216: VecScale(v,1.0/norm);
218: /* if relerr<tol, accept eigenpair */
219: if (relerr<eps->tol) {
220: eps->nconv = eps->nconv + 1;
221: if (eps->nconv==eps->nev) eps->reason = EPS_CONVERGED_TOL;
222: else {
223: v = eps->V[eps->nconv];
224: EPSGetStartVector(eps,eps->nconv,v,&breakdown);
225: if (breakdown) {
226: eps->reason = EPS_DIVERGED_BREAKDOWN;
227: PetscInfo(eps,"Unable to generate more start vectors\n");
228: }
229: }
230: }
231: if (eps->its >= eps->max_it) eps->reason = EPS_DIVERGED_ITS;
232: }
233: PetscFree(select);
234: return(0);
235: #endif
236: }
240: PetscErrorCode EPSSolve_TS_Power(EPS eps)
241: {
242: #if defined(SLEPC_MISSING_LAPACK_LAEV2)
244: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"LAEV2 - Lapack routine is unavailable");
245: #else
247: EPS_POWER *power = (EPS_POWER*)eps->data;
248: Vec v,w,y,z,e;
249: Mat A;
250: PetscReal relerr,norm,rt1,rt2,cs1;
251: PetscScalar theta,alpha,beta,rho,delta,sigma,alpha2,beta1,sn1;
254: v = eps->V[0];
255: y = eps->work[1];
256: e = eps->work[0];
257: w = eps->W[0];
258: z = eps->work[2];
260: EPSGetStartVector(eps,0,v,NULL);
261: EPSGetStartVectorLeft(eps,0,w,NULL);
262: STGetShift(eps->st,&sigma); /* original shift */
263: rho = sigma;
265: while (eps->its<eps->max_it) {
266: eps->its++;
268: /* y = OP v, z = OP' w */
269: STApply(eps->st,v,y);
270: STApplyTranspose(eps->st,w,z);
272: /* theta = (v,z)_B */
273: IPInnerProduct(eps->ip,v,z,&theta);
275: if (power->shift_type == EPS_POWER_SHIFT_CONSTANT) { /* direct & inverse iteration */
277: /* approximate eigenvalue is the Rayleigh quotient */
278: eps->eigr[eps->nconv] = theta;
280: /* compute relative errors (right and left) */
281: VecCopy(y,e);
282: VecAXPY(e,-theta,v);
283: VecNorm(e,NORM_2,&norm);
284: relerr = norm / PetscAbsScalar(theta);
285: eps->errest[eps->nconv] = relerr;
286: VecCopy(z,e);
287: VecAXPY(e,-theta,w);
288: VecNorm(e,NORM_2,&norm);
289: relerr = norm / PetscAbsScalar(theta);
290: eps->errest_left[eps->nconv] = relerr;
292: } else { /* RQI */
294: /* delta = sqrt(y,z)_B */
295: IPInnerProduct(eps->ip,y,z,&alpha);
296: if (alpha==0.0) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Breakdown in two-sided Power/RQI");
297: delta = PetscSqrtScalar(alpha);
299: /* compute relative error */
300: if (rho == 0.0) relerr = PETSC_MAX_REAL;
301: else relerr = 1.0 / (PetscAbsScalar(delta*rho));
302: eps->errest[eps->nconv] = relerr;
303: eps->errest_left[eps->nconv] = relerr;
305: /* approximate eigenvalue is the shift */
306: eps->eigr[eps->nconv] = rho;
308: /* compute new shift */
309: if (eps->errest[eps->nconv]<eps->tol && eps->errest_left[eps->nconv]<eps->tol) {
310: rho = sigma; /* if converged, restore original shift */
311: STSetShift(eps->st,rho);
312: } else {
313: rho = rho + theta/(delta*delta); /* Rayleigh quotient R(v,w) */
314: if (power->shift_type == EPS_POWER_SHIFT_WILKINSON) {
315: /* beta1 is the norm of the residual associated to R(v,w) */
316: VecAXPY(v,-theta/(delta*delta),y);
317: VecScale(v,1.0/delta);
318: IPNorm(eps->ip,v,&norm);
319: beta1 = norm;
321: /* alpha2 = (e'*A*e)/(beta1*beta1), where e is the residual */
322: STGetOperators(eps->st,0,&A);
323: MatMult(A,v,e);
324: VecDot(v,e,&alpha2);
325: alpha2 = alpha2 / (beta1 * beta1);
327: /* choose the eigenvalue of [rho beta1; beta1 alpha2] closest to rho */
328: PetscFPTrapPush(PETSC_FP_TRAP_OFF);
329: PetscStackCallBLAS("LAPACKlaev2",LAPACKlaev2_(&rho,&beta1,&alpha2,&rt1,&rt2,&cs1,&sn1));
330: PetscFPTrapPop();
331: if (PetscAbsScalar(rt1-rho) < PetscAbsScalar(rt2-rho)) rho = rt1;
332: else rho = rt2;
333: }
334: /* update operator according to new shift */
335: PetscPushErrorHandler(PetscIgnoreErrorHandler,NULL);
336: STSetShift(eps->st,rho);
337: PetscPopErrorHandler();
338: if (ierr) {
339: eps->eigr[eps->nconv] = rho;
340: eps->errest[eps->nconv] = PETSC_MACHINE_EPSILON;
341: eps->errest_left[eps->nconv] = PETSC_MACHINE_EPSILON;
342: rho = sigma;
343: STSetShift(eps->st,rho);
344: }
345: }
346: }
348: EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,eps->nconv+1);
349: EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest_left,eps->nconv+1);
351: /* purge previously converged eigenvectors */
352: IPBiOrthogonalize(eps->ip,eps->nconv,eps->V,eps->W,z,NULL,NULL);
353: IPBiOrthogonalize(eps->ip,eps->nconv,eps->W,eps->V,y,NULL,NULL);
355: /* normalize so that (y,z)_B=1 */
356: VecCopy(y,v);
357: VecCopy(z,w);
358: IPInnerProduct(eps->ip,y,z,&alpha);
359: if (alpha==0.0) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Breakdown in two-sided Power/RQI");
360: delta = PetscSqrtScalar(PetscAbsScalar(alpha));
361: beta = 1.0/PetscConj(alpha/delta);
362: delta = 1.0/delta;
363: VecScale(w,beta);
364: VecScale(v,delta);
366: /* if relerr<tol (both right and left), accept eigenpair */
367: if (eps->errest[eps->nconv]<eps->tol && eps->errest_left[eps->nconv]<eps->tol) {
368: eps->nconv = eps->nconv + 1;
369: if (eps->nconv==eps->nev) break;
370: v = eps->V[eps->nconv];
371: EPSGetStartVector(eps,eps->nconv,v,NULL);
372: w = eps->W[eps->nconv];
373: EPSGetStartVectorLeft(eps,eps->nconv,w,NULL);
374: }
375: }
376: if (eps->nconv == eps->nev) eps->reason = EPS_CONVERGED_TOL;
377: else eps->reason = EPS_DIVERGED_ITS;
378: return(0);
379: #endif
380: }
384: PetscErrorCode EPSBackTransform_Power(EPS eps)
385: {
387: EPS_POWER *power = (EPS_POWER*)eps->data;
390: if (power->shift_type == EPS_POWER_SHIFT_CONSTANT) {
391: EPSBackTransform_Default(eps);
392: }
393: return(0);
394: }
398: PetscErrorCode EPSSetFromOptions_Power(EPS eps)
399: {
400: PetscErrorCode ierr;
401: EPS_POWER *power = (EPS_POWER*)eps->data;
402: PetscBool flg;
403: EPSPowerShiftType shift;
406: PetscOptionsHead("EPS Power Options");
407: PetscOptionsEnum("-eps_power_shift_type","Shift type","EPSPowerSetShiftType",EPSPowerShiftTypes,(PetscEnum)power->shift_type,(PetscEnum*)&shift,&flg);
408: if (flg) {
409: EPSPowerSetShiftType(eps,shift);
410: }
411: if (power->shift_type != EPS_POWER_SHIFT_CONSTANT) {
412: STSetType(eps->st,STSINVERT);
413: }
414: PetscOptionsTail();
415: return(0);
416: }
420: static PetscErrorCode EPSPowerSetShiftType_Power(EPS eps,EPSPowerShiftType shift)
421: {
422: EPS_POWER *power = (EPS_POWER*)eps->data;
425: switch (shift) {
426: case EPS_POWER_SHIFT_CONSTANT:
427: case EPS_POWER_SHIFT_RAYLEIGH:
428: case EPS_POWER_SHIFT_WILKINSON:
429: power->shift_type = shift;
430: break;
431: default:
432: SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Invalid shift type");
433: }
434: return(0);
435: }
439: /*@
440: EPSPowerSetShiftType - Sets the type of shifts used during the power
441: iteration. This can be used to emulate the Rayleigh Quotient Iteration
442: (RQI) method.
444: Logically Collective on EPS
446: Input Parameters:
447: + eps - the eigenproblem solver context
448: - shift - the type of shift
450: Options Database Key:
451: . -eps_power_shift_type - Sets the shift type (either 'constant' or
452: 'rayleigh' or 'wilkinson')
454: Notes:
455: By default, shifts are constant (EPS_POWER_SHIFT_CONSTANT) and the iteration
456: is the simple power method (or inverse iteration if a shift-and-invert
457: transformation is being used).
459: A variable shift can be specified (EPS_POWER_SHIFT_RAYLEIGH or
460: EPS_POWER_SHIFT_WILKINSON). In this case, the iteration behaves rather like
461: a cubic converging method as RQI. See the users manual for details.
463: Level: advanced
465: .seealso: EPSPowerGetShiftType(), STSetShift(), EPSPowerShiftType
466: @*/
467: PetscErrorCode EPSPowerSetShiftType(EPS eps,EPSPowerShiftType shift)
468: {
474: PetscTryMethod(eps,"EPSPowerSetShiftType_C",(EPS,EPSPowerShiftType),(eps,shift));
475: return(0);
476: }
480: static PetscErrorCode EPSPowerGetShiftType_Power(EPS eps,EPSPowerShiftType *shift)
481: {
482: EPS_POWER *power = (EPS_POWER*)eps->data;
485: *shift = power->shift_type;
486: return(0);
487: }
491: /*@C
492: EPSPowerGetShiftType - Gets the type of shifts used during the power
493: iteration.
495: Not Collective
497: Input Parameter:
498: . eps - the eigenproblem solver context
500: Input Parameter:
501: . shift - the type of shift
503: Level: advanced
505: .seealso: EPSPowerSetShiftType(), EPSPowerShiftType
506: @*/
507: PetscErrorCode EPSPowerGetShiftType(EPS eps,EPSPowerShiftType *shift)
508: {
514: PetscTryMethod(eps,"EPSPowerGetShiftType_C",(EPS,EPSPowerShiftType*),(eps,shift));
515: return(0);
516: }
520: PetscErrorCode EPSDestroy_Power(EPS eps)
521: {
525: PetscFree(eps->data);
526: PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetShiftType_C",NULL);
527: PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetShiftType_C",NULL);
528: return(0);
529: }
533: PetscErrorCode EPSView_Power(EPS eps,PetscViewer viewer)
534: {
536: EPS_POWER *power = (EPS_POWER*)eps->data;
537: PetscBool isascii;
540: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
541: if (isascii) {
542: PetscViewerASCIIPrintf(viewer," Power: %s shifts\n",EPSPowerShiftTypes[power->shift_type]);
543: }
544: return(0);
545: }
549: PETSC_EXTERN PetscErrorCode EPSCreate_Power(EPS eps)
550: {
554: PetscNewLog(eps,EPS_POWER,&eps->data);
555: eps->ops->setup = EPSSetUp_Power;
556: eps->ops->setfromoptions = EPSSetFromOptions_Power;
557: eps->ops->destroy = EPSDestroy_Power;
558: eps->ops->reset = EPSReset_Default;
559: eps->ops->view = EPSView_Power;
560: eps->ops->backtransform = EPSBackTransform_Power;
561: eps->ops->computevectors = EPSComputeVectors_Default;
562: PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetShiftType_C",EPSPowerSetShiftType_Power);
563: PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetShiftType_C",EPSPowerGetShiftType_Power);
564: return(0);
565: }