Actual source code: solve.c

  1: /*
  2:       EPS routines related to the solution process.

  4:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  5:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  6:    Copyright (c) 2002-2011, Universitat Politecnica de Valencia, Spain

  8:    This file is part of SLEPc.
  9:       
 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 <private/epsimpl.h>   /*I "slepceps.h" I*/

 26: typedef struct {
 27:   /* old values of eps */
 28:   EPSWhich old_which;
 29:   PetscErrorCode (*old_which_func)(EPS,PetscScalar,PetscScalar,PetscScalar,PetscScalar, PetscInt*,void*);
 30:   void *old_which_ctx;
 31: } EPSSortForSTData;

 35: PetscErrorCode EPSSortForSTFunc(EPS eps,PetscScalar ar,PetscScalar ai,
 36:                                 PetscScalar br,PetscScalar bi,PetscInt *r,void *ctx)
 37: {
 38:   EPSSortForSTData *data = (EPSSortForSTData*)ctx;
 39:   PetscErrorCode   ierr;

 42:   /* Back-transform the harmonic values */
 43:   STBackTransform(eps->OP,1,&ar,&ai);
 44:   STBackTransform(eps->OP,1,&br,&bi);

 46:   /* Compare values using the user options for the eigenpairs selection */
 47:   if (data->old_which==EPS_ALL) eps->which = EPS_TARGET_MAGNITUDE;
 48:   else eps->which = data->old_which;
 49:   eps->which_func = data->old_which_func;
 50:   eps->which_ctx = data->old_which_ctx;
 51:   EPSCompareEigenvalues(eps,ar,ai,br,bi,r);

 53:   /* Restore the eps values */
 54:   eps->which = EPS_WHICH_USER;
 55:   eps->which_func = EPSSortForSTFunc;
 56:   eps->which_ctx = data;
 57:   return(0);
 58: }

 62: /*@
 63:    EPSSolve - Solves the eigensystem.

 65:    Collective on EPS

 67:    Input Parameter:
 68: .  eps - eigensolver context obtained from EPSCreate()

 70:    Options Database:
 71: +   -eps_view - print information about the solver used
 72: .   -eps_view_binary - save the matrices to the default binary file
 73: -   -eps_plot_eigs - plot computed eigenvalues

 75:    Level: beginner

 77: .seealso: EPSCreate(), EPSSetUp(), EPSDestroy(), EPSSetTolerances() 
 78: @*/
 79: PetscErrorCode EPSSolve(EPS eps)
 80: {
 82:   PetscInt       i;
 83:   PetscReal      re,im;
 84:   PetscScalar    dot;
 85:   PetscBool      flg,isfold,iscayley,viewed=PETSC_FALSE;
 86:   PetscViewer    viewer;
 87:   PetscDraw      draw;
 88:   PetscDrawSP    drawsp;
 89:   STMatMode      matmode;
 90:   char           filename[PETSC_MAX_PATH_LEN];
 91:   char           view[10];
 92:   EPSSortForSTData data;
 93:   Mat            A,B;
 94:   KSP            ksp;
 95:   Vec            w,x;


100:   flg = PETSC_FALSE;
101:   PetscOptionsGetBool(((PetscObject)eps)->prefix,"-eps_view_binary",&flg,PETSC_NULL);
102:   if (flg) {
103:     STGetOperators(eps->OP,&A,&B);
104:     MatView(A,PETSC_VIEWER_BINARY_(((PetscObject)eps)->comm));
105:     if (B) MatView(B,PETSC_VIEWER_BINARY_(((PetscObject)eps)->comm));
106:   }

108:   PetscOptionsGetString(((PetscObject)eps)->prefix,"-eps_view",view,10,&flg);
109:   if (flg) {
110:     PetscStrcmp(view,"before",&viewed);
111:     if (viewed){
112:       PetscViewer viewer;
113:       PetscViewerASCIIGetStdout(((PetscObject)eps)->comm,&viewer);
114:       EPSView(eps,viewer);
115:     }
116:   }

118:   /* reset the convergence flag from the previous solves */
119:   eps->reason = EPS_CONVERGED_ITERATING;

121:   /* call setup */
122:   if (!eps->setupcalled) { EPSSetUp(eps); }
123:   eps->evecsavailable = PETSC_FALSE;
124:   eps->nconv = 0;
125:   eps->its = 0;
126:   for (i=0;i<eps->ncv;i++) eps->eigr[i]=eps->eigi[i]=eps->errest[i]=0.0;
127:   EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,eps->ncv);

129:   PetscLogEventBegin(EPS_Solve,eps,eps->V[0],eps->V[0],0);

131:   PetscTypeCompareAny((PetscObject)eps,&flg,EPSARPACK,EPSBLZPACK,EPSTRLAN,EPSBLOPEX,EPSPRIMME,"");
132:   if (!flg) {
133:     /* temporarily change which */
134:     data.old_which = eps->which;
135:     data.old_which_func = eps->which_func;
136:     data.old_which_ctx = eps->which_ctx;
137:     eps->which = EPS_WHICH_USER;
138:     eps->which_func = EPSSortForSTFunc;
139:     eps->which_ctx = &data;
140:   }

142:   /* call solver */
143:   (*eps->ops->solve)(eps);

145:   if (!flg) {
146:     /* restore which */
147:     eps->which = data.old_which;
148:     eps->which_func = data.old_which_func;
149:     eps->which_ctx = data.old_which_ctx;
150:   }

152:   STGetMatMode(eps->OP,&matmode);
153:   if (matmode == ST_MATMODE_INPLACE && eps->ispositive) {
154:     /* Purify eigenvectors before reverting operator */
155:     (*eps->ops->computevectors)(eps);
156:   }
157:   STPostSolve(eps->OP);
158:   PetscLogEventEnd(EPS_Solve,eps,eps->V[0],eps->V[0],0);

160:   if (!eps->reason) {
161:     SETERRQ(((PetscObject)eps)->comm,1,"Internal error, solver returned without setting converged reason");
162:   }

164:   /* Map eigenvalues back to the original problem, necessary in some 
165:   * spectral transformations */
166:   if (eps->ops->backtransform) {
167:     (*eps->ops->backtransform)(eps);
168:   }

170:   /* Adjust left eigenvectors in generalized problems: y = B^T y */
171:   if (eps->isgeneralized && eps->leftvecs) {
172:     STGetOperators(eps->OP,PETSC_NULL,&B);
173:     KSPCreate(((PetscObject)eps)->comm,&ksp);
174:     KSPSetOperators(ksp,B,B,DIFFERENT_NONZERO_PATTERN);
175:     KSPSetFromOptions(ksp);
176:     MatGetVecs(B,PETSC_NULL,&w);
177:     for (i=0;i<eps->nconv;i++) {
178:       VecCopy(eps->W[i],w);
179:       KSPSolveTranspose(ksp,w,eps->W[i]);
180:     }
181:     KSPDestroy(&ksp);
182:     VecDestroy(&w);
183:   }

