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

Actual source code: solve.c

      1: /*
      2:       EPS routines related to the solution process.

      4:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      5:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      6:    Copyright (c) 2002-2013, Universitat Politecnica de Valencia, Spain

      8:    This file is part of SLEPc.

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

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

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

     24: #include <slepc-private/epsimpl.h>   /*I "slepceps.h" I*/
     25: #include <petscdraw.h>

     27: typedef struct {
     28:   PetscErrorCode (*comparison)(PetscScalar,PetscScalar,PetscScalar,PetscScalar,PetscInt*,void*);
     29:   void *comparisonctx;
     30:   ST st;
     31: } EPSSortForSTData;

     35: static PetscErrorCode EPSSortForSTFunc(PetscScalar ar,PetscScalar ai,
     36:                                 PetscScalar br,PetscScalar bi,PetscInt *r,void *ctx)
     37: {
     38:   EPSSortForSTData *data = (EPSSortForSTData*)ctx;
     39:   PetscErrorCode   ierr;

     42:   STBackTransform(data->st,1,&ar,&ai);
     43:   STBackTransform(data->st,1,&br,&bi);
     44:   (*data->comparison)(ar,ai,br,bi,r,data->comparisonctx);
     45:   return(0);
     46: }

     50: /*@
     51:    EPSSolve - Solves the eigensystem.

     53:    Collective on EPS

     55:    Input Parameter:
     56: .  eps - eigensolver context obtained from EPSCreate()

     58:    Options Database Keys:
     59: +  -eps_view - print information about the solver used
     60: .  -eps_view_mat0 binary - save the first matrix (A) to the default binary viewer
     61: .  -eps_view_mat1 binary - save the second matrix (B) to the default binary viewer
     62: -  -eps_plot_eigs - plot computed eigenvalues

     64:    Level: beginner

     66: .seealso: EPSCreate(), EPSSetUp(), EPSDestroy(), EPSSetTolerances()
     67: @*/
     68: PetscErrorCode EPSSolve(EPS eps)
     69: {
     70:   PetscErrorCode    ierr;
     71:   PetscInt          i,nmat;
     72:   PetscReal         re,im;
     73:   PetscScalar       dot;
     74:   PetscBool         flg,isfold,iscayley;
     75:   PetscViewer       viewer;
     76:   PetscViewerFormat format;
     77:   PetscDraw         draw;
     78:   PetscDrawSP       drawsp;
     79:   STMatMode         matmode;
     80:   EPSSortForSTData  data;
     81:   Mat               A,B;
     82:   KSP               ksp;
     83:   Vec               w,x;

     87:   PetscLogEventBegin(EPS_Solve,eps,0,0,0);

     89:   /* call setup */
     90:   EPSSetUp(eps);
     91:   STGetNumMatrices(eps->st,&nmat);
     92:   STGetOperators(eps->st,0,&A);
     93:   if (nmat>1) { STGetOperators(eps->st,1,&B); }
     94:   eps->evecsavailable = PETSC_FALSE;
     95:   eps->nconv = 0;
     96:   eps->its   = 0;
     97:   for (i=0;i<eps->ncv;i++) {
     98:     eps->eigr[i]   = 0.0;
     99:     eps->eigi[i]   = 0.0;
    100:     eps->errest[i] = 0.0;
    101:   }
    102:   EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,eps->ncv);

    104:   PetscObjectTypeCompareAny((PetscObject)eps,&flg,EPSARPACK,EPSBLZPACK,EPSTRLAN,EPSBLOPEX,EPSPRIMME,"");
    105:   if (!flg) {
    106:     /* temporarily change eigenvalue comparison function */
    107:     data.comparison    = eps->comparison;
    108:     data.comparisonctx = eps->comparisonctx;
    109:     data.st            = eps->st;
    110:     eps->comparison    = (eps->which==EPS_ALL)? SlepcCompareLargestMagnitude: EPSSortForSTFunc;
    111:     eps->comparisonctx = (eps->which==EPS_ALL)? NULL: &data;
    112:   }
    113:   DSSetEigenvalueComparison(eps->ds,eps->comparison,eps->comparisonctx);

    115:   /* call solver */
    116:   (*eps->ops->solve)(eps);

    118:   if (!flg) {
    119:     /* restore comparison function */
    120:     eps->comparison    = data.comparison;
    121:     eps->comparisonctx = data.comparisonctx;
    122:   }

    124:   STGetMatMode(eps->st,&matmode);
    125:   if (matmode == ST_MATMODE_INPLACE && eps->ispositive) {
    126:     /* Purify eigenvectors before reverting operator */
    127:     (*eps->ops->computevectors)(eps);
    128:   }
    129:   STPostSolve(eps->st);

    131:   if (!eps->reason) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Internal error, solver returned without setting converged reason");

    133:   /* Map eigenvalues back to the original problem, necessary in some
    134:   * spectral transformations */
    135:   if (eps->ops->backtransform) {
    136:     (*eps->ops->backtransform)(eps);
    137:   }

    139:   /* Adjust left eigenvectors in generalized problems: y = B^T y */
    140:   if (eps->isgeneralized && eps->leftvecs) {
    141:     KSPCreate(PetscObjectComm((PetscObject)eps),&ksp);
    142:     KSPSetOperators(ksp,B,B,DIFFERENT_NONZERO_PATTERN);
    143:     KSPSetFromOptions(ksp);
    144:     MatGetVecs(B,NULL,&w);
    145:     for (i=0;i<eps->nconv;i++) {
    146:       VecCopy(eps->W[i],w);
    147:       KSPSolveTranspose(ksp,w,eps->W[i]);
    148:     }
    149:     KSPDestroy(&ksp);
    150:     VecDestroy(&w);
    151:   }

    153: #if !defined(PETSC_USE_COMPLEX)
    154:   /* reorder conjugate eigenvalues (positive imaginary first) */
    155:   for (i=0; i<eps->nconv-1; i++) {
    156:     if (eps->eigi[i] != 0) {
    157:       if (eps->eigi[i] < 0) {
    158:         eps->eigi[i] = -eps->eigi[i];
    159:         eps->eigi[i+1] = -eps->eigi[i+1];
    160:         if (!eps->evecsavailable) {
    161:           /* the next correction only works with eigenvectors */
    162:           (*eps->ops->computevectors)(eps);
    163:         }
    164:         VecScale(eps->V[i+1],-1.0);
    165:       }
    166:       i++;
    167:     }
    168:   }
    169: #endif

    171:   /* quick and dirty solution for FOLD: recompute eigenvalues as Rayleigh quotients */
    172:   PetscObjectTypeCompare((PetscObject)eps->st,STFOLD,&isfold);
    173:   if (isfold) {
    174:     MatGetVecs(A,&w,NULL);
    175:     if (!eps->evecsavailable) { (*eps->ops->computevectors)(eps); }
    176:     for (i=0;i<eps->nconv;i++) {
    177:       x = eps->V[i];
    178:       MatMult(A,x,w);
    179:       VecDot(w,x,&eps->eigr[i]);
    180:       if (eps->isgeneralized) {
    181:         MatMult(B,x,w);
    182:         VecDot(w,x,&dot);
    183:         eps->eigr[i] /= dot;
    184:       }
    185:     }
    186:     VecDestroy(&w);
    187:   }

    189:   /* In the case of Cayley transform, eigenvectors need to be B-normalized */
    190:   PetscObjectTypeCompare((PetscObject)eps->st,STCAYLEY,&iscayley);
    191:   if (iscayley && eps->isgeneralized && eps->ishermitian) {
    192:     MatGetVecs(B,NULL,&w);
    193:     if (!eps->evecsavailable) { (*eps->ops->computevectors)(eps); }
    194:     for (i=0;i<eps->nconv;i++) {
    195:       x = eps->V[i];
    196:       MatMult(B,x,w);
    197:       VecDot(w,x,&dot);
    198:       VecScale(x,1.0/PetscSqrtScalar(dot));
    199:     }
    200:     VecDestroy(&w);
    201:   }

    203:   /* sort eigenvalues according to eps->which parameter */
    204:   EPSSortEigenvalues(eps,eps->nconv,eps->eigr,eps->eigi,eps->perm);

    206:   PetscLogEventEnd(EPS_Solve,eps,0,0,0);

    208:   /* various viewers */
    209:   MatViewFromOptions(A,((PetscObject)eps)->prefix,"-eps_view_mat0");
    210:   if (nmat>1) { MatViewFromOptions(B,((PetscObject)eps)->prefix,"-eps_view_mat1"); }

    212:   PetscOptionsGetViewer(PetscObjectComm((PetscObject)eps),((PetscObject)eps)->prefix,"-eps_view",&viewer,&format,&flg);
    213:   if (flg && !PetscPreLoadingOn) {
    214:     PetscViewerPushFormat(viewer,format);
    215:     EPSView(eps,viewer);
    216:     PetscViewerPopFormat(viewer);
    217:     PetscViewerDestroy(&viewer);
    218:   }

    220:   flg = PETSC_FALSE;
    221:   PetscOptionsGetBool(((PetscObject)eps)->prefix,"-eps_plot_eigs",&flg,NULL);
    222:   if (flg) {
    223:     PetscViewerDrawOpen(PETSC_COMM_SELF,0,"Computed Eigenvalues",PETSC_DECIDE,PETSC_DECIDE,300,300,&viewer);
    224:     PetscViewerDrawGetDraw(viewer,0,&draw);
    225:     PetscDrawSPCreate(draw,1,&drawsp);
    226:     for (i=0;i<eps->nconv;i++) {
    227: #if defined(PETSC_USE_COMPLEX)
    228:       re = PetscRealPart(eps->eigr[i]);
    229:       im = PetscImaginaryPart(eps->eigi[i]);
    230: #else
    231:       re = eps->eigr[i];
    232:       im = eps->eigi[i];
    233: #endif
    234:       PetscDrawSPAddPoint(drawsp,&re,&im);
    235:     }
    236:     PetscDrawSPDraw(drawsp,PETSC_TRUE);
    237:     PetscDrawSPDestroy(&drawsp);
    238:     PetscViewerDestroy(&viewer);
    239:   }

    241:   /* Remove the initial subspaces */
    242:   eps->nini = 0;
    243:   eps->ninil = 0;
    244:   return(0);
    245: }

    249: /*@
    250:    EPSGetIterationNumber - Gets the current iteration number. If the
    251:    call to EPSSolve() is complete, then it returns the number of iterations
    252:    carried out by the solution method.

    254:    Not Collective

    256:    Input Parameter:
    257: .  eps - the eigensolver context

    259:    Output Parameter:
    260: .  its - number of iterations

    262:    Level: intermediate

    264:    Note:
    265:    During the i-th iteration this call returns i-1. If EPSSolve() is
    266:    complete, then parameter "its" contains either the iteration number at
    267:    which convergence was successfully reached, or failure was detected.
    268:    Call EPSGetConvergedReason() to determine if the solver converged or
    269:    failed and why.

    271: .seealso: EPSGetConvergedReason(), EPSSetTolerances()
    272: @*/
    273: PetscErrorCode EPSGetIterationNumber(EPS eps,PetscInt *its)
    274: {
    278:   *its = eps->its;
    279:   return(0);
    280: }

    284: /*@
    285:    EPSGetOperationCounters - Gets the total number of operator applications,
    286:    inner product operations and linear iterations used by the ST object
    287:    during the last EPSSolve() call.

    289:    Not Collective

    291:    Input Parameter:
    292: .  eps - EPS context

    294:    Output Parameter:
    295: +  ops  - number of operator applications
    296: .  dots - number of inner product operations
    297: -  lits - number of linear iterations

    299:    Notes:
    300:    When the eigensolver algorithm invokes STApply() then a linear system
    301:    must be solved (except in the case of standard eigenproblems and shift
    302:    transformation). The number of iterations required in this solve is
    303:    accumulated into a counter whose value is returned by this function.

    305:    These counters are reset to zero at each successive call to EPSSolve().

    307:    Level: intermediate

    309: @*/
    310: PetscErrorCode EPSGetOperationCounters(EPS eps,PetscInt* ops,PetscInt* dots,PetscInt* lits)
    311: {

    316:   if (!eps->st) { EPSGetST(eps,&eps->st); }
    317:   STGetOperationCounters(eps->st,ops,lits);
    318:   if (dots) {
    319:     if (!eps->ip) { EPSGetIP(eps,&eps->ip); }
    320:     IPGetOperationCounters(eps->ip,dots);
    321:   }
    322:   return(0);
    323: }

    327: /*@
    328:    EPSGetConverged - Gets the number of converged eigenpairs.

    330:    Not Collective

    332:    Input Parameter:
    333: .  eps - the eigensolver context

    335:    Output Parameter:
    336: .  nconv - number of converged eigenpairs

    338:    Note:
    339:    This function should be called after EPSSolve() has finished.

    341:    Level: beginner

    343: .seealso: EPSSetDimensions(), EPSSolve()
    344: @*/
    345: PetscErrorCode EPSGetConverged(EPS eps,PetscInt *nconv)
    346: {
    350:   *nconv = eps->nconv;
    351:   return(0);
    352: }

    356: /*@C
    357:    EPSGetConvergedReason - Gets the reason why the EPSSolve() iteration was
    358:    stopped.

    360:    Not Collective

    362:    Input Parameter:
    363: .  eps - the eigensolver context

    365:    Output Parameter:
    366: .  reason - negative value indicates diverged, positive value converged

    368:    Possible values for reason:
    369: +  EPS_CONVERGED_TOL - converged up to tolerance
    370: .  EPS_DIVERGED_ITS - required more than its to reach convergence
    371: -  EPS_DIVERGED_BREAKDOWN - generic breakdown in method

    373:    Note:
    374:    Can only be called after the call to EPSSolve() is complete.

    376:    Level: intermediate

    378: .seealso: EPSSetTolerances(), EPSSolve(), EPSConvergedReason
    379: @*/
    380: PetscErrorCode EPSGetConvergedReason(EPS eps,EPSConvergedReason *reason)
    381: {
    385:   *reason = eps->reason;
    386:   return(0);
    387: }

    391: /*@
    392:    EPSGetInvariantSubspace - Gets an orthonormal basis of the computed invariant
    393:    subspace.

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

    397:    Input Parameter:
    398: .  eps - the eigensolver context

    400:    Output Parameter:
    401: .  v - an array of vectors

    403:    Notes:
    404:    This function should be called after EPSSolve() has finished.

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

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

    416:    Level: intermediate

    418: .seealso: EPSGetEigenpair(), EPSGetConverged(), EPSSolve(), EPSGetInvariantSubspaceLeft()
    419: @*/
    420: PetscErrorCode EPSGetInvariantSubspace(EPS eps,Vec *v)
    421: {
    423:   PetscInt       i;

    429:   if (!eps->V) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
    430:   if (!eps->ishermitian && eps->evecsavailable) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSGetInvariantSubspace must be called before EPSGetEigenpair,EPSGetEigenvector,EPSComputeRelativeError or EPSComputeResidualNorm");
    431:   if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
    432:     for (i=0;i<eps->nconv;i++) {
    433:       VecPointwiseDivide(v[i],eps->V[i],eps->D);
    434:       VecNormalize(v[i],NULL);
    435:     }
    436:   } else {
    437:     for (i=0;i<eps->nconv;i++) {
    438:       VecCopy(eps->V[i],v[i]);
    439:     }
    440:   }
    441:   return(0);
    442: }

    446: /*@
    447:    EPSGetInvariantSubspaceLeft - Gets an orthonormal basis of the computed left
    448:    invariant subspace (only available in two-sided eigensolvers).

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

    452:    Input Parameter:
    453: .  eps - the eigensolver context

    455:    Output Parameter:
    456: .  v - an array of vectors

    458:    Notes:
    459:    This function should be called after EPSSolve() has finished.

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

    464:    The first k vectors returned in v span a left invariant subspace associated
    465:    with the first k computed eigenvalues (note that this is not true if the
    466:    k-th eigenvalue is complex and matrix A is real; in this case the first
    467:    k+1 vectors should be used). A left invariant subspace Y of A satisfies y'A
    468:    in Y for all y in Y (a similar definition applies for generalized
    469:    eigenproblems).

    471:    Level: intermediate

    473: .seealso: EPSGetEigenpair(), EPSGetConverged(), EPSSolve(), EPSGetInvariantSubspace
    474: @*/
    475: PetscErrorCode EPSGetInvariantSubspaceLeft(EPS eps,Vec *v)
    476: {
    478:   PetscInt       i;

    484:   if (!eps->leftvecs) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
    485:   if (!eps->W) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
    486:   if (!eps->ishermitian && eps->evecsavailable) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSGetInvariantSubspaceLeft must be called before EPSGetEigenpairLeft,EPSComputeRelativeErrorLeft or EPSComputeResidualNormLeft");
    487:   for (i=0;i<eps->nconv;i++) {
    488:     VecCopy(eps->W[i],v[i]);
    489:   }
    490:   return(0);
    491: }

    495: /*@
    496:    EPSGetEigenpair - Gets the i-th solution of the eigenproblem as computed by
    497:    EPSSolve(). The solution consists in both the eigenvalue and the eigenvector.

    499:    Logically Collective on EPS

    501:    Input Parameters:
    502: +  eps - eigensolver context
    503: -  i   - index of the solution

    505:    Output Parameters:
    506: +  eigr - real part of eigenvalue
    507: .  eigi - imaginary part of eigenvalue
    508: .  Vr   - real part of eigenvector
    509: -  Vi   - imaginary part of eigenvector

    511:    Notes:
    512:    If the eigenvalue is real, then eigi and Vi are set to zero. If PETSc is
    513:    configured with complex scalars the eigenvalue is stored
    514:    directly in eigr (eigi is set to zero) and the eigenvector in Vr (Vi is
    515:    set to zero).

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

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

    525:    Level: beginner

    527: .seealso: EPSGetEigenvalue(), EPSGetEigenvector(), EPSGetEigenvectorLeft(), EPSSolve(),
    528:           EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetInvariantSubspace()
    529: @*/
    530: PetscErrorCode EPSGetEigenpair(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)
    531: {

    537:   if (!eps->eigr || !eps->eigi || !eps->V) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
    538:   if (i<0 || i>=eps->nconv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
    539:   EPSGetEigenvalue(eps,i,eigr,eigi);
    540:   if (Vr || Vi) { EPSGetEigenvector(eps,i,Vr,Vi); }
    541:   return(0);
    542: }

    546: /*@
    547:    EPSGetEigenvalue - Gets the i-th eigenvalue as computed by EPSSolve().

    549:    Not Collective

    551:    Input Parameters:
    552: +  eps - eigensolver context
    553: -  i   - index of the solution

    555:    Output Parameters:
    556: +  eigr - real part of eigenvalue
    557: -  eigi - imaginary part of eigenvalue

    559:    Notes:
    560:    If the eigenvalue is real, then eigi is set to zero. If PETSc is
    561:    configured with complex scalars the eigenvalue is stored
    562:    directly in eigr (eigi is set to zero).

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

    568:    Level: beginner

    570: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(),
    571:           EPSGetEigenpair()
    572: @*/
    573: PetscErrorCode EPSGetEigenvalue(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi)
    574: {
    575:   PetscInt       k;

    579:   if (!eps->eigr || !eps->eigi) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
    580:   if (i<0 || i>=eps->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
    581:   if (!eps->perm) k = i;
    582:   else k = eps->perm[i];
    583: #if defined(PETSC_USE_COMPLEX)
    584:   if (eigr) *eigr = eps->eigr[k];
    585:   if (eigi) *eigi = 0;
    586: #else
    587:   if (eigr) *eigr = eps->eigr[k];
    588:   if (eigi) *eigi = eps->eigi[k];
    589: #endif
    590:   return(0);
    591: }

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

    598:    Logically Collective on EPS

    600:    Input Parameters:
    601: +  eps - eigensolver context
    602: -  i   - index of the solution

    604:    Output Parameters:
    605: +  Vr   - real part of eigenvector
    606: -  Vi   - imaginary part of eigenvector

    608:    Notes:
    609:    If the corresponding eigenvalue is real, then Vi is set to zero. If PETSc is
    610:    configured with complex scalars the eigenvector is stored
    611:    directly in Vr (Vi is set to zero).

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

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

    621:    Level: beginner

    623: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(),
    624:           EPSGetEigenpair(), EPSGetEigenvectorLeft()
    625: @*/
    626: PetscErrorCode EPSGetEigenvector(EPS eps,PetscInt i,Vec Vr,Vec Vi)
    627: {
    629:   PetscInt       k;

    637:   if (!eps->V) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
    638:   if (i<0 || i>=eps->nconv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
    639:   if (!eps->evecsavailable) {
    640:     (*eps->ops->computevectors)(eps);
    641:   }
    642:   if (!eps->perm) k = i;
    643:   else k = eps->perm[i];
    644: #if defined(PETSC_USE_COMPLEX)
    645:   VecCopy(eps->V[k],Vr);
    646:   if (Vi) { VecSet(Vi,0.0); }
    647: #else
    648:   if (eps->eigi[k] > 0) { /* first value of conjugate pair */
    649:     VecCopy(eps->V[k],Vr);
    650:     if (Vi) {
    651:       VecCopy(eps->V[k+1],Vi);
    652:     }
    653:   } else if (eps->eigi[k] < 0) { /* second value of conjugate pair */
    654:     VecCopy(eps->V[k-1],Vr);
    655:     if (Vi) {
    656:       VecCopy(eps->V[k],Vi);
    657:       VecScale(Vi,-1.0);
    658:     }
    659:   } else { /* real eigenvalue */
    660:     VecCopy(eps->V[k],Vr);
    661:     if (Vi) { VecSet(Vi,0.0); }
    662:   }
    663: #endif
    664:   return(0);
    665: }

    669: /*@
    670:    EPSGetEigenvectorLeft - Gets the i-th left eigenvector as computed by EPSSolve()
    671:    (only available in two-sided eigensolvers).

    673:    Logically Collective on EPS

    675:    Input Parameters:
    676: +  eps - eigensolver context
    677: -  i   - index of the solution

    679:    Output Parameters:
    680: +  Wr   - real part of eigenvector
    681: -  Wi   - imaginary part of eigenvector

    683:    Notes:
    684:    If the corresponding eigenvalue is real, then Wi is set to zero. If PETSc is
    685:    configured with complex scalars the eigenvector is stored
    686:    directly in Wr (Wi is set to zero).

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

    692:    Level: beginner

    694: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(),
    695:           EPSGetEigenpair(), EPSGetEigenvector()
    696: @*/
    697: PetscErrorCode EPSGetEigenvectorLeft(EPS eps,PetscInt i,Vec Wr,Vec Wi)
    698: {
    700:   PetscInt       k;

    708:   if (!eps->leftvecs) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
    709:   if (!eps->W) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
    710:   if (i<0 || i>=eps->nconv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
    711:   if (!eps->evecsavailable) {
    712:     (*eps->ops->computevectors)(eps);
    713:   }
    714:   if (!eps->perm) k = i;
    715:   else k = eps->perm[i];
    716: #if defined(PETSC_USE_COMPLEX)
    717:   VecCopy(eps->W[k],Wr);
    718:   if (Wi) { VecSet(Wi,0.0); }
    719: #else
    720:   if (eps->eigi[k] > 0) { /* first value of conjugate pair */
    721:     VecCopy(eps->W[k],Wr);
    722:     if (Wi) {
    723:       VecCopy(eps->W[k+1],Wi);
    724:     }
    725:   } else if (eps->eigi[k] < 0) { /* second value of conjugate pair */
    726:     VecCopy(eps->W[k-1],Wr);
    727:     if (Wi) {
    728:       VecCopy(eps->W[k],Wi);
    729:       VecScale(Wi,-1.0);
    730:     }
    731:   } else { /* real eigenvalue */
    732:     VecCopy(eps->W[k],Wr);
    733:     if (Wi) { VecSet(Wi,0.0); }
    734:   }
    735: #endif
    736:   return(0);
    737: }

    741: /*@
    742:    EPSGetErrorEstimate - Returns the error estimate associated to the i-th
    743:    computed eigenpair.

    745:    Not Collective

    747:    Input Parameter:
    748: +  eps - eigensolver context
    749: -  i   - index of eigenpair

    751:    Output Parameter:
    752: .  errest - the error estimate

    754:    Notes:
    755:    This is the error estimate used internally by the eigensolver. The actual
    756:    error bound can be computed with EPSComputeRelativeError(). See also the users
    757:    manual for details.

    759:    Level: advanced

    761: .seealso: EPSComputeRelativeError()
    762: @*/
    763: PetscErrorCode EPSGetErrorEstimate(EPS eps,PetscInt i,PetscReal *errest)
    764: {
    768:   if (!eps->eigr || !eps->eigi) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
    769:   if (i<0 || i>=eps->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
    770:   if (eps->perm) i = eps->perm[i];
    771:   if (errest) *errest = eps->errest[i];
    772:   return(0);
    773: }

    777: /*@
    778:    EPSGetErrorEstimateLeft - Returns the left error estimate associated to the i-th
    779:    computed eigenpair (only available in two-sided eigensolvers).

    781:    Not Collective

    783:    Input Parameter:
    784: +  eps - eigensolver context
    785: -  i   - index of eigenpair

    787:    Output Parameter:
    788: .  errest - the left error estimate

    790:    Notes:
    791:    This is the error estimate used internally by the eigensolver. The actual
    792:    error bound can be computed with EPSComputeRelativeErrorLeft(). See also the users
    793:    manual for details.

    795:    Level: advanced

    797: .seealso: EPSComputeRelativeErrorLeft()
    798: @*/
    799: PetscErrorCode EPSGetErrorEstimateLeft(EPS eps,PetscInt i,PetscReal *errest)
    800: {
    804:   if (!eps->eigr || !eps->eigi) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
    805:   if (!eps->leftvecs) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
    806:   if (i<0 || i>=eps->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
    807:   if (eps->perm) i = eps->perm[i];
    808:   if (errest) *errest = eps->errest_left[i];
    809:   return(0);
    810: }

    814: /*
    815:    EPSComputeResidualNorm_Private - Computes the norm of the residual vector
    816:    associated with an eigenpair.
    817: */
    818: PetscErrorCode EPSComputeResidualNorm_Private(EPS eps,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,PetscReal *norm)
    819: {
    821:   PetscInt       nmat;
    822:   Vec            u,w;
    823:   Mat            A,B;
    824: #if !defined(PETSC_USE_COMPLEX)
    825:   Vec            v;
    826:   PetscReal      ni,nr;
    827: #endif

    830:   STGetNumMatrices(eps->st,&nmat);
    831:   STGetOperators(eps->st,0,&A);
    832:   if (nmat>1) { STGetOperators(eps->st,1,&B); }
    833:   VecDuplicate(eps->V[0],&u);
    834:   VecDuplicate(eps->V[0],&w);

    836: #if !defined(PETSC_USE_COMPLEX)
    837:   if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
    838: #endif
    839:     MatMult(A,xr,u);                             /* u=A*x */
    840:     if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
    841:       if (eps->isgeneralized) { MatMult(B,xr,w); }
    842:       else { VecCopy(xr,w); }                    /* w=B*x */
    843:       VecAXPY(u,-kr,w);                          /* u=A*x-k*B*x */
    844:     }
    845:     VecNorm(u,NORM_2,norm);
    846: #if !defined(PETSC_USE_COMPLEX)
    847:   } else {
    848:     VecDuplicate(eps->V[0],&v);
    849:     MatMult(A,xr,u);                             /* u=A*xr */
    850:     if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
    851:       if (eps->isgeneralized) { MatMult(B,xr,v); }
    852:       else { VecCopy(xr,v); }                    /* v=B*xr */
    853:       VecAXPY(u,-kr,v);                          /* u=A*xr-kr*B*xr */
    854:       if (eps->isgeneralized) { MatMult(B,xi,w); }
    855:       else { VecCopy(xi,w); }                    /* w=B*xi */
    856:       VecAXPY(u,ki,w);                           /* u=A*xr-kr*B*xr+ki*B*xi */
    857:     }
    858:     VecNorm(u,NORM_2,&nr);
    859:     MatMult(A,xi,u);                             /* u=A*xi */
    860:     if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
    861:       VecAXPY(u,-kr,w);                          /* u=A*xi-kr*B*xi */
    862:       VecAXPY(u,-ki,v);                          /* u=A*xi-kr*B*xi-ki*B*xr */
    863:     }
    864:     VecNorm(u,NORM_2,&ni);
    865:     *norm = SlepcAbsEigenvalue(nr,ni);
    866:     VecDestroy(&v);
    867:   }
    868: #endif

    870:   VecDestroy(&w);
    871:   VecDestroy(&u);
    872:   return(0);
    873: }

    877: /*@
    878:    EPSComputeResidualNorm - Computes the norm of the residual vector associated with
    879:    the i-th computed eigenpair.

    881:    Collective on EPS

    883:    Input Parameter:
    884: +  eps - the eigensolver context
    885: -  i   - the solution index

    887:    Output Parameter:
    888: .  norm - the residual norm, computed as ||Ax-kBx||_2 where k is the
    889:    eigenvalue and x is the eigenvector.
    890:    If k=0 then the residual norm is computed as ||Ax||_2.

    892:    Notes:
    893:    The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
    894:    Eigenpairs are indexed according to the ordering criterion established
    895:    with EPSSetWhichEigenpairs().

    897:    Level: beginner

    899: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs()
    900: @*/
    901: PetscErrorCode EPSComputeResidualNorm(EPS eps,PetscInt i,PetscReal *norm)
    902: {
    904:   Vec            xr,xi;
    905:   PetscScalar    kr,ki;

    911:   VecDuplicate(eps->V[0],&xr);
    912:   VecDuplicate(eps->V[0],&xi);
    913:   EPSGetEigenpair(eps,i,&kr,&ki,xr,xi);
    914:   EPSComputeResidualNorm_Private(eps,kr,ki,xr,xi,norm);
    915:   VecDestroy(&xr);
    916:   VecDestroy(&xi);
    917:   return(0);
    918: }

    922: /*@
    923:    EPSComputeResidualNormLeft - Computes the norm of the residual vector associated with
    924:    the i-th computed left eigenvector (only available in two-sided eigensolvers).

    926:    Collective on EPS

    928:    Input Parameter:
    929: +  eps - the eigensolver context
    930: -  i   - the solution index

    932:    Output Parameter:
    933: .  norm - the residual norm, computed as ||y'A-ky'B||_2 where k is the
    934:    eigenvalue and y is the left eigenvector.
    935:    If k=0 then the residual norm is computed as ||y'A||_2.

    937:    Notes:
    938:    The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
    939:    Eigenpairs are indexed according to the ordering criterion established
    940:    with EPSSetWhichEigenpairs().

    942:    Level: beginner

    944: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs()
    945: @*/
    946: PetscErrorCode EPSComputeResidualNormLeft(EPS eps,PetscInt i,PetscReal *norm)
    947: {
    949:   Vec            u,v,w,xr,xi;
    950:   Mat            A,B;
    951:   PetscInt       nmat;
    952:   PetscScalar    kr,ki;
    953: #if !defined(PETSC_USE_COMPLEX)
    954:   PetscReal      ni,nr;
    955: #endif

    961:   if (!eps->leftvecs) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
    962:   STGetNumMatrices(eps->st,&nmat);
    963:   STGetOperators(eps->st,0,&A);
    964:   if (nmat>1) { STGetOperators(eps->st,1,&B); }
    965:   VecDuplicate(eps->W[0],&u);
    966:   VecDuplicate(eps->W[0],&v);
    967:   VecDuplicate(eps->W[0],&w);
    968:   VecDuplicate(eps->W[0],&xr);
    969:   VecDuplicate(eps->W[0],&xi);
    970:   EPSGetEigenvalue(eps,i,&kr,&ki);
    971:   EPSGetEigenvectorLeft(eps,i,xr,xi);

    973: #if !defined(PETSC_USE_COMPLEX)
    974:   if (ki == 0 ||
    975:     PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
    976: #endif
    977:     MatMultTranspose(A,xr,u); /* u=A'*x */
    978:     if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
    979:       if (eps->isgeneralized) { MatMultTranspose(B,xr,w); }
    980:       else { VecCopy(xr,w); } /* w=B'*x */
    981:       VecAXPY(u,-kr,w); /* u=A'*x-k*B'*x */
    982:     }
    983:     VecNorm(u,NORM_2,norm);
    984: #if !defined(PETSC_USE_COMPLEX)
    985:   } else {
    986:     MatMultTranspose(A,xr,u); /* u=A'*xr */
    987:     if (eps->isgeneralized) { MatMultTranspose(B,xr,v); }
    988:     else { VecCopy(xr,v); } /* v=B'*xr */
    989:     VecAXPY(u,-kr,v); /* u=A'*xr-kr*B'*xr */
    990:     if (eps->isgeneralized) { MatMultTranspose(B,xi,w); }
    991:     else { VecCopy(xi,w); } /* w=B'*xi */
    992:     VecAXPY(u,ki,w); /* u=A'*xr-kr*B'*xr+ki*B'*xi */
    993:     VecNorm(u,NORM_2,&nr);
    994:     MatMultTranspose(A,xi,u); /* u=A'*xi */
    995:     VecAXPY(u,-kr,w); /* u=A'*xi-kr*B'*xi */
    996:     VecAXPY(u,-ki,v); /* u=A'*xi-kr*B'*xi-ki*B'*xr */
    997:     VecNorm(u,NORM_2,&ni);
    998:     *norm = SlepcAbsEigenvalue(nr,ni);
    999:   }
    1000: #endif

    1002:   VecDestroy(&w);
    1003:   VecDestroy(&v);
    1004:   VecDestroy(&u);
    1005:   VecDestroy(&xr);
    1006:   VecDestroy(&xi);
    1007:   return(0);
    1008: }

    1012: /*
    1013:    EPSComputeRelativeError_Private - Computes the relative error bound
    1014:    associated with an eigenpair.
    1015: */
    1016: PetscErrorCode EPSComputeRelativeError_Private(EPS eps,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,PetscReal *error)
    1017: {
    1019:   PetscReal      norm,er;
    1020: #if !defined(PETSC_USE_COMPLEX)
    1021:   PetscReal      ei;
    1022: #endif

    1025:   EPSComputeResidualNorm_Private(eps,kr,ki,xr,xi,&norm);

    1027: #if !defined(PETSC_USE_COMPLEX)
    1028:   if (ki == 0) {
    1029: #endif
    1030:     VecNorm(xr,NORM_2,&er);
    1031: #if !defined(PETSC_USE_COMPLEX)
    1032:   } else {
    1033:     VecNorm(xr,NORM_2,&er);
    1034:     VecNorm(xi,NORM_2,&ei);
    1035:     er = SlepcAbsEigenvalue(er,ei);
    1036:   }
    1037: #endif
    1038:   (*eps->converged)(eps,kr,ki,norm/er,error,eps->convergedctx);
    1039:   return(0);
    1040: }

    1044: /*@
    1045:    EPSComputeRelativeError - Computes the relative error bound associated
    1046:    with the i-th computed eigenpair.

    1048:    Collective on EPS

    1050:    Input Parameter:
    1051: +  eps - the eigensolver context
    1052: -  i   - the solution index

    1054:    Output Parameter:
    1055: .  error - the relative error bound, computed as ||Ax-kBx||_2/||kx||_2 where
    1056:    k is the eigenvalue and x is the eigenvector.
    1057:    If k=0 the relative error is computed as ||Ax||_2/||x||_2.

    1059:    Level: beginner

    1061: .seealso: EPSSolve(), EPSComputeResidualNorm(), EPSGetErrorEstimate()
    1062: @*/
    1063: PetscErrorCode EPSComputeRelativeError(EPS eps,PetscInt i,PetscReal *error)
    1064: {
    1066:   Vec            xr,xi;
    1067:   PetscScalar    kr,ki;

    1073:   VecDuplicate(eps->V[0],&xr);
    1074:   VecDuplicate(eps->V[0],&xi);
    1075:   EPSGetEigenpair(eps,i,&kr,&ki,xr,xi);
    1076:   EPSComputeRelativeError_Private(eps,kr,ki,xr,xi,error);
    1077:   VecDestroy(&xr);
    1078:   VecDestroy(&xi);
    1079:   return(0);
    1080: }

    1084: /*@
    1085:    EPSComputeRelativeErrorLeft - Computes the relative error bound associated
    1086:    with the i-th computed eigenvalue and left eigenvector (only available in
    1087:    two-sided eigensolvers).

    1089:    Collective on EPS

    1091:    Input Parameter:
    1092: +  eps - the eigensolver context
    1093: -  i   - the solution index

    1095:    Output Parameter:
    1096: .  error - the relative error bound, computed as ||y'A-ky'B||_2/||ky||_2 where
    1097:    k is the eigenvalue and y is the left eigenvector.
    1098:    If k=0 the relative error is computed as ||y'A||_2/||y||_2.

    1100:    Level: beginner

    1102: .seealso: EPSSolve(), EPSComputeResidualNormLeft(), EPSGetErrorEstimateLeft()
    1103: @*/
    1104: PetscErrorCode EPSComputeRelativeErrorLeft(EPS eps,PetscInt i,PetscReal *error)
    1105: {
    1107:   Vec            xr,xi;
    1108:   PetscScalar    kr,ki;
    1109:   PetscReal      norm,er;
    1110: #if !defined(PETSC_USE_COMPLEX)
    1111:   Vec            u;
    1112:   PetscReal      ei;
    1113: #endif

    1117:   EPSComputeResidualNormLeft(eps,i,&norm);
    1120:   VecDuplicate(eps->W[0],&xr);
    1121:   VecDuplicate(eps->W[0],&xi);
    1122:   EPSGetEigenvalue(eps,i,&kr,&ki);
    1123:   EPSGetEigenvectorLeft(eps,i,xr,xi);

    1125: #if !defined(PETSC_USE_COMPLEX)
    1126:   if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
    1127: #endif
    1128:     VecNorm(xr,NORM_2,&er);
    1129:     if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) *error = norm/(PetscAbsScalar(kr)*er);
    1130:     else *error = norm / er;
    1131: #if !defined(PETSC_USE_COMPLEX)
    1132:   } else {
    1133:     VecDuplicate(xi,&u);
    1134:     VecCopy(xi,u);
    1135:     VecAXPBY(u,kr,-ki,xr);
    1136:     VecNorm(u,NORM_2,&er);
    1137:     VecAXPBY(xi,kr,ki,xr);
    1138:     VecNorm(xi,NORM_2,&ei);
    1139:     VecDestroy(&u);
    1140:     *error = norm / SlepcAbsEigenvalue(er,ei);
    1141:   }
    1142: #endif

    1144:   VecDestroy(&xr);
    1145:   VecDestroy(&xi);
    1146:   return(0);
    1147: }

    1151: /*@
    1152:    EPSSortEigenvalues - Sorts a list of eigenvalues according to the criterion
    1153:    specified via EPSSetWhichEigenpairs().

    1155:    Not Collective

    1157:    Input Parameters:
    1158: +  eps   - the eigensolver context
    1159: .  n     - number of eigenvalues in the list
    1160: .  eigr  - pointer to the array containing the eigenvalues
    1161: -  eigi  - imaginary part of the eigenvalues (only when using real numbers)

    1163:    Output Parameter:
    1164: .  perm  - resulting permutation

    1166:    Note:
    1167:    The result is a list of indices in the original eigenvalue array
    1168:    corresponding to the first nev eigenvalues sorted in the specified
    1169:    criterion.

    1171:    Level: developer

    1173: .seealso: EPSSetWhichEigenpairs()
    1174: @*/
    1175: PetscErrorCode EPSSortEigenvalues(EPS eps,PetscInt n,PetscScalar *eigr,PetscScalar *eigi,PetscInt *perm)
    1176: {
    1178:   PetscScalar    re,im;
    1179:   PetscInt       i,j,result,tmp;

    1186:   for (i=0; i<n; i++) { perm[i] = i; }
    1187:   /* insertion sort */
    1188:   for (i=n-1; i>=0; i--) {
    1189:     re = eigr[perm[i]];
    1190:     im = eigi[perm[i]];
    1191:     j = i + 1;
    1192: #if !defined(PETSC_USE_COMPLEX)
    1193:     if (im != 0) {
    1194:       /* complex eigenvalue */
    1195:       i--;
    1196:       im = eigi[perm[i]];
    1197:     }
    1198: #endif
    1199:     while (j<n) {
    1200:       EPSCompareEigenvalues(eps,re,im,eigr[perm[j]],eigi[perm[j]],&result);
    1201:       if (result < 0) break;
    1202: #if !defined(PETSC_USE_COMPLEX)
    1203:       /* keep together every complex conjugated eigenpair */
    1204:       if (im == 0) {
    1205:         if (eigi[perm[j]] == 0) {
    1206: #endif
    1207:           tmp = perm[j-1]; perm[j-1] = perm[j]; perm[j] = tmp;
    1208:           j++;
    1209: #if !defined(PETSC_USE_COMPLEX)
    1210:         } else {
    1211:           tmp = perm[j-1]; perm[j-1] = perm[j]; perm[j] = perm[j+1]; perm[j+1] = tmp;
    1212:           j+=2;
    1213:         }
    1214:       } else {
    1215:         if (eigi[perm[j]] == 0) {
    1216:           tmp = perm[j-2]; perm[j-2] = perm[j]; perm[j] = perm[j-1]; perm[j-1] = tmp;
    1217:           j++;
    1218:         } else {
    1219:           tmp = perm[j-2]; perm[j-2] = perm[j]; perm[j] = tmp;
    1220:           tmp = perm[j-1]; perm[j-1] = perm[j+1]; perm[j+1] = tmp;
    1221:           j+=2;
    1222:         }
    1223:       }
    1224: #endif
    1225:     }
    1226:   }
    1227:   return(0);
    1228: }

    1232: /*@
    1233:    EPSCompareEigenvalues - Compares two (possibly complex) eigenvalues according
    1234:    to a certain criterion.

    1236:    Not Collective

    1238:    Input Parameters:
    1239: +  eps   - the eigensolver context
    1240: .  ar     - real part of the 1st eigenvalue
    1241: .  ai     - imaginary part of the 1st eigenvalue
    1242: .  br     - real part of the 2nd eigenvalue
    1243: -  bi     - imaginary part of the 2nd eigenvalue

    1245:    Output Parameter:
    1246: .  res    - result of comparison

    1248:    Notes:
    1249:    The returning parameter 'res' can be:
    1250: +  negative - if the 1st eigenvalue is preferred to the 2st one
    1251: .  zero     - if both eigenvalues are equally preferred
    1252: -  positive - if the 2st eigenvalue is preferred to the 1st one

    1254:    The criterion of comparison is related to the 'which' parameter set with
    1255:    EPSSetWhichEigenpairs().

    1257:    Level: developer

    1259: .seealso: EPSSortEigenvalues(), EPSSetWhichEigenpairs()
    1260: @*/
    1261: PetscErrorCode EPSCompareEigenvalues(EPS eps,PetscScalar ar,PetscScalar ai,PetscScalar br,PetscScalar bi,PetscInt *result)
    1262: {

    1268:   if (!eps->comparison) SETERRQ(PETSC_COMM_SELF,1,"Undefined eigenvalue comparison function");
    1269:   (*eps->comparison)(ar,ai,br,bi,result,eps->comparisonctx);
    1270:   return(0);
    1271: }

    1275: /*@
    1276:    EPSGetStartVector - Gets a suitable vector to be used as the starting vector
    1277:    for the recurrence that builds the right subspace.

    1279:    Collective on EPS and Vec

    1281:    Input Parameters:
    1282: +  eps - the eigensolver context
    1283: -  i   - iteration number

    1285:    Output Parameters:
    1286: +  vec - the start vector
    1287: -  breakdown - flag indicating that a breakdown has occurred

    1289:    Notes:
    1290:    The start vector is computed from another vector: for the first step (i=0),
    1291:    the first initial vector is used (see EPSSetInitialSpace()); otherwise a random
    1292:    vector is created. Then this vector is forced to be in the range of OP (only
    1293:    for generalized definite problems) and orthonormalized with respect to all
    1294:    V-vectors up to i-1.

    1296:    The flag breakdown is set to true if either i=0 and the vector belongs to the
    1297:    deflation space, or i>0 and the vector is linearly dependent with respect
    1298:    to the V-vectors.

    1300:    The caller must pass a vector already allocated with dimensions conforming
    1301:    to the initial vector. This vector is overwritten.

    1303:    Level: developer

    1305: .seealso: EPSSetInitialSpace()
    1306: @*/
    1307: PetscErrorCode EPSGetStartVector(EPS eps,PetscInt i,Vec vec,PetscBool *breakdown)
    1308: {
    1310:   PetscReal      norm;
    1311:   PetscBool      lindep;
    1312:   Vec            w;

    1320:   VecDuplicate(eps->V[0],&w);

    1322:   /* For the first step, use the first initial vector, otherwise a random one */
    1323:   if (i==0 && eps->nini>0) {
    1324:     VecCopy(eps->V[0],w);
    1325:   } else {
    1326:     SlepcVecSetRandom(w,eps->rand);
    1327:   }

    1329:   /* Force the vector to be in the range of OP for definite generalized problems */
    1330:   if (eps->ispositive || (eps->isgeneralized && eps->ishermitian)) {
    1331:     STApply(eps->st,w,vec);
    1332:   } else {
    1333:     VecCopy(w,vec);
    1334:   }

    1336:   /* Orthonormalize the vector with respect to previous vectors */
    1337:   IPOrthogonalize(eps->ip,eps->nds,eps->defl,i,NULL,eps->V,vec,NULL,&norm,&lindep);
    1338:   if (breakdown) *breakdown = lindep;
    1339:   else if (lindep || norm == 0.0) {
    1340:     if (i==0) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Initial vector is zero or belongs to the deflation space");
    1341:     else SETERRQ(PetscObjectComm((PetscObject)eps),1,"Unable to generate more start vectors");
    1342:   }
    1343:   VecScale(vec,1.0/norm);

    1345:   VecDestroy(&w);
    1346:   return(0);
    1347: }

    1351: /*@
    1352:    EPSGetStartVectorLeft - Gets a suitable vector to be used as the starting vector
    1353:    in the recurrence that builds the left subspace (in methods that work with two
    1354:    subspaces).

    1356:    Collective on EPS and Vec

    1358:    Input Parameters:
    1359: +  eps - the eigensolver context
    1360: -  i   - iteration number

    1362:    Output Parameter:
    1363: +  vec - the start vector
    1364: -  breakdown - flag indicating that a breakdown has occurred

    1366:    Notes:
    1367:    The start vector is computed from another vector: for the first step (i=0),
    1368:    the first left initial vector is used (see EPSSetInitialSpaceLeft()); otherwise
    1369:    a random vector is created. Then this vector is forced to be in the range
    1370:    of OP' and orthonormalized with respect to all W-vectors up to i-1.

    1372:    The flag breakdown is set to true if i>0 and the vector is linearly dependent
    1373:    with respect to the W-vectors.

    1375:    The caller must pass a vector already allocated with dimensions conforming
    1376:    to the left initial vector. This vector is overwritten.

    1378:    Level: developer

    1380: .seealso: EPSSetInitialSpaceLeft()
    1381: @*/
    1382: PetscErrorCode EPSGetStartVectorLeft(EPS eps,PetscInt i,Vec vec,PetscBool *breakdown)
    1383: {
    1385:   PetscReal      norm;
    1386:   PetscBool      lindep;
    1387:   Vec            w;

    1395:   VecDuplicate(eps->W[0],&w);

    1397:   /* For the first step, use the first initial left vector, otherwise a random one */
    1398:   if (i==0 && eps->ninil>0) {
    1399:     VecCopy(eps->W[0],w);
    1400:   } else {
    1401:     SlepcVecSetRandom(w,eps->rand);
    1402:   }

    1404:   /* Force the vector to be in the range of OP' */
    1405:   STApplyTranspose(eps->st,w,vec);

    1407:   /* Orthonormalize the vector with respect to previous vectors */
    1408:   IPOrthogonalize(eps->ip,0,NULL,i,NULL,eps->W,vec,NULL,&norm,&lindep);
    1409:   if (breakdown) *breakdown = lindep;
    1410:   else if (lindep || norm == 0.0) {
    1411:     if (i==0) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Left initial vector is zero");
    1412:     else SETERRQ(PetscObjectComm((PetscObject)eps),1,"Unable to generate more left start vectors");
    1413:   }
    1414:   VecScale(vec,1/norm);

    1416:   VecDestroy(&w);
    1417:   return(0);
    1418: }