Date: 2013-09-02T10:03:10+00:00

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