Date: 2013-09-02T10:04:45+00:00

Actual source code: rqcg.c

      1: /*

      3:    SLEPc eigensolver: "rqcg"

      5:    Method: Rayleigh Quotient Conjugate Gradient

      7:    Algorithm:

      9:        Conjugate Gradient minimization of the Rayleigh quotient with
     10:        periodic Rayleigh-Ritz acceleration.

     12:    References:

     14:        [1] L. Bergamaschi et al., "Parallel preconditioned conjugate gradient
     15:            optimization of the Rayleigh quotient for the solution of sparse
     16:            eigenproblems", Appl. Math. Comput. 175(2):1694-1715, 2006.

     18:    Last update: Jul 2012

     20:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     21:    SLEPc - Scalable Library for Eigenvalue Problem Computations
     22:    Copyright (c) 2002-2013, Universitat Politecnica de Valencia, Spain

     24:    This file is part of SLEPc.

     26:    SLEPc is free software: you can redistribute it and/or modify it under  the
     27:    terms of version 3 of the GNU Lesser General Public License as published by
     28:    the Free Software Foundation.

     30:    SLEPc  is  distributed in the hope that it will be useful, but WITHOUT  ANY
     31:    WARRANTY;  without even the implied warranty of MERCHANTABILITY or  FITNESS
     32:    FOR  A  PARTICULAR PURPOSE. See the GNU Lesser General Public  License  for
     33:    more details.

     35:    You  should have received a copy of the GNU Lesser General  Public  License
     36:    along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
     37:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     38: */

     40: #include <slepc-private/epsimpl.h>                /*I "slepceps.h" I*/
     41: #include <slepcblaslapack.h>

     43: PetscErrorCode EPSSolve_RQCG(EPS);

     45: typedef struct {
     46:   PetscInt nrest;
     47:   Vec      *AV,*BV,*P,*G;
     48: } EPS_RQCG;

     52: PetscErrorCode EPSSetUp_RQCG(EPS eps)
     53: {
     55:   PetscBool      precond;
     56:   PetscInt       nmat;
     57:   EPS_RQCG       *ctx = (EPS_RQCG*)eps->data;

     60:   if (!eps->ishermitian) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"RQCG only works for Hermitian problems");
     61:   if (eps->ncv) { /* ncv set */
     62:     if (eps->ncv<eps->nev) SETERRQ(PetscObjectComm((PetscObject)eps),1,"The value of ncv must be at least nev");
     63:   }
     64:   else if (eps->mpd) { /* mpd set */
     65:     eps->ncv = PetscMin(eps->n,eps->nev+eps->mpd);
     66:   }
     67:   else { /* neither set: defaults depend on nev being small or large */
     68:     if (eps->nev<500) eps->ncv = PetscMin(eps->n,PetscMax(2*eps->nev,eps->nev+15));
     69:     else {
     70:       eps->mpd = 500;
     71:       eps->ncv = PetscMin(eps->n,eps->nev+eps->mpd);
     72:     }
     73:   }
     74:   if (!eps->mpd) eps->mpd = eps->ncv;
     75:   if (!eps->max_it) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
     76:   if (!eps->which) eps->which = EPS_SMALLEST_REAL;
     77:   if (eps->which!=EPS_SMALLEST_REAL) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Wrong value of eps->which");
     78:   if (!eps->extraction) {
     79:     EPSSetExtraction(eps,EPS_RITZ);
     80:   } else if (eps->extraction!=EPS_RITZ) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Unsupported extraction type");
     81:   if (eps->arbitrary) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Arbitrary selection of eigenpairs not supported in this solver");
     82:   /* Set STPrecond as the default ST */
     83:   if (!((PetscObject)eps->st)->type_name) {
     84:     STSetType(eps->st,STPRECOND);
     85:   }
     86:   PetscObjectTypeCompare((PetscObject)eps->st,STPRECOND,&precond);
     87:   if (!precond) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"RQCG only works with precond ST");

     89:   if (!ctx->nrest) ctx->nrest = 20;

     91:   EPSAllocateSolution(eps);
     92:   VecDuplicateVecs(eps->t,eps->mpd,&ctx->AV);
     93:   PetscLogObjectParent(eps,ctx->AV);
     94:   STGetNumMatrices(eps->st,&nmat);
     95:   if (nmat>1) {
     96:     VecDuplicateVecs(eps->t,eps->mpd,&ctx->BV);
     97:     PetscLogObjectParent(eps,ctx->BV);
     98:   }
     99:   VecDuplicateVecs(eps->t,eps->mpd,&ctx->P);
    100:   PetscLogObjectParent(eps,ctx->P);
    101:   VecDuplicateVecs(eps->t,eps->mpd,&ctx->G);
    102:   PetscLogObjectParent(eps,ctx->G);
    103:   DSSetType(eps->ds,DSHEP);
    104:   DSAllocate(eps->ds,eps->ncv);
    105:   EPSSetWorkVecs(eps,1);

    107:   /* dispatch solve method */
    108:   if (eps->leftvecs) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Left vectors not supported in this solver");
    109:   eps->ops->solve = EPSSolve_RQCG;
    110:   return(0);
    111: }

    115: PetscErrorCode EPSSolve_RQCG(EPS eps)
    116: {
    118:   EPS_RQCG       *ctx = (EPS_RQCG*)eps->data;
    119:   PetscInt       i,j,k,ld,off,nv,ncv = eps->ncv,kini,nmat;
    120:   PetscScalar    *C,*Y,*gamma,g,pap,pbp,pbx,pax,nu,mu,alpha,beta;
    121:   PetscReal      resnorm,norm,a,b,c,disc,t;
    122:   PetscBool      reset,breakdown;
    123:   Mat            A,B;
    124:   Vec            w=eps->work[0];

    127:   DSGetLeadingDimension(eps->ds,&ld);
    128:   STGetNumMatrices(eps->st,&nmat);
    129:   STGetOperators(eps->st,0,&A);
    130:   if (nmat>1) { STGetOperators(eps->st,1,&B); }
    131:   else B = NULL;
    132:   PetscMalloc(eps->mpd*sizeof(PetscScalar),&gamma);

    134:   kini = eps->nini;
    135:   while (eps->reason == EPS_CONVERGED_ITERATING) {
    136:     eps->its++;
    137:     nv = PetscMin(eps->nconv+eps->mpd,ncv);
    138:     DSSetDimensions(eps->ds,nv,0,eps->nconv,0);
    139:     /* Generate more initial vectors if necessary */
    140:     while (kini<nv) {
    141:       SlepcVecSetRandom(eps->V[kini],eps->rand);
    142:       IPOrthogonalize(eps->ip,eps->nds,eps->defl,kini,NULL,eps->V,eps->V[kini],NULL,&norm,&breakdown);
    143:       if (norm>0.0 && !breakdown) {
    144:         VecScale(eps->V[kini],1.0/norm);
    145:         kini++;
    146:       }
    147:     }
    148:     reset = (eps->its>1 && (eps->its-1)%ctx->nrest==0)? PETSC_TRUE: PETSC_FALSE;

    150:     if (reset) {
    151:       /* Compute Rayleigh quotient */
    152:       DSGetArray(eps->ds,DS_MAT_A,&C);
    153:       for (i=eps->nconv;i<nv;i++) {
    154:         MatMult(A,eps->V[i],ctx->AV[i-eps->nconv]);
    155:         VecMDot(ctx->AV[i-eps->nconv],i-eps->nconv+1,eps->V+eps->nconv,C+eps->nconv+i*ld);
    156:         for (j=eps->nconv;j<i-1;j++) C[i+j*ld] = C[j+i*ld];
    157:       }
    158:       DSRestoreArray(eps->ds,DS_MAT_A,&C);
    159:       DSSetState(eps->ds,DS_STATE_RAW);

    161:       /* Solve projected problem */
    162:       DSSolve(eps->ds,eps->eigr,eps->eigi);
    163:       DSSort(eps->ds,eps->eigr,eps->eigi,NULL,NULL,NULL);

    165:       /* Update vectors V(:,idx) = V * Y(:,idx) */
    166:       DSGetArray(eps->ds,DS_MAT_Q,&Y);
    167:       off = eps->nconv+eps->nconv*ld;
    168:       SlepcUpdateVectors(nv-eps->nconv,ctx->AV,0,nv-eps->nconv,Y+off,ld,PETSC_FALSE);
    169:       SlepcUpdateVectors(nv-eps->nconv,eps->V+eps->nconv,0,nv-eps->nconv,Y+off,ld,PETSC_FALSE);
    170:       DSRestoreArray(eps->ds,DS_MAT_Q,&Y);

    172:     } else {
    173:       /* No need to do Rayleigh-Ritz, just take diag(V'*A*V) */
    174:       for (i=eps->nconv;i<nv;i++) {
    175:         MatMult(A,eps->V[i],ctx->AV[i-eps->nconv]);
    176:         VecDot(ctx->AV[i-eps->nconv],eps->V[i],eps->eigr+i);
    177:       }
    178:     }

    180:     /* Compute gradient and check convergence */
    181:     k = -1;
    182:     for (i=eps->nconv;i<nv;i++) {
    183:       if (B) {
    184:         MatMult(B,eps->V[i],ctx->BV[i-eps->nconv]);
    185:         VecWAXPY(ctx->G[i-eps->nconv],-eps->eigr[i],ctx->BV[i-eps->nconv],ctx->AV[i-eps->nconv]);
    186:       } else {
    187:         VecWAXPY(ctx->G[i-eps->nconv],-eps->eigr[i],eps->V[i],ctx->AV[i-eps->nconv]);
    188:       }
    189:       VecNorm(ctx->G[i-eps->nconv],NORM_2,&resnorm);
    190:       (*eps->converged)(eps,eps->eigr[i],0.0,resnorm,&eps->errest[i],eps->convergedctx);
    191:       if (k==-1 && eps->errest[i] >= eps->tol) k = i;
    192:     }
    193:     if (k==-1) k = nv;
    194:     if (eps->its >= eps->max_it) eps->reason = EPS_DIVERGED_ITS;
    195:     if (k >= eps->nev) eps->reason = EPS_CONVERGED_TOL;

    197:     /* The next lines are necessary to avoid DS zeroing eigr */
    198:     DSGetArray(eps->ds,DS_MAT_A,&C);
    199:     for (i=eps->nconv;i<k;i++) C[i+i*ld] = eps->eigr[i];
    200:     DSRestoreArray(eps->ds,DS_MAT_A,&C);

    202:     if (eps->reason == EPS_CONVERGED_ITERATING) {

    204:       /* Search direction */
    205:       for (i=0;i<nv-eps->nconv;i++) {
    206:         STMatSolve(eps->st,0,ctx->G[i],w);
    207:         VecDot(ctx->G[i],w,&g);
    208:         beta = (!reset && eps->its>1)? g/gamma[i]: 0.0;
    209:         gamma[i] = g;
    210:         VecAXPBY(ctx->P[i],1.0,beta,w);
    211:         IPOrthogonalize(eps->ip,eps->nds,eps->defl,i+eps->nconv,NULL,eps->V,ctx->P[i],NULL,&resnorm,&breakdown);
    212:       }

    214:       /* Minimization problem */
    215:       for (i=eps->nconv;i<nv;i++) {
    216:         VecDot(eps->V[i],ctx->AV[i-eps->nconv],&nu);
    217:         VecDot(ctx->P[i-eps->nconv],ctx->AV[i-eps->nconv],&pax);
    218:         MatMult(A,ctx->P[i-eps->nconv],w);
    219:         VecDot(ctx->P[i-eps->nconv],w,&pap);
    220:         if (B) {
    221:           VecDot(eps->V[i],ctx->BV[i-eps->nconv],&mu);
    222:           VecDot(ctx->P[i-eps->nconv],ctx->BV[i-eps->nconv],&pbx);
    223:           MatMult(B,ctx->P[i-eps->nconv],w);
    224:           VecDot(ctx->P[i-eps->nconv],w,&pbp);
    225:         } else {
    226:           VecDot(eps->V[i],eps->V[i],&mu);
    227:           VecDot(ctx->P[i-eps->nconv],eps->V[i],&pbx);
    228:           VecDot(ctx->P[i-eps->nconv],ctx->P[i-eps->nconv],&pbp);
    229:         }
    230:         a = PetscRealPart(pap*pbx-pax*pbp);
    231:         b = PetscRealPart(nu*pbp-mu*pap);
    232:         c = PetscRealPart(mu*pax-nu*pbx);
    233:         t = PetscMax(PetscMax(PetscAbsReal(a),PetscAbsReal(b)),PetscAbsReal(c));
    234:         if (t!=0.0) { a /= t; b /= t; c /= t; }
    235:         disc = PetscSqrtReal(PetscAbsReal(b*b-4.0*a*c));
    236:         if (b>=0.0 && a!=0.0) alpha = (b+disc)/(2.0*a);
    237:         else if (b!=disc) alpha = 2.0*c/(b-disc);
    238:         else alpha = 0;
    239:         /* Next iterate */
    240:         if (alpha!=0.0) {
    241:           VecAXPY(eps->V[i],alpha,ctx->P[i-eps->nconv]);
    242:         }
    243:         IPOrthogonalize(eps->ip,eps->nds,eps->defl,i,NULL,eps->V,eps->V[i],NULL,&norm,&breakdown);
    244:         if (!breakdown && norm!=0.0) {
    245:           VecScale(eps->V[i],1.0/norm);
    246:         }
    247:       }
    248:     }

    250:     EPSMonitor(eps,eps->its,k,eps->eigr,eps->eigi,eps->errest,nv);
    251:     eps->nconv = k;
    252:   }

    254:   PetscFree(gamma);
    255:   /* truncate Schur decomposition and change the state to raw so that
    256:      PSVectors() computes eigenvectors from scratch */
    257:   DSSetDimensions(eps->ds,eps->nconv,0,0,0);
    258:   DSSetState(eps->ds,DS_STATE_RAW);
    259:   return(0);
    260: }

    264: static PetscErrorCode EPSRQCGSetReset_RQCG(EPS eps,PetscInt nrest)
    265: {
    266:   EPS_RQCG *ctx = (EPS_RQCG*)eps->data;

    269:   ctx->nrest = nrest;
    270:   return(0);
    271: }

    275: /*@
    276:    EPSRQCGSetReset - Sets the reset parameter of the RQCG iteration. Every
    277:    nrest iterations, the solver performs a Rayleigh-Ritz projection step.

    279:    Logically Collective on EPS

    281:    Input Parameters:
    282: +  eps - the eigenproblem solver context
    283: -  nrest - the number of iterations between resets

    285:    Options Database Key:
    286: .  -eps_rqcg_reset - Sets the reset parameter

    288:    Level: advanced

    290: .seealso: EPSRQCGGetReset()
    291: @*/
    292: PetscErrorCode EPSRQCGSetReset(EPS eps,PetscInt nrest)
    293: {

    299:   PetscTryMethod(eps,"EPSRQCGSetReset_C",(EPS,PetscInt),(eps,nrest));
    300:   return(0);
    301: }

    305: static PetscErrorCode EPSRQCGGetReset_RQCG(EPS eps,PetscInt *nrest)
    306: {
    307:   EPS_RQCG *ctx = (EPS_RQCG*)eps->data;

    310:   *nrest = ctx->nrest;
    311:   return(0);
    312: }

    316: /*@
    317:    EPSRQCGGetReset - Gets the reset parameter used in the RQCG method.

    319:    Not Collective

    321:    Input Parameter:
    322: .  eps - the eigenproblem solver context

    324:    Output Parameter:
    325: .  nrest - the reset parameter

    327:    Level: advanced

    329: .seealso: EPSRQCGSetReset()
    330: @*/
    331: PetscErrorCode EPSRQCGGetReset(EPS eps,PetscInt *nrest)
    332: {

    338:   PetscTryMethod(eps,"EPSRQCGGetReset_C",(EPS,PetscInt*),(eps,nrest));
    339:   return(0);
    340: }

    344: PetscErrorCode EPSReset_RQCG(EPS eps)
    345: {
    347:   EPS_RQCG       *ctx = (EPS_RQCG*)eps->data;

    350:   VecDestroyVecs(eps->mpd,&ctx->AV);
    351:   VecDestroyVecs(eps->mpd,&ctx->BV);
    352:   VecDestroyVecs(eps->mpd,&ctx->P);
    353:   VecDestroyVecs(eps->mpd,&ctx->G);
    354:   ctx->nrest = 0;
    355:   EPSReset_Default(eps);
    356:   return(0);
    357: }

    361: PetscErrorCode EPSSetFromOptions_RQCG(EPS eps)
    362: {
    364:   PetscBool      flg;
    365:   PetscInt       nrest;

    368:   PetscOptionsHead("EPS RQCG Options");
    369:   PetscOptionsInt("-eps_rqcg_reset","RQCG reset parameter","EPSRQCGSetReset",20,&nrest,&flg);
    370:   if (flg) {
    371:     EPSRQCGSetReset(eps,nrest);
    372:   }
    373:   PetscOptionsTail();
    374:   return(0);
    375: }

    379: PetscErrorCode EPSDestroy_RQCG(EPS eps)
    380: {

    384:   PetscFree(eps->data);
    385:   PetscObjectComposeFunction((PetscObject)eps,"EPSRQCGSetReset_C",NULL);
    386:   PetscObjectComposeFunction((PetscObject)eps,"EPSRQCGGetReset_C",NULL);
    387:   return(0);
    388: }

    392: PetscErrorCode EPSView_RQCG(EPS eps,PetscViewer viewer)
    393: {
    395:   EPS_RQCG       *ctx = (EPS_RQCG*)eps->data;
    396:   PetscBool      isascii;

    399:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
    400:   if (isascii) {
    401:     PetscViewerASCIIPrintf(viewer,"  RQCG: reset every %D iterations\n",ctx->nrest);
    402:   }
    403:   return(0);
    404: }

    408: PETSC_EXTERN PetscErrorCode EPSCreate_RQCG(EPS eps)
    409: {

    413:   PetscNewLog(eps,EPS_RQCG,&eps->data);
    414:   eps->ops->setup          = EPSSetUp_RQCG;
    415:   eps->ops->setfromoptions = EPSSetFromOptions_RQCG;
    416:   eps->ops->destroy        = EPSDestroy_RQCG;
    417:   eps->ops->reset          = EPSReset_RQCG;
    418:   eps->ops->view           = EPSView_RQCG;
    419:   eps->ops->backtransform  = EPSBackTransform_Default;
    420:   eps->ops->computevectors = EPSComputeVectors_Default;
    421:   STSetType(eps->st,STPRECOND);
    422:   STPrecondSetKSPHasMat(eps->st,PETSC_TRUE);
    423:   PetscObjectComposeFunction((PetscObject)eps,"EPSRQCGSetReset_C",EPSRQCGSetReset_RQCG);
    424:   PetscObjectComposeFunction((PetscObject)eps,"EPSRQCGGetReset_C",EPSRQCGGetReset_RQCG);
    425:   return(0);
    426: }