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: }