185: #if !defined(PETSC_USE_COMPLEX)
186:   /* reorder conjugate eigenvalues (positive imaginary first) */
187:   for (i=0; i<eps->nconv-1; i++) {
188:     if (eps->eigi[i] != 0) {
189:       if (eps->eigi[i] < 0) {
190:         eps->eigi[i] = -eps->eigi[i];
191:         eps->eigi[i+1] = -eps->eigi[i+1];
192:         if (!eps->evecsavailable) {
193:           /* the next correction only works with eigenvectors */
194:           (*eps->ops->computevectors)(eps);
195:         }
196:         VecScale(eps->V[i+1],-1.0);
197:       }
198:       i++;
199:     }
200:   }
201: #endif

203:   /* quick and dirty solution for FOLD: recompute eigenvalues as Rayleigh quotients */
204:   PetscTypeCompare((PetscObject)eps->OP,STFOLD,&isfold);
205:   if (isfold) {
206:     STGetOperators(eps->OP,&A,&B);
207:     MatGetVecs(A,&w,PETSC_NULL);
208:     if (!eps->evecsavailable) { (*eps->ops->computevectors)(eps); }
209:     for (i=0;i<eps->nconv;i++) {
210:       x = eps->V[i];
211:       MatMult(A,x,w);
212:       VecDot(w,x,&eps->eigr[i]);
213:       if (eps->isgeneralized) {
214:         MatMult(B,x,w);
215:         VecDot(w,x,&dot);
216:         eps->eigr[i] /= dot;
217:       }
218:     }
219:     VecDestroy(&w);
220:   }

222:   /* In the case of Cayley transform, eigenvectors need to be B-normalized */
223:   PetscTypeCompare((PetscObject)eps->OP,STCAYLEY,&iscayley);
224:   if (iscayley && eps->isgeneralized && eps->ishermitian) {
225:     STGetOperators(eps->OP,PETSC_NULL,&B);
226:     MatGetVecs(B,PETSC_NULL,&w);
227:     if (!eps->evecsavailable) { (*eps->ops->computevectors)(eps); }
228:     for (i=0;i<eps->nconv;i++) {
229:       x = eps->V[i];
230:       MatMult(B,x,w);
231:       VecDot(w,x,&dot);
232:       VecScale(x,1.0/PetscSqrtScalar(dot));
233:     }
234:     VecDestroy(&w);
235:   }

237:   /* sort eigenvalues according to eps->which parameter */
238:   flg = (eps->which == EPS_ALL)? PETSC_TRUE: PETSC_FALSE;
239:   if (flg) eps->which = EPS_SMALLEST_REAL;
240:   EPSSortEigenvalues(eps,eps->nconv,eps->eigr,eps->eigi,eps->perm);
241:   if (flg) eps->which = EPS_ALL;

243:   if (!viewed) {
244:     PetscOptionsGetString(((PetscObject)eps)->prefix,"-eps_view",filename,PETSC_MAX_PATH_LEN,&flg);
245:     if (flg && !PetscPreLoadingOn) {
246:       PetscViewerASCIIOpen(((PetscObject)eps)->comm,filename,&viewer);
247:       EPSView(eps,viewer);
248:       PetscViewerDestroy(&viewer);
249:     }
250:   }

252:   flg = PETSC_FALSE;
253:   PetscOptionsGetBool(((PetscObject)eps)->prefix,"-eps_plot_eigs",&flg,PETSC_NULL);
254:   if (flg) {
255:     PetscViewerDrawOpen(PETSC_COMM_SELF,0,"Computed Eigenvalues",
256:                              PETSC_DECIDE,PETSC_DECIDE,300,300,&viewer);
257:     PetscViewerDrawGetDraw(viewer,0,&draw);
258:     PetscDrawSPCreate(draw,1,&drawsp);
259:     for (i=0;i<eps->nconv;i++) {
260: #if defined(PETSC_USE_COMPLEX)
261:       re = PetscRealPart(eps->eigr[i]);
262:       im = PetscImaginaryPart(eps->eigi[i]);
263: #else
264:       re = eps->eigr[i];
265:       im = eps->eigi[i];
266: #endif
267:       PetscDrawSPAddPoint(drawsp,&re,&im);
268:     }
269:     PetscDrawSPDraw(drawsp);
270:     PetscDrawSPDestroy(&drawsp);
271:     PetscViewerDestroy(&viewer);
272:   }

274:   /* Remove the initial subspaces */
275:   eps->nini = 0;
276:   eps->ninil = 0;
277:   return(0);
278: }

282: /*@
283:    EPSGetIterationNumber - Gets the current iteration number. If the 
284:    call to EPSSolve() is complete, then it returns the number of iterations 
285:    carried out by the solution method.
286:  
287:    Not Collective

289:    Input Parameter:
290: .  eps - the eigensolver context

292:    Output Parameter:
293: .  its - number of iterations

295:    Level: intermediate

297:    Note:
298:    During the i-th iteration this call returns i-1. If EPSSolve() is 
299:    complete, then parameter "its" contains either the iteration number at
300:    which convergence was successfully reached, or failure was detected.  
301:    Call EPSGetConvergedReason() to determine if the solver converged or 
302:    failed and why.

304: .seealso: EPSGetConvergedReason(), EPSSetTolerances()
305: @*/
306: PetscErrorCode EPSGetIterationNumber(EPS eps,PetscInt *its)
307: {
311:   *its = eps->its;
312:   return(0);
313: }

317: /*@
318:    EPSGetOperationCounters - Gets the total number of operator applications,
319:    inner product operations and linear iterations used by the ST object 
320:    during the last EPSSolve() call.

322:    Not Collective

324:    Input Parameter:
325: .  eps - EPS context

327:    Output Parameter:
328: +  ops  - number of operator applications
329: .  dots - number of inner product operations
330: -  lits - number of linear iterations

332:    Notes:
333:    When the eigensolver algorithm invokes STApply() then a linear system 
334:    must be solved (except in the case of standard eigenproblems and shift
335:    transformation). The number of iterations required in this solve is
336:    accumulated into a counter whose value is returned by this function.

338:    These counters are reset to zero at each successive call to EPSSolve().

340:    Level: intermediate

342: @*/
343: PetscErrorCode EPSGetOperationCounters(EPS eps,PetscInt* ops,PetscInt* dots,PetscInt* lits)
344: {

349:   if (!eps->OP) { EPSGetST(eps,&eps->OP); }
350:   STGetOperationCounters(eps->OP,ops,lits);
351:   if (dots) {
352:     if (!eps->ip) { EPSGetIP(eps,&eps->ip); }
353:     IPGetOperationCounters(eps->ip,dots);
354:   }
355:   return(0);
356: }

360: /*@
361:    EPSGetConverged - Gets the number of converged eigenpairs.

363:    Not Collective

365:    Input Parameter:
366: .  eps - the eigensolver context
367:   
368:    Output Parameter:
369: .  nconv - number of converged eigenpairs 

371:    Note:
372:    This function should be called after EPSSolve() has finished.

374:    Level: beginner

376: .seealso: EPSSetDimensions(), EPSSolve()
377: @*/
378: PetscErrorCode EPSGetConverged(EPS eps,PetscInt *nconv)
379: {
383:   *nconv = eps->nconv;
384:   return(0);
385: }


