Actual source code: pepsolve.c

slepc-3.7.0 2016-05-16
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>

 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:   if (pep->state>=PEP_STATE_SOLVED) return(0);
104:   PetscLogEventBegin(PEP_Solve,pep,0,0,0);

106:   /* call setup */
107:   PEPSetUp(pep);
108:   pep->nconv = 0;
109:   pep->its   = 0;
110:   k = pep->lineariz? pep->ncv: pep->ncv*(pep->nmat-1);
111:   for (i=0;i<k;i++) {
112:     pep->eigr[i]   = 0.0;
113:     pep->eigi[i]   = 0.0;
114:     pep->errest[i] = 0.0;
115:     pep->perm[i]   = i;
116:   }
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 !defined(PETSC_USE_COMPLEX)
136:   /* reorder conjugate eigenvalues (positive imaginary first) */
137:   for (i=0;i<pep->nconv-1;i++) {
138:     if (pep->eigi[i] != 0) {
139:       if (pep->eigi[i] < 0) {
140:         pep->eigi[i] = -pep->eigi[i];
141:         pep->eigi[i+1] = -pep->eigi[i+1];
142:         /* the next correction only works with eigenvectors */
143:         PEPComputeVectors(pep);
144:         BVScaleColumn(pep->V,i+1,-1.0);
145:       }
146:       i++;
147:     }
148:   }
149: #endif

151:   if (pep->refine==PEP_REFINE_SIMPLE && pep->rits>0 && pep->nconv>0) {
152:     PEPComputeVectors(pep);
153:     PEPNewtonRefinementSimple(pep,&pep->rits,pep->rtol,pep->nconv);
154:   }

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_CONVERGED_USER - converged due to a user-defined condition
258: .  PEP_DIVERGED_ITS - required more than max_it iterations to reach convergence
259: .  PEP_DIVERGED_BREAKDOWN - generic breakdown in method
260: -  PEP_DIVERGED_SYMMETRY_LOST - pseudo-Lanczos was not able to keep symmetry

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

265:    Level: intermediate

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

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

285:    Logically Collective on EPS

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

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

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

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

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

311:    Level: beginner

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

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

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

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

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

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

368:    Not Collective

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

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

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

382:    Level: advanced

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

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

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

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

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

489:    Collective on PEP

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

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

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

504:    Level: beginner

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

522:   PEPCheckSolved(pep,1);

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

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

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