Actual source code: pepsolve.c

slepc-3.7.3 2016-09-29
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:     if (pep->ops->extractvectors) {
 72:       (*pep->ops->extractvectors)(pep);
 73:     }
 74:     break;
 75:   default:
 76:     break;
 77:   }
 78:   return(0);
 79: }

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

 86:    Collective on PEP

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

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

102:    Level: beginner

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

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

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

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

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

146:   pep->state = PEP_STATE_SOLVED;

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

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

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

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

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

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

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

200:    Not Collective

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

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

208:    Level: intermediate

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

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

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

233:    Not Collective

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

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

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

244:    Level: beginner

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

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

264:    Not Collective

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

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

272:    Notes:

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

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

283:    Level: intermediate

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

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

303:    Logically Collective on EPS

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

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

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

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

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

329:    Level: beginner

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

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

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

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

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

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

386:    Not Collective

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

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

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

400:    Level: advanced

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

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

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

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

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

507:    Collective on PEP

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

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

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

522:    Level: beginner

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

540:   PEPCheckSolved(pep,1);

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

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

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