Date: 2021-02-01T14:41:55+00:00

Actual source code: epssolve.c
slepc-3.14.2 2021-02-01
Report Typos and Errors

      1: /*
      2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      4:    Copyright (c) 2002-2020, 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: {

     23:   EPSCheckSolved(eps,1);
     24:   if (eps->state==EPS_STATE_SOLVED && eps->ops->computevectors) {
     25:     (*eps->ops->computevectors)(eps);
     26:   }
     27:   eps->state = EPS_STATE_EIGENVECTORS;
     28:   return(0);
     29: }

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

     33: static PetscErrorCode EPSComputeValues(EPS eps)
     34: {
     36:   PetscBool      injective,iscomp,isfilter;
     37:   PetscInt       i,n,aux,nconv0;
     38:   Mat            A,B=NULL,G,Z;

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

    100: /*@
    101:    EPSSolve - Solves the eigensystem.

    103:    Collective on eps

    105:    Input Parameter:
    106: .  eps - eigensolver context obtained from EPSCreate()

    108:    Options Database Keys:
    109: +  -eps_view - print information about the solver used
    110: .  -eps_view_mat0 binary - save the first matrix (A) to the default binary viewer
    111: .  -eps_view_mat1 binary - save the second matrix (B) to the default binary viewer
    112: .  -eps_view_vectors binary - save the computed eigenvectors to the default binary viewer
    113: .  -eps_view_values - print computed eigenvalues
    114: .  -eps_converged_reason - print reason for convergence, and number of iterations
    115: .  -eps_error_absolute - print absolute errors of each eigenpair
    116: .  -eps_error_relative - print relative errors of each eigenpair
    117: -  -eps_error_backward - print backward errors of each eigenpair

    119:    Level: beginner

    121: .seealso: EPSCreate(), EPSSetUp(), EPSDestroy(), EPSSetTolerances()
    122: @*/
    123: PetscErrorCode EPSSolve(EPS eps)
    124: {
    126:   PetscInt       i;
    127:   STMatMode      matmode;
    128:   Mat            A,B;

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

    135:   /* Call setup */
    136:   EPSSetUp(eps);
    137:   eps->nconv = 0;
    138:   eps->its   = 0;
    139:   for (i=0;i<eps->ncv;i++) {
    140:     eps->eigr[i]   = 0.0;
    141:     eps->eigi[i]   = 0.0;
    142:     eps->errest[i] = 0.0;
    143:     eps->perm[i]   = i;
    144:   }
    145:   EPSViewFromOptions(eps,NULL,"-eps_view_pre");
    146:   RGViewFromOptions(eps->rg,NULL,"-rg_view");

    148:   /* Call solver */
    149:   (*eps->ops->solve)(eps);
    150:   if (!eps->reason) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Internal error, solver returned without setting converged reason");
    151:   eps->state = EPS_STATE_SOLVED;

    153:   /* Only the first nconv columns contain useful information (except in CISS) */
    154:   BVSetActiveColumns(eps->V,0,eps->nconv);
    155:   if (eps->twosided) { BVSetActiveColumns(eps->W,0,eps->nconv); }

    157:   /* If inplace, purify eigenvectors before reverting operator */
    158:   STGetMatMode(eps->st,&matmode);
    159:   if (matmode == ST_MATMODE_INPLACE && eps->ispositive) {
    160:     EPSComputeVectors(eps);
    161:   }
    162:   STPostSolve(eps->st);

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

    167: #if !defined(PETSC_USE_COMPLEX)
    168:   /* Reorder conjugate eigenvalues (positive imaginary first) */
    169:   for (i=0;i<eps->nconv-1;i++) {
    170:     if (eps->eigi[i] != 0) {
    171:       if (eps->eigi[i] < 0) {
    172:         eps->eigi[i] = -eps->eigi[i];
    173:         eps->eigi[i+1] = -eps->eigi[i+1];
    174:         /* the next correction only works with eigenvectors */
    175:         EPSComputeVectors(eps);
    176:         BVScaleColumn(eps->V,i+1,-1.0);
    177:       }
    178:       i++;
    179:     }
    180:   }
    181: #endif

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

    187:   /* Various viewers */
    188:   EPSViewFromOptions(eps,NULL,"-eps_view");
    189:   EPSConvergedReasonViewFromOptions(eps);
    190:   EPSErrorViewFromOptions(eps);
    191:   EPSValuesViewFromOptions(eps);
    192:   EPSVectorsViewFromOptions(eps);
    193:   EPSGetOperators(eps,&A,&B);
    194:   MatViewFromOptions(A,(PetscObject)eps,"-eps_view_mat0");
    195:   if (eps->isgeneralized) {
    196:     MatViewFromOptions(B,(PetscObject)eps,"-eps_view_mat1");
    197:   }

    199:   /* Remove deflation and initial subspaces */
    200:   if (eps->nds) {
    201:     BVSetNumConstraints(eps->V,0);
    202:     eps->nds = 0;
    203:   }
    204:   eps->nini = 0;
    205:   return(0);
    206: }

    208: /*@
    209:    EPSGetIterationNumber - Gets the current iteration number. If the
    210:    call to EPSSolve() is complete, then it returns the number of iterations
    211:    carried out by the solution method.

    213:    Not Collective

    215:    Input Parameter:
    216: .  eps - the eigensolver context

    218:    Output Parameter:
    219: .  its - number of iterations

    221:    Note:
    222:    During the i-th iteration this call returns i-1. If EPSSolve() is
    223:    complete, then parameter "its" contains either the iteration number at
    224:    which convergence was successfully reached, or failure was detected.
    225:    Call EPSGetConvergedReason() to determine if the solver converged or
    226:    failed and why.

    228:    Level: intermediate

    230: .seealso: EPSGetConvergedReason(), EPSSetTolerances()
    231: @*/
    232: PetscErrorCode EPSGetIterationNumber(EPS eps,PetscInt *its)
    233: {
    237:   *its = eps->its;
    238:   return(0);
    239: }

    241: /*@
    242:    EPSGetConverged - Gets the number of converged eigenpairs.

    244:    Not Collective

    246:    Input Parameter:
    247: .  eps - the eigensolver context

    249:    Output Parameter:
    250: .  nconv - number of converged eigenpairs

    252:    Note:
    253:    This function should be called after EPSSolve() has finished.

    255:    Level: beginner

    257: .seealso: EPSSetDimensions(), EPSSolve()
    258: @*/
    259: PetscErrorCode EPSGetConverged(EPS eps,PetscInt *nconv)
    260: {
    264:   EPSCheckSolved(eps,1);
    265:   *nconv = eps->nconv;
    266:   return(0);
    267: }

    269: /*@
    270:    EPSGetConvergedReason - Gets the reason why the EPSSolve() iteration was
    271:    stopped.

    273:    Not Collective

    275:    Input Parameter:
    276: .  eps - the eigensolver context

    278:    Output Parameter:
    279: .  reason - negative value indicates diverged, positive value converged

    281:    Notes:
    282:    Possible values for reason are
    283: +  EPS_CONVERGED_TOL - converged up to tolerance
    284: .  EPS_CONVERGED_USER - converged due to a user-defined condition
    285: .  EPS_DIVERGED_ITS - required more than max_it iterations to reach convergence
    286: .  EPS_DIVERGED_BREAKDOWN - generic breakdown in method
    287: -  EPS_DIVERGED_SYMMETRY_LOST - pseudo-Lanczos was not able to keep symmetry

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

    291:    Level: intermediate

    293: .seealso: EPSSetTolerances(), EPSSolve(), EPSConvergedReason
    294: @*/
    295: PetscErrorCode EPSGetConvergedReason(EPS eps,EPSConvergedReason *reason)
    296: {
    300:   EPSCheckSolved(eps,1);
    301:   *reason = eps->reason;
    302:   return(0);
    303: }

    305: /*@
    306:    EPSGetInvariantSubspace - Gets an orthonormal basis of the computed invariant
    307:    subspace.

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

    311:    Input Parameter:
    312: .  eps - the eigensolver context

    314:    Output Parameter:
    315: .  v - an array of vectors

    317:    Notes:
    318:    This function should be called after EPSSolve() has finished.

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

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

    330:    Level: intermediate

    332: .seealso: EPSGetEigenpair(), EPSGetConverged(), EPSSolve()
    333: @*/
    334: PetscErrorCode EPSGetInvariantSubspace(EPS eps,Vec v[])
    335: {
    337:   PetscInt       i;
    338:   BV             V=eps->V;
    339:   Vec            w;

    345:   EPSCheckSolved(eps,1);
    346:   if (!eps->ishermitian && eps->state==EPS_STATE_EIGENVECTORS) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSGetInvariantSubspace must be called before EPSGetEigenpair,EPSGetEigenvector or EPSComputeError");
    347:   if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
    348:     BVDuplicateResize(eps->V,eps->nconv,&V);
    349:     BVSetActiveColumns(eps->V,0,eps->nconv);
    350:     BVCopy(eps->V,V);
    351:     for (i=0;i<eps->nconv;i++) {
    352:       BVGetColumn(V,i,&w);
    353:       VecPointwiseDivide(w,w,eps->D);
    354:       BVRestoreColumn(V,i,&w);
    355:     }
    356:     BVOrthogonalize(V,NULL);
    357:   }
    358:   for (i=0;i<eps->nconv;i++) {
    359:     BVCopyVec(V,i,v[i]);
    360:   }
    361:   if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
    362:     BVDestroy(&V);
    363:   }
    364:   return(0);
    365: }

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

    371:    Logically Collective on eps

    373:    Input Parameters:
    374: +  eps - eigensolver context
    375: -  i   - index of the solution

    377:    Output Parameters:
    378: +  eigr - real part of eigenvalue
    379: .  eigi - imaginary part of eigenvalue
    380: .  Vr   - real part of eigenvector
    381: -  Vi   - imaginary part of eigenvector

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

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

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

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

    401:    Level: beginner

    403: .seealso: EPSGetEigenvalue(), EPSGetEigenvector(), EPSGetLeftEigenvector(), EPSSolve(),
    404:           EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetInvariantSubspace()
    405: @*/
    406: PetscErrorCode EPSGetEigenpair(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)
    407: {

    413:   EPSCheckSolved(eps,1);
    414:   if (i<0 || i>=eps->nconv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
    415:   EPSGetEigenvalue(eps,i,eigr,eigi);
    416:   if (Vr || Vi) { EPSGetEigenvector(eps,i,Vr,Vi); }
    417:   return(0);
    418: }

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

    423:    Not Collective

    425:    Input Parameters:
    426: +  eps - eigensolver context
    427: -  i   - index of the solution

    429:    Output Parameters:
    430: +  eigr - real part of eigenvalue
    431: -  eigi - imaginary part of eigenvalue

    433:    Notes:
    434:    If the eigenvalue is real, then eigi is set to zero. If PETSc is
    435:    configured with complex scalars the eigenvalue is stored
    436:    directly in eigr (eigi is set to zero).

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

    442:    Level: beginner

    444: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetEigenpair()
    445: @*/
    446: PetscErrorCode EPSGetEigenvalue(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi)
    447: {
    448:   PetscInt k;

    452:   EPSCheckSolved(eps,1);
    453:   if (i<0 || i>=eps->nconv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
    454:   k = eps->perm[i];
    455: #if defined(PETSC_USE_COMPLEX)
    456:   if (eigr) *eigr = eps->eigr[k];
    457:   if (eigi) *eigi = 0;
    458: #else
    459:   if (eigr) *eigr = eps->eigr[k];
    460:   if (eigi) *eigi = eps->eigi[k];
    461: #endif
    462:   return(0);
    463: }

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

    468:    Logically Collective on eps

    470:    Input Parameters:
    471: +  eps - eigensolver context
    472: -  i   - index of the solution

    474:    Output Parameters:
    475: +  Vr   - real part of eigenvector
    476: -  Vi   - imaginary part of eigenvector

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

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

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

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

    495:    Level: beginner

    497: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetEigenpair(), EPSGetLeftEigenvector()
    498: @*/
    499: PetscErrorCode EPSGetEigenvector(EPS eps,PetscInt i,Vec Vr,Vec Vi)
    500: {
    502:   PetscInt       k;

    509:   EPSCheckSolved(eps,1);
    510:   if (i<0 || i>=eps->nconv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
    511:   EPSComputeVectors(eps);
    512:   k = eps->perm[i];
    513:   BV_GetEigenvector(eps->V,k,eps->eigi[k],Vr,Vi);
    514:   return(0);
    515: }

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

    520:    Logically Collective on eps

    522:    Input Parameters:
    523: +  eps - eigensolver context
    524: -  i   - index of the solution

    526:    Output Parameters:
    527: +  Wr   - real part of left eigenvector
    528: -  Wi   - imaginary part of left eigenvector

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

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

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

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

    546:    Level: intermediate

    548: .seealso: EPSGetEigenvector(), EPSGetConverged(), EPSSetWhichEigenpairs(), EPSSetTwoSided()
    549: @*/
    550: PetscErrorCode EPSGetLeftEigenvector(EPS eps,PetscInt i,Vec Wr,Vec Wi)
    551: {
    553:   PetscInt       k;

    560:   EPSCheckSolved(eps,1);
    561:   if (!eps->twosided) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetTwoSided");
    562:   if (i<0 || i>=eps->nconv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
    563:   EPSComputeVectors(eps);
    564:   k = eps->perm[i];
    565:   BV_GetEigenvector(eps->W,k,eps->eigi[k],Wr,Wi);
    566:   return(0);
    567: }

    569: /*@
    570:    EPSGetErrorEstimate - Returns the error estimate associated to the i-th
    571:    computed eigenpair.

    573:    Not Collective

    575:    Input Parameter:
    576: +  eps - eigensolver context
    577: -  i   - index of eigenpair

    579:    Output Parameter:
    580: .  errest - the error estimate

    582:    Notes:
    583:    This is the error estimate used internally by the eigensolver. The actual
    584:    error bound can be computed with EPSComputeError(). See also the users
    585:    manual for details.

    587:    Level: advanced

    589: .seealso: EPSComputeError()
    590: @*/
    591: PetscErrorCode EPSGetErrorEstimate(EPS eps,PetscInt i,PetscReal *errest)
    592: {
    596:   EPSCheckSolved(eps,1);
    597:   if (i<0 || i>=eps->nconv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
    598:   *errest = eps->errest[eps->perm[i]];
    599:   return(0);
    600: }

    602: /*
    603:    EPSComputeResidualNorm_Private - Computes the norm of the residual vector
    604:    associated with an eigenpair.

    606:    Input Parameters:
    607:      trans - whether A' must be used instead of A
    608:      kr,ki - eigenvalue
    609:      xr,xi - eigenvector
    610:      z     - three work vectors (the second one not referenced in complex scalars)
    611: */
    612: PetscErrorCode EPSComputeResidualNorm_Private(EPS eps,PetscBool trans,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,Vec *z,PetscReal *norm)
    613: {
    615:   PetscInt       nmat;
    616:   Mat            A,B;
    617:   Vec            u,w;
    618:   PetscScalar    alpha;
    619: #if !defined(PETSC_USE_COMPLEX)
    620:   Vec            v;
    621:   PetscReal      ni,nr;
    622: #endif
    623:   PetscErrorCode (*matmult)(Mat,Vec,Vec) = trans? MatMultHermitianTranspose: MatMult;

    626:   u = z[0]; w = z[2];
    627:   STGetNumMatrices(eps->st,&nmat);
    628:   STGetMatrix(eps->st,0,&A);
    629:   if (nmat>1) { STGetMatrix(eps->st,1,&B); }

    631: #if !defined(PETSC_USE_COMPLEX)
    632:   v = z[1];
    633:   if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
    634: #endif
    635:     (*matmult)(A,xr,u);                          /* u=A*x */
    636:     if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
    637:       if (nmat>1) { (*matmult)(B,xr,w); }
    638:       else { VecCopy(xr,w); }                    /* w=B*x */
    639:       alpha = trans? -PetscConj(kr): -kr;
    640:       VecAXPY(u,alpha,w);                        /* u=A*x-k*B*x */
    641:     }
    642:     VecNorm(u,NORM_2,norm);
    643: #if !defined(PETSC_USE_COMPLEX)
    644:   } else {
    645:     (*matmult)(A,xr,u);                          /* u=A*xr */
    646:     if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
    647:       if (nmat>1) { (*matmult)(B,xr,v); }
    648:       else { VecCopy(xr,v); }                    /* v=B*xr */
    649:       VecAXPY(u,-kr,v);                          /* u=A*xr-kr*B*xr */
    650:       if (nmat>1) { (*matmult)(B,xi,w); }
    651:       else { VecCopy(xi,w); }                    /* w=B*xi */
    652:       VecAXPY(u,trans?-ki:ki,w);                 /* u=A*xr-kr*B*xr+ki*B*xi */
    653:     }
    654:     VecNorm(u,NORM_2,&nr);
    655:     (*matmult)(A,xi,u);                          /* u=A*xi */
    656:     if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
    657:       VecAXPY(u,-kr,w);                          /* u=A*xi-kr*B*xi */
    658:       VecAXPY(u,trans?ki:-ki,v);                 /* u=A*xi-kr*B*xi-ki*B*xr */
    659:     }
    660:     VecNorm(u,NORM_2,&ni);
    661:     *norm = SlepcAbsEigenvalue(nr,ni);
    662:   }
    663: #endif
    664:   return(0);
    665: }

    667: /*@
    668:    EPSComputeError - Computes the error (based on the residual norm) associated
    669:    with the i-th computed eigenpair.

    671:    Collective on eps

    673:    Input Parameter:
    674: +  eps  - the eigensolver context
    675: .  i    - the solution index
    676: -  type - the type of error to compute

    678:    Output Parameter:
    679: .  error - the error

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

    685:    Level: beginner

    687: .seealso: EPSErrorType, EPSSolve(), EPSGetErrorEstimate()
    688: @*/
    689: PetscErrorCode EPSComputeError(EPS eps,PetscInt i,EPSErrorType type,PetscReal *error)
    690: {
    692:   Mat            A,B;
    693:   Vec            xr,xi,w[3];
    694:   PetscReal      t,vecnorm=1.0,errorl;
    695:   PetscScalar    kr,ki;
    696:   PetscBool      flg;

    703:   EPSCheckSolved(eps,1);

    705:   /* allocate work vectors */
    706: #if defined(PETSC_USE_COMPLEX)
    707:   EPSSetWorkVecs(eps,3);
    708:   xi   = NULL;
    709:   w[1] = NULL;
    710: #else
    711:   EPSSetWorkVecs(eps,5);
    712:   xi   = eps->work[3];
    713:   w[1] = eps->work[4];
    714: #endif
    715:   xr   = eps->work[0];
    716:   w[0] = eps->work[1];
    717:   w[2] = eps->work[2];

    719:   /* compute residual norm */
    720:   EPSGetEigenpair(eps,i,&kr,&ki,xr,xi);
    721:   EPSComputeResidualNorm_Private(eps,PETSC_FALSE,kr,ki,xr,xi,w,error);

    723:   /* compute 2-norm of eigenvector */
    724:   if (eps->problem_type==EPS_GHEP) {
    725:     VecNorm(xr,NORM_2,&vecnorm);
    726:   }

    728:   /* if two-sided, compute left residual norm and take the maximum */
    729:   if (eps->twosided) {
    730:     EPSGetLeftEigenvector(eps,i,xr,xi);
    731:     EPSComputeResidualNorm_Private(eps,PETSC_TRUE,kr,ki,xr,xi,w,&errorl);
    732:     *error = PetscMax(*error,errorl);
    733:   }

    735:   /* compute error */
    736:   switch (type) {
    737:     case EPS_ERROR_ABSOLUTE:
    738:       break;
    739:     case EPS_ERROR_RELATIVE:
    740:       *error /= SlepcAbsEigenvalue(kr,ki)*vecnorm;
    741:       break;
    742:     case EPS_ERROR_BACKWARD:
    743:       /* initialization of matrix norms */
    744:       if (!eps->nrma) {
    745:         STGetMatrix(eps->st,0,&A);
    746:         MatHasOperation(A,MATOP_NORM,&flg);
    747:         if (!flg) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"The computation of backward errors requires a matrix norm operation");
    748:         MatNorm(A,NORM_INFINITY,&eps->nrma);
    749:       }
    750:       if (eps->isgeneralized) {
    751:         if (!eps->nrmb) {
    752:           STGetMatrix(eps->st,1,&B);
    753:           MatHasOperation(B,MATOP_NORM,&flg);
    754:           if (!flg) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"The computation of backward errors requires a matrix norm operation");
    755:           MatNorm(B,NORM_INFINITY,&eps->nrmb);
    756:         }
    757:       } else eps->nrmb = 1.0;
    758:       t = SlepcAbsEigenvalue(kr,ki);
    759:       *error /= (eps->nrma+t*eps->nrmb)*vecnorm;
    760:       break;
    761:     default:
    762:       SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Invalid error type");
    763:   }
    764:   return(0);
    765: }

    767: /*
    768:    EPSGetStartVector - Generate a suitable vector to be used as the starting vector
    769:    for the recurrence that builds the right subspace.

    771:    Collective on eps

    773:    Input Parameters:
    774: +  eps - the eigensolver context
    775: -  i   - iteration number

    777:    Output Parameters:
    778: .  breakdown - flag indicating that a breakdown has occurred

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

    787:    The flag breakdown is set to true if either i=0 and the vector belongs to the
    788:    deflation space, or i>0 and the vector is linearly dependent with respect
    789:    to the V-vectors.
    790: */
    791: PetscErrorCode EPSGetStartVector(EPS eps,PetscInt i,PetscBool *breakdown)
    792: {
    794:   PetscReal      norm;
    795:   PetscBool      lindep;
    796:   Vec            w,z;

    802:   /* For the first step, use the first initial vector, otherwise a random one */
    803:   if (i>0 || eps->nini==0) {
    804:     BVSetRandomColumn(eps->V,i);
    805:   }

    807:   /* Force the vector to be in the range of OP for definite generalized problems */
    808:   if (eps->ispositive || (eps->isgeneralized && eps->ishermitian)) {
    809:     BVCreateVec(eps->V,&w);
    810:     BVCopyVec(eps->V,i,w);
    811:     BVGetColumn(eps->V,i,&z);
    812:     STApply(eps->st,w,z);
    813:     BVRestoreColumn(eps->V,i,&z);
    814:     VecDestroy(&w);
    815:   }

    817:   /* Orthonormalize the vector with respect to previous vectors */
    818:   BVOrthogonalizeColumn(eps->V,i,NULL,&norm,&lindep);
    819:   if (breakdown) *breakdown = lindep;
    820:   else if (lindep || norm == 0.0) {
    821:     if (i==0) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Initial vector is zero or belongs to the deflation space");
    822:     else SETERRQ(PetscObjectComm((PetscObject)eps),1,"Unable to generate more start vectors");
    823:   }
    824:   BVScaleColumn(eps->V,i,1.0/norm);
    825:   return(0);
    826: }

    828: /*
    829:    EPSGetLeftStartVector - Generate a suitable vector to be used as the left starting
    830:    vector for the recurrence that builds the left subspace. See EPSGetStartVector().
    831: */
    832: PetscErrorCode EPSGetLeftStartVector(EPS eps,PetscInt i,PetscBool *breakdown)
    833: {
    835:   PetscReal      norm;
    836:   PetscBool      lindep;

    842:   /* For the first step, use the first initial vector, otherwise a random one */
    843:   if (i>0 || eps->ninil==0) {
    844:     BVSetRandomColumn(eps->W,i);
    845:   }

    847:   /* Orthonormalize the vector with respect to previous vectors */
    848:   BVOrthogonalizeColumn(eps->W,i,NULL,&norm,&lindep);
    849:   if (breakdown) *breakdown = lindep;
    850:   else if (lindep || norm == 0.0) {
    851:     if (i==0) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Left initial vector is zero");
    852:     else SETERRQ(PetscObjectComm((PetscObject)eps),1,"Unable to generate more left start vectors");
    853:   }
    854:   BVScaleColumn(eps->W,i,1.0/norm);
    855:   return(0);
    856: }