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: }