390: /*@C
391:    EPSGetConvergedReason - Gets the reason why the EPSSolve() iteration was 
392:    stopped.

394:    Not Collective

396:    Input Parameter:
397: .  eps - the eigensolver context

399:    Output Parameter:
400: .  reason - negative value indicates diverged, positive value converged

402:    Possible values for reason:
403: +  EPS_CONVERGED_TOL - converged up to tolerance
404: .  EPS_DIVERGED_ITS - required more than its to reach convergence
405: -  EPS_DIVERGED_BREAKDOWN - generic breakdown in method

407:    Note:
408:    Can only be called after the call to EPSSolve() is complete.

410:    Level: intermediate

412: .seealso: EPSSetTolerances(), EPSSolve(), EPSConvergedReason
413: @*/
414: PetscErrorCode EPSGetConvergedReason(EPS eps,EPSConvergedReason *reason)
415: {
419:   *reason = eps->reason;
420:   return(0);
421: }

425: /*@
426:    EPSGetInvariantSubspace - Gets an orthonormal basis of the computed invariant 
427:    subspace.

429:    Not Collective, but vectors are shared by all processors that share the EPS

431:    Input Parameter:
432: .  eps - the eigensolver context
433:   
434:    Output Parameter:
435: .  v - an array of vectors

437:    Notes:
438:    This function should be called after EPSSolve() has finished.

440:    The user should provide in v an array of nconv vectors, where nconv is
441:    the value returned by EPSGetConverged().

443:    The first k vectors returned in v span an invariant subspace associated 
444:    with the first k computed eigenvalues (note that this is not true if the 
445:    k-th eigenvalue is complex and matrix A is real; in this case the first 
446:    k+1 vectors should be used). An invariant subspace X of A satisfies Ax 
447:    in X for all x in X (a similar definition applies for generalized 
448:    eigenproblems). 

450:    Level: intermediate

452: .seealso: EPSGetEigenpair(), EPSGetConverged(), EPSSolve(), EPSGetInvariantSubspaceLeft()
453: @*/
454: PetscErrorCode EPSGetInvariantSubspace(EPS eps,Vec *v)
455: {
457:   PetscInt       i;

463:   if (!eps->V) {
464:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
465:   }
466:   if (!eps->ishermitian && eps->evecsavailable) {
467:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSGetInvariantSubspace must be called before EPSGetEigenpair,EPSGetEigenvector,EPSComputeRelativeError or EPSComputeResidualNorm");
468:   }
469:   if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
470:     for (i=0;i<eps->nconv;i++) {
471:       VecPointwiseDivide(v[i],eps->V[i],eps->D);
472:       VecNormalize(v[i],PETSC_NULL);
473:     }
474:   }
475:   else {
476:     for (i=0;i<eps->nconv;i++) {
477:       VecCopy(eps->V[i],v[i]);
478:     }
479:   }
480:   return(0);
481: }

485: /*@
486:    EPSGetInvariantSubspaceLeft - Gets an orthonormal basis of the computed left
487:    invariant subspace (only available in two-sided eigensolvers).

489:    Not Collective, but vectors are shared by all processors that share the EPS

491:    Input Parameter:
492: .  eps - the eigensolver context
493:   
494:    Output Parameter:
495: .  v - an array of vectors

497:    Notes:
498:    This function should be called after EPSSolve() has finished.

500:    The user should provide in v an array of nconv vectors, where nconv is
501:    the value returned by EPSGetConverged().

503:    The first k vectors returned in v span a left invariant subspace associated 
504:    with the first k computed eigenvalues (note that this is not true if the 
505:    k-th eigenvalue is complex and matrix A is real; in this case the first 
506:    k+1 vectors should be used). A left invariant subspace Y of A satisfies y'A 
507:    in Y for all y in Y (a similar definition applies for generalized 
508:    eigenproblems). 

510:    Level: intermediate

512: .seealso: EPSGetEigenpair(), EPSGetConverged(), EPSSolve(), EPSGetInvariantSubspace
513: @*/
514: PetscErrorCode EPSGetInvariantSubspaceLeft(EPS eps,Vec *v)
515: {
517:   PetscInt       i;

523:   if (!eps->leftvecs) {
524:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
525:   }
526:   if (!eps->W) {
527:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
528:   }
529:   if (!eps->ishermitian && eps->evecsavailable) {
530:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSGetInvariantSubspaceLeft must be called before EPSGetEigenpairLeft,EPSComputeRelativeErrorLeft or EPSComputeResidualNormLeft");
531:   }
532:   for (i=0;i<eps->nconv;i++) {
533:     VecCopy(eps->W[i],v[i]);
534:   }
535:   return(0);
536: }

540: /*@
541:    EPSGetEigenpair - Gets the i-th solution of the eigenproblem as computed by 
542:    EPSSolve(). The solution consists in both the eigenvalue and the eigenvector.

544:    Not Collective, but vectors are shared by all processors that share the EPS

546:    Input Parameters:
547: +  eps - eigensolver context 
548: -  i   - index of the solution

550:    Output Parameters:
551: +  eigr - real part of eigenvalue
552: .  eigi - imaginary part of eigenvalue
553: .  Vr   - real part of eigenvector
554: -  Vi   - imaginary part of eigenvector

556:    Notes:
557:    If the eigenvalue is real, then eigi and Vi are set to zero. If PETSc is 
558:    configured with complex scalars the eigenvalue is stored 
559:    directly in eigr (eigi is set to zero) and the eigenvector in Vr (Vi is 
560:    set to zero).

562:    The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
563:    Eigenpairs are indexed according to the ordering criterion established 
564:    with EPSSetWhichEigenpairs().

566:    The 2-norm of the eigenvector is one unless the problem is generalized 
567:    Hermitian. In this case the eigenvector is normalized with respect to the 
568:    norm defined by the B matrix.

570:    Level: beginner

572: .seealso: EPSGetEigenvalue(), EPSGetEigenvector(), EPSGetEigenvectorLeft(), EPSSolve(), 
573:           EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetInvariantSubspace()
574: @*/
575: PetscErrorCode EPSGetEigenpair(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)
576: {

581:   if (!eps->eigr || !eps->eigi || !eps->V) {
582:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
583:   }
584:   if (i<0 || i>=eps->nconv) {
585:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
586:   }
587:   EPSGetEigenvalue(eps,i,eigr,eigi);
588:   EPSGetEigenvector(eps,i,Vr,Vi);
589:   return(0);
590: }

