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