Date: 2022-10-01T06:39:42+00:00

Actual source code: epsdefault.c
slepc-3.18.0 2022-10-01
Report Typos and Errors

      1: /*
      2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      4:    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain

      6:    This file is part of SLEPc.
      7:    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
      8:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      9: */
     10: /*
     11:    This file contains some simple default routines for common operations
     12: */

     14: #include <slepc/private/epsimpl.h>
     15: #include <slepcvec.h>

     17: PetscErrorCode EPSBackTransform_Default(EPS eps)
     18: {
     19:   STBackTransform(eps->st,eps->nconv,eps->eigr,eps->eigi);
     20:   return 0;
     21: }

     23: /*
     24:   EPSComputeVectors_Hermitian - Copies the Lanczos vectors as eigenvectors
     25:   using purification for generalized eigenproblems.
     26:  */
     27: PetscErrorCode EPSComputeVectors_Hermitian(EPS eps)
     28: {
     29:   PetscBool      iscayley,indef;
     30:   Mat            B,C;

     32:   if (eps->purify) {
     33:     EPS_Purify(eps,eps->nconv);
     34:     BVNormalize(eps->V,NULL);
     35:   } else {
     36:     /* In the case of Cayley transform, eigenvectors need to be B-normalized */
     37:     PetscObjectTypeCompare((PetscObject)eps->st,STCAYLEY,&iscayley);
     38:     if (iscayley && eps->isgeneralized) {
     39:       STGetMatrix(eps->st,1,&B);
     40:       BVGetMatrix(eps->V,&C,&indef);
     42:       BVSetMatrix(eps->V,B,PETSC_FALSE);
     43:       BVNormalize(eps->V,NULL);
     44:       BVSetMatrix(eps->V,C,PETSC_FALSE);  /* restore original matrix */
     45:     }
     46:   }
     47:   return 0;
     48: }

     50: /*
     51:   EPSComputeVectors_Indefinite - similar to the Schur version but
     52:   for indefinite problems
     53:  */
     54: PetscErrorCode EPSComputeVectors_Indefinite(EPS eps)
     55: {
     56:   PetscInt       n;
     57:   Mat            X;

     59:   DSGetDimensions(eps->ds,&n,NULL,NULL,NULL);
     60:   DSVectors(eps->ds,DS_MAT_X,NULL,NULL);
     61:   DSGetMat(eps->ds,DS_MAT_X,&X);
     62:   BVMultInPlace(eps->V,X,0,n);
     63:   DSRestoreMat(eps->ds,DS_MAT_X,&X);

     65:   /* purification */
     66:   if (eps->purify) EPS_Purify(eps,eps->nconv);

     68:   /* normalization */
     69:   BVNormalize(eps->V,eps->eigi);
     70:   return 0;
     71: }

     73: /*
     74:   EPSComputeVectors_Twosided - Adjust left eigenvectors in generalized problems: y = B^-* y.
     75:  */
     76: PetscErrorCode EPSComputeVectors_Twosided(EPS eps)
     77: {
     78:   PetscInt       i;
     79:   Vec            w,y;

     81:   if (!eps->twosided || !eps->isgeneralized) return 0;
     82:   EPSSetWorkVecs(eps,1);
     83:   w = eps->work[0];
     84:   for (i=0;i<eps->nconv;i++) {
     85:     BVCopyVec(eps->W,i,w);
     86:     VecConjugate(w);
     87:     BVGetColumn(eps->W,i,&y);
     88:     STMatSolveTranspose(eps->st,w,y);
     89:     VecConjugate(y);
     90:     BVRestoreColumn(eps->W,i,&y);
     91:   }
     92:   return 0;
     93: }

     95: /*
     96:   EPSComputeVectors_Schur - Compute eigenvectors from the vectors
     97:   provided by the eigensolver. This version is intended for solvers
     98:   that provide Schur vectors. Given the partial Schur decomposition
     99:   OP*V=V*T, the following steps are performed:
    100:       1) compute eigenvectors of T: T*Z=Z*D
    101:       2) compute eigenvectors of OP: X=V*Z
    102:  */
    103: PetscErrorCode EPSComputeVectors_Schur(EPS eps)
    104: {
    105:   PetscInt       i;
    106:   Mat            Z;
    107:   Vec            z;

    109:   if (eps->ishermitian) {
    110:     if (eps->isgeneralized && !eps->ispositive) EPSComputeVectors_Indefinite(eps);
    111:     else EPSComputeVectors_Hermitian(eps);
    112:     return 0;
    113:   }

    115:   /* right eigenvectors */
    116:   DSVectors(eps->ds,DS_MAT_X,NULL,NULL);

    118:   /* V = V * Z */
    119:   DSGetMat(eps->ds,DS_MAT_X,&Z);
    120:   BVMultInPlace(eps->V,Z,0,eps->nconv);
    121:   DSRestoreMat(eps->ds,DS_MAT_X,&Z);

    123:   /* Purify eigenvectors */
    124:   if (eps->purify) EPS_Purify(eps,eps->nconv);

    126:   /* Fix eigenvectors if balancing was used */
    127:   if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
    128:     for (i=0;i<eps->nconv;i++) {
    129:       BVGetColumn(eps->V,i,&z);
    130:       VecPointwiseDivide(z,z,eps->D);
    131:       BVRestoreColumn(eps->V,i,&z);
    132:     }
    133:   }

    135:   /* normalize eigenvectors (when using purification or balancing) */
    136:   if (eps->purify || (eps->balance!=EPS_BALANCE_NONE && eps->D)) BVNormalize(eps->V,eps->eigi);

    138:   /* left eigenvectors */
    139:   if (eps->twosided) {
    140:     DSVectors(eps->ds,DS_MAT_Y,NULL,NULL);
    141:     /* W = W * Z */
    142:     DSGetMat(eps->ds,DS_MAT_Y,&Z);
    143:     BVMultInPlace(eps->W,Z,0,eps->nconv);
    144:     DSRestoreMat(eps->ds,DS_MAT_Y,&Z);
    145:     /* Fix left eigenvectors if balancing was used */
    146:     if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
    147:       for (i=0;i<eps->nconv;i++) {
    148:         BVGetColumn(eps->W,i,&z);
    149:         VecPointwiseMult(z,z,eps->D);
    150:         BVRestoreColumn(eps->W,i,&z);
    151:       }
    152:     }
    153:     EPSComputeVectors_Twosided(eps);
    154:     /* normalize */
    155:     BVNormalize(eps->W,eps->eigi);
    156: #if !defined(PETSC_USE_COMPLEX)
    157:     for (i=0;i<eps->nconv-1;i++) {
    158:       if (eps->eigi[i] != 0.0) {
    159:         if (eps->eigi[i] > 0.0) BVScaleColumn(eps->W,i+1,-1.0);
    160:         i++;
    161:       }
    162:     }
    163: #endif
    164:   }
    165:   return 0;
    166: }

    168: /*@
    169:    EPSSetWorkVecs - Sets a number of work vectors into an EPS object.

    171:    Collective on eps

    173:    Input Parameters:
    174: +  eps - eigensolver context
    175: -  nw  - number of work vectors to allocate

    177:    Developer Notes:
    178:    This is SLEPC_EXTERN because it may be required by user plugin EPS
    179:    implementations.

    181:    Level: developer

    183: .seealso: EPSSetUp()
    184: @*/
    185: PetscErrorCode EPSSetWorkVecs(EPS eps,PetscInt nw)
    186: {
    187:   Vec            t;

    192:   if (eps->nwork < nw) {
    193:     VecDestroyVecs(eps->nwork,&eps->work);
    194:     eps->nwork = nw;
    195:     BVGetColumn(eps->V,0,&t);
    196:     VecDuplicateVecs(t,nw,&eps->work);
    197:     BVRestoreColumn(eps->V,0,&t);
    198:   }
    199:   return 0;
    200: }

    202: /*
    203:   EPSSetWhichEigenpairs_Default - Sets the default value for which,
    204:   depending on the ST.
    205:  */
    206: PetscErrorCode EPSSetWhichEigenpairs_Default(EPS eps)
    207: {
    208:   PetscBool      target;

    210:   PetscObjectTypeCompareAny((PetscObject)eps->st,&target,STSINVERT,STCAYLEY,"");
    211:   if (target) eps->which = EPS_TARGET_MAGNITUDE;
    212:   else eps->which = EPS_LARGEST_MAGNITUDE;
    213:   return 0;
    214: }

    216: /*
    217:   EPSConvergedRelative - Checks convergence relative to the eigenvalue.
    218: */
    219: PetscErrorCode EPSConvergedRelative(EPS eps,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
    220: {
    221:   PetscReal w;

    223:   w = SlepcAbsEigenvalue(eigr,eigi);
    224:   *errest = res/w;
    225:   return 0;
    226: }

    228: /*
    229:   EPSConvergedAbsolute - Checks convergence absolutely.
    230: */
    231: PetscErrorCode EPSConvergedAbsolute(EPS eps,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
    232: {
    233:   *errest = res;
    234:   return 0;
    235: }

    237: /*
    238:   EPSConvergedNorm - Checks convergence relative to the eigenvalue and
    239:   the matrix norms.
    240: */
    241: PetscErrorCode EPSConvergedNorm(EPS eps,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
    242: {
    243:   PetscReal w;

    245:   w = SlepcAbsEigenvalue(eigr,eigi);
    246:   *errest = res / (eps->nrma + w*eps->nrmb);
    247:   return 0;
    248: }

    250: /*@C
    251:    EPSStoppingBasic - Default routine to determine whether the outer eigensolver
    252:    iteration must be stopped.

    254:    Collective on eps

    256:    Input Parameters:
    257: +  eps    - eigensolver context obtained from EPSCreate()
    258: .  its    - current number of iterations
    259: .  max_it - maximum number of iterations
    260: .  nconv  - number of currently converged eigenpairs
    261: .  nev    - number of requested eigenpairs
    262: -  ctx    - context (not used here)

    264:    Output Parameter:
    265: .  reason - result of the stopping test

    267:    Notes:
    268:    A positive value of reason indicates that the iteration has finished successfully
    269:    (converged), and a negative value indicates an error condition (diverged). If
    270:    the iteration needs to be continued, reason must be set to EPS_CONVERGED_ITERATING
    271:    (zero).

    273:    EPSStoppingBasic() will stop if all requested eigenvalues are converged, or if
    274:    the maximum number of iterations has been reached.

    276:    Use EPSSetStoppingTest() to provide your own test instead of using this one.

    278:    Level: advanced

    280: .seealso: EPSSetStoppingTest(), EPSConvergedReason, EPSGetConvergedReason()
    281: @*/
    282: PetscErrorCode EPSStoppingBasic(EPS eps,PetscInt its,PetscInt max_it,PetscInt nconv,PetscInt nev,EPSConvergedReason *reason,void *ctx)
    283: {
    284:   *reason = EPS_CONVERGED_ITERATING;
    285:   if (nconv >= nev) {
    286:     PetscInfo(eps,"Linear eigensolver finished successfully: %" PetscInt_FMT " eigenpairs converged at iteration %" PetscInt_FMT "\n",nconv,its);
    287:     *reason = EPS_CONVERGED_TOL;
    288:   } else if (its >= max_it) {
    289:     *reason = EPS_DIVERGED_ITS;
    290:     PetscInfo(eps,"Linear eigensolver iteration reached maximum number of iterations (%" PetscInt_FMT ")\n",its);
    291:   }
    292:   return 0;
    293: }

    295: /*
    296:   EPSComputeRitzVector - Computes the current Ritz vector.

    298:   Simple case (complex scalars or real scalars with Zi=NULL):
    299:     x = V*Zr  (V is a basis of nv vectors, Zr has length nv)

    301:   Split case:
    302:     x = V*Zr  y = V*Zi  (Zr and Zi have length nv)
    303: */
    304: PetscErrorCode EPSComputeRitzVector(EPS eps,PetscScalar *Zr,PetscScalar *Zi,BV V,Vec x,Vec y)
    305: {
    306:   PetscInt       l,k;
    307:   PetscReal      norm;
    308: #if !defined(PETSC_USE_COMPLEX)
    309:   Vec            z;
    310: #endif

    312:   /* compute eigenvector */
    313:   BVGetActiveColumns(V,&l,&k);
    314:   BVSetActiveColumns(V,0,k);
    315:   BVMultVec(V,1.0,0.0,x,Zr);

    317:   /* purify eigenvector if necessary */
    318:   if (eps->purify) {
    319:     STApply(eps->st,x,y);
    320:     if (eps->ishermitian) BVNormVec(eps->V,y,NORM_2,&norm);
    321:     else VecNorm(y,NORM_2,&norm);
    322:     VecScale(y,1.0/norm);
    323:     VecCopy(y,x);
    324:   }
    325:   /* fix eigenvector if balancing is used */
    326:   if (!eps->ishermitian && eps->balance!=EPS_BALANCE_NONE && eps->D) VecPointwiseDivide(x,x,eps->D);
    327: #if !defined(PETSC_USE_COMPLEX)
    328:   /* compute imaginary part of eigenvector */
    329:   if (Zi) {
    330:     BVMultVec(V,1.0,0.0,y,Zi);
    331:     if (eps->ispositive) {
    332:       BVCreateVec(V,&z);
    333:       STApply(eps->st,y,z);
    334:       VecNorm(z,NORM_2,&norm);
    335:       VecScale(z,1.0/norm);
    336:       VecCopy(z,y);
    337:       VecDestroy(&z);
    338:     }
    339:     if (eps->balance!=EPS_BALANCE_NONE && eps->D) VecPointwiseDivide(y,y,eps->D);
    340:   } else
    341: #endif
    342:     VecSet(y,0.0);

    344:   /* normalize eigenvectors (when using balancing) */
    345:   if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
    346: #if !defined(PETSC_USE_COMPLEX)
    347:     if (Zi) VecNormalizeComplex(x,y,PETSC_TRUE,NULL);
    348:     else
    349: #endif
    350:     VecNormalize(x,NULL);
    351:   }
    352:   BVSetActiveColumns(V,l,k);
    353:   return 0;
    354: }

    356: /*
    357:   EPSBuildBalance_Krylov - uses a Krylov subspace method to compute the
    358:   diagonal matrix to be applied for balancing in non-Hermitian problems.
    359: */
    360: PetscErrorCode EPSBuildBalance_Krylov(EPS eps)
    361: {
    362:   Vec               z,p,r;
    363:   PetscInt          i,j;
    364:   PetscReal         norma;
    365:   PetscScalar       *pz,*pD;
    366:   const PetscScalar *pr,*pp;
    367:   PetscRandom       rand;

    369:   EPSSetWorkVecs(eps,3);
    370:   BVGetRandomContext(eps->V,&rand);
    371:   r = eps->work[0];
    372:   p = eps->work[1];
    373:   z = eps->work[2];
    374:   VecSet(eps->D,1.0);

    376:   for (j=0;j<eps->balance_its;j++) {

    378:     /* Build a random vector of +-1's */
    379:     VecSetRandom(z,rand);
    380:     VecGetArray(z,&pz);
    381:     for (i=0;i<eps->nloc;i++) {
    382:       if (PetscRealPart(pz[i])<0.5) pz[i]=-1.0;
    383:       else pz[i]=1.0;
    384:     }
    385:     VecRestoreArray(z,&pz);

    387:     /* Compute p=DA(D\z) */
    388:     VecPointwiseDivide(r,z,eps->D);
    389:     STApply(eps->st,r,p);
    390:     VecPointwiseMult(p,p,eps->D);
    391:     if (eps->balance == EPS_BALANCE_TWOSIDE) {
    392:       if (j==0) {
    393:         /* Estimate the matrix inf-norm */
    394:         VecAbs(p);
    395:         VecMax(p,NULL,&norma);
    396:       }
    397:       /* Compute r=D\(A'Dz) */
    398:       VecPointwiseMult(z,z,eps->D);
    399:       STApplyHermitianTranspose(eps->st,z,r);
    400:       VecPointwiseDivide(r,r,eps->D);
    401:     }

    403:     /* Adjust values of D */
    404:     VecGetArrayRead(r,&pr);
    405:     VecGetArrayRead(p,&pp);
    406:     VecGetArray(eps->D,&pD);
    407:     for (i=0;i<eps->nloc;i++) {
    408:       if (eps->balance == EPS_BALANCE_TWOSIDE) {
    409:         if (PetscAbsScalar(pp[i])>eps->balance_cutoff*norma && pr[i]!=0.0)
    410:           pD[i] *= PetscSqrtReal(PetscAbsScalar(pr[i]/pp[i]));
    411:       } else {
    412:         if (pp[i]!=0.0) pD[i] /= PetscAbsScalar(pp[i]);
    413:       }
    414:     }
    415:     VecRestoreArrayRead(r,&pr);
    416:     VecRestoreArrayRead(p,&pp);
    417:     VecRestoreArray(eps->D,&pD);
    418:   }
    419:   return 0;
    420: }