594: /*@
595:    EPSGetEigenvalue - Gets the i-th eigenvalue as computed by EPSSolve(). 

597:    Not Collective

599:    Input Parameters:
600: +  eps - eigensolver context 
601: -  i   - index of the solution

603:    Output Parameters:
604: +  eigr - real part of eigenvalue
605: -  eigi - imaginary part of eigenvalue

607:    Notes:
608:    If the eigenvalue is real, then eigi is set to zero. If PETSc is 
609:    configured with complex scalars the eigenvalue is stored 
610:    directly in eigr (eigi is set to zero).

612:    The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
613:    Eigenpairs are indexed according to the ordering criterion established 
614:    with EPSSetWhichEigenpairs().

616:    Level: beginner

618: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(), 
619:           EPSGetEigenpair()
620: @*/
621: PetscErrorCode EPSGetEigenvalue(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi)
622: {
623:   PetscInt       k;

627:   if (!eps->eigr || !eps->eigi) {
628:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
629:   }
630:   if (i<0 || i>=eps->nconv) {
631:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
632:   }
633:   if (!eps->perm) k = i;
634:   else k = eps->perm[i];
635: #if defined(PETSC_USE_COMPLEX)
636:   if (eigr) *eigr = eps->eigr[k];
637:   if (eigi) *eigi = 0;
638: #else
639:   if (eigr) *eigr = eps->eigr[k];
640:   if (eigi) *eigi = eps->eigi[k];
641: #endif
642:   return(0);
643: }

647: /*@
648:    EPSGetEigenvector - Gets the i-th right eigenvector as computed by EPSSolve(). 

650:    Not Collective, but vectors are shared by all processors that share the EPS

652:    Input Parameters:
653: +  eps - eigensolver context 
654: -  i   - index of the solution

656:    Output Parameters:
657: +  Vr   - real part of eigenvector
658: -  Vi   - imaginary part of eigenvector

660:    Notes:
661:    If the corresponding eigenvalue is real, then Vi is set to zero. If PETSc is 
662:    configured with complex scalars the eigenvector is stored 
663:    directly in Vr (Vi is set to zero).

665:    The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
666:    Eigenpairs are indexed according to the ordering criterion established 
667:    with EPSSetWhichEigenpairs().

669:    The 2-norm of the eigenvector is one unless the problem is generalized 
670:    Hermitian. In this case the eigenvector is normalized with respect to the 
671:    norm defined by the B matrix.

673:    Level: beginner

675: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(), 
676:           EPSGetEigenpair(), EPSGetEigenvectorLeft()
677: @*/
678: PetscErrorCode EPSGetEigenvector(EPS eps,PetscInt i,Vec Vr,Vec Vi)
679: {
681:   PetscInt       k;

687:   if (!eps->V) {
688:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
689:   }
690:   if (i<0 || i>=eps->nconv) {
691:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
692:   }
693:   if (!eps->evecsavailable && (Vr || Vi)) {
694:     (*eps->ops->computevectors)(eps);
695:   }
696:   if (!eps->perm) k = i;
697:   else k = eps->perm[i];
698: #if defined(PETSC_USE_COMPLEX)
699:   if (Vr) { VecCopy(eps->V[k],Vr); }
700:   if (Vi) { VecSet(Vi,0.0); }
701: #else
702:   if (eps->eigi[k] > 0) { /* first value of conjugate pair */
703:     if (Vr) { VecCopy(eps->V[k],Vr); }
704:     if (Vi) { VecCopy(eps->V[k+1],Vi); }
705:   } else if (eps->eigi[k] < 0) { /* second value of conjugate pair */
706:     if (Vr) { VecCopy(eps->V[k-1],Vr); }
707:     if (Vi) {
708:       VecCopy(eps->V[k],Vi);
709:       VecScale(Vi,-1.0);
710:     }
711:   } else { /* real eigenvalue */
712:     if (Vr) { VecCopy(eps->V[k],Vr); }
713:     if (Vi) { VecSet(Vi,0.0); }
714:   }
715: #endif
716:   return(0);
717: }

721: /*@
722:    EPSGetEigenvectorLeft - Gets the i-th left eigenvector as computed by EPSSolve() 
723:    (only available in two-sided eigensolvers). 

725:    Not Collective, but vectors are shared by all processors that share the EPS

727:    Input Parameters:
728: +  eps - eigensolver context 
729: -  i   - index of the solution

731:    Output Parameters:
732: +  Wr   - real part of eigenvector
733: -  Wi   - imaginary part of eigenvector

735:    Notes:
736:    If the corresponding eigenvalue is real, then Wi is set to zero. If PETSc is 
737:    configured with complex scalars the eigenvector is stored 
738:    directly in Wr (Wi is set to zero).

740:    The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
741:    Eigenpairs are indexed according to the ordering criterion established 
742:    with EPSSetWhichEigenpairs().

744:    Level: beginner

746: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(), 
747:           EPSGetEigenpair(), EPSGetEigenvector()
748: @*/
749: PetscErrorCode EPSGetEigenvectorLeft(EPS eps,PetscInt i,Vec Wr,Vec Wi)
750: {
752:   PetscInt       k;

758:   if (!eps->leftvecs) {
759:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
760:   }
761:   if (!eps->W) {
762:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
763:   }
764:   if (i<0 || i>=eps->nconv) {
765:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
766:   }
767:   if (!eps->evecsavailable && (Wr || Wi)) {
768:     (*eps->ops->computevectors)(eps);
769:   }
770:   if (!eps->perm) k = i;
771:   else k = eps->perm[i];
772: #if defined(PETSC_USE_COMPLEX)
773:   if (Wr) { VecCopy(eps->W[k],Wr); }
774:   if (Wi) { VecSet(Wi,0.0); }
775: #else
776:   if (eps->eigi[k] > 0) { /* first value of conjugate pair */
777:     if (Wr) { VecCopy(eps->W[k],Wr); }
778:     if (Wi) { VecCopy(eps->W[k+1],Wi); }
779:   } else if (eps->eigi[k] < 0) { /* second value of conjugate pair */
780:     if (Wr) { VecCopy(eps->W[k-1],Wr); }
781:     if (Wi) {
782:       VecCopy(eps->W[k],Wi);
783:       VecScale(Wi,-1.0);
784:     }
785:   } else { /* real eigenvalue */
786:     if (Wr) { VecCopy(eps->W[k],Wr); }
787:     if (Wi) { VecSet(Wi,0.0); }
788:   }
789: #endif
790:   return(0);
791: }

795: /*@
796:    EPSGetErrorEstimate - Returns the error estimate associated to the i-th 
797:    computed eigenpair.

799:    Not Collective

801:    Input Parameter:
802: +  eps - eigensolver context 
803: -  i   - index of eigenpair

805:    Output Parameter:
806: .  errest - the error estimate

808:    Notes:
809:    This is the error estimate used internally by the eigensolver. The actual
810:    error bound can be computed with EPSComputeRelativeError(). See also the users
811:    manual for details.

813:    Level: advanced

815: .seealso: EPSComputeRelativeError()
816: @*/
817: PetscErrorCode EPSGetErrorEstimate(EPS eps,PetscInt i,PetscReal *errest)
818: {
822:   if (!eps->eigr || !eps->eigi) {
823:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
824:   }
825:   if (i<0 || i>=eps->nconv) {
826:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
827:   }
828:   if (eps->perm) i = eps->perm[i];
829:   if (errest) *errest = eps->errest[i];
830:   return(0);
831: }

