Date: 2023-01-26T12:18:31+00:00

Actual source code: epssolve.c
slepc-3.18.2 2023-01-26
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:    EPS routines related to the solution process
     12: */

     14: #include <slepc/private/epsimpl.h>
     15: #include <slepc/private/bvimpl.h>
     16: #include <petscdraw.h>

     18: PetscErrorCode EPSComputeVectors(EPS eps)
     19: {
     20:   EPSCheckSolved(eps,1);
     21:   if (eps->state==EPS_STATE_SOLVED) PetscTryTypeMethod(eps,computevectors);
     22:   eps->state = EPS_STATE_EIGENVECTORS;
     23:   return 0;
     24: }

     26: #define SWAP(a,b,t) {t=a;a=b;b=t;}

     28: static PetscErrorCode EPSComputeValues(EPS eps)
     29: {
     30:   PetscBool      injective,iscomp,isfilter;
     31:   PetscInt       i,n,aux,nconv0;
     32:   Mat            A,B=NULL,G,Z;

     34:   switch (eps->categ) {
     35:     case EPS_CATEGORY_KRYLOV:
     36:     case EPS_CATEGORY_OTHER:
     37:       STIsInjective(eps->st,&injective);
     38:       if (injective) {
     39:         /* one-to-one mapping: backtransform eigenvalues */
     40:         PetscUseTypeMethod(eps,backtransform);
     41:       } else {
     42:         /* compute eigenvalues from Rayleigh quotient */
     43:         DSGetDimensions(eps->ds,&n,NULL,NULL,NULL);
     44:         if (!n) break;
     45:         EPSGetOperators(eps,&A,&B);
     46:         BVSetActiveColumns(eps->V,0,n);
     47:         DSGetCompact(eps->ds,&iscomp);
     48:         DSSetCompact(eps->ds,PETSC_FALSE);
     49:         DSGetMat(eps->ds,DS_MAT_A,&G);
     50:         BVMatProject(eps->V,A,eps->V,G);
     51:         DSRestoreMat(eps->ds,DS_MAT_A,&G);
     52:         if (B) {
     53:           DSGetMat(eps->ds,DS_MAT_B,&G);
     54:           BVMatProject(eps->V,B,eps->V,G);
     55:           DSRestoreMat(eps->ds,DS_MAT_A,&G);
     56:         }
     57:         DSSolve(eps->ds,eps->eigr,eps->eigi);
     58:         DSSort(eps->ds,eps->eigr,eps->eigi,NULL,NULL,NULL);
     59:         DSSynchronize(eps->ds,eps->eigr,eps->eigi);
     60:         DSSetCompact(eps->ds,iscomp);
     61:         if (eps->ishermitian && (!eps->isgeneralized || eps->ispositive)) { /* V = V * Z */
     62:           DSVectors(eps->ds,DS_MAT_X,NULL,NULL);
     63:           DSGetMat(eps->ds,DS_MAT_X,&Z);
     64:           BVMultInPlace(eps->V,Z,0,n);
     65:           DSRestoreMat(eps->ds,DS_MAT_X,&Z);
     66:         }
     67:         /* in case of STFILTER discard computed eigenvalues that lie outside the wanted interval */
     68:         PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilter);
     69:         if (isfilter) {
     70:           nconv0 = eps->nconv;
     71:           for (i=0;i<eps->nconv;i++) {
     72:             if (PetscRealPart(eps->eigr[eps->perm[i]])<eps->inta || PetscRealPart(eps->eigr[eps->perm[i]])>eps->intb) {
     73:               eps->nconv--;
     74:               if (i<eps->nconv) { SWAP(eps->perm[i],eps->perm[eps->nconv],aux); i--; }
     75:             }
     76:           }
     77:           if (nconv0>eps->nconv) PetscInfo(eps,"Discarded %" PetscInt_FMT " computed eigenvalues lying outside the interval\n",nconv0-eps->nconv);
     78:         }
     79:       }
     80:       break;
     81:     case EPS_CATEGORY_PRECOND:
     82:     case EPS_CATEGORY_CONTOUR:
     83:       /* eigenvalues already available as an output of the solver */
     84:       break;
     85:   }
     86:   return 0;
     87: }

     89: /*@
     90:    EPSSolve - Solves the eigensystem.

     92:    Collective on eps

     94:    Input Parameter:
     95: .  eps - eigensolver context obtained from EPSCreate()

     97:    Options Database Keys:
     98: +  -eps_view - print information about the solver used
     99: .  -eps_view_mat0 - view the first matrix (A)
    100: .  -eps_view_mat1 - view the second matrix (B)
    101: .  -eps_view_vectors - view the computed eigenvectors
    102: .  -eps_view_values - view the computed eigenvalues
    103: .  -eps_converged_reason - print reason for convergence, and number of iterations
    104: .  -eps_error_absolute - print absolute errors of each eigenpair
    105: .  -eps_error_relative - print relative errors of each eigenpair
    106: -  -eps_error_backward - print backward errors of each eigenpair

    108:    Notes:
    109:    All the command-line options listed above admit an optional argument specifying
    110:    the viewer type and options. For instance, use '-eps_view_mat0 binary:amatrix.bin'
    111:    to save the A matrix to a binary file, '-eps_view_values draw' to draw the computed
    112:    eigenvalues graphically, or '-eps_error_relative :myerr.m:ascii_matlab' to save
    113:    the errors in a file that can be executed in Matlab.

    115:    Level: beginner

    117: .seealso: EPSCreate(), EPSSetUp(), EPSDestroy(), EPSSetTolerances()
    118: @*/
    119: PetscErrorCode EPSSolve(EPS eps)
    120: {
    121:   PetscInt       i;
    122:   STMatMode      matmode;
    123:   Mat            A,B;

    126:   if (eps->state>=EPS_STATE_SOLVED) return 0;
    127:   PetscLogEventBegin(EPS_Solve,eps,0,0,0);

    129:   /* Call setup */
    130:   EPSSetUp(eps);
    131:   eps->nconv = 0;
    132:   eps->its   = 0;
    133:   for (i=0;i<eps->ncv;i++) {
    134:     eps->eigr[i]   = 0.0;
    135:     eps->eigi[i]   = 0.0;
    136:     eps->errest[i] = 0.0;
    137:     eps->perm[i]   = i;
    138:   }
    139:   EPSViewFromOptions(eps,NULL,"-eps_view_pre");
    140:   RGViewFromOptions(eps->rg,NULL,"-rg_view");

    142:   /* Call solver */
    143:   PetscUseTypeMethod(eps,solve);
    145:   eps->state = EPS_STATE_SOLVED;

    147:   /* Only the first nconv columns contain useful information (except in CISS) */
    148:   BVSetActiveColumns(eps->V,0,eps->nconv);
    149:   if (eps->twosided) BVSetActiveColumns(eps->W,0,eps->nconv);

    151:   /* If inplace, purify eigenvectors before reverting operator */
    152:   STGetMatMode(eps->st,&matmode);
    153:   if (matmode == ST_MATMODE_INPLACE && eps->ispositive) EPSComputeVectors(eps);
    154:   STPostSolve(eps->st);

    156:   /* Map eigenvalues back to the original problem if appropriate */
    157:   EPSComputeValues(eps);

    159: #if !defined(PETSC_USE_COMPLEX)
    160:   /* Reorder conjugate eigenvalues (positive imaginary first) */
    161:   for (i=0;i<eps->nconv-1;i++) {
    162:     if (eps->eigi[i] != 0) {
    163:       if (eps->eigi[i] < 0) {
    164:         eps->eigi[i] = -eps->eigi[i];
    165:         eps->eigi[i+1] = -eps->eigi[i+1];
    166:         /* the next correction only works with eigenvectors */
    167:         EPSComputeVectors(eps);
    168:         BVScaleColumn(eps->V,i+1,-1.0);
    169:       }
    170:       i++;
    171:     }
    172:   }
    173: #endif

    175:   /* Sort eigenvalues according to eps->which parameter */
    176:   SlepcSortEigenvalues(eps->sc,eps->nconv,eps->eigr,eps->eigi,eps->perm);
    177:   PetscLogEventEnd(EPS_Solve,eps,0,0,0);

    179:   /* Various viewers */
    180:   EPSViewFromOptions(eps,NULL,"-eps_view");
    181:   EPSConvergedReasonViewFromOptions(eps);
    182:   EPSErrorViewFromOptions(eps);
    183:   EPSValuesViewFromOptions(eps);
    184:   EPSVectorsViewFromOptions(eps);
    185:   EPSGetOperators(eps,&A,&B);
    186:   MatViewFromOptions(A,(PetscObject)eps,"-eps_view_mat0");
    187:   if (eps->isgeneralized) MatViewFromOptions(B,(PetscObject)eps,"-eps_view_mat1");

    189:   /* Remove deflation and initial subspaces */
    190:   if (eps->nds) {
    191:     BVSetNumConstraints(eps->V,0);
    192:     eps->nds = 0;
    193:   }
    194:   eps->nini = 0;
    195:   return 0;
    196: }

    198: /*@
    199:    EPSGetIterationNumber - Gets the current iteration number. If the
    200:    call to EPSSolve() is complete, then it returns the number of iterations
    201:    carried out by the solution method.

    203:    Not Collective

    205:    Input Parameter:
    206: .  eps - the eigensolver context

    208:    Output Parameter:
    209: .  its - number of iterations

    211:    Note:
    212:    During the i-th iteration this call returns i-1. If EPSSolve() is
    213:    complete, then parameter "its" contains either the iteration number at
    214:    which convergence was successfully reached, or failure was detected.
    215:    Call EPSGetConvergedReason() to determine if the solver converged or
    216:    failed and why.

    218:    Level: intermediate

    220: .seealso: EPSGetConvergedReason(), EPSSetTolerances()
    221: @*/
    222: PetscErrorCode EPSGetIterationNumber(EPS eps,PetscInt *its)
    223: {
    226:   *its = eps->its;
    227:   return 0;
    228: }

    230: /*@
    231:    EPSGetConverged - Gets the number of converged eigenpairs.

    233:    Not Collective

    235:    Input Parameter:
    236: .  eps - the eigensolver context

    238:    Output Parameter:
    239: .  nconv - number of converged eigenpairs

    241:    Note:
    242:    This function should be called after EPSSolve() has finished.

    244:    Level: beginner

    246: .seealso: EPSSetDimensions(), EPSSolve(), EPSGetEigenpair()
    247: @*/
    248: PetscErrorCode EPSGetConverged(EPS eps,PetscInt *nconv)
    249: {
    252:   EPSCheckSolved(eps,1);
    253:   *nconv = eps->nconv;
    254:   return 0;
    255: }

    257: /*@
    258:    EPSGetConvergedReason - Gets the reason why the EPSSolve() iteration was
    259:    stopped.

    261:    Not Collective

    263:    Input Parameter:
    264: .  eps - the eigensolver context

    266:    Output Parameter:
    267: .  reason - negative value indicates diverged, positive value converged

    269:    Options Database Key:
    270: .  -eps_converged_reason - print the reason to a viewer

    272:    Notes:
    273:    Possible values for reason are
    274: +  EPS_CONVERGED_TOL - converged up to tolerance
    275: .  EPS_CONVERGED_USER - converged due to a user-defined condition
    276: .  EPS_DIVERGED_ITS - required more than max_it iterations to reach convergence
    277: .  EPS_DIVERGED_BREAKDOWN - generic breakdown in method
    278: -  EPS_DIVERGED_SYMMETRY_LOST - pseudo-Lanczos was not able to keep symmetry

    280:    Can only be called after the call to EPSSolve() is complete.

    282:    Level: intermediate

    284: .seealso: EPSSetTolerances(), EPSSolve(), EPSConvergedReason
    285: @*/
    286: PetscErrorCode EPSGetConvergedReason(EPS eps,EPSConvergedReason *reason)
    287: {
    290:   EPSCheckSolved(eps,1);
    291:   *reason = eps->reason;
    292:   return 0;
    293: }

    295: /*@
    296:    EPSGetInvariantSubspace - Gets an orthonormal basis of the computed invariant
    297:    subspace.

    299:    Not Collective, but vectors are shared by all processors that share the EPS

    301:    Input Parameter:
    302: .  eps - the eigensolver context

    304:    Output Parameter:
    305: .  v - an array of vectors

    307:    Notes:
    308:    This function should be called after EPSSolve() has finished.

    310:    The user should provide in v an array of nconv vectors, where nconv is
    311:    the value returned by EPSGetConverged().

    313:    The first k vectors returned in v span an invariant subspace associated
    314:    with the first k computed eigenvalues (note that this is not true if the
    315:    k-th eigenvalue is complex and matrix A is real; in this case the first
    316:    k+1 vectors should be used). An invariant subspace X of A satisfies Ax
    317:    in X for all x in X (a similar definition applies for generalized
    318:    eigenproblems).

    320:    Level: intermediate

    322: .seealso: EPSGetEigenpair(), EPSGetConverged(), EPSSolve()
    323: @*/
    324: PetscErrorCode EPSGetInvariantSubspace(EPS eps,Vec v[])
    325: {
    326:   PetscInt       i;
    327:   BV             V=eps->V;
    328:   Vec            w;

    333:   EPSCheckSolved(eps,1);
    335:   if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
    336:     BVDuplicateResize(eps->V,eps->nconv,&V);
    337:     BVSetActiveColumns(eps->V,0,eps->nconv);
    338:     BVCopy(eps->V,V);
    339:     for (i=0;i<eps->nconv;i++) {
    340:       BVGetColumn(V,i,&w);
    341:       VecPointwiseDivide(w,w,eps->D);
    342:       BVRestoreColumn(V,i,&w);
    343:     }
    344:     BVOrthogonalize(V,NULL);
    345:   }
    346:   for (i=0;i<eps->nconv;i++) BVCopyVec(V,i,v[i]);
    347:   if (eps->balance!=EPS_BALANCE_NONE && eps->D) BVDestroy(&V);
    348:   return 0;
    349: }

    351: /*@C
    352:    EPSGetEigenpair - Gets the i-th solution of the eigenproblem as computed by
    353:    EPSSolve(). The solution consists in both the eigenvalue and the eigenvector.

    355:    Logically Collective on eps

    357:    Input Parameters:
    358: +  eps - eigensolver context
    359: -  i   - index of the solution

    361:    Output Parameters:
    362: +  eigr - real part of eigenvalue
    363: .  eigi - imaginary part of eigenvalue
    364: .  Vr   - real part of eigenvector
    365: -  Vi   - imaginary part of eigenvector

    367:    Notes:
    368:    It is allowed to pass NULL for Vr and Vi, if the eigenvector is not
    369:    required. Otherwise, the caller must provide valid Vec objects, i.e.,
    370:    they must be created by the calling program with e.g. MatCreateVecs().

    372:    If the eigenvalue is real, then eigi and Vi are set to zero. If PETSc is
    373:    configured with complex scalars the eigenvalue is stored
    374:    directly in eigr (eigi is set to zero) and the eigenvector in Vr (Vi is
    375:    set to zero). In both cases, the user can pass NULL in eigi and Vi.

    377:    The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
    378:    Eigenpairs are indexed according to the ordering criterion established
    379:    with EPSSetWhichEigenpairs().

    381:    The 2-norm of the eigenvector is one unless the problem is generalized
    382:    Hermitian. In this case the eigenvector is normalized with respect to the
    383:    norm defined by the B matrix.

    385:    Level: beginner

    387: .seealso: EPSGetEigenvalue(), EPSGetEigenvector(), EPSGetLeftEigenvector(), EPSSolve(),
    388:           EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetInvariantSubspace()
    389: @*/
    390: PetscErrorCode EPSGetEigenpair(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)
    391: {
    394:   EPSCheckSolved(eps,1);
    397:   EPSGetEigenvalue(eps,i,eigr,eigi);
    398:   if (Vr || Vi) EPSGetEigenvector(eps,i,Vr,Vi);
    399:   return 0;
    400: }

    402: /*@C
    403:    EPSGetEigenvalue - Gets the i-th eigenvalue as computed by EPSSolve().

    405:    Not Collective

    407:    Input Parameters:
    408: +  eps - eigensolver context
    409: -  i   - index of the solution

    411:    Output Parameters:
    412: +  eigr - real part of eigenvalue
    413: -  eigi - imaginary part of eigenvalue

    415:    Notes:
    416:    If the eigenvalue is real, then eigi is set to zero. If PETSc is
    417:    configured with complex scalars the eigenvalue is stored
    418:    directly in eigr (eigi is set to zero).

    420:    The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
    421:    Eigenpairs are indexed according to the ordering criterion established
    422:    with EPSSetWhichEigenpairs().

    424:    Level: beginner

    426: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetEigenpair()
    427: @*/
    428: PetscErrorCode EPSGetEigenvalue(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi)
    429: {
    430:   PetscInt k;

    433:   EPSCheckSolved(eps,1);
    436:   k = eps->perm[i];
    437: #if defined(PETSC_USE_COMPLEX)
    438:   if (eigr) *eigr = eps->eigr[k];
    439:   if (eigi) *eigi = 0;
    440: #else
    441:   if (eigr) *eigr = eps->eigr[k];
    442:   if (eigi) *eigi = eps->eigi[k];
    443: #endif
    444:   return 0;
    445: }

    447: /*@
    448:    EPSGetEigenvector - Gets the i-th right eigenvector as computed by EPSSolve().

    450:    Logically Collective on eps

    452:    Input Parameters:
    453: +  eps - eigensolver context
    454: -  i   - index of the solution

    456:    Output Parameters:
    457: +  Vr   - real part of eigenvector
    458: -  Vi   - imaginary part of eigenvector

    460:    Notes:
    461:    The caller must provide valid Vec objects, i.e., they must be created
    462:    by the calling program with e.g. MatCreateVecs().

    464:    If the corresponding eigenvalue is real, then Vi is set to zero. If PETSc is
    465:    configured with complex scalars the eigenvector is stored
    466:    directly in Vr (Vi is set to zero). In any case, the user can pass NULL in Vr
    467:    or Vi if one of them is not required.

    469:    The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
    470:    Eigenpairs are indexed according to the ordering criterion established
    471:    with EPSSetWhichEigenpairs().

    473:    The 2-norm of the eigenvector is one unless the problem is generalized
    474:    Hermitian. In this case the eigenvector is normalized with respect to the
    475:    norm defined by the B matrix.

    477:    Level: beginner

    479: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetEigenpair(), EPSGetLeftEigenvector()
    480: @*/
    481: PetscErrorCode EPSGetEigenvector(EPS eps,PetscInt i,Vec Vr,Vec Vi)
    482: {
    483:   PetscInt       k;

    489:   EPSCheckSolved(eps,1);
    492:   EPSComputeVectors(eps);
    493:   k = eps->perm[i];
    494:   BV_GetEigenvector(eps->V,k,eps->eigi[k],Vr,Vi);
    495:   return 0;
    496: }

    498: /*@
    499:    EPSGetLeftEigenvector - Gets the i-th left eigenvector as computed by EPSSolve().

    501:    Logically Collective on eps

    503:    Input Parameters:
    504: +  eps - eigensolver context
    505: -  i   - index of the solution

    507:    Output Parameters:
    508: +  Wr   - real part of left eigenvector
    509: -  Wi   - imaginary part of left eigenvector

    511:    Notes:
    512:    The caller must provide valid Vec objects, i.e., they must be created
    513:    by the calling program with e.g. MatCreateVecs().

    515:    If the corresponding eigenvalue is real, then Wi is set to zero. If PETSc is
    516:    configured with complex scalars the eigenvector is stored directly in Wr
    517:    (Wi is set to zero). In any case, the user can pass NULL in Wr or Wi if
    518:    one of them is not required.

    520:    The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
    521:    Eigensolutions are indexed according to the ordering criterion established
    522:    with EPSSetWhichEigenpairs().

    524:    Left eigenvectors are available only if the twosided flag was set, see
    525:    EPSSetTwoSided().

    527:    Level: intermediate

    529: .seealso: EPSGetEigenvector(), EPSGetConverged(), EPSSetWhichEigenpairs(), EPSSetTwoSided()
    530: @*/
    531: PetscErrorCode EPSGetLeftEigenvector(EPS eps,PetscInt i,Vec Wr,Vec Wi)
    532: {
    533:   PetscInt       k;

    539:   EPSCheckSolved(eps,1);
    543:   EPSComputeVectors(eps);
    544:   k = eps->perm[i];
    545:   BV_GetEigenvector(eps->W,k,eps->eigi[k],Wr,Wi);
    546:   return 0;
    547: }

    549: /*@
    550:    EPSGetErrorEstimate - Returns the error estimate associated to the i-th
    551:    computed eigenpair.

    553:    Not Collective

    555:    Input Parameters:
    556: +  eps - eigensolver context
    557: -  i   - index of eigenpair

    559:    Output Parameter:
    560: .  errest - the error estimate

    562:    Notes:
    563:    This is the error estimate used internally by the eigensolver. The actual
    564:    error bound can be computed with EPSComputeError(). See also the users
    565:    manual for details.

    567:    Level: advanced

    569: .seealso: EPSComputeError()
    570: @*/
    571: PetscErrorCode EPSGetErrorEstimate(EPS eps,PetscInt i,PetscReal *errest)
    572: {
    575:   EPSCheckSolved(eps,1);
    578:   *errest = eps->errest[eps->perm[i]];
    579:   return 0;
    580: }

    582: /*
    583:    EPSComputeResidualNorm_Private - Computes the norm of the residual vector
    584:    associated with an eigenpair.

    586:    Input Parameters:
    587:      trans - whether A' must be used instead of A
    588:      kr,ki - eigenvalue
    589:      xr,xi - eigenvector
    590:      z     - three work vectors (the second one not referenced in complex scalars)
    591: */
    592: PetscErrorCode EPSComputeResidualNorm_Private(EPS eps,PetscBool trans,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,Vec *z,PetscReal *norm)
    593: {
    594:   PetscInt       nmat;
    595:   Mat            A,B;
    596:   Vec            u,w;
    597:   PetscScalar    alpha;
    598: #if !defined(PETSC_USE_COMPLEX)
    599:   Vec            v;
    600:   PetscReal      ni,nr;
    601: #endif
    602:   PetscErrorCode (*matmult)(Mat,Vec,Vec) = trans? MatMultHermitianTranspose: MatMult;

    604:   u = z[0]; w = z[2];
    605:   STGetNumMatrices(eps->st,&nmat);
    606:   STGetMatrix(eps->st,0,&A);
    607:   if (nmat>1) STGetMatrix(eps->st,1,&B);

    609: #if !defined(PETSC_USE_COMPLEX)
    610:   v = z[1];
    611:   if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
    612: #endif
    613:     (*matmult)(A,xr,u);                          /* u=A*x */
    614:     if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
    615:       if (nmat>1) (*matmult)(B,xr,w);
    616:       else VecCopy(xr,w);                        /* w=B*x */
    617:       alpha = trans? -PetscConj(kr): -kr;
    618:       VecAXPY(u,alpha,w);                        /* u=A*x-k*B*x */
    619:     }
    620:     VecNorm(u,NORM_2,norm);
    621: #if !defined(PETSC_USE_COMPLEX)
    622:   } else {
    623:     (*matmult)(A,xr,u);                          /* u=A*xr */
    624:     if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
    625:       if (nmat>1) (*matmult)(B,xr,v);
    626:       else VecCopy(xr,v);                        /* v=B*xr */
    627:       VecAXPY(u,-kr,v);                          /* u=A*xr-kr*B*xr */
    628:       if (nmat>1) (*matmult)(B,xi,w);
    629:       else VecCopy(xi,w);                        /* w=B*xi */
    630:       VecAXPY(u,trans?-ki:ki,w);                 /* u=A*xr-kr*B*xr+ki*B*xi */
    631:     }
    632:     VecNorm(u,NORM_2,&nr);
    633:     (*matmult)(A,xi,u);                          /* u=A*xi */
    634:     if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
    635:       VecAXPY(u,-kr,w);                          /* u=A*xi-kr*B*xi */
    636:       VecAXPY(u,trans?ki:-ki,v);                 /* u=A*xi-kr*B*xi-ki*B*xr */
    637:     }
    638:     VecNorm(u,NORM_2,&ni);
    639:     *norm = SlepcAbsEigenvalue(nr,ni);
    640:   }
    641: #endif
    642:   return 0;
    643: }

    645: /*@
    646:    EPSComputeError - Computes the error (based on the residual norm) associated
    647:    with the i-th computed eigenpair.

    649:    Collective on eps

    651:    Input Parameters:
    652: +  eps  - the eigensolver context
    653: .  i    - the solution index
    654: -  type - the type of error to compute

    656:    Output Parameter:
    657: .  error - the error

    659:    Notes:
    660:    The error can be computed in various ways, all of them based on the residual
    661:    norm ||Ax-kBx||_2 where k is the eigenvalue and x is the eigenvector.

    663:    Level: beginner

    665: .seealso: EPSErrorType, EPSSolve(), EPSGetErrorEstimate()
    666: @*/
    667: PetscErrorCode EPSComputeError(EPS eps,PetscInt i,EPSErrorType type,PetscReal *error)
    668: {
    669:   Mat            A,B;
    670:   Vec            xr,xi,w[3];
    671:   PetscReal      t,vecnorm=1.0,errorl;
    672:   PetscScalar    kr,ki;
    673:   PetscBool      flg;

    679:   EPSCheckSolved(eps,1);

    681:   /* allocate work vectors */
    682: #if defined(PETSC_USE_COMPLEX)
    683:   EPSSetWorkVecs(eps,3);
    684:   xi   = NULL;
    685:   w[1] = NULL;
    686: #else
    687:   EPSSetWorkVecs(eps,5);
    688:   xi   = eps->work[3];
    689:   w[1] = eps->work[4];
    690: #endif
    691:   xr   = eps->work[0];
    692:   w[0] = eps->work[1];
    693:   w[2] = eps->work[2];

    695:   /* compute residual norm */
    696:   EPSGetEigenpair(eps,i,&kr,&ki,xr,xi);
    697:   EPSComputeResidualNorm_Private(eps,PETSC_FALSE,kr,ki,xr,xi,w,error);

    699:   /* compute 2-norm of eigenvector */
    700:   if (eps->problem_type==EPS_GHEP) VecNorm(xr,NORM_2,&vecnorm);

    702:   /* if two-sided, compute left residual norm and take the maximum */
    703:   if (eps->twosided) {
    704:     EPSGetLeftEigenvector(eps,i,xr,xi);
    705:     EPSComputeResidualNorm_Private(eps,PETSC_TRUE,kr,ki,xr,xi,w,&errorl);
    706:     *error = PetscMax(*error,errorl);
    707:   }

    709:   /* compute error */
    710:   switch (type) {
    711:     case EPS_ERROR_ABSOLUTE:
    712:       break;
    713:     case EPS_ERROR_RELATIVE:
    714:       *error /= SlepcAbsEigenvalue(kr,ki)*vecnorm;
    715:       break;
    716:     case EPS_ERROR_BACKWARD:
    717:       /* initialization of matrix norms */
    718:       if (!eps->nrma) {
    719:         STGetMatrix(eps->st,0,&A);
    720:         MatHasOperation(A,MATOP_NORM,&flg);
    722:         MatNorm(A,NORM_INFINITY,&eps->nrma);
    723:       }
    724:       if (eps->isgeneralized) {
    725:         if (!eps->nrmb) {
    726:           STGetMatrix(eps->st,1,&B);
    727:           MatHasOperation(B,MATOP_NORM,&flg);
    729:           MatNorm(B,NORM_INFINITY,&eps->nrmb);
    730:         }
    731:       } else eps->nrmb = 1.0;
    732:       t = SlepcAbsEigenvalue(kr,ki);
    733:       *error /= (eps->nrma+t*eps->nrmb)*vecnorm;
    734:       break;
    735:     default:
    736:       SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Invalid error type");
    737:   }
    738:   return 0;
    739: }

    741: /*
    742:    EPSGetStartVector - Generate a suitable vector to be used as the starting vector
    743:    for the recurrence that builds the right subspace.

    745:    Collective on eps

    747:    Input Parameters:
    748: +  eps - the eigensolver context
    749: -  i   - iteration number

    751:    Output Parameters:
    752: .  breakdown - flag indicating that a breakdown has occurred

    754:    Notes:
    755:    The start vector is computed from another vector: for the first step (i=0),
    756:    the first initial vector is used (see EPSSetInitialSpace()); otherwise a random
    757:    vector is created. Then this vector is forced to be in the range of OP (only
    758:    for generalized definite problems) and orthonormalized with respect to all
    759:    V-vectors up to i-1. The resulting vector is placed in V[i].

    761:    The flag breakdown is set to true if either i=0 and the vector belongs to the
    762:    deflation space, or i>0 and the vector is linearly dependent with respect
    763:    to the V-vectors.
    764: */
    765: PetscErrorCode EPSGetStartVector(EPS eps,PetscInt i,PetscBool *breakdown)
    766: {
    767:   PetscReal      norm;
    768:   PetscBool      lindep;
    769:   Vec            w,z;

    774:   /* For the first step, use the first initial vector, otherwise a random one */
    775:   if (i>0 || eps->nini==0) BVSetRandomColumn(eps->V,i);

    777:   /* Force the vector to be in the range of OP for definite generalized problems */
    778:   if (eps->ispositive || (eps->isgeneralized && eps->ishermitian)) {
    779:     BVCreateVec(eps->V,&w);
    780:     BVCopyVec(eps->V,i,w);
    781:     BVGetColumn(eps->V,i,&z);
    782:     STApply(eps->st,w,z);
    783:     BVRestoreColumn(eps->V,i,&z);
    784:     VecDestroy(&w);
    785:   }

    787:   /* Orthonormalize the vector with respect to previous vectors */
    788:   BVOrthogonalizeColumn(eps->V,i,NULL,&norm,&lindep);
    789:   if (breakdown) *breakdown = lindep;
    790:   else if (lindep || norm == 0.0) {
    793:   }
    794:   BVScaleColumn(eps->V,i,1.0/norm);
    795:   return 0;
    796: }

    798: /*
    799:    EPSGetLeftStartVector - Generate a suitable vector to be used as the left starting
    800:    vector for the recurrence that builds the left subspace. See EPSGetStartVector().
    801: */
    802: PetscErrorCode EPSGetLeftStartVector(EPS eps,PetscInt i,PetscBool *breakdown)
    803: {
    804:   PetscReal      norm;
    805:   PetscBool      lindep;

    810:   /* For the first step, use the first initial vector, otherwise a random one */
    811:   if (i>0 || eps->ninil==0) BVSetRandomColumn(eps->W,i);

    813:   /* Orthonormalize the vector with respect to previous vectors */
    814:   BVOrthogonalizeColumn(eps->W,i,NULL,&norm,&lindep);
    815:   if (breakdown) *breakdown = lindep;
    816:   else if (lindep || norm == 0.0) {
    818:     SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_CONV_FAILED,"Unable to generate more left start vectors");
    819:   }
    820:   BVScaleColumn(eps->W,i,1.0/norm);
    821:   return 0;
    822: }