Date: 2017-05-17T08:26:49+00:00

Actual source code: pepsolve.c
slepc-3.7.4 2017-05-17
Report Typos and Errors

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

      4:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      5:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      6:    Copyright (c) 2002-2016, 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/pepimpl.h>       /*I "slepcpep.h" I*/
     25: #include <petscdraw.h>

     27: static PetscBool  cited = PETSC_FALSE;
     28: static const char citation[] =
     29:   "@Article{slepc-pep-refine,\n"
     30:   "   author = \"C. Campos and J. E. Roman\",\n"
     31:   "   title = \"Parallel iterative refinement in polynomial eigenvalue problems\",\n"
     32:   "   journal = \"Numer. Linear Algebra Appl.\",\n"
     33:   "   volume = \"to appear\",\n"
     34:   "   number = \"\",\n"
     35:   "   pages = \"\",\n"
     36:   "   year = \"2016,\"\n"
     37:   "   doi = \"http://dx.doi.org/10.1002/nla.2052\"\n"
     38:   "}\n";

     42: PetscErrorCode PEPComputeVectors(PEP pep)
     43: {

     47:   PEPCheckSolved(pep,1);
     48:   switch (pep->state) {
     49:   case PEP_STATE_SOLVED:
     50:     if (pep->ops->computevectors) {
     51:       (*pep->ops->computevectors)(pep);
     52:     }
     53:     break;
     54:   default:
     55:     break;
     56:   }
     57:   pep->state = PEP_STATE_EIGENVECTORS;
     58:   return(0);
     59: }

     63: PetscErrorCode PEPExtractVectors(PEP pep)
     64: {

     68:   PEPCheckSolved(pep,1);
     69:   switch (pep->state) {
     70:   case PEP_STATE_SOLVED:
     71:     BVSetActiveColumns(pep->V,0,pep->nconv);
     72:     if (pep->ops->extractvectors) {
     73:       (*pep->ops->extractvectors)(pep);
     74:     }
     75:     break;
     76:   default:
     77:     break;
     78:   }
     79:   return(0);
     80: }

     84: /*@
     85:    PEPSolve - Solves the polynomial eigensystem.

     87:    Collective on PEP

     89:    Input Parameter:
     90: .  pep - eigensolver context obtained from PEPCreate()

     92:    Options Database Keys:
     93: +  -pep_view - print information about the solver used
     94: .  -pep_view_matk binary - save any of the coefficient matrices (Ak) to the
     95:                 default binary viewer (replace k by an integer from 0 to nmat-1)
     96: .  -pep_view_vectors binary - save the computed eigenvectors to the default binary viewer
     97: .  -pep_view_values - print computed eigenvalues
     98: .  -pep_converged_reason - print reason for convergence, and number of iterations
     99: .  -pep_error_absolute - print absolute errors of each eigenpair
    100: .  -pep_error_relative - print relative errors of each eigenpair
    101: -  -pep_error_backward - print backward errors of each eigenpair

    103:    Level: beginner

    105: .seealso: PEPCreate(), PEPSetUp(), PEPDestroy(), PEPSetTolerances()
    106: @*/
    107: PetscErrorCode PEPSolve(PEP pep)
    108: {
    110:   PetscInt       i,k;
    111:   PetscBool      flg,islinear;
    112: #define OPTLEN 16
    113:   char           str[OPTLEN];

    117:   if (pep->state>=PEP_STATE_SOLVED) return(0);
    118:   PetscLogEventBegin(PEP_Solve,pep,0,0,0);

    120:   /* call setup */
    121:   PEPSetUp(pep);
    122:   pep->nconv = 0;
    123:   pep->its   = 0;
    124:   k = pep->lineariz? pep->ncv: pep->ncv*(pep->nmat-1);
    125:   for (i=0;i<k;i++) {
    126:     pep->eigr[i]   = 0.0;
    127:     pep->eigi[i]   = 0.0;
    128:     pep->errest[i] = 0.0;
    129:     pep->perm[i]   = i;
    130:   }
    131:   PEPViewFromOptions(pep,NULL,"-pep_view_pre");

    133:   (*pep->ops->solve)(pep);
    134:
    135:   if (!pep->reason) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_PLIB,"Internal error, solver returned without setting converged reason");

    137:   PetscObjectTypeCompare((PetscObject)pep,PEPLINEAR,&islinear);
    138:   if (!islinear) {
    139:     STPostSolve(pep->st);
    140:     /* Map eigenvalues back to the original problem */
    141:     STGetTransform(pep->st,&flg);
    142:     if (flg && pep->ops->backtransform) {
    143:       (*pep->ops->backtransform)(pep);
    144:     }
    145:   }

    147:   pep->state = PEP_STATE_SOLVED;

    149: #if !defined(PETSC_USE_COMPLEX)
    150:   /* reorder conjugate eigenvalues (positive imaginary first) */
    151:   for (i=0;i<pep->nconv-1;i++) {
    152:     if (pep->eigi[i] != 0) {
    153:       if (pep->eigi[i] < 0) {
    154:         pep->eigi[i] = -pep->eigi[i];
    155:         pep->eigi[i+1] = -pep->eigi[i+1];
    156:         /* the next correction only works with eigenvectors */
    157:         PEPComputeVectors(pep);
    158:         BVScaleColumn(pep->V,i+1,-1.0);
    159:       }
    160:       i++;
    161:     }
    162:   }
    163: #endif

    165:   if (pep->refine!=PEP_REFINE_NONE) {
    166:     PetscCitationsRegister(citation,&cited);
    167:   }

    169:   if (pep->refine==PEP_REFINE_SIMPLE && pep->rits>0 && pep->nconv>0) {
    170:     PEPComputeVectors(pep);
    171:     PEPNewtonRefinementSimple(pep,&pep->rits,pep->rtol,pep->nconv);
    172:   }

    174:   /* sort eigenvalues according to pep->which parameter */
    175:   SlepcSortEigenvalues(pep->sc,pep->nconv,pep->eigr,pep->eigi,pep->perm);
    176:   PetscLogEventEnd(PEP_Solve,pep,0,0,0);

    178:   /* various viewers */
    179:   PEPViewFromOptions(pep,NULL,"-pep_view");
    180:   PEPReasonViewFromOptions(pep);
    181:   PEPErrorViewFromOptions(pep);
    182:   PEPValuesViewFromOptions(pep);
    183:   PEPVectorsViewFromOptions(pep);
    184:   for (i=0;i<pep->nmat;i++) {
    185:     PetscSNPrintf(str,OPTLEN,"-pep_view_mat%d",(int)i);
    186:     MatViewFromOptions(pep->A[i],(PetscObject)pep,str);
    187:   }

    189:   /* Remove the initial subspace */
    190:   pep->nini = 0;
    191:   return(0);
    192: }

    196: /*@
    197:    PEPGetIterationNumber - Gets the current iteration number. If the
    198:    call to PEPSolve() is complete, then it returns the number of iterations
    199:    carried out by the solution method.

    201:    Not Collective

    203:    Input Parameter:
    204: .  pep - the polynomial eigensolver context

    206:    Output Parameter:
    207: .  its - number of iterations

    209:    Level: intermediate

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

    218: .seealso: PEPGetConvergedReason(), PEPSetTolerances()
    219: @*/
    220: PetscErrorCode PEPGetIterationNumber(PEP pep,PetscInt *its)
    221: {
    225:   *its = pep->its;
    226:   return(0);
    227: }

    231: /*@
    232:    PEPGetConverged - Gets the number of converged eigenpairs.

    234:    Not Collective

    236:    Input Parameter:
    237: .  pep - the polynomial eigensolver context

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

    242:    Note:
    243:    This function should be called after PEPSolve() has finished.

    245:    Level: beginner

    247: .seealso: PEPSetDimensions(), PEPSolve()
    248: @*/
    249: PetscErrorCode PEPGetConverged(PEP pep,PetscInt *nconv)
    250: {
    254:   PEPCheckSolved(pep,1);
    255:   *nconv = pep->nconv;
    256:   return(0);
    257: }

    261: /*@
    262:    PEPGetConvergedReason - Gets the reason why the PEPSolve() iteration was
    263:    stopped.

    265:    Not Collective

    267:    Input Parameter:
    268: .  pep - the polynomial eigensolver context

    270:    Output Parameter:
    271: .  reason - negative value indicates diverged, positive value converged

    273:    Notes:

    275:    Possible values for reason are
    276: +  PEP_CONVERGED_TOL - converged up to tolerance
    277: .  PEP_CONVERGED_USER - converged due to a user-defined condition
    278: .  PEP_DIVERGED_ITS - required more than max_it iterations to reach convergence
    279: .  PEP_DIVERGED_BREAKDOWN - generic breakdown in method
    280: -  PEP_DIVERGED_SYMMETRY_LOST - pseudo-Lanczos was not able to keep symmetry

    282:    Can only be called after the call to PEPSolve() is complete.

    284:    Level: intermediate

    286: .seealso: PEPSetTolerances(), PEPSolve(), PEPConvergedReason
    287: @*/
    288: PetscErrorCode PEPGetConvergedReason(PEP pep,PEPConvergedReason *reason)
    289: {
    293:   PEPCheckSolved(pep,1);
    294:   *reason = pep->reason;
    295:   return(0);
    296: }

    300: /*@
    301:    PEPGetEigenpair - Gets the i-th solution of the eigenproblem as computed by
    302:    PEPSolve(). The solution consists in both the eigenvalue and the eigenvector.

    304:    Logically Collective on EPS

    306:    Input Parameters:
    307: +  pep - polynomial eigensolver context
    308: -  i   - index of the solution

    310:    Output Parameters:
    311: +  eigr - real part of eigenvalue
    312: .  eigi - imaginary part of eigenvalue
    313: .  Vr   - real part of eigenvector
    314: -  Vi   - imaginary part of eigenvector

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

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

    326:    The index i should be a value between 0 and nconv-1 (see PEPGetConverged()).
    327:    Eigenpairs are indexed according to the ordering criterion established
    328:    with PEPSetWhichEigenpairs().

    330:    Level: beginner

    332: .seealso: PEPSolve(), PEPGetConverged(), PEPSetWhichEigenpairs()
    333: @*/
    334: PetscErrorCode PEPGetEigenpair(PEP pep,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)
    335: {
    336:   PetscInt       k;

    344:   PEPCheckSolved(pep,1);
    345:   if (i<0 || i>=pep->nconv) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");

    347:   PEPComputeVectors(pep);
    348:   k = pep->perm[i];

    350:   /* eigenvalue */
    351: #if defined(PETSC_USE_COMPLEX)
    352:   if (eigr) *eigr = pep->eigr[k];
    353:   if (eigi) *eigi = 0;
    354: #else
    355:   if (eigr) *eigr = pep->eigr[k];
    356:   if (eigi) *eigi = pep->eigi[k];
    357: #endif

    359:   /* eigenvector */
    360: #if defined(PETSC_USE_COMPLEX)
    361:   if (Vr) { BVCopyVec(pep->V,k,Vr); }
    362:   if (Vi) { VecSet(Vi,0.0); }
    363: #else
    364:   if (pep->eigi[k]>0) { /* first value of conjugate pair */
    365:     if (Vr) { BVCopyVec(pep->V,k,Vr); }
    366:     if (Vi) { BVCopyVec(pep->V,k+1,Vi); }
    367:   } else if (pep->eigi[k]<0) { /* second value of conjugate pair */
    368:     if (Vr) { BVCopyVec(pep->V,k-1,Vr); }
    369:     if (Vi) {
    370:       BVCopyVec(pep->V,k,Vi);
    371:       VecScale(Vi,-1.0);
    372:     }
    373:   } else { /* real eigenvalue */
    374:     if (Vr) { BVCopyVec(pep->V,k,Vr); }
    375:     if (Vi) { VecSet(Vi,0.0); }
    376:   }
    377: #endif
    378:   return(0);
    379: }

    383: /*@
    384:    PEPGetErrorEstimate - Returns the error estimate associated to the i-th
    385:    computed eigenpair.

    387:    Not Collective

    389:    Input Parameter:
    390: +  pep - polynomial eigensolver context
    391: -  i   - index of eigenpair

    393:    Output Parameter:
    394: .  errest - the error estimate

    396:    Notes:
    397:    This is the error estimate used internally by the eigensolver. The actual
    398:    error bound can be computed with PEPComputeError(). See also the users
    399:    manual for details.

    401:    Level: advanced

    403: .seealso: PEPComputeError()
    404: @*/
    405: PetscErrorCode PEPGetErrorEstimate(PEP pep,PetscInt i,PetscReal *errest)
    406: {
    410:   PEPCheckSolved(pep,1);
    411:   if (i<0 || i>=pep->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
    412:   if (errest) *errest = pep->errest[pep->perm[i]];
    413:   return(0);
    414: }

    418: /*
    419:    PEPComputeResidualNorm_Private - Computes the norm of the residual vector
    420:    associated with an eigenpair.

    422:    Input Parameters:
    423:      kr,ki - eigenvalue
    424:      xr,xi - eigenvector
    425:      z     - array of 4 work vectors (z[2],z[3] not referenced in complex scalars)
    426: */
    427: PetscErrorCode PEPComputeResidualNorm_Private(PEP pep,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,Vec *z,PetscReal *norm)
    428: {
    430:   Mat            *A=pep->A;
    431:   PetscInt       i,nmat=pep->nmat;
    432:   PetscScalar    t[20],*vals=t,*ivals=NULL;
    433:   Vec            u,w;
    434: #if !defined(PETSC_USE_COMPLEX)
    435:   Vec            ui,wi;
    436:   PetscReal      ni;
    437:   PetscBool      imag;
    438:   PetscScalar    it[20];
    439: #endif

    442:   u = z[0]; w = z[1];
    443:   VecSet(u,0.0);
    444: #if !defined(PETSC_USE_COMPLEX)
    445:   ui = z[2]; wi = z[3];
    446:   ivals = it;
    447: #endif
    448:   if (nmat>20) {
    449:     PetscMalloc1(nmat,&vals);
    450: #if !defined(PETSC_USE_COMPLEX)
    451:     PetscMalloc1(nmat,&ivals);
    452: #endif
    453:   }
    454:   PEPEvaluateBasis(pep,kr,ki,vals,ivals);
    455: #if !defined(PETSC_USE_COMPLEX)
    456:   if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON))
    457:     imag = PETSC_FALSE;
    458:   else {
    459:     imag = PETSC_TRUE;
    460:     VecSet(ui,0.0);
    461:   }
    462: #endif
    463:   for (i=0;i<nmat;i++) {
    464:     if (vals[i]!=0.0) {
    465:       MatMult(A[i],xr,w);
    466:       VecAXPY(u,vals[i],w);
    467:     }
    468: #if !defined(PETSC_USE_COMPLEX)
    469:     if (imag) {
    470:       if (ivals[i]!=0 || vals[i]!=0) {
    471:         MatMult(A[i],xi,wi);
    472:         if (vals[i]==0) {
    473:           MatMult(A[i],xr,w);
    474:         }
    475:       }
    476:       if (ivals[i]!=0){
    477:         VecAXPY(u,-ivals[i],wi);
    478:         VecAXPY(ui,ivals[i],w);
    479:       }
    480:       if (vals[i]!=0) {
    481:         VecAXPY(ui,vals[i],wi);
    482:       }
    483:     }
    484: #endif
    485:   }
    486:   VecNorm(u,NORM_2,norm);
    487: #if !defined(PETSC_USE_COMPLEX)
    488:   if (imag) {
    489:     VecNorm(ui,NORM_2,&ni);
    490:     *norm = SlepcAbsEigenvalue(*norm,ni);
    491:   }
    492: #endif
    493:   if (nmat>20) {
    494:     PetscFree(vals);
    495: #if !defined(PETSC_USE_COMPLEX)
    496:     PetscFree(ivals);
    497: #endif
    498:   }
    499:   return(0);
    500: }

    504: /*@
    505:    PEPComputeError - Computes the error (based on the residual norm) associated
    506:    with the i-th computed eigenpair.

    508:    Collective on PEP

    510:    Input Parameter:
    511: +  pep  - the polynomial eigensolver context
    512: .  i    - the solution index
    513: -  type - the type of error to compute

    515:    Output Parameter:
    516: .  error - the error

    518:    Notes:
    519:    The error can be computed in various ways, all of them based on the residual
    520:    norm ||P(l)x||_2 where l is the eigenvalue and x is the eigenvector.
    521:    See the users guide for additional details.

    523:    Level: beginner

    525: .seealso: PEPErrorType, PEPSolve(), PEPGetErrorEstimate()
    526: @*/
    527: PetscErrorCode PEPComputeError(PEP pep,PetscInt i,PEPErrorType type,PetscReal *error)
    528: {
    530:   Vec            xr,xi,w[4];
    531:   PetscScalar    kr,ki;
    532:   PetscReal      t,z=0.0;
    533:   PetscInt       j;
    534:   PetscBool      flg;

    541:   PEPCheckSolved(pep,1);

    543:   /* allocate work vectors */
    544: #if defined(PETSC_USE_COMPLEX)
    545:   PEPSetWorkVecs(pep,3);
    546:   xi   = NULL;
    547:   w[2] = NULL;
    548:   w[3] = NULL;
    549: #else
    550:   PEPSetWorkVecs(pep,6);
    551:   xi   = pep->work[3];
    552:   w[2] = pep->work[4];
    553:   w[3] = pep->work[5];
    554: #endif
    555:   xr   = pep->work[0];
    556:   w[0] = pep->work[1];
    557:   w[1] = pep->work[2];

    559:   /* compute residual norms */
    560:   PEPGetEigenpair(pep,i,&kr,&ki,xr,xi);
    561:   PEPComputeResidualNorm_Private(pep,kr,ki,xr,xi,w,error);

    563:   /* compute error */
    564:   switch (type) {
    565:     case PEP_ERROR_ABSOLUTE:
    566:       break;
    567:     case PEP_ERROR_RELATIVE:
    568:       *error /= SlepcAbsEigenvalue(kr,ki);
    569:       break;
    570:     case PEP_ERROR_BACKWARD:
    571:       /* initialization of matrix norms */
    572:       if (!pep->nrma[pep->nmat-1]) {
    573:         for (j=0;j<pep->nmat;j++) {
    574:           MatHasOperation(pep->A[j],MATOP_NORM,&flg);
    575:           if (!flg) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_WRONG,"The computation of backward errors requires a matrix norm operation");
    576:           MatNorm(pep->A[j],NORM_INFINITY,&pep->nrma[j]);
    577:         }
    578:       }
    579:       t = SlepcAbsEigenvalue(kr,ki);
    580:       for (j=pep->nmat-1;j>=0;j--) {
    581:         z = z*t+pep->nrma[j];
    582:       }
    583:       *error /= z;
    584:       break;
    585:     default:
    586:       SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_OUTOFRANGE,"Invalid error type");
    587:   }
    588:   return(0);
    589: }