Date: 2015-09-03T15:05:33+00:00

Actual source code: pepsolve.c
slepc-3.6.1 2015-09-03
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-2015, 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>

     29: PetscErrorCode PEPComputeVectors(PEP pep)
     30: {

     34:   PEPCheckSolved(pep,1);
     35:   switch (pep->state) {
     36:   case PEP_STATE_SOLVED:
     37:     if (pep->ops->computevectors) {
     38:       (*pep->ops->computevectors)(pep);
     39:     }
     40:     break;
     41:   default:
     42:     break;
     43:   }
     44:   pep->state = PEP_STATE_EIGENVECTORS;
     45:   return(0);
     46: }

     50: PetscErrorCode PEPExtractVectors(PEP pep)
     51: {

     55:   PEPCheckSolved(pep,1);
     56:   switch (pep->state) {
     57:   case PEP_STATE_SOLVED:
     58:     if (pep->ops->extractvectors) {
     59:       (*pep->ops->extractvectors)(pep);
     60:     }
     61:     break;
     62:   default:
     63:     break;
     64:   }
     65:   return(0);
     66: }

     70: /*@
     71:    PEPSolve - Solves the polynomial eigensystem.

     73:    Collective on PEP

     75:    Input Parameter:
     76: .  pep - eigensolver context obtained from PEPCreate()

     78:    Options Database Keys:
     79: +  -pep_view - print information about the solver used
     80: .  -pep_view_matk binary - save any of the coefficient matrices (Ak) to the
     81:                 default binary viewer (replace k by an integer from 0 to nmat-1)
     82: .  -pep_view_vectors binary - save the computed eigenvectors to the default binary viewer
     83: .  -pep_view_values - print computed eigenvalues
     84: .  -pep_converged_reason - print reason for convergence, and number of iterations
     85: .  -pep_error_absolute - print absolute errors of each eigenpair
     86: .  -pep_error_relative - print relative errors of each eigenpair
     87: -  -pep_error_backward - print backward errors of each eigenpair

     89:    Level: beginner

     91: .seealso: PEPCreate(), PEPSetUp(), PEPDestroy(), PEPSetTolerances()
     92: @*/
     93: PetscErrorCode PEPSolve(PEP pep)
     94: {
     96:   PetscInt       i,k;
     97:   PetscBool      flg,islinear;
     98: #define OPTLEN 16
     99:   char           str[OPTLEN];

    103:   PetscLogEventBegin(PEP_Solve,pep,0,0,0);

    105:   /* call setup */
    106:   PEPSetUp(pep);
    107:   pep->nconv = 0;
    108:   pep->its   = 0;
    109:   k = pep->lineariz? pep->ncv: pep->ncv*(pep->nmat-1);
    110:   for (i=0;i<k;i++) {
    111:     pep->eigr[i]   = 0.0;
    112:     pep->eigi[i]   = 0.0;
    113:     pep->errest[i] = 0.0;
    114:     pep->perm[i]   = i;
    115:   }
    116:   PEPMonitor(pep,pep->its,pep->nconv,pep->eigr,pep->eigi,pep->errest,k);
    117:   PEPViewFromOptions(pep,NULL,"-pep_view_pre");

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

    123:   PetscObjectTypeCompare((PetscObject)pep,PEPLINEAR,&islinear);
    124:   if (!islinear) {
    125:     STPostSolve(pep->st);
    126:     /* Map eigenvalues back to the original problem */
    127:     STGetTransform(pep->st,&flg);
    128:     if (flg && pep->ops->backtransform) {
    129:       (*pep->ops->backtransform)(pep);
    130:     }
    131:   }

    133:   pep->state = PEP_STATE_SOLVED;

    135:   if (pep->refine==PEP_REFINE_SIMPLE && pep->rits>0) {
    136:     PEPComputeVectors(pep);
    137:     PEPNewtonRefinementSimple(pep,&pep->rits,&pep->rtol,pep->nconv);
    138:   }

    140: #if !defined(PETSC_USE_COMPLEX)
    141:   /* reorder conjugate eigenvalues (positive imaginary first) */
    142:   for (i=0;i<pep->nconv-1;i++) {
    143:     if (pep->eigi[i] != 0) {
    144:       if (pep->eigi[i] < 0) {
    145:         pep->eigi[i] = -pep->eigi[i];
    146:         pep->eigi[i+1] = -pep->eigi[i+1];
    147:         /* the next correction only works with eigenvectors */
    148:         PEPComputeVectors(pep);
    149:         BVScaleColumn(pep->V,i+1,-1.0);
    150:       }
    151:       i++;
    152:     }
    153:   }
    154: #endif

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

    160:   /* various viewers */
    161:   PEPViewFromOptions(pep,NULL,"-pep_view");
    162:   PEPReasonViewFromOptions(pep);
    163:   PEPErrorViewFromOptions(pep);
    164:   PEPValuesViewFromOptions(pep);
    165:   PEPVectorsViewFromOptions(pep);
    166:   for (i=0;i<pep->nmat;i++) {
    167:     PetscSNPrintf(str,OPTLEN,"-pep_view_mat%d",(int)i);
    168:     MatViewFromOptions(pep->A[i],(PetscObject)pep,str);
    169:   }

    171:   /* Remove the initial subspace */
    172:   pep->nini = 0;
    173:   return(0);
    174: }

    178: /*@
    179:    PEPGetIterationNumber - Gets the current iteration number. If the
    180:    call to PEPSolve() is complete, then it returns the number of iterations
    181:    carried out by the solution method.

    183:    Not Collective

    185:    Input Parameter:
    186: .  pep - the polynomial eigensolver context

    188:    Output Parameter:
    189: .  its - number of iterations

    191:    Level: intermediate

    193:    Note:
    194:    During the i-th iteration this call returns i-1. If PEPSolve() is
    195:    complete, then parameter "its" contains either the iteration number at
    196:    which convergence was successfully reached, or failure was detected.
    197:    Call PEPGetConvergedReason() to determine if the solver converged or
    198:    failed and why.

    200: .seealso: PEPGetConvergedReason(), PEPSetTolerances()
    201: @*/
    202: PetscErrorCode PEPGetIterationNumber(PEP pep,PetscInt *its)
    203: {
    207:   *its = pep->its;
    208:   return(0);
    209: }

    213: /*@
    214:    PEPGetConverged - Gets the number of converged eigenpairs.

    216:    Not Collective

    218:    Input Parameter:
    219: .  pep - the polynomial eigensolver context

    221:    Output Parameter:
    222: .  nconv - number of converged eigenpairs

    224:    Note:
    225:    This function should be called after PEPSolve() has finished.

    227:    Level: beginner

    229: .seealso: PEPSetDimensions(), PEPSolve()
    230: @*/
    231: PetscErrorCode PEPGetConverged(PEP pep,PetscInt *nconv)
    232: {
    236:   PEPCheckSolved(pep,1);
    237:   *nconv = pep->nconv;
    238:   return(0);
    239: }

    243: /*@
    244:    PEPGetConvergedReason - Gets the reason why the PEPSolve() iteration was
    245:    stopped.

    247:    Not Collective

    249:    Input Parameter:
    250: .  pep - the polynomial eigensolver context

    252:    Output Parameter:
    253: .  reason - negative value indicates diverged, positive value converged

    255:    Possible values for reason:
    256: +  PEP_CONVERGED_TOL - converged up to tolerance
    257: .  PEP_DIVERGED_ITS - required more than its to reach convergence
    258: .  PEP_DIVERGED_BREAKDOWN - generic breakdown in method
    259: -  PEP_DIVERGED_SYMMETRY_LOST - pseudo-Lanczos was not able to keep symmetry

    261:    Note:
    262:    Can only be called after the call to PEPSolve() is complete.

    264:    Level: intermediate

    266: .seealso: PEPSetTolerances(), PEPSolve(), PEPConvergedReason
    267: @*/
    268: PetscErrorCode PEPGetConvergedReason(PEP pep,PEPConvergedReason *reason)
    269: {
    273:   PEPCheckSolved(pep,1);
    274:   *reason = pep->reason;
    275:   return(0);
    276: }

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

    284:    Logically Collective on EPS

    286:    Input Parameters:
    287: +  pep - polynomial eigensolver context
    288: -  i   - index of the solution

    290:    Output Parameters:
    291: +  eigr - real part of eigenvalue
    292: .  eigi - imaginary part of eigenvalue
    293: .  Vr   - real part of eigenvector
    294: -  Vi   - imaginary part of eigenvector

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

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

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

    310:    Level: beginner

    312: .seealso: PEPSolve(), PEPGetConverged(), PEPSetWhichEigenpairs()
    313: @*/
    314: PetscErrorCode PEPGetEigenpair(PEP pep,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)
    315: {
    316:   PetscInt       k;

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

    327:   PEPComputeVectors(pep);
    328:   k = pep->perm[i];

    330:   /* eigenvalue */
    331: #if defined(PETSC_USE_COMPLEX)
    332:   if (eigr) *eigr = pep->eigr[k];
    333:   if (eigi) *eigi = 0;
    334: #else
    335:   if (eigr) *eigr = pep->eigr[k];
    336:   if (eigi) *eigi = pep->eigi[k];
    337: #endif

    339:   /* eigenvector */
    340: #if defined(PETSC_USE_COMPLEX)
    341:   if (Vr) { BVCopyVec(pep->V,k,Vr); }
    342:   if (Vi) { VecSet(Vi,0.0); }
    343: #else
    344:   if (pep->eigi[k]>0) { /* first value of conjugate pair */
    345:     if (Vr) { BVCopyVec(pep->V,k,Vr); }
    346:     if (Vi) { BVCopyVec(pep->V,k+1,Vi); }
    347:   } else if (pep->eigi[k]<0) { /* second value of conjugate pair */
    348:     if (Vr) { BVCopyVec(pep->V,k-1,Vr); }
    349:     if (Vi) {
    350:       BVCopyVec(pep->V,k,Vi);
    351:       VecScale(Vi,-1.0);
    352:     }
    353:   } else { /* real eigenvalue */
    354:     if (Vr) { BVCopyVec(pep->V,k,Vr); }
    355:     if (Vi) { VecSet(Vi,0.0); }
    356:   }
    357: #endif
    358:   return(0);
    359: }

    363: /*@
    364:    PEPGetErrorEstimate - Returns the error estimate associated to the i-th
    365:    computed eigenpair.

    367:    Not Collective

    369:    Input Parameter:
    370: +  pep - polynomial eigensolver context
    371: -  i   - index of eigenpair

    373:    Output Parameter:
    374: .  errest - the error estimate

    376:    Notes:
    377:    This is the error estimate used internally by the eigensolver. The actual
    378:    error bound can be computed with PEPComputeError(). See also the users
    379:    manual for details.

    381:    Level: advanced

    383: .seealso: PEPComputeError()
    384: @*/
    385: PetscErrorCode PEPGetErrorEstimate(PEP pep,PetscInt i,PetscReal *errest)
    386: {
    390:   PEPCheckSolved(pep,1);
    391:   if (i<0 || i>=pep->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
    392:   if (errest) *errest = pep->errest[pep->perm[i]];
    393:   return(0);
    394: }

    398: /*
    399:    PEPComputeResidualNorm_Private - Computes the norm of the residual vector
    400:    associated with an eigenpair.

    402:    Input Parameters:
    403:      kr,ki - eigenvalue
    404:      xr,xi - eigenvector
    405:      z     - array of 4 work vectors (z[2],z[3] not referenced in complex scalars)
    406: */
    407: PetscErrorCode PEPComputeResidualNorm_Private(PEP pep,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,Vec *z,PetscReal *norm)
    408: {
    410:   Mat            *A=pep->A;
    411:   PetscInt       i,nmat=pep->nmat;
    412:   PetscScalar    t[20],*vals=t,*ivals=NULL;
    413:   Vec            u,w;
    414: #if !defined(PETSC_USE_COMPLEX)
    415:   Vec            ui,wi;
    416:   PetscReal      ni;
    417:   PetscBool      imag;
    418:   PetscScalar    it[20];
    419: #endif

    422:   u = z[0]; w = z[1];
    423:   VecSet(u,0.0);
    424: #if !defined(PETSC_USE_COMPLEX)
    425:   ui = z[2]; wi = z[3];
    426:   ivals = it;
    427: #endif
    428:   if (nmat>20) {
    429:     PetscMalloc(nmat*sizeof(PetscScalar),&vals);
    430: #if !defined(PETSC_USE_COMPLEX)
    431:     PetscMalloc(nmat*sizeof(PetscScalar),&ivals);
    432: #endif
    433:   }
    434:   PEPEvaluateBasis(pep,kr,ki,vals,ivals);
    435: #if !defined(PETSC_USE_COMPLEX)
    436:   if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON))
    437:     imag = PETSC_FALSE;
    438:   else {
    439:     imag = PETSC_TRUE;
    440:     VecSet(ui,0.0);
    441:   }
    442: #endif
    443:   for (i=0;i<nmat;i++) {
    444:     if (vals[i]!=0.0) {
    445:       MatMult(A[i],xr,w);
    446:       VecAXPY(u,vals[i],w);
    447:     }
    448: #if !defined(PETSC_USE_COMPLEX)
    449:     if (imag) {
    450:       if (ivals[i]!=0 || vals[i]!=0) {
    451:         MatMult(A[i],xi,wi);
    452:         if (vals[i]==0) {
    453:           MatMult(A[i],xr,w);
    454:         }
    455:       }
    456:       if (ivals[i]!=0){
    457:         VecAXPY(u,-ivals[i],wi);
    458:         VecAXPY(ui,ivals[i],w);
    459:       }
    460:       if (vals[i]!=0) {
    461:         VecAXPY(ui,vals[i],wi);
    462:       }
    463:     }
    464: #endif
    465:   }
    466:   VecNorm(u,NORM_2,norm);
    467: #if !defined(PETSC_USE_COMPLEX)
    468:   if (imag) {
    469:     VecNorm(ui,NORM_2,&ni);
    470:     *norm = SlepcAbsEigenvalue(*norm,ni);
    471:   }
    472: #endif
    473:   if (nmat>20) {
    474:     PetscFree(vals);
    475: #if !defined(PETSC_USE_COMPLEX)
    476:     PetscFree(ivals);
    477: #endif
    478:   }
    479:   return(0);
    480: }

    484: /*@
    485:    PEPComputeError - Computes the error (based on the residual norm) associated
    486:    with the i-th computed eigenpair.

    488:    Collective on PEP

    490:    Input Parameter:
    491: +  pep  - the polynomial eigensolver context
    492: .  i    - the solution index
    493: -  type - the type of error to compute

    495:    Output Parameter:
    496: .  error - the error

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

    503:    Level: beginner

    505: .seealso: PEPErrorType, PEPSolve(), PEPGetErrorEstimate()
    506: @*/
    507: PetscErrorCode PEPComputeError(PEP pep,PetscInt i,PEPErrorType type,PetscReal *error)
    508: {
    510:   Vec            xr,xi,w[4];
    511:   PetscScalar    kr,ki;
    512:   PetscReal      t,z=0.0;
    513:   PetscInt       j;
    514:   PetscBool      flg;

    521:   PEPCheckSolved(pep,1);

    523:   /* allocate work vectors */
    524: #if defined(PETSC_USE_COMPLEX)
    525:   PEPSetWorkVecs(pep,3);
    526:   xi   = NULL;
    527:   w[2] = NULL;
    528:   w[3] = NULL;
    529: #else
    530:   PEPSetWorkVecs(pep,6);
    531:   xi   = pep->work[3];
    532:   w[2] = pep->work[4];
    533:   w[3] = pep->work[5];
    534: #endif
    535:   xr   = pep->work[0];
    536:   w[0] = pep->work[1];
    537:   w[1] = pep->work[2];

    539:   /* compute residual norms */
    540:   PEPGetEigenpair(pep,i,&kr,&ki,xr,xi);
    541:   PEPComputeResidualNorm_Private(pep,kr,ki,xr,xi,w,error);

    543:   /* compute error */
    544:   switch (type) {
    545:     case PEP_ERROR_ABSOLUTE:
    546:       break;
    547:     case PEP_ERROR_RELATIVE:
    548:       *error /= SlepcAbsEigenvalue(kr,ki);
    549:       break;
    550:     case PEP_ERROR_BACKWARD:
    551:       /* initialization of matrix norms */
    552:       if (!pep->nrma[pep->nmat-1]) {
    553:         for (j=0;j<pep->nmat;j++) {
    554:           MatHasOperation(pep->A[j],MATOP_NORM,&flg);
    555:           if (!flg) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_WRONG,"The computation of backward errors requires a matrix norm operation");
    556:           MatNorm(pep->A[j],NORM_INFINITY,&pep->nrma[j]);
    557:         }
    558:       }
    559:       t = SlepcAbsEigenvalue(kr,ki);
    560:       for (j=pep->nmat-1;j>=0;j--) {
    561:         z = z*t+pep->nrma[j];
    562:       }
    563:       *error /= z;
    564:       break;
    565:     default:
    566:       SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_OUTOFRANGE,"Invalid error type");
    567:   }
    568:   return(0);
    569: }