835: /*@
836:    EPSGetErrorEstimateLeft - Returns the left error estimate associated to the i-th 
837:    computed eigenpair (only available in two-sided eigensolvers).

839:    Not Collective

841:    Input Parameter:
842: +  eps - eigensolver context 
843: -  i   - index of eigenpair

845:    Output Parameter:
846: .  errest - the left error estimate

848:    Notes:
849:    This is the error estimate used internally by the eigensolver. The actual
850:    error bound can be computed with EPSComputeRelativeErrorLeft(). See also the users
851:    manual for details.

853:    Level: advanced

855: .seealso: EPSComputeRelativeErrorLeft()
856: @*/
857: PetscErrorCode EPSGetErrorEstimateLeft(EPS eps,PetscInt i,PetscReal *errest)
858: {
862:   if (!eps->eigr || !eps->eigi) {
863:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
864:   }
865:   if (!eps->leftvecs) {
866:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
867:   }
868:   if (i<0 || i>=eps->nconv) {
869:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
870:   }
871:   if (eps->perm) i = eps->perm[i];
872:   if (errest) *errest = eps->errest_left[i];
873:   return(0);
874: }

878: /*
879:    EPSComputeResidualNorm_Private - Computes the norm of the residual vector 
880:    associated with an eigenpair.
881: */
882: PetscErrorCode EPSComputeResidualNorm_Private(EPS eps,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,PetscReal *norm)
883: {
885:   Vec            u,w;
886:   Mat            A,B;
887: #if !defined(PETSC_USE_COMPLEX)
888:   Vec            v;
889:   PetscReal      ni,nr;
890: #endif
891: 
893:   STGetOperators(eps->OP,&A,&B);
894:   VecDuplicate(eps->V[0],&u);
895:   VecDuplicate(eps->V[0],&w);
896: 
897: #if !defined(PETSC_USE_COMPLEX)
898:   if (ki == 0 ||
899:     PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
900: #endif
901:     MatMult(A,xr,u);                             /* u=A*x */
902:     if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
903:       if (eps->isgeneralized) { MatMult(B,xr,w); }
904:       else { VecCopy(xr,w); }                    /* w=B*x */
905:       VecAXPY(u,-kr,w);                          /* u=A*x-k*B*x */
906:     }
907:     VecNorm(u,NORM_2,norm);
908: #if !defined(PETSC_USE_COMPLEX)
909:   } else {
910:     VecDuplicate(eps->V[0],&v);
911:     MatMult(A,xr,u);                             /* u=A*xr */
912:     if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
913:       if (eps->isgeneralized) { MatMult(B,xr,v); }
914:       else { VecCopy(xr,v); }                    /* v=B*xr */
915:       VecAXPY(u,-kr,v);                          /* u=A*xr-kr*B*xr */
916:       if (eps->isgeneralized) { MatMult(B,xi,w); }
917:       else { VecCopy(xi,w); }                    /* w=B*xi */
918:       VecAXPY(u,ki,w);                           /* u=A*xr-kr*B*xr+ki*B*xi */
919:     }
920:     VecNorm(u,NORM_2,&nr);
921:     MatMult(A,xi,u);                             /* u=A*xi */
922:     if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
923:       VecAXPY(u,-kr,w);                          /* u=A*xi-kr*B*xi */
924:       VecAXPY(u,-ki,v);                          /* u=A*xi-kr*B*xi-ki*B*xr */
925:     }
926:     VecNorm(u,NORM_2,&ni);
927:     *norm = SlepcAbsEigenvalue(nr,ni);
928:     VecDestroy(&v);
929:   }
930: #endif

932:   VecDestroy(&w);
933:   VecDestroy(&u);
934:   return(0);
935: }

939: /*@
940:    EPSComputeResidualNorm - Computes the norm of the residual vector associated with 
941:    the i-th computed eigenpair.

943:    Collective on EPS

945:    Input Parameter:
946: .  eps - the eigensolver context
947: .  i   - the solution index

949:    Output Parameter:
950: .  norm - the residual norm, computed as ||Ax-kBx||_2 where k is the 
951:    eigenvalue and x is the eigenvector. 
952:    If k=0 then the residual norm is computed as ||Ax||_2.

954:    Notes:
955:    The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
956:    Eigenpairs are indexed according to the ordering criterion established 
957:    with EPSSetWhichEigenpairs().

959:    Level: beginner

961: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs()
962: @*/
963: PetscErrorCode EPSComputeResidualNorm(EPS eps,PetscInt i,PetscReal *norm)
964: {
966:   Vec            xr,xi;
967:   PetscScalar    kr,ki;
968: 
973:   VecDuplicate(eps->V[0],&xr);
974:   VecDuplicate(eps->V[0],&xi);
975:   EPSGetEigenpair(eps,i,&kr,&ki,xr,xi);
976:   EPSComputeResidualNorm_Private(eps,kr,ki,xr,xi,norm);
977:   VecDestroy(&xr);
978:   VecDestroy(&xi);
979:   return(0);
980: }

984: /*@
985:    EPSComputeResidualNormLeft - Computes the norm of the residual vector associated with 
986:    the i-th computed left eigenvector (only available in two-sided eigensolvers).

988:    Collective on EPS

990:    Input Parameter:
991: .  eps - the eigensolver context
992: .  i   - the solution index

994:    Output Parameter:
995: .  norm - the residual norm, computed as ||y'A-ky'B||_2 where k is the 
996:    eigenvalue and y is the left eigenvector. 
997:    If k=0 then the residual norm is computed as ||y'A||_2.

999:    Notes:
1000:    The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
1001:    Eigenpairs are indexed according to the ordering criterion established 
1002:    with EPSSetWhichEigenpairs().

1004:    Level: beginner

1006: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs()
1007: @*/
1008: PetscErrorCode EPSComputeResidualNormLeft(EPS eps,PetscInt i,PetscReal *norm)
1009: {
1011:   Vec            u,v,w,xr,xi;
1012:   Mat            A,B;
1013:   PetscScalar    kr,ki;
1014: #if !defined(PETSC_USE_COMPLEX)
1015:   PetscReal      ni,nr;
1016: #endif
1017: 
1022:   if (!eps->leftvecs) {
1023:     SETERRQ(((PetscObject)eps)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
1024:   }
1025:   STGetOperators(eps->OP,&A,&B);
1026:   VecDuplicate(eps->W[0],&u);
1027:   VecDuplicate(eps->W[0],&v);
1028:   VecDuplicate(eps->W[0],&w);
1029:   VecDuplicate(eps->W[0],&xr);
1030:   VecDuplicate(eps->W[0],&xi);
1031:   EPSGetEigenvalue(eps,i,&kr,&ki);
1032:   EPSGetEigenvectorLeft(eps,i,xr,xi);

1034: #if !defined(PETSC_USE_COMPLEX)
1035:   if (ki == 0 ||
1036:     PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
1037: #endif
1038:     MatMultTranspose(A,xr,u); /* u=A'*x */
1039:     if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
1040:       if (eps->isgeneralized) { MatMultTranspose(B,xr,w); }
1041:       else { VecCopy(xr,w); } /* w=B'*x */
1042:       VecAXPY(u,-kr,w); /* u=A'*x-k*B'*x */
1043:     }
1044:     VecNorm(u,NORM_2,norm);
1045: #if !defined(PETSC_USE_COMPLEX)
1046:   } else {
1047:     MatMultTranspose(A,xr,u); /* u=A'*xr */
1048:     if (eps->isgeneralized) { MatMultTranspose(B,xr,v); }
1049:     else { VecCopy(xr,v); } /* v=B'*xr */
1050:     VecAXPY(u,-kr,v); /* u=A'*xr-kr*B'*xr */
1051:     if (eps->isgeneralized) { MatMultTranspose(B,xi,w); }
1052:     else { VecCopy(xi,w); } /* w=B'*xi */
1053:     VecAXPY(u,ki,w); /* u=A'*xr-kr*B'*xr+ki*B'*xi */
1054:     VecNorm(u,NORM_2,&nr);
1055:     MatMultTranspose(A,xi,u); /* u=A'*xi */
1056:     VecAXPY(u,-kr,w); /* u=A'*xi-kr*B'*xi */
1057:     VecAXPY(u,-ki,v); /* u=A'*xi-kr*B'*xi-ki*B'*xr */
1058:     VecNorm(u,NORM_2,&ni);
1059:     *norm = SlepcAbsEigenvalue(nr,ni);
1060:   }
1061: #endif

1063:   VecDestroy(&w);
1064:   VecDestroy(&v);
1065:   VecDestroy(&u);
1066:   VecDestroy(&xr);
1067:   VecDestroy(&xi);
1068:   return(0);
1069: }

