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

Actual source code: krylovschur.c

      1: /*

      3:    SLEPc eigensolver: "krylovschur"

      5:    Method: Krylov-Schur

      7:    Algorithm:

      9:        Single-vector Krylov-Schur method for non-symmetric problems,
     10:        including harmonic extraction.

     12:    References:

     14:        [1] "Krylov-Schur Methods in SLEPc", SLEPc Technical Report STR-7,
     15:            available at http://www.grycap.upv.es/slepc.

     17:        [2] G.W. Stewart, "A Krylov-Schur Algorithm for Large Eigenproblems",
     18:            SIAM J. Matrix Anal. App. 23(3):601-614, 2001.

     20:        [3] "Practical Implementation of Harmonic Krylov-Schur", SLEPc Technical
     21:             Report STR-9, available at http://www.grycap.upv.es/slepc.

     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>
     45:  #include krylovschur.h

     49: PetscErrorCode EPSGetArbitraryValues(EPS eps,PetscScalar *rr,PetscScalar *ri)
     50: {
     52:   PetscInt       i,newi,ld,n,l;
     53:   Vec            xr=eps->work[1],xi=eps->work[2];
     54:   PetscScalar    re,im,*Zr,*Zi,*X;

     57:   DSGetLeadingDimension(eps->ds,&ld);
     58:   DSGetDimensions(eps->ds,&n,NULL,&l,NULL,NULL);
     59:   for (i=l;i<n;i++) {
     60:     re = eps->eigr[i];
     61:     im = eps->eigi[i];
     62:     STBackTransform(eps->st,1,&re,&im);
     63:     newi = i;
     64:     DSVectors(eps->ds,DS_MAT_X,&newi,NULL);
     65:     DSGetArray(eps->ds,DS_MAT_X,&X);
     66:     Zr = X+i*ld;
     67:     if (newi==i+1) Zi = X+newi*ld;
     68:     else Zi = NULL;
     69:     EPSComputeRitzVector(eps,Zr,Zi,eps->V,n,xr,xi);
     70:     DSRestoreArray(eps->ds,DS_MAT_X,&X);
     71:     (*eps->arbitrary)(re,im,xr,xi,rr+i,ri+i,eps->arbitraryctx);
     72:   }
     73:   return(0);
     74: }

     78: PetscErrorCode EPSSetUp_KrylovSchur(EPS eps)
     79: {
     80:   PetscErrorCode  ierr;
     81:   PetscBool       issinv;
     82:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
     83:   enum { EPS_KS_DEFAULT,EPS_KS_SYMM,EPS_KS_SLICE,EPS_KS_INDEF } variant;

     86:   /* spectrum slicing requires special treatment of default values */
     87:   if (eps->which==EPS_ALL) {
     88:     if (eps->inta==0.0 && eps->intb==0.0) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"Must define a computational interval when using EPS_ALL");
     89:     if (!eps->ishermitian) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Spectrum slicing only available for symmetric/Hermitian eigenproblems");
     90:     if (eps->arbitrary) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Arbitrary selection of eigenpairs cannot be used with spectrum slicing");
     91:     if (!((PetscObject)(eps->st))->type_name) { /* default to shift-and-invert */
     92:       STSetType(eps->st,STSINVERT);
     93:     }
     94:     PetscObjectTypeCompareAny((PetscObject)eps->st,&issinv,STSINVERT,STCAYLEY,"");
     95:     if (!issinv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Shift-and-invert or Cayley ST is needed for spectrum slicing");
     96: #if defined(PETSC_USE_REAL_DOUBLE)
     97:     if (eps->tol==PETSC_DEFAULT) eps->tol = 1e-10;  /* use tighter tolerance */
     98: #endif
     99:     if (eps->intb >= PETSC_MAX_REAL) { /* right-open interval */
    100:       if (eps->inta <= PETSC_MIN_REAL) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"The defined computational interval should have at least one of their sides bounded");
    101:       STSetDefaultShift(eps->st,eps->inta);
    102:     } else {
    103:       STSetDefaultShift(eps->st,eps->intb);
    104:     }

    106:     if (eps->nev==1) eps->nev = 40;  /* nev not set, use default value */
    107:     if (eps->nev<10) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"nev cannot be less than 10 in spectrum slicing runs");
    108:     eps->ops->backtransform = NULL;
    109:   }

    111:   if (eps->isgeneralized && eps->ishermitian && !eps->ispositive && eps->arbitrary) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Arbitrary selection of eigenpairs not implemented for indefinite problems");

    113:   /* proceed with the general case */
    114:   if (eps->ncv) { /* ncv set */
    115:     if (eps->ncv<eps->nev+1) SETERRQ(PetscObjectComm((PetscObject)eps),1,"The value of ncv must be at least nev+1");
    116:   } else if (eps->mpd) { /* mpd set */
    117:     eps->ncv = PetscMin(eps->n,eps->nev+eps->mpd);
    118:   } else { /* neither set: defaults depend on nev being small or large */
    119:     if (eps->nev<500) eps->ncv = PetscMin(eps->n,PetscMax(2*eps->nev,eps->nev+15));
    120:     else {
    121:       eps->mpd = 500;
    122:       eps->ncv = PetscMin(eps->n,eps->nev+eps->mpd);
    123:     }
    124:   }
    125:   if (!eps->mpd) eps->mpd = eps->ncv;
    126:   if (eps->ncv>eps->nev+eps->mpd) SETERRQ(PetscObjectComm((PetscObject)eps),1,"The value of ncv must not be larger than nev+mpd");
    127:   if (!eps->max_it) {
    128:     if (eps->which==EPS_ALL) eps->max_it = 100;  /* special case for spectrum slicing */
    129:     else eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
    130:   }
    131:   if (!eps->which) { EPSSetWhichEigenpairs_Default(eps); }
    132:   if (eps->ishermitian && (eps->which==EPS_LARGEST_IMAGINARY || eps->which==EPS_SMALLEST_IMAGINARY)) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Wrong value of eps->which");

    134:   if (!eps->extraction) {
    135:     EPSSetExtraction(eps,EPS_RITZ);
    136:   } else if (eps->extraction!=EPS_RITZ && eps->extraction!=EPS_HARMONIC)
    137:     SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Unsupported extraction type");

    139:   if (!ctx->keep) ctx->keep = 0.5;

    141:   EPSAllocateSolution(eps);
    142:   if (eps->arbitrary) {
    143:     EPSSetWorkVecs(eps,3);
    144:   } else if (eps->ishermitian && !eps->ispositive){
    145:     EPSSetWorkVecs(eps,2);
    146:   } else {
    147:     EPSSetWorkVecs(eps,1);
    148:   }

    150:   /* dispatch solve method */
    151:   if (eps->leftvecs) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Left vectors not supported in this solver");
    152:   if (eps->ishermitian) {
    153:     if (eps->which==EPS_ALL) {
    154:       if (eps->isgeneralized && !eps->ispositive) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Spectrum slicing not implemented for indefinite problems");
    155:       else variant = EPS_KS_SLICE;
    156:     } else if (eps->isgeneralized && !eps->ispositive) {
    157:       variant = EPS_KS_INDEF;
    158:     } else {
    159:       switch (eps->extraction) {
    160:         case EPS_RITZ:     variant = EPS_KS_SYMM; break;
    161:         case EPS_HARMONIC: variant = EPS_KS_DEFAULT; break;
    162:         default: SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Unsupported extraction type");
    163:       }
    164:     }
    165:   } else {
    166:     switch (eps->extraction) {
    167:       case EPS_RITZ:     variant = EPS_KS_DEFAULT; break;
    168:       case EPS_HARMONIC: variant = EPS_KS_DEFAULT; break;
    169:       default: SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Unsupported extraction type");
    170:     }
    171:   }
    172:   switch (variant) {
    173:     case EPS_KS_DEFAULT:
    174:       eps->ops->solve = EPSSolve_KrylovSchur_Default;
    175:       DSSetType(eps->ds,DSNHEP);
    176:       break;
    177:     case EPS_KS_SYMM:
    178:       eps->ops->solve = EPSSolve_KrylovSchur_Symm;
    179:       DSSetType(eps->ds,DSHEP);
    180:       DSSetCompact(eps->ds,PETSC_TRUE);
    181:       DSSetExtraRow(eps->ds,PETSC_TRUE);
    182:       break;
    183:     case EPS_KS_SLICE:
    184:       eps->ops->solve = EPSSolve_KrylovSchur_Slice;
    185:       DSSetType(eps->ds,DSHEP);
    186:       DSSetCompact(eps->ds,PETSC_TRUE);
    187:       break;
    188:     case EPS_KS_INDEF:
    189:       eps->ops->solve = EPSSolve_KrylovSchur_Indefinite;
    190:       DSSetType(eps->ds,DSGHIEP);
    191:       DSSetCompact(eps->ds,PETSC_TRUE);
    192:       break;
    193:     default: SETERRQ(PetscObjectComm((PetscObject)eps),1,"Unexpected error");
    194:   }
    195:   DSAllocate(eps->ds,eps->ncv+1);
    196:   return(0);
    197: }

    201: PetscErrorCode EPSSolve_KrylovSchur_Default(EPS eps)
    202: {
    203:   PetscErrorCode  ierr;
    204:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
    205:   PetscInt        i,j,*pj,k,l,nv,ld;
    206:   Vec             u=eps->work[0];
    207:   PetscScalar     *S,*Q,*g;
    208:   PetscReal       beta,gamma=1.0;
    209:   PetscBool       breakdown,harmonic;

    212:   DSGetLeadingDimension(eps->ds,&ld);
    213:   harmonic = (eps->extraction==EPS_HARMONIC || eps->extraction==EPS_REFINED_HARMONIC)?PETSC_TRUE:PETSC_FALSE;
    214:   if (harmonic) { PetscMalloc(ld*sizeof(PetscScalar),&g); }
    215:   if (eps->arbitrary) pj = &j;
    216:   else pj = NULL;

    218:   /* Get the starting Arnoldi vector */
    219:   EPSGetStartVector(eps,0,eps->V[0],NULL);
    220:   l = 0;

    222:   /* Restart loop */
    223:   while (eps->reason == EPS_CONVERGED_ITERATING) {
    224:     eps->its++;

    226:     /* Compute an nv-step Arnoldi factorization */
    227:     nv = PetscMin(eps->nconv+eps->mpd,eps->ncv);
    228:     DSGetArray(eps->ds,DS_MAT_A,&S);
    229:     EPSBasicArnoldi(eps,PETSC_FALSE,S,ld,eps->V,eps->nconv+l,&nv,u,&beta,&breakdown);
    230:     VecScale(u,1.0/beta);
    231:     DSRestoreArray(eps->ds,DS_MAT_A,&S);
    232:     DSSetDimensions(eps->ds,nv,0,eps->nconv,eps->nconv+l);
    233:     if (l==0) {
    234:       DSSetState(eps->ds,DS_STATE_INTERMEDIATE);
    235:     } else {
    236:       DSSetState(eps->ds,DS_STATE_RAW);
    237:     }

    239:     /* Compute translation of Krylov decomposition if harmonic extraction used */
    240:     if (harmonic) {
    241:       DSTranslateHarmonic(eps->ds,eps->target,beta,PETSC_FALSE,g,&gamma);
    242:     }

    244:     /* Solve projected problem */
    245:     DSSolve(eps->ds,eps->eigr,eps->eigi);
    246:     if (eps->arbitrary) {
    247:       EPSGetArbitraryValues(eps,eps->rr,eps->ri);
    248:       j=1;
    249:     }
    250:     DSSort(eps->ds,eps->eigr,eps->eigi,eps->rr,eps->ri,pj);

    252:     /* Check convergence */
    253:     EPSKrylovConvergence(eps,PETSC_FALSE,eps->nconv,nv-eps->nconv,eps->V,nv,beta,gamma,&k);
    254:     if (eps->its >= eps->max_it) eps->reason = EPS_DIVERGED_ITS;
    255:     if (k >= eps->nev) eps->reason = EPS_CONVERGED_TOL;

    257:     /* Update l */
    258:     if (eps->reason != EPS_CONVERGED_ITERATING || breakdown) l = 0;
    259:     else {
    260:       l = PetscMax(1,(PetscInt)((nv-k)*ctx->keep));
    261: #if !defined(PETSC_USE_COMPLEX)
    262:       DSGetArray(eps->ds,DS_MAT_A,&S);
    263:       if (S[k+l+(k+l-1)*ld] != 0.0) {
    264:         if (k+l<nv-1) l = l+1;
    265:         else l = l-1;
    266:       }
    267:       DSRestoreArray(eps->ds,DS_MAT_A,&S);
    268: #endif
    269:     }

    271:     if (eps->reason == EPS_CONVERGED_ITERATING) {
    272:       if (breakdown) {
    273:         /* Start a new Arnoldi factorization */
    274:         PetscInfo2(eps,"Breakdown in Krylov-Schur method (it=%D norm=%G)\n",eps->its,beta);
    275:         EPSGetStartVector(eps,k,eps->V[k],&breakdown);
    276:         if (breakdown) {
    277:           eps->reason = EPS_DIVERGED_BREAKDOWN;
    278:           PetscInfo(eps,"Unable to generate more start vectors\n");
    279:         }
    280:       } else {
    281:         /* Undo translation of Krylov decomposition */
    282:         if (harmonic) {
    283:           DSSetDimensions(eps->ds,nv,0,k,l);
    284:           DSTranslateHarmonic(eps->ds,0.0,beta,PETSC_TRUE,g,&gamma);
    285:           /* gamma u^ = u - U*g~ */
    286:           SlepcVecMAXPBY(u,1.0,-1.0,nv,g,eps->V);
    287:           VecScale(u,1.0/gamma);
    288:         }
    289:         /* Prepare the Rayleigh quotient for restart */
    290:         DSGetArray(eps->ds,DS_MAT_A,&S);
    291:         DSGetArray(eps->ds,DS_MAT_Q,&Q);
    292:         for (i=k;i<k+l;i++) {
    293:           S[k+l+i*ld] = Q[nv-1+i*ld]*beta*gamma;
    294:         }
    295:         DSRestoreArray(eps->ds,DS_MAT_A,&S);
    296:         DSRestoreArray(eps->ds,DS_MAT_Q,&Q);
    297:       }
    298:     }
    299:     /* Update the corresponding vectors V(:,idx) = V*Q(:,idx) */
    300:     DSGetArray(eps->ds,DS_MAT_Q,&Q);
    301:     SlepcUpdateVectors(nv,eps->V,eps->nconv,k+l,Q,ld,PETSC_FALSE);
    302:     DSRestoreArray(eps->ds,DS_MAT_Q,&Q);

    304:     if (eps->reason == EPS_CONVERGED_ITERATING && !breakdown) {
    305:       VecCopy(u,eps->V[k+l]);
    306:     }
    307:     eps->nconv = k;
    308:     EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,nv);
    309:   }

    311:   if (harmonic) { PetscFree(g); }
    312:   /* truncate Schur decomposition and change the state to raw so that
    313:      PSVectors() computes eigenvectors from scratch */
    314:   DSSetDimensions(eps->ds,eps->nconv,0,0,0);
    315:   DSSetState(eps->ds,DS_STATE_RAW);
    316:   return(0);
    317: }

    321: static PetscErrorCode EPSKrylovSchurSetRestart_KrylovSchur(EPS eps,PetscReal keep)
    322: {
    323:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;

    326:   if (keep==PETSC_DEFAULT) ctx->keep = 0.5;
    327:   else {
    328:     if (keep<0.1 || keep>0.9) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The keep argument must be in the range [0.1,0.9]");
    329:     ctx->keep = keep;
    330:   }
    331:   return(0);
    332: }

    336: /*@
    337:    EPSKrylovSchurSetRestart - Sets the restart parameter for the Krylov-Schur
    338:    method, in particular the proportion of basis vectors that must be kept
    339:    after restart.

    341:    Logically Collective on EPS

    343:    Input Parameters:
    344: +  eps - the eigenproblem solver context
    345: -  keep - the number of vectors to be kept at restart

    347:    Options Database Key:
    348: .  -eps_krylovschur_restart - Sets the restart parameter

    350:    Notes:
    351:    Allowed values are in the range [0.1,0.9]. The default is 0.5.

    353:    Level: advanced

    355: .seealso: EPSKrylovSchurGetRestart()
    356: @*/
    357: PetscErrorCode EPSKrylovSchurSetRestart(EPS eps,PetscReal keep)
    358: {

    364:   PetscTryMethod(eps,"EPSKrylovSchurSetRestart_C",(EPS,PetscReal),(eps,keep));
    365:   return(0);
    366: }

    370: static PetscErrorCode EPSKrylovSchurGetRestart_KrylovSchur(EPS eps,PetscReal *keep)
    371: {
    372:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;

    375:   *keep = ctx->keep;
    376:   return(0);
    377: }

    381: /*@
    382:    EPSKrylovSchurGetRestart - Gets the restart parameter used in the
    383:    Krylov-Schur method.

    385:    Not Collective

    387:    Input Parameter:
    388: .  eps - the eigenproblem solver context

    390:    Output Parameter:
    391: .  keep - the restart parameter

    393:    Level: advanced

    395: .seealso: EPSKrylovSchurSetRestart()
    396: @*/
    397: PetscErrorCode EPSKrylovSchurGetRestart(EPS eps,PetscReal *keep)
    398: {

    404:   PetscTryMethod(eps,"EPSKrylovSchurGetRestart_C",(EPS,PetscReal*),(eps,keep));
    405:   return(0);
    406: }

    410: PetscErrorCode EPSSetFromOptions_KrylovSchur(EPS eps)
    411: {
    413:   PetscBool      flg;
    414:   PetscReal      keep;

    417:   PetscOptionsHead("EPS Krylov-Schur Options");
    418:   PetscOptionsReal("-eps_krylovschur_restart","Proportion of vectors kept after restart","EPSKrylovSchurSetRestart",0.5,&keep,&flg);
    419:   if (flg) {
    420:     EPSKrylovSchurSetRestart(eps,keep);
    421:   }
    422:   PetscOptionsTail();
    423:   return(0);
    424: }

    428: PetscErrorCode EPSView_KrylovSchur(EPS eps,PetscViewer viewer)
    429: {
    430:   PetscErrorCode  ierr;
    431:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
    432:   PetscBool       isascii;

    435:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
    436:   if (isascii) {
    437:     PetscViewerASCIIPrintf(viewer,"  Krylov-Schur: %d%% of basis vectors kept after restart\n",(int)(100*ctx->keep));
    438:   }
    439:   return(0);
    440: }

    444: PetscErrorCode EPSReset_KrylovSchur(EPS eps)
    445: {
    446:   PetscErrorCode  ierr;
    447:   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;

    450:   ctx->keep = 0.0;
    451:   EPSReset_Default(eps);
    452:   return(0);
    453: }

    457: PetscErrorCode EPSDestroy_KrylovSchur(EPS eps)
    458: {

    462:   PetscFree(eps->data);
    463:   PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetRestart_C",NULL);
    464:   PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetRestart_C",NULL);
    465:   return(0);
    466: }

    470: PETSC_EXTERN PetscErrorCode EPSCreate_KrylovSchur(EPS eps)
    471: {

    475:   PetscNewLog(eps,EPS_KRYLOVSCHUR,&eps->data);
    476:   eps->ops->setup          = EPSSetUp_KrylovSchur;
    477:   eps->ops->setfromoptions = EPSSetFromOptions_KrylovSchur;
    478:   eps->ops->destroy        = EPSDestroy_KrylovSchur;
    479:   eps->ops->reset          = EPSReset_KrylovSchur;
    480:   eps->ops->view           = EPSView_KrylovSchur;
    481:   eps->ops->backtransform  = EPSBackTransform_Default;
    482:   eps->ops->computevectors = EPSComputeVectors_Schur;
    483:   PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurSetRestart_C",EPSKrylovSchurSetRestart_KrylovSchur);
    484:   PetscObjectComposeFunction((PetscObject)eps,"EPSKrylovSchurGetRestart_C",EPSKrylovSchurGetRestart_KrylovSchur);
    485:   return(0);
    486: }