1073: /*
1074:    EPSComputeRelativeError_Private - Computes the relative error bound 
1075:    associated with an eigenpair.
1076: */
1077: PetscErrorCode EPSComputeRelativeError_Private(EPS eps,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,PetscReal *error)
1078: {
1080:   PetscReal      norm,er;
1081: #if !defined(PETSC_USE_COMPLEX)
1082:   PetscReal      ei;
1083: #endif
1084: 
1086:   EPSComputeResidualNorm_Private(eps,kr,ki,xr,xi,&norm);

1088: #if !defined(PETSC_USE_COMPLEX)
1089:   if (ki == 0) {
1090: #endif
1091:     VecNorm(xr,NORM_2,&er);
1092: #if !defined(PETSC_USE_COMPLEX)
1093:   } else {
1094:     VecNorm(xr,NORM_2,&er);
1095:     VecNorm(xi,NORM_2,&ei);
1096:     er = SlepcAbsEigenvalue(er,ei);
1097:   }
1098: #endif    
1099:   (*eps->conv_func)(eps,kr,ki,norm/er,error,eps->conv_ctx);
1100:   return(0);
1101: }

1105: /*@
1106:    EPSComputeRelativeError - Computes the relative error bound associated 
1107:    with the i-th computed eigenpair.

1109:    Collective on EPS

1111:    Input Parameter:
1112: .  eps - the eigensolver context
1113: .  i   - the solution index

1115:    Output Parameter:
1116: .  error - the relative error bound, computed as ||Ax-kBx||_2/||kx||_2 where 
1117:    k is the eigenvalue and x is the eigenvector. 
1118:    If k=0 the relative error is computed as ||Ax||_2/||x||_2.

1120:    Level: beginner

1122: .seealso: EPSSolve(), EPSComputeResidualNorm(), EPSGetErrorEstimate()
1123: @*/
1124: PetscErrorCode EPSComputeRelativeError(EPS eps,PetscInt i,PetscReal *error)
1125: {
1127:   Vec            xr,xi;
1128:   PetscScalar    kr,ki;
1129: 
1134:   VecDuplicate(eps->V[0],&xr);
1135:   VecDuplicate(eps->V[0],&xi);
1136:   EPSGetEigenpair(eps,i,&kr,&ki,xr,xi);
1137:   EPSComputeRelativeError_Private(eps,kr,ki,xr,xi,error);
1138:   VecDestroy(&xr);
1139:   VecDestroy(&xi);
1140:   return(0);
1141: }

1145: /*@
1146:    EPSComputeRelativeErrorLeft - Computes the relative error bound associated 
1147:    with the i-th computed eigenvalue and left eigenvector (only available in
1148:    two-sided eigensolvers).

1150:    Collective on EPS

1152:    Input Parameter:
1153: .  eps - the eigensolver context
1154: .  i   - the solution index

1156:    Output Parameter:
1157: .  error - the relative error bound, computed as ||y'A-ky'B||_2/||ky||_2 where 
1158:    k is the eigenvalue and y is the left eigenvector. 
1159:    If k=0 the relative error is computed as ||y'A||_2/||y||_2.

1161:    Level: beginner

1163: .seealso: EPSSolve(), EPSComputeResidualNormLeft(), EPSGetErrorEstimateLeft()
1164: @*/
1165: PetscErrorCode EPSComputeRelativeErrorLeft(EPS eps,PetscInt i,PetscReal *error)
1166: {
1168:   Vec            xr,xi;
1169:   PetscScalar    kr,ki;
1170:   PetscReal      norm,er;
1171: #if !defined(PETSC_USE_COMPLEX)
1172:   Vec            u;
1173:   PetscReal      ei;
1174: #endif
1175: 
1178:   EPSComputeResidualNormLeft(eps,i,&norm);
1181:   VecDuplicate(eps->W[0],&xr);
1182:   VecDuplicate(eps->W[0],&xi);
1183:   EPSGetEigenvalue(eps,i,&kr,&ki);
1184:   EPSGetEigenvectorLeft(eps,i,xr,xi);

1186: #if !defined(PETSC_USE_COMPLEX)
1187:   if (ki == 0 ||
1188:     PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
1189: #endif
1190:     VecNorm(xr,NORM_2,&er);
1191:     if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
1192:       *error =  norm / (PetscAbsScalar(kr) * er);
1193:     } else {
1194:       *error = norm / er;
1195:     }
1196: #if !defined(PETSC_USE_COMPLEX)
1197:   } else {
1198:     VecDuplicate(xi,&u);
1199:     VecCopy(xi,u);
1200:     VecAXPBY(u,kr,-ki,xr);
1201:     VecNorm(u,NORM_2,&er);
1202:     VecAXPBY(xi,kr,ki,xr);
1203:     VecNorm(xi,NORM_2,&ei);
1204:     VecDestroy(&u);
1205:     *error = norm / SlepcAbsEigenvalue(er,ei);
1206:   }
1207: #endif    
1208: 
1209:   VecDestroy(&xr);
1210:   VecDestroy(&xi);
1211:   return(0);
1212: }

1214: #define SWAP(a,b,t) {t=a;a=b;b=t;}

1218: /*@
1219:    EPSSortEigenvalues - Sorts a list of eigenvalues according to the criterion 
1220:    specified via EPSSetWhichEigenpairs().

1222:    Not Collective

1224:    Input Parameters:
1225: +  eps   - the eigensolver context
1226: .  n     - number of eigenvalues in the list
1227: .  eigr  - pointer to the array containing the eigenvalues
1228: -  eigi  - imaginary part of the eigenvalues (only when using real numbers)

1230:    Output Parameter:
1231: .  perm  - resulting permutation

1233:    Note:
1234:    The result is a list of indices in the original eigenvalue array 
1235:    corresponding to the first nev eigenvalues sorted in the specified
1236:    criterion.

1238:    Level: developer

1240: .seealso: EPSSortEigenvaluesReal(), EPSSetWhichEigenpairs()
1241: @*/
1242: PetscErrorCode EPSSortEigenvalues(EPS eps,PetscInt n,PetscScalar *eigr,PetscScalar *eigi,PetscInt *perm)
1243: {
1245:   PetscScalar    re,im;
1246:   PetscInt       i,j,result,tmp;

1253:   for (i=0; i<n; i++) { perm[i] = i; }
1254:   /* insertion sort */
1255:   for (i=n-1; i>=0; i--) {
1256:     re = eigr[perm[i]];
1257:     im = eigi[perm[i]];
1258:     j = i + 1;
1259: #if !defined(PETSC_USE_COMPLEX)
1260:     if (im != 0) {
1261:       /* complex eigenvalue */
1262:       i--;
1263:       im = eigi[perm[i]];
1264:     }
1265: #endif
1266:     while (j<n) {
1267:       EPSCompareEigenvalues(eps,re,im,eigr[perm[j]],eigi[perm[j]],&result);
1268:       if (result < 0) break;
1269: #if !defined(PETSC_USE_COMPLEX)
1270:       /* keep together every complex conjugated eigenpair */
1271:       if (im == 0) {
1272:         if (eigi[perm[j]] == 0) {
1273: #endif
1274:           tmp = perm[j-1]; perm[j-1] = perm[j]; perm[j] = tmp;
1275:           j++;
1276: #if !defined(PETSC_USE_COMPLEX)
1277:         } else {
1278:           tmp = perm[j-1]; perm[j-1] = perm[j]; perm[j] = perm[j+1]; perm[j+1] = tmp;
1279:           j+=2;
1280:         }
1281:       } else {
1282:         if (eigi[perm[j]] == 0) {
1283:           tmp = perm[j-2]; perm[j-2] = perm[j]; perm[j] = perm[j-1]; perm[j-1] = tmp;
1284:           j++;
1285:         } else {
1286:           tmp = perm[j-2]; perm[j-2] = perm[j]; perm[j] = tmp;
1287:           tmp = perm[j-1]; perm[j-1] = perm[j+1]; perm[j+1] = tmp;
1288:           j+=2;
1289:         }
1290:       }
1291: #endif
1292:     }
1293:   }
1294:   return(0);
1295: }

1299: /*@
1300:    EPSSortEigenvaluesReal - Sorts a list of eigenvalues according to a certain
1301:    criterion (version for real eigenvalues only).

1303:    Not Collective

1305:    Input Parameters:
1306: +  eps   - the eigensolver context
1307: .  n     - number of eigenvalue in the list
1308: -  eig   - pointer to the array containing the eigenvalues (real)

1310:    Output Parameter:
1311: .  perm  - resulting permutation

1313:    Note:
1314:    The result is a list of indices in the original eigenvalue array 
1315:    corresponding to the first nev eigenvalues sorted in the specified
1316:    criterion.

1318:    Level: developer

1320: .seealso: EPSSortEigenvalues(), EPSSetWhichEigenpairs(), EPSCompareEigenvalues()
1321: @*/
1322: PetscErrorCode EPSSortEigenvaluesReal(EPS eps,PetscInt n,PetscReal *eig,PetscInt *perm)
1323: {
1325:   PetscScalar    re;
1326:   PetscInt       i,j,result,tmp;

1332:   for (i=0; i<n; i++) { perm[i] = i; }
1333:   /* insertion sort */
1334:   for (i=1; i<n; i++) {
1335:     re = eig[perm[i]];
1336:     j = i-1;
1337:     EPSCompareEigenvalues(eps,re,0.0,eig[perm[j]],0.0,&result);
1338:     while (result<=0 && j>=0) {
1339:       tmp = perm[j]; perm[j] = perm[j+1]; perm[j+1] = tmp; j--;
1340:       if (j>=0) {
1341:         EPSCompareEigenvalues(eps,re,0.0,eig[perm[j]],0.0,&result);
1342:       }
1343:     }
1344:   }
1345:   return(0);
1346: }

1350: /*@
1351:    EPSCompareEigenvalues - Compares two (possibly complex) eigenvalues according
1352:    to a certain criterion.

1354:    Not Collective

1356:    Input Parameters:
1357: +  eps   - the eigensolver context
1358: .  ar     - real part of the 1st eigenvalue
1359: .  ai     - imaginary part of the 1st eigenvalue
1360: .  br     - real part of the 2nd eigenvalue
1361: -  bi     - imaginary part of the 2nd eigenvalue

1363:    Output Parameter:
1364: .  res    - result of comparison

1366:    Notes:
1367:    The returning parameter 'res' can be:
1368: +  negative - if the 1st eigenvalue is preferred to the 2st one
1369: .  zero     - if both eigenvalues are equally preferred
1370: -  positive - if the 2st eigenvalue is preferred to the 1st one

1372:    The criterion of comparison is related to the 'which' parameter set with
1373:    EPSSetWhichEigenpairs().

1375:    Level: developer

1377: .seealso: EPSSortEigenvalues(), EPSSetWhichEigenpairs()
1378: @*/
1379: PetscErrorCode EPSCompareEigenvalues(EPS eps,PetscScalar ar,PetscScalar ai,PetscScalar br,PetscScalar bi,PetscInt *result)
1380: {
1382:   PetscReal      a,b;

1387:   switch(eps->which) {
1388:     case EPS_WHICH_USER:
1389:       if (!eps->which_func) SETERRQ(((PetscObject)eps)->comm,1,"Undefined eigenvalue comparison function");
1390:       (*eps->which_func)(eps,ar,ai,br,bi,result,eps->which_ctx);
1391:       a = 0.0; b = 0.0;
1392:       break;
1393:     case EPS_LARGEST_MAGNITUDE:
1394:     case EPS_SMALLEST_MAGNITUDE:
1395:       a = SlepcAbsEigenvalue(ar,ai);
1396:       b = SlepcAbsEigenvalue(br,bi);
1397:       break;
1398:     case EPS_LARGEST_REAL:
1399:     case EPS_SMALLEST_REAL:
1400:       a = PetscRealPart(ar);
1401:       b = PetscRealPart(br);
1402:       break;
1403:     case EPS_LARGEST_IMAGINARY:
1404:     case EPS_SMALLEST_IMAGINARY:
1405: #if defined(PETSC_USE_COMPLEX)
1406:       a = PetscImaginaryPart(ar);
1407:       b = PetscImaginaryPart(br);
1408: #else
1409:       a = PetscAbsReal(ai);
1410:       b = PetscAbsReal(bi);
1411: #endif
1412:       break;
1413:     case EPS_TARGET_MAGNITUDE:
1414:       /* complex target only allowed if scalartype=complex */
1415:       a = SlepcAbsEigenvalue(ar-eps->target,ai);
1416:       b = SlepcAbsEigenvalue(br-eps->target,bi);
1417:       break;
1418:     case EPS_TARGET_REAL:
1419:       a = PetscAbsReal(PetscRealPart(ar-eps->target));
1420:       b = PetscAbsReal(PetscRealPart(br-eps->target));
1421:       break;
1422:     case EPS_TARGET_IMAGINARY:
1423: #if !defined(PETSC_USE_COMPLEX)
1424:       /* complex target only allowed if scalartype=complex */
1425:       a = PetscAbsReal(ai);
1426:       b = PetscAbsReal(bi);
1427: #else
1428:       a = PetscAbsReal(PetscImaginaryPart(ar-eps->target));
1429:       b = PetscAbsReal(PetscImaginaryPart(br-eps->target));
1430: #endif
1431:       break;
1432:     default: SETERRQ(((PetscObject)eps)->comm,1,"Wrong value of which");
1433:   }
1434:   switch(eps->which) {
1435:     case EPS_WHICH_USER:
1436:       break;
1437:     case EPS_LARGEST_MAGNITUDE:
1438:     case EPS_LARGEST_REAL:
1439:     case EPS_LARGEST_IMAGINARY:
1440:       if (a<b) *result = 1;
1441:       else if (a>b) *result = -1;
1442:       else *result = 0;
1443:       break;
1444:     default:
1445:       if (a>b) *result = 1;
1446:       else if (a<b) *result = -1;
1447:       else *result = 0;
1448:   }
1449:   return(0);
1450: }

1454: /*@
1455:    EPSGetStartVector - Gets a suitable vector to be used as the starting vector
1456:    for the recurrence that builds the right subspace.

1458:    Collective on EPS and Vec

1460:    Input Parameters:
1461: +  eps - the eigensolver context
1462: -  i   - iteration number

1464:    Output Parameters:
1465: +  vec - the start vector
1466: -  breakdown - flag indicating that a breakdown has occurred

1468:    Notes:
1469:    The start vector is computed from another vector: for the first step (i=0),
1470:    the first initial vector is used (see EPSSetInitialSpace()); otherwise a random
1471:    vector is created. Then this vector is forced to be in the range of OP (only
1472:    for generalized definite problems) and orthonormalized with respect to all
1473:    V-vectors up to i-1.

1475:    The flag breakdown is set to true if either i=0 and the vector belongs to the
1476:    deflation space, or i>0 and the vector is linearly dependent with respect
1477:    to the V-vectors.

1479:    The caller must pass a vector already allocated with dimensions conforming
1480:    to the initial vector. This vector is overwritten.

1482:    Level: developer

1484: .seealso: EPSSetInitialSpace()
1485: @*/
1486: PetscErrorCode EPSGetStartVector(EPS eps,PetscInt i,Vec vec,PetscBool *breakdown)
1487: {
1489:   PetscReal      norm;
1490:   PetscBool      lindep;
1491:   Vec            w;
1492: 

1499:   VecDuplicate(eps->V[0],&w);

1501:   /* For the first step, use the first initial vector, otherwise a random one */
1502:   if (i==0 && eps->nini>0) {
1503:     VecCopy(eps->V[0],w);
1504:   } else {
1505:     SlepcVecSetRandom(w,eps->rand);
1506:   }

1508:   /* Force the vector to be in the range of OP for definite generalized problems */
1509:   if (eps->ispositive) {
1510:     STApply(eps->OP,w,vec);
1511:   } else {
1512:     VecCopy(w,vec);
1513:   }

1515:   /* Orthonormalize the vector with respect to previous vectors */
1516:   IPOrthogonalize(eps->ip,eps->nds,eps->DS,i,PETSC_NULL,eps->V,vec,PETSC_NULL,&norm,&lindep);
1517:   if (breakdown) *breakdown = lindep;
1518:   else if (lindep || norm == 0.0) {
1519:     if (i==0) { SETERRQ(((PetscObject)eps)->comm,1,"Initial vector is zero or belongs to the deflation space"); }
1520:     else { SETERRQ(((PetscObject)eps)->comm,1,"Unable to generate more start vectors"); }
1521:   }
1522:   VecScale(vec,1.0/norm);

1524:   VecDestroy(&w);
1525:   return(0);
1526: }

1530: /*@
1531:    EPSGetStartVectorLeft - Gets a suitable vector to be used as the starting vector
1532:    in the recurrence that builds the left subspace (in methods that work with two
1533:    subspaces).

1535:    Collective on EPS and Vec

1537:    Input Parameters:
1538: +  eps - the eigensolver context
1539: -  i   - iteration number

1541:    Output Parameter:
1542: +  vec - the start vector
1543: -  breakdown - flag indicating that a breakdown has occurred

1545:    Notes:
1546:    The start vector is computed from another vector: for the first step (i=0),
1547:    the first left initial vector is used (see EPSSetInitialSpaceLeft()); otherwise 
1548:    a random vector is created. Then this vector is forced to be in the range 
1549:    of OP' and orthonormalized with respect to all W-vectors up to i-1.

1551:    The flag breakdown is set to true if i>0 and the vector is linearly dependent
1552:    with respect to the W-vectors.

1554:    The caller must pass a vector already allocated with dimensions conforming
1555:    to the left initial vector. This vector is overwritten.

1557:    Level: developer

1559: .seealso: EPSSetInitialSpaceLeft()

1561: @*/
1562: PetscErrorCode EPSGetStartVectorLeft(EPS eps,PetscInt i,Vec vec,PetscBool *breakdown)
1563: {
1565:   PetscReal      norm;
1566:   PetscBool      lindep;
1567:   Vec            w;
1568: 

1575:   VecDuplicate(eps->W[0],&w);

1577:   /* For the first step, use the first initial left vector, otherwise a random one */
1578:   if (i==0 && eps->ninil>0) {
1579:     VecCopy(eps->W[0],w);
1580:   } else {
1581:     SlepcVecSetRandom(w,eps->rand);
1582:   }

1584:   /* Force the vector to be in the range of OP' */
1585:   STApplyTranspose(eps->OP,w,vec);

1587:   /* Orthonormalize the vector with respect to previous vectors */
1588:   IPOrthogonalize(eps->ip,0,PETSC_NULL,i,PETSC_NULL,eps->W,vec,PETSC_NULL,&norm,&lindep);
1589:   if (breakdown) *breakdown = lindep;
1590:   else if (lindep || norm == 0.0) {
1591:     if (i==0) { SETERRQ(((PetscObject)eps)->comm,1,"Left initial vector is zero"); }
1592:     else { SETERRQ(((PetscObject)eps)->comm,1,"Unable to generate more left start vectors"); }
1593:   }
1594:   VecScale(vec,1/norm);

1596:   VecDestroy(&w);
1597:   return(0);